diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2021-07-24 17:32:28 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2021-07-24 17:32:28 +0300 |
commit | 9bff211ac9e38de090ac2cddd2bbe9636443af6f (patch) | |
tree | cfea5324a6b776729b5520ea007bfb9200e30eec | |
parent | 23209dc8f9aedf90ddf4cc53d7170d38ddaeb5d7 (diff) | |
parent | 05c7d935e77025b87c5593dcbae38de42ed5a3ce (diff) |
Merge branch 'master' into node-group-single-socket-nodes
467 files changed, 10366 insertions, 5567 deletions
diff --git a/build_files/cmake/cmake_netbeans_project.py b/build_files/cmake/cmake_netbeans_project.py index cfc3ff6b6fa..a16fc42c9b7 100755 --- a/build_files/cmake/cmake_netbeans_project.py +++ b/build_files/cmake/cmake_netbeans_project.py @@ -82,7 +82,7 @@ def create_nb_project_main(): make_exe = cmake_cache_var("CMAKE_MAKE_PROGRAM") make_exe_basename = os.path.basename(make_exe) - # --------------- NB specific + # --------------- NetBeans specific. defines = [("%s=%s" % cdef) if cdef[1] else cdef[0] for cdef in defines] defines += [cdef.replace("#define", "").strip() for cdef in cmake_compiler_defines()] diff --git a/doc/manpage/blender.1.py b/doc/manpage/blender.1.py index 950a2119f91..020bab05a21 100755 --- a/doc/manpage/blender.1.py +++ b/doc/manpage/blender.1.py @@ -122,7 +122,7 @@ is a full-featured 3D application. It supports the entirety of the 3D pipeline - '''modeling, rigging, animation, simulation, rendering, compositing, motion tracking, and video editing. Use Blender to create 3D images and animations, films and commercials, content for games, ''' -r'''architectural and industrial visualizatons, and scientific visualizations. +r'''architectural and industrial visualizations, and scientific visualizations. https://www.blender.org''') diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 4be27e0f0e8..d6c1d7b51b8 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -1047,6 +1047,7 @@ context_type_map = { "annotation_data": ("GreasePencil", False), "annotation_data_owner": ("ID", False), "armature": ("Armature", False), + "asset_library": ("AssetLibraryReference", False), "bone": ("Bone", False), "brush": ("Brush", False), "camera": ("Camera", False), @@ -1113,6 +1114,7 @@ context_type_map = { "texture_slot": ("MaterialTextureSlot", False), "texture_user": ("ID", False), "texture_user_property": ("Property", False), + "ui_list": ("UIList", False), "vertex_paint_object": ("Object", False), "view_layer": ("ViewLayer", False), "visible_bones": ("EditBone", True), diff --git a/extern/rangetree/intern/generic_alloc_impl.h b/extern/rangetree/intern/generic_alloc_impl.h index 0f9f5184637..fd6e85a155a 100644 --- a/extern/rangetree/intern/generic_alloc_impl.h +++ b/extern/rangetree/intern/generic_alloc_impl.h @@ -32,7 +32,7 @@ * - #TPOOL_STRUCT: Name for pool struct name. * - #TPOOL_CHUNK_SIZE: Chunk size (optional), use 64kb when not defined. * - * \note #TPOOL_ALLOC_TYPE must be at least ``sizeof(void *)``. + * \note #TPOOL_ALLOC_TYPE must be at least `sizeof(void *)`. * * Defines the API, uses #TPOOL_IMPL_PREFIX to prefix each function. * diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 30892cdbbc0..058528aeff5 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1136,7 +1136,7 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel): col = row.column(align=True) col.operator("object.material_slot_add", icon='ADD', text="") col.operator("object.material_slot_remove", icon='REMOVE', text="") - + col.separator() col.menu("MATERIAL_MT_context_menu", icon='DOWNARROW_HLT', text="") if is_sortable: @@ -1151,16 +1151,15 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel): row.operator("object.material_slot_select", text="Select") row.operator("object.material_slot_deselect", text="Deselect") - split = layout.split(factor=0.65) + row = layout.row() if ob: - split.template_ID(ob, "active_material", new="material.new") - row = split.row() + row.template_ID(ob, "active_material", new="material.new") if slot: - row.prop(slot, "link", text="") - else: - row.label() + icon_link = 'MESH_DATA' if slot.link == 'DATA' else 'OBJECT_DATA' + row.prop(slot, "link", text="", icon=icon_link, icon_only=True) + elif mat: split.template_ID(space, "pin_id") split.separator() diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index 9bd6e3a5e2d..7dc79f48145 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -993,7 +993,7 @@ void OSLCompiler::parameter_array(const char *name, const float f[], int arrayle void OSLCompiler::parameter_color_array(const char *name, const array<float3> &f) { - /* NB: cycles float3 type is actually 4 floats! need to use an explicit array */ + /* NOTE: cycles float3 type is actually 4 floats! need to use an explicit array. */ array<float[3]> table(f.size()); for (int i = 0; i < f.size(); ++i) { diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index db3f9bd561e..3dec4f4a7d1 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -628,7 +628,7 @@ extern void GHOST_ScreenToClient( GHOST_WindowHandle windowhandle, int32_t inX, int32_t inY, int32_t *outX, int32_t *outY); /** - * Converts a point in screen coordinates to client rectangle coordinates + * Converts a point in client rectangle coordinates to screen coordinates. * \param windowhandle: The handle to the window. * \param inX: The x-coordinate in the client rectangle. * \param inY: The y-coordinate in the client rectangle. diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index f870791b345..5f9bd808c8c 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -133,7 +133,7 @@ class GHOST_IWindow { virtual void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const = 0; /** - * Converts a point in screen coordinates to client rectangle coordinates + * Converts a point in client rectangle coordinates to screen coordinates. * \param inX: The x-coordinate in the client rectangle. * \param inY: The y-coordinate in the client rectangle. * \param outX: The x-coordinate on the screen. diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index ff93de4f203..ddebfa7e816 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -683,6 +683,10 @@ typedef struct GHOST_XrDrawViewInfo { /** Set if the buffer should be submitted with a SRGB transfer applied. */ char expects_srgb_buffer; + + /** The view that this info represents. Not necessarily the "eye index" (e.g. for quad view + * systems, etc). */ + char view_idx; } GHOST_XrDrawViewInfo; typedef struct GHOST_XrError { diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm index 687173ded09..7af243846c2 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.mm +++ b/intern/ghost/intern/GHOST_ContextCGL.mm @@ -217,7 +217,7 @@ static void makeAttribList(std::vector<NSOpenGLPixelFormatAttribute> &attribs, attribs.push_back(NSOpenGLPFAOpenGLProfile); attribs.push_back(coreProfile ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy); - // Pixel Format Attributes for the windowed NSOpenGLContext + /* Pixel Format Attributes for the windowed NSOpenGLContext. */ attribs.push_back(NSOpenGLPFADoubleBuffer); if (softwareGL) { @@ -250,7 +250,8 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext() static const bool needAlpha = false; #endif - static bool softwareGL = getenv("BLENDER_SOFTWAREGL"); // command-line argument would be better + /* Command-line argument would be better. */ + static bool softwareGL = getenv("BLENDER_SOFTWAREGL"); std::vector<NSOpenGLPixelFormatAttribute> attribs; attribs.reserve(40); @@ -287,7 +288,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext() if (m_metalView) { if (m_defaultFramebuffer == 0) { - // Create a virtual framebuffer + /* Create a virtual frame-buffer. */ [m_openGLContext makeCurrentContext]; metalInitFramebuffer(); initClearGL(); @@ -342,11 +343,11 @@ void GHOST_ContextCGL::metalInit() /* clang-format on */ id<MTLDevice> device = m_metalLayer.device; - // Create a command queue for blit/present operation + /* Create a command queue for blit/present operation. */ m_metalCmdQueue = (MTLCommandQueue *)[device newCommandQueue]; [m_metalCmdQueue retain]; - // Create shaders for blit operation + /* Create shaders for blit operation. */ NSString *source = @R"msl( using namespace metal; @@ -387,7 +388,7 @@ void GHOST_ContextCGL::metalInit() "GHOST_ContextCGL::metalInit: newLibraryWithSource:options:error: failed!"); } - // Create a render pipeline for blit operation + /* Create a render pipeline for blit operation. */ MTLRenderPipelineDescriptor *desc = [[[MTLRenderPipelineDescriptor alloc] init] autorelease]; desc.fragmentFunction = [library newFunctionWithName:@"fragment_shader"]; @@ -460,7 +461,7 @@ void GHOST_ContextCGL::metalUpdateFramebuffer() "GHOST_ContextCGL::metalUpdateFramebuffer: CVPixelBufferCreate failed!"); } - // Create an OpenGL texture + /* Create an OpenGL texture. */ CVOpenGLTextureCacheRef cvGLTexCache = nil; cvret = CVOpenGLTextureCacheCreate(kCFAllocatorDefault, nil, @@ -485,7 +486,7 @@ void GHOST_ContextCGL::metalUpdateFramebuffer() unsigned int glTex; glTex = CVOpenGLTextureGetName(cvGLTex); - // Create a Metal texture + /* Create a Metal texture. */ CVMetalTextureCacheRef cvMetalTexCache = nil; cvret = CVMetalTextureCacheCreate( kCFAllocatorDefault, nil, m_metalLayer.device, nil, &cvMetalTexCache); diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp index 0fee200ea1a..a64b2aef6a5 100644 --- a/intern/ghost/intern/GHOST_ContextEGL.cpp +++ b/intern/ghost/intern/GHOST_ContextEGL.cpp @@ -283,8 +283,8 @@ GHOST_TSuccess GHOST_ContextEGL::setSwapInterval(int interval) GHOST_TSuccess GHOST_ContextEGL::getSwapInterval(int &intervalOut) { - // This is a bit of a kludge because there does not seem to - // be a way to query the swap interval with EGL. + /* This is a bit of a kludge because there does not seem to + * be a way to query the swap interval with EGL. */ intervalOut = m_swap_interval; return GHOST_kSuccess; @@ -365,21 +365,21 @@ static const std::string &api_string(EGLenum api) GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() { - // objects have to be declared here due to the use of goto + /* Objects have to be declared here due to the use of `goto`. */ std::vector<EGLint> attrib_list; EGLint num_config = 0; if (m_stereoVisual) fprintf(stderr, "Warning! Stereo OpenGL ES contexts are not supported.\n"); - m_stereoVisual = false; // It doesn't matter what the Window wants. + m_stereoVisual = false; /* It doesn't matter what the Window wants. */ if (!initContextEGLEW()) { return GHOST_kFailure; } #ifdef WITH_GL_ANGLE - // d3dcompiler_XX.dll needs to be loaded before ANGLE will work + /* `d3dcompiler_XX.dll` needs to be loaded before ANGLE will work. */ if (s_d3dcompiler == NULL) { s_d3dcompiler = LoadLibrary(D3DCOMPILER); @@ -410,13 +410,13 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() if (!bindAPI(m_api)) goto error; - // build attribute list + /* Build attribute list. */ attrib_list.reserve(20); if (m_api == EGL_OPENGL_ES_API && EGLEW_VERSION_1_2) { - // According to the spec it seems that you are required to set EGL_RENDERABLE_TYPE, - // but some implementations (ANGLE) do not seem to care. + /* According to the spec it seems that you are required to set EGL_RENDERABLE_TYPE, + * but some implementations (ANGLE) do not seem to care. */ if (m_contextMajorVersion == 1) { attrib_list.push_back(EGL_RENDERABLE_TYPE); @@ -469,7 +469,7 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() #endif if (m_nativeWindow == 0) { - // off-screen surface + /* Off-screen surface. */ attrib_list.push_back(EGL_SURFACE_TYPE); attrib_list.push_back(EGL_PBUFFER_BIT); } @@ -479,8 +479,8 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() if (!EGL_CHK(::eglChooseConfig(m_display, &(attrib_list[0]), &m_config, 1, &num_config))) goto error; - // A common error is to assume that ChooseConfig worked because it returned EGL_TRUE - if (num_config != 1) // num_config should be exactly 1 + /* A common error is to assume that ChooseConfig worked because it returned EGL_TRUE. */ + if (num_config != 1) /* `num_config` should be exactly 1. */ goto error; if (m_nativeWindow != 0) { diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp index ddb34a8afd9..b5b3fab838d 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.cpp +++ b/intern/ghost/intern/GHOST_ContextWGL.cpp @@ -335,10 +335,11 @@ void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD) if (!WIN32_CHK(::wglMakeCurrent(dummyHDC, dummyHGLRC))) goto finalize; - if (GLEW_CHK(glewInit()) != GLEW_OK) + if (GLEW_CHK(glewInit()) != GLEW_OK) { fprintf(stderr, "Warning! Dummy GLEW/WGLEW failed to initialize properly.\n"); + } - // the following are not technially WGLEW, but they also require a context to work + /* The following are not technically WGLEW, but they also require a context to work. */ #ifndef NDEBUG free((void *)m_dummyRenderer); diff --git a/intern/ghost/intern/GHOST_DisplayManager.cpp b/intern/ghost/intern/GHOST_DisplayManager.cpp index fe12a76753d..9abc652378a 100644 --- a/intern/ghost/intern/GHOST_DisplayManager.cpp +++ b/intern/ghost/intern/GHOST_DisplayManager.cpp @@ -51,7 +51,7 @@ GHOST_TSuccess GHOST_DisplayManager::initialize(void) GHOST_TSuccess GHOST_DisplayManager::getNumDisplays(uint8_t & /*numDisplays*/) const { - // Don't know if we have a display... + /* Don't know if we have a display. */ return GHOST_kFailure; } @@ -120,18 +120,18 @@ GHOST_TSuccess GHOST_DisplayManager::findMatch(uint8_t display, (int)setting.xPixels, (int)setting.yPixels, (int)setting.bpp, (int)setting.frequency}; int capabilities[4]; double field, score; - double best = 1e12; // A big number + double best = 1e12; /* A big number. */ int found = 0; - // Look at all the display modes + /* Look at all the display modes. */ for (int i = 0; (i < (int)m_settings[display].size()); i++) { - // Store the capabilities of the display device + /* Store the capabilities of the display device. */ capabilities[0] = m_settings[display][i].xPixels; capabilities[1] = m_settings[display][i].yPixels; capabilities[2] = m_settings[display][i].bpp; capabilities[3] = m_settings[display][i].frequency; - // Match against all the fields of the display settings + /* Match against all the fields of the display settings. */ score = 0; for (int j = 0; j < 4; j++) { field = capabilities[j] - criteria[j]; diff --git a/intern/ghost/intern/GHOST_DropTargetX11.cpp b/intern/ghost/intern/GHOST_DropTargetX11.cpp index 8758a27930e..dba1d305144 100644 --- a/intern/ghost/intern/GHOST_DropTargetX11.cpp +++ b/intern/ghost/intern/GHOST_DropTargetX11.cpp @@ -115,8 +115,10 @@ GHOST_DropTargetX11::~GHOST_DropTargetX11() /* Based on: https://stackoverflow.com/a/2766963/432509 */ typedef enum DecodeState_e { - STATE_SEARCH = 0, ///< searching for an ampersand to convert - STATE_CONVERTING ///< convert the two proceeding characters from hex + /** Searching for an ampersand to convert. */ + STATE_SEARCH = 0, + /** Convert the two proceeding characters from hex. */ + STATE_CONVERTING } DecodeState_e; void GHOST_DropTargetX11::UrlDecode(char *decodedOut, int bufferSize, const char *encodedIn) diff --git a/intern/ghost/intern/GHOST_EventDragnDrop.h b/intern/ghost/intern/GHOST_EventDragnDrop.h index 537717b1717..0095cedb8c8 100644 --- a/intern/ghost/intern/GHOST_EventDragnDrop.h +++ b/intern/ghost/intern/GHOST_EventDragnDrop.h @@ -90,7 +90,7 @@ class GHOST_EventDragnDrop : public GHOST_Event { ~GHOST_EventDragnDrop() { - // Free the dropped object data + /* Free the dropped object data. */ if (m_dragnDropEventData.data == NULL) return; diff --git a/intern/ghost/intern/GHOST_EventManager.cpp b/intern/ghost/intern/GHOST_EventManager.cpp index 15befb9afcb..6ddc362ac77 100644 --- a/intern/ghost/intern/GHOST_EventManager.cpp +++ b/intern/ghost/intern/GHOST_EventManager.cpp @@ -108,12 +108,12 @@ GHOST_TSuccess GHOST_EventManager::addConsumer(GHOST_IEventConsumer *consumer) GHOST_TSuccess success; GHOST_ASSERT(consumer, "invalid consumer"); - // Check to see whether the consumer is already in our list + /* Check to see whether the consumer is already in our list. */ TConsumerVector::const_iterator iter = std::find( m_consumers.begin(), m_consumers.end(), consumer); if (iter == m_consumers.end()) { - // Add the consumer + /* Add the consumer. */ m_consumers.push_back(consumer); success = GHOST_kSuccess; } @@ -128,11 +128,11 @@ GHOST_TSuccess GHOST_EventManager::removeConsumer(GHOST_IEventConsumer *consumer GHOST_TSuccess success; GHOST_ASSERT(consumer, "invalid consumer"); - // Check to see whether the consumer is in our list + /* Check to see whether the consumer is in our list. */ TConsumerVector::iterator iter = std::find(m_consumers.begin(), m_consumers.end(), consumer); if (iter != m_consumers.end()) { - // Remove the consumer + /* Remove the consumer. */ m_consumers.erase(iter); success = GHOST_kSuccess; } diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp index 079ad67f737..0317c175273 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.cpp +++ b/intern/ghost/intern/GHOST_NDOFManager.cpp @@ -22,51 +22,51 @@ #include <limits.h> #include <math.h> -#include <stdio.h> // for error/info reporting -#include <string.h> // for memory functions +#include <stdio.h> /* For error/info reporting. */ +#include <string.h> /* For memory functions. */ #ifdef DEBUG_NDOF_MOTION -// printable version of each GHOST_TProgress value +/* Printable version of each GHOST_TProgress value. */ static const char *progress_string[] = { "not started", "starting", "in progress", "finishing", "finished"}; #endif #ifdef DEBUG_NDOF_BUTTONS static const char *ndof_button_names[] = { - // used internally, never sent + /* used internally, never sent */ "NDOF_BUTTON_NONE", - // these two are available from any 3Dconnexion device + /* these two are available from any 3Dconnexion device */ "NDOF_BUTTON_MENU", "NDOF_BUTTON_FIT", - // standard views + /* standard views */ "NDOF_BUTTON_TOP", "NDOF_BUTTON_BOTTOM", "NDOF_BUTTON_LEFT", "NDOF_BUTTON_RIGHT", "NDOF_BUTTON_FRONT", "NDOF_BUTTON_BACK", - // more views + /* more views */ "NDOF_BUTTON_ISO1", "NDOF_BUTTON_ISO2", - // 90 degree rotations + /* 90 degree rotations */ "NDOF_BUTTON_ROLL_CW", "NDOF_BUTTON_ROLL_CCW", "NDOF_BUTTON_SPIN_CW", "NDOF_BUTTON_SPIN_CCW", "NDOF_BUTTON_TILT_CW", "NDOF_BUTTON_TILT_CCW", - // device control + /* device control */ "NDOF_BUTTON_ROTATE", "NDOF_BUTTON_PANZOOM", "NDOF_BUTTON_DOMINANT", "NDOF_BUTTON_PLUS", "NDOF_BUTTON_MINUS", - // keyboard emulation + /* keyboard emulation */ "NDOF_BUTTON_ESC", "NDOF_BUTTON_ALT", "NDOF_BUTTON_SHIFT", "NDOF_BUTTON_CTRL", - // general-purpose buttons + /* general-purpose buttons */ "NDOF_BUTTON_1", "NDOF_BUTTON_2", "NDOF_BUTTON_3", @@ -77,17 +77,17 @@ static const char *ndof_button_names[] = { "NDOF_BUTTON_8", "NDOF_BUTTON_9", "NDOF_BUTTON_10", - // more general-purpose buttons + /* more general-purpose buttons */ "NDOF_BUTTON_A", "NDOF_BUTTON_B", "NDOF_BUTTON_C", - // the end + /* the end */ "NDOF_BUTTON_LAST"}; #endif -// shared by the latest 3Dconnexion hardware -// SpacePilotPro uses all of these -// smaller devices use only some, based on button mask +/* Shared by the latest 3Dconnexion hardware + * SpacePilotPro uses all of these + * smaller devices use only some, based on button mask. */ static const NDOF_ButtonT Modern3Dx_HID_map[] = { NDOF_BUTTON_MENU, NDOF_BUTTON_FIT, NDOF_BUTTON_TOP, NDOF_BUTTON_LEFT, NDOF_BUTTON_RIGHT, NDOF_BUTTON_FRONT, NDOF_BUTTON_BOTTOM, NDOF_BUTTON_BACK, @@ -116,15 +116,15 @@ static const NDOF_ButtonT SpaceExplorer_HID_map[] = { NDOF_BUTTON_ROTATE, }; -// this is the older SpacePilot (sans Pro) -// thanks to polosson for info about this device +/* This is the older SpacePilot (sans Pro) + * thanks to polosson for info about this device. */ static const NDOF_ButtonT SpacePilot_HID_map[] = { NDOF_BUTTON_1, NDOF_BUTTON_2, NDOF_BUTTON_3, NDOF_BUTTON_4, NDOF_BUTTON_5, NDOF_BUTTON_6, NDOF_BUTTON_TOP, NDOF_BUTTON_LEFT, NDOF_BUTTON_RIGHT, NDOF_BUTTON_FRONT, NDOF_BUTTON_ESC, NDOF_BUTTON_ALT, NDOF_BUTTON_SHIFT, NDOF_BUTTON_CTRL, NDOF_BUTTON_FIT, NDOF_BUTTON_MENU, NDOF_BUTTON_PLUS, NDOF_BUTTON_MINUS, NDOF_BUTTON_DOMINANT, NDOF_BUTTON_ROTATE, - NDOF_BUTTON_NONE // the CONFIG button -- what does it do? + NDOF_BUTTON_NONE /* the CONFIG button -- what does it do? */ }; static const NDOF_ButtonT Generic_HID_map[] = { @@ -146,7 +146,7 @@ static const int genericButtonCount = sizeof(Generic_HID_map) / sizeof(NDOF_Butt GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System &sys) : m_system(sys), - m_deviceType(NDOF_UnknownDevice), // each platform has its own device detection code + m_deviceType(NDOF_UnknownDevice), /* Each platform has its own device detection code. */ m_buttonCount(genericButtonCount), m_buttonMask(0), m_hidMap(Generic_HID_map), @@ -157,37 +157,37 @@ GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System &sys) m_motionEventPending(false), m_deadZone(0.0f) { - // to avoid the rare situation where one triple is updated and - // the other is not, initialize them both here: + /* To avoid the rare situation where one triple is updated and + * the other is not, initialize them both here: */ memset(m_translation, 0, sizeof(m_translation)); memset(m_rotation, 0, sizeof(m_rotation)); } bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short product_id) { - // call this function until it returns true - // it's a good idea to stop calling it after that, as it will "forget" - // whichever device it already found + /* Call this function until it returns true + * it's a good idea to stop calling it after that, as it will "forget" + * whichever device it already found */ - // default to safe generic behavior for "unknown" devices - // unidentified devices will emit motion events like normal - // rogue buttons do nothing by default, but can be customized by the user + /* Default to safe generic behavior for "unknown" devices + * unidentified devices will emit motion events like normal + * rogue buttons do nothing by default, but can be customized by the user. */ m_deviceType = NDOF_UnknownDevice; m_hidMap = Generic_HID_map; m_buttonCount = genericButtonCount; m_buttonMask = 0; - // "mystery device" owners can help build a HID_map for their hardware - // A few users have already contributed information about several older devices - // that I don't have access to. Thanks! + /* "mystery device" owners can help build a HID_map for their hardware + * A few users have already contributed information about several older devices + * that I don't have access to. Thanks! */ switch (vendor_id) { - case 0x046D: // Logitech (3Dconnexion was a subsidiary) + case 0x046D: /* Logitech (3Dconnexion was a subsidiary). */ switch (product_id) { - // -- current devices -- - case 0xC626: // full-size SpaceNavigator - case 0xC628: // the "for Notebooks" one + /* -- current devices -- */ + case 0xC626: /* full-size SpaceNavigator */ + case 0xC628: /* the "for Notebooks" one */ puts("ndof: using SpaceNavigator"); m_deviceType = NDOF_SpaceNavigator; m_buttonCount = 2; @@ -209,12 +209,12 @@ bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ puts("ndof: using SpaceMouse Pro"); m_deviceType = NDOF_SpaceMousePro; m_buttonCount = 27; - // ^^ actually has 15 buttons, but their HID codes range from 0 to 26 + /* ^^ actually has 15 buttons, but their HID codes range from 0 to 26 */ m_buttonMask = 0x07C0F137; m_hidMap = Modern3Dx_HID_map; break; - // -- older devices -- + /* -- older devices -- */ case 0xC625: puts("ndof: using SpacePilot"); m_deviceType = NDOF_SpacePilot; @@ -236,21 +236,21 @@ bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ printf("ndof: unknown Logitech product %04hx\n", product_id); } break; - case 0x256F: // 3Dconnexion + case 0x256F: /* 3Dconnexion */ switch (product_id) { - case 0xC62E: // plugged in - case 0xC62F: // wireless + case 0xC62E: /* Plugged in. */ + case 0xC62F: /* Wireless. */ puts("ndof: using SpaceMouse Wireless"); m_deviceType = NDOF_SpaceMouseWireless; m_buttonCount = 2; m_hidMap = Modern3Dx_HID_map; break; - case 0xC631: // plugged in - case 0xC632: // wireless + case 0xC631: /* Plugged in. */ + case 0xC632: /* Wireless. */ puts("ndof: using SpaceMouse Pro Wireless"); m_deviceType = NDOF_SpaceMouseProWireless; m_buttonCount = 27; - // ^^ actually has 15 buttons, but their HID codes range from 0 to 26 + /* ^^ actually has 15 buttons, but their HID codes range from 0 to 26. */ m_buttonMask = 0x07C0F137; m_hidMap = Modern3Dx_HID_map; break; @@ -364,16 +364,16 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t tim int mask = 1 << button_number; if (press) { - m_buttons |= mask; // set this button's bit + m_buttons |= mask; /* Set this button's bit. */ } else { - m_buttons &= ~mask; // clear this button's bit + m_buttons &= ~mask; /* Clear this button's bit. */ } } void GHOST_NDOFManager::updateButtons(int button_bits, uint64_t time) { - button_bits &= m_buttonMask; // discard any "garbage" bits + button_bits &= m_buttonMask; /* Discard any "garbage" bits. */ int diff = m_buttons ^ button_bits; @@ -390,11 +390,11 @@ void GHOST_NDOFManager::updateButtons(int button_bits, uint64_t time) void GHOST_NDOFManager::setDeadZone(float dz) { if (dz < 0.0f) { - // negative values don't make sense, so clamp at zero + /* Negative values don't make sense, so clamp at zero. */ dz = 0.0f; } else if (dz > 0.5f) { - // warn the rogue user/developer, but allow it + /* Warn the rogue user/developer, but allow it. */ GHOST_PRINTF("ndof: dead zone of %.2f is rather high...\n", dz); } m_deadZone = dz; @@ -426,22 +426,22 @@ bool GHOST_NDOFManager::sendMotionEvent() if (!m_motionEventPending) return false; - m_motionEventPending = false; // any pending motion is handled right now + m_motionEventPending = false; /* Any pending motion is handled right now. */ GHOST_IWindow *window = m_system.getWindowManager()->getActiveWindow(); if (window == NULL) { - m_motionState = GHOST_kNotStarted; // avoid large 'dt' times when changing windows - return false; // delivery will fail, so don't bother sending + m_motionState = GHOST_kNotStarted; /* Avoid large `dt` times when changing windows. */ + return false; /* Delivery will fail, so don't bother sending. */ } GHOST_EventNDOFMotion *event = new GHOST_EventNDOFMotion(m_motionTime, window); GHOST_TEventNDOFMotionData *data = (GHOST_TEventNDOFMotionData *)event->getData(); - // scale axis values here to normalize them to around +/- 1 - // they are scaled again for overall sensitivity in the WM based on user prefs + /* Scale axis values here to normalize them to around +/- 1 + * they are scaled again for overall sensitivity in the WM based on user preferences. */ - const float scale = 1.0f / 350.0f; // 3Dconnexion devices send +/- 350 usually + const float scale = 1.0f / 350.0f; /* 3Dconnexion devices send +/- 350 usually */ data->tx = scale * m_translation[0]; data->ty = scale * m_translation[1]; @@ -451,24 +451,24 @@ bool GHOST_NDOFManager::sendMotionEvent() data->ry = scale * m_rotation[1]; data->rz = scale * m_rotation[2]; - data->dt = 0.001f * (m_motionTime - m_prevMotionTime); // in seconds + data->dt = 0.001f * (m_motionTime - m_prevMotionTime); /* In seconds. */ m_prevMotionTime = m_motionTime; bool weHaveMotion = !nearHomePosition(data, m_deadZone); - // determine what kind of motion event to send (Starting, InProgress, Finishing) - // and where that leaves this NDOF manager (NotStarted, InProgress, Finished) + /* Determine what kind of motion event to send `(Starting, InProgress, Finishing)` + * and where that leaves this NDOF manager `(NotStarted, InProgress, Finished)`. */ switch (m_motionState) { case GHOST_kNotStarted: case GHOST_kFinished: if (weHaveMotion) { data->progress = GHOST_kStarting; m_motionState = GHOST_kInProgress; - // prev motion time will be ancient, so just make up a reasonable time delta + /* Previous motion time will be ancient, so just make up a reasonable time delta. */ data->dt = 0.0125f; } else { - // send no event and keep current state + /* Send no event and keep current state. */ #ifdef DEBUG_NDOF_MOTION printf("ndof motion ignored -- %s\n", progress_string[data->progress]); #endif @@ -479,20 +479,22 @@ bool GHOST_NDOFManager::sendMotionEvent() case GHOST_kInProgress: if (weHaveMotion) { data->progress = GHOST_kInProgress; - // remain 'InProgress' + /* Remain 'InProgress'. */ } else { data->progress = GHOST_kFinishing; m_motionState = GHOST_kFinished; } break; - default:; // will always be one of the above + default: + /* Will always be one of the above. */ + break; } #ifdef DEBUG_NDOF_MOTION printf("ndof motion sent -- %s\n", progress_string[data->progress]); - // show details about this motion event + /* Show details about this motion event. */ printf(" T=(%d,%d,%d) R=(%d,%d,%d) raw\n", m_translation[0], m_translation[1], diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h index 7be129c327c..31b11a352db 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.h +++ b/intern/ghost/intern/GHOST_NDOFManager.h @@ -28,7 +28,7 @@ typedef enum { NDOF_UnknownDevice, - // current devices + /* Current devices. */ NDOF_SpaceNavigator, NDOF_SpaceExplorer, NDOF_SpacePilotPro, @@ -37,51 +37,51 @@ typedef enum { NDOF_SpaceMouseProWireless, NDOF_SpaceMouseEnterprise, - // older devices + /* Older devices. */ NDOF_SpacePilot, NDOF_Spaceball5000, NDOF_SpaceTraveler } NDOF_DeviceT; -// NDOF device button event types +/* NDOF device button event types */ typedef enum { - // used internally, never sent + /* Used internally, never sent. */ NDOF_BUTTON_NONE, - // these two are available from any 3Dconnexion device + /* These two are available from any 3Dconnexion device. */ NDOF_BUTTON_MENU, NDOF_BUTTON_FIT, - // standard views + /* Standard views. */ NDOF_BUTTON_TOP, NDOF_BUTTON_BOTTOM, NDOF_BUTTON_LEFT, NDOF_BUTTON_RIGHT, NDOF_BUTTON_FRONT, NDOF_BUTTON_BACK, - // more views + /* More views. */ NDOF_BUTTON_ISO1, NDOF_BUTTON_ISO2, - // 90 degree rotations - // these don't all correspond to physical buttons + /* 90 degree rotations. + * These don't all correspond to physical buttons. */ NDOF_BUTTON_ROLL_CW, NDOF_BUTTON_ROLL_CCW, NDOF_BUTTON_SPIN_CW, NDOF_BUTTON_SPIN_CCW, NDOF_BUTTON_TILT_CW, NDOF_BUTTON_TILT_CCW, - // device control + /* Device control. */ NDOF_BUTTON_ROTATE, NDOF_BUTTON_PANZOOM, NDOF_BUTTON_DOMINANT, NDOF_BUTTON_PLUS, NDOF_BUTTON_MINUS, - // keyboard emulation + /* Keyboard emulation. */ NDOF_BUTTON_ESC, NDOF_BUTTON_ALT, NDOF_BUTTON_SHIFT, NDOF_BUTTON_CTRL, - // general-purpose buttons - // users can assign functions via keymap editor + /* General-purpose buttons. + * Users can assign functions via keymap editor. */ NDOF_BUTTON_1, NDOF_BUTTON_2, NDOF_BUTTON_3, @@ -92,11 +92,11 @@ typedef enum { NDOF_BUTTON_8, NDOF_BUTTON_9, NDOF_BUTTON_10, - // more general-purpose buttons + /* More general-purpose buttons. */ NDOF_BUTTON_A, NDOF_BUTTON_B, NDOF_BUTTON_C, - // the end + /* The end. */ NDOF_BUTTON_LAST } NDOF_ButtonT; @@ -107,40 +107,53 @@ class GHOST_NDOFManager { { } - // whether multi-axis functionality is available (via the OS or driver) - // does not imply that a device is plugged in or being used + /** + * Whether multi-axis functionality is available (via the OS or driver) + * does not imply that a device is plugged in or being used. + */ virtual bool available() = 0; - // each platform's device detection should call this - // use standard USB/HID identifiers + /** + * Each platform's device detection should call this + * use standard USB/HID identifiers. + */ bool setDevice(unsigned short vendor_id, unsigned short product_id); - // filter out small/accidental/uncalibrated motions by - // setting up a "dead zone" around home position - // set to 0 to disable - // 0.1 is a safe and reasonable value + /** + * Filter out small/accidental/un-calibrated motions by + * setting up a "dead zone" around home position + * set to 0 to disable + * 0.1 is a safe and reasonable value. + */ void setDeadZone(float); - // the latest raw axis data from the device - // NOTE: axis data should be in blender view coordinates - // +X is to the right - // +Y is up - // +Z is out of the screen - // for rotations, look from origin to each +axis - // rotations are + when CCW, - when CW - // each platform is responsible for getting axis data into this form - // these values should not be scaled (just shuffled or flipped) + /** + * The latest raw axis data from the device. + * + * \note axis data should be in blender view coordinates + * - +X is to the right. + * - +Y is up. + * - +Z is out of the screen. + * - for rotations, look from origin to each +axis. + * - rotations are + when CCW, - when CW. + * Each platform is responsible for getting axis data into this form + * these values should not be scaled (just shuffled or flipped). + */ void updateTranslation(const int t[3], uint64_t time); void updateRotation(const int r[3], uint64_t time); - // the latest raw button data from the device - // use HID button encoding (not NDOF_ButtonT) + /** + * The latest raw button data from the device + * use HID button encoding (not #NDOF_ButtonT). + */ void updateButton(int button_number, bool press, uint64_t time); void updateButtons(int button_bits, uint64_t time); - // NDOFButton events are sent immediately + /* #NDOFButton events are sent immediately */ - // processes and sends most recent raw data as an NDOFMotion event - // returns whether an event was sent + /** + * Processes and sends most recent raw data as an #NDOFMotion event + * returns whether an event was sent. + */ bool sendMotionEvent(); protected: @@ -157,12 +170,12 @@ class GHOST_NDOFManager { int m_translation[3]; int m_rotation[3]; - int m_buttons; // bit field + int m_buttons; /* Bit field. */ - uint64_t m_motionTime; // in milliseconds - uint64_t m_prevMotionTime; // time of most recent Motion event sent + uint64_t m_motionTime; /* In milliseconds. */ + uint64_t m_prevMotionTime; /* Time of most recent motion event sent. */ GHOST_TProgress m_motionState; bool m_motionEventPending; - float m_deadZone; // discard motion with each component < this + float m_deadZone; /* Discard motion with each component < this. */ }; diff --git a/intern/ghost/intern/GHOST_Rect.cpp b/intern/ghost/intern/GHOST_Rect.cpp index 8ef9486f35a..78c88cb0a71 100644 --- a/intern/ghost/intern/GHOST_Rect.cpp +++ b/intern/ghost/intern/GHOST_Rect.cpp @@ -26,14 +26,14 @@ void GHOST_Rect::inset(int32_t i) { if (i > 0) { - // Grow the rectangle + /* Grow the rectangle. */ m_l -= i; m_r += i; m_t -= i; m_b += i; } else if (i < 0) { - // Shrink the rectangle, check for insets larger than half the size + /* Shrink the rectangle, check for insets larger than half the size. */ int32_t i2 = i * 2; if (getWidth() > i2) { m_l += i; @@ -62,12 +62,12 @@ GHOST_TVisibility GHOST_Rect::getVisibility(GHOST_Rect &r) const bool rb = isInside(r.m_r, r.m_b); GHOST_TVisibility v; if (lt && rt && lb && rb) { - // All points inside, rectangle is inside this + /* All points inside, rectangle is inside this. */ v = GHOST_kFullyVisible; } else if (!(lt || rt || lb || rb)) { - // None of the points inside - // Check to see whether the rectangle is larger than this one + /* None of the points inside. + * Check to see whether the rectangle is larger than this one. */ if ((r.m_l < m_l) && (r.m_t < m_t) && (r.m_r > m_r) && (r.m_b > m_b)) { v = GHOST_kPartiallyVisible; } @@ -76,7 +76,7 @@ GHOST_TVisibility GHOST_Rect::getVisibility(GHOST_Rect &r) const } } else { - // Some of the points inside, rectangle is partially inside + /* Some of the points inside, rectangle is partially inside. */ v = GHOST_kPartiallyVisible; } return v; diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp index f6659cf50dc..d09c167cb95 100644 --- a/intern/ghost/intern/GHOST_System.cpp +++ b/intern/ghost/intern/GHOST_System.cpp @@ -72,7 +72,7 @@ GHOST_ITimerTask *GHOST_System::installTimer(uint64_t delay, GHOST_TimerTask *timer = new GHOST_TimerTask(millis + delay, interval, timerProc, userData); if (timer) { if (m_timerManager->addTimer(timer) == GHOST_kSuccess) { - // Check to see whether we need to fire the timer right away + /* Check to see whether we need to fire the timer right away. */ m_timerManager->fireTimers(millis); } else { @@ -208,7 +208,7 @@ bool GHOST_System::getFullScreen(void) void GHOST_System::dispatchEvents() { #ifdef WITH_INPUT_NDOF - // NDOF Motion event is sent only once per dispatch, so do it now: + /* NDOF Motion event is sent only once per dispatch, so do it now: */ if (m_ndofManager) { m_ndofManager->sendMotionEvent(); } @@ -260,10 +260,10 @@ GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent *event) GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bool &isDown) const { GHOST_ModifierKeys keys; - // Get the state of all modifier keys + /* Get the state of all modifier keys. */ GHOST_TSuccess success = getModifierKeys(keys); if (success) { - // Isolate the state of the key requested + /* Isolate the state of the key requested. */ isDown = keys.get(mask); } return success; @@ -272,10 +272,10 @@ GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bo GHOST_TSuccess GHOST_System::getButtonState(GHOST_TButtonMask mask, bool &isDown) const { GHOST_Buttons buttons; - // Get the state of all mouse buttons + /* Get the state of all mouse buttons. */ GHOST_TSuccess success = getButtons(buttons); if (success) { - // Isolate the state of the mouse button requested + /* Isolate the state of the mouse button requested. */ isDown = buttons.get(mask); } return success; @@ -311,7 +311,7 @@ GHOST_TSuccess GHOST_System::init() m_eventPrinter = new GHOST_EventPrinter(); m_eventManager->addConsumer(m_eventPrinter); } -#endif // WITH_GHOST_DEBUG +#endif /* WITH_GHOST_DEBUG */ if (m_timerManager && m_windowManager && m_eventManager) { return GHOST_kSuccess; @@ -359,7 +359,7 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, if (alphaBackground) glSettings.flags |= GHOST_glAlphaBackground; - /* note: don't use getCurrentDisplaySetting() because on X11 we may + /* NOTE: don't use #getCurrentDisplaySetting() because on X11 we may * be zoomed in and the desktop may be bigger than the viewport. */ GHOST_ASSERT(m_displayManager, "GHOST_System::createFullScreenWindow(): invalid display manager"); diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp index f2f1b26b8e5..0309a4f9c52 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.cpp +++ b/intern/ghost/intern/GHOST_SystemSDL.cpp @@ -143,7 +143,7 @@ GHOST_IContext *GHOST_SystemSDL::createOffscreenContext(GHOST_GLSettings glSetti { GHOST_Context *context = new GHOST_ContextSDL(0, NULL, - 0, // profile bit + 0, /* Profile bit. */ 3, 3, GHOST_OPENGL_SDL_CONTEXT_FLAGS, @@ -279,7 +279,7 @@ static GHOST_TKey convertSDLKey(SDL_Scancode key) GXMAP(type, SDL_SCANCODE_AUDIOPLAY, GHOST_kKeyMediaPlay); GXMAP(type, SDL_SCANCODE_AUDIOSTOP, GHOST_kKeyMediaStop); GXMAP(type, SDL_SCANCODE_AUDIOPREV, GHOST_kKeyMediaFirst); - // GXMAP(type,XF86XK_AudioRewind, GHOST_kKeyMediaFirst); + // GXMAP(type, XF86XK_AudioRewind, GHOST_kKeyMediaFirst); GXMAP(type, SDL_SCANCODE_AUDIONEXT, GHOST_kKeyMediaLast); default: @@ -315,7 +315,10 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event) SDL_WindowEvent &sdl_sub_evt = sdl_event->window; GHOST_WindowSDL *window = findGhostWindow( SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID)); - // assert(window != NULL); // can be NULL on close window. + /* Can be NULL on close window. */ +#if 0 + assert(window != NULL); +#endif switch (sdl_sub_evt.event) { case SDL_WINDOWEVENT_EXPOSED: @@ -376,14 +379,14 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event) bounds.wrapPoint(x_new, y_new, 8, window->getCursorGrabAxis()); window->getCursorGrabAccum(x_accum, y_accum); - // can't use setCursorPosition because the mouse may have no focus! + /* Can't use #setCursorPosition because the mouse may have no focus! */ if (x_new != x_root || y_new != y_root) { - if (1) { //xme.time > m_last_warp) { + if (1 /* `xme.time > m_last_warp` */ ) { /* when wrapping we don't need to add an event because the - * setCursorPosition call will cause a new event after */ + * #setCursorPosition call will cause a new event after */ SDL_WarpMouseInWindow(sdl_win, x_new - x_win, y_new - y_win); /* wrap */ window->setCursorGrabAccum(x_accum + (x_root - x_new), y_accum + (y_root - y_new)); - // m_last_warp= lastEventTime(xme.time); + // m_last_warp = lastEventTime(xme.time); } else { // setCursorPosition(x_new, y_new); /* wrap but don't accumulate */ @@ -659,8 +662,8 @@ bool GHOST_SystemSDL::generateWindowExposeEvents() bool GHOST_SystemSDL::processEvents(bool waitForEvent) { - // Get all the current events -- translate them into - // ghost events and call base class pushEvent() method. + /* Get all the current events - translate them into + * ghost events and call base class #pushEvent() method. */ bool anyProcessed = false; @@ -679,7 +682,7 @@ bool GHOST_SystemSDL::processEvents(bool waitForEvent) if (maxSleep >= 0) { SDL_WaitEventTimeout(NULL, next - getMilliSeconds()); - // SleepTillEvent(m_display, next - getMilliSeconds()); // X11 + // SleepTillEvent(m_display, next - getMilliSeconds()); /* X11. */ } } } @@ -707,10 +710,10 @@ GHOST_WindowSDL *GHOST_SystemSDL::findGhostWindow(SDL_Window *sdl_win) if (sdl_win == NULL) return NULL; - // It is not entirely safe to do this as the backptr may point - // to a window that has recently been removed. - // We should always check the window manager's list of windows - // and only process events on these windows. + /* It is not entirely safe to do this as the backptr may point + * to a window that has recently been removed. + * We should always check the window manager's list of windows + * and only process events on these windows. */ const std::vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows(); diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index 6c786aedfb1..17e9adff8bc 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -360,8 +360,8 @@ class GHOST_SystemWin32 : public GHOST_System { static GHOST_EventKey *processKeyEvent(GHOST_WindowWin32 *window, RAWINPUT const &raw); /** - * Process special keys (VK_OEM_*), to see if current key layout - * gives us anything special, like ! on french AZERTY. + * Process special keys `VK_OEM_*`, to see if current key layout + * gives us anything special, like `!` on French AZERTY. * \param vKey: The virtual key from #hardKey. * \param scanCode: The ScanCode of pressed key (similar to PS/2 Set 1). */ diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 172fcbeb3de..e36bfd1aaeb 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -396,15 +396,15 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title, */ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSettings) { - // During development: - // try 4.x compatibility profile - // try 3.3 compatibility profile - // fall back to 3.0 if needed - // - // Final Blender 2.8: - // try 4.x core profile - // try 3.3 core profile - // no fallbacks + /* During development: + * try 4.x compatibility profile + * try 3.3 compatibility profile + * fall back to 3.0 if needed + * + * Final Blender 2.8: + * try 4.x core profile + * try 3.3 core profile + * no fall-backs. */ const bool debug_context = (glSettings.flags & GHOST_glDebugContext) != 0; @@ -2014,7 +2014,7 @@ void GHOST_SystemX11::getClipboard_xcout(const XEvent *evt, return; } - // not using INCR mechanism, just read the property + /* Not using INCR mechanism, just read the property. */ XGetWindowProperty(m_display, win, m_atom.XCLIP_OUT, diff --git a/intern/ghost/intern/GHOST_TimerManager.cpp b/intern/ghost/intern/GHOST_TimerManager.cpp index 195135f5f85..0c88150381f 100644 --- a/intern/ghost/intern/GHOST_TimerManager.cpp +++ b/intern/ghost/intern/GHOST_TimerManager.cpp @@ -55,7 +55,7 @@ GHOST_TSuccess GHOST_TimerManager::addTimer(GHOST_TimerTask *timer) { GHOST_TSuccess success; if (!getTimerFound(timer)) { - // Add the timer task + /* Add the timer task. */ m_timers.push_back(timer); success = GHOST_kSuccess; } @@ -70,7 +70,7 @@ GHOST_TSuccess GHOST_TimerManager::removeTimer(GHOST_TimerTask *timer) GHOST_TSuccess success; TTimerVector::iterator iter = std::find(m_timers.begin(), m_timers.end(), timer); if (iter != m_timers.end()) { - // Remove the timer task + /* Remove the timer task. */ m_timers.erase(iter); delete timer; success = GHOST_kSuccess; @@ -113,14 +113,14 @@ bool GHOST_TimerManager::fireTimer(uint64_t time, GHOST_TimerTask *task) { uint64_t next = task->getNext(); - // Check if the timer should be fired + /* Check if the timer should be fired. */ if (time > next) { - // Fire the timer + /* Fire the timer. */ GHOST_TimerProcPtr timerProc = task->getTimerProc(); uint64_t start = task->getStart(); timerProc(task, time - start); - // Update the time at which we will fire it again + /* Update the time at which we will fire it again. */ uint64_t interval = task->getInterval(); uint64_t numCalls = (next - start) / interval; numCalls++; diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index 0fd70514ac6..68ac507f0e0 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -157,7 +157,7 @@ class GHOST_WindowCocoa : public GHOST_Window { void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const; /** - * Converts a point in screen coordinates to client rectangle coordinates + * Converts a point in client rectangle coordinates to screen coordinates. * \param inX: The x-coordinate in the client rectangle. * \param inY: The y-coordinate in the client rectangle. * \param outX: The x-coordinate on the screen. @@ -166,7 +166,7 @@ class GHOST_WindowCocoa : public GHOST_Window { void clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const; /** - * Converts a point in screen coordinates to client rectangle coordinates + * Converts a point in client rectangle coordinates to screen coordinates. * but without the y coordinate conversion needed for ghost compatibility. * \param inX: The x-coordinate in the client rectangle. * \param inY: The y-coordinate in the client rectangle. @@ -178,10 +178,10 @@ class GHOST_WindowCocoa : public GHOST_Window { /** * Converts a point in screen coordinates to client rectangle coordinates, * but without the y coordinate conversion needed for ghost compatibility. - * \param inX: The x-coordinate in the client rectangle. - * \param inY: The y-coordinate in the client rectangle. - * \param outX: The x-coordinate on the screen. - * \param outY: The y-coordinate on the screen. + * \param inX: The x-coordinate on the screen. + * \param inY: The y-coordinate on the screen. + * \param outX: The x-coordinate in the client rectangle. + * \param outY: The y-coordinate in the client rectangle. */ void screenToClientIntern(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const; diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp index eec4bc5f7d0..4cb80884209 100644 --- a/intern/ghost/intern/GHOST_WindowManager.cpp +++ b/intern/ghost/intern/GHOST_WindowManager.cpp @@ -45,7 +45,7 @@ GHOST_TSuccess GHOST_WindowManager::addWindow(GHOST_IWindow *window) GHOST_TSuccess success = GHOST_kFailure; if (window) { if (!getWindowFound(window)) { - // Store the pointer to the window + /* Store the pointer to the window. */ m_windows.push_back(window); success = GHOST_kSuccess; } diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp index d0c8cfb9e73..71062a4b6d6 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cpp +++ b/intern/ghost/intern/GHOST_WindowWayland.cpp @@ -34,7 +34,7 @@ static constexpr size_t base_dpi = 96; struct window_t { GHOST_WindowWayland *w; wl_surface *surface; - // outputs on which the window is currently shown on + /* Outputs on which the window is currently shown on. */ std::unordered_set<const output_t *> outputs; uint16_t dpi = 0; int scale = 1; @@ -154,8 +154,8 @@ static bool update_scale(GHOST_WindowWayland *window) if (scale > 0 && window->scale() != scale) { window->scale() = scale; - // using the real DPI will cause wrong scaling of the UI - // use a multiplier for the default DPI as workaround + /* Using the real DPI will cause wrong scaling of the UI + * use a multiplier for the default DPI as workaround. */ window->dpi() = scale * base_dpi; wl_surface_set_buffer_scale(window->surface(), scale); return true; diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index 40a658bf88b..ed5292f1712 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -183,7 +183,7 @@ class GHOST_WindowWin32 : public GHOST_Window { void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const; /** - * Converts a point in screen coordinates to client rectangle coordinates + * Converts a point in client rectangle coordinates to screen coordinates. * \param inX: The x-coordinate in the client rectangle. * \param inY: The y-coordinate in the client rectangle. * \param outX: The x-coordinate on the screen. diff --git a/intern/ghost/intern/GHOST_XrSession.cpp b/intern/ghost/intern/GHOST_XrSession.cpp index 35280e77e22..6140b2aab46 100644 --- a/intern/ghost/intern/GHOST_XrSession.cpp +++ b/intern/ghost/intern/GHOST_XrSession.cpp @@ -120,7 +120,7 @@ static void create_reference_spaces(OpenXRSessionData &oxr, const GHOST_XrPose & XrReferenceSpaceCreateInfo create_info = {XR_TYPE_REFERENCE_SPACE_CREATE_INFO}; create_info.poseInReferenceSpace.orientation.w = 1.0f; - create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL; + create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE; #if 0 /* TODO * @@ -144,8 +144,47 @@ static void create_reference_spaces(OpenXRSessionData &oxr, const GHOST_XrPose & (void)base_pose; #endif - CHECK_XR(xrCreateReferenceSpace(oxr.session, &create_info, &oxr.reference_space), - "Failed to create reference space."); + XrResult result = xrCreateReferenceSpace(oxr.session, &create_info, &oxr.reference_space); + + if (XR_FAILED(result)) { + /* One of the rare cases where we don't want to immediately throw an exception on failure, + * since runtimes are not required to support the stage reference space. Although we need the + * stage reference space for absolute tracking, if the runtime doesn't support it then just + * fallback to the local space. */ + if (result == XR_ERROR_REFERENCE_SPACE_UNSUPPORTED) { + printf( + "Warning: XR runtime does not support stage reference space, disabling absolute " + "tracking.\n"); + + create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL; + CHECK_XR(xrCreateReferenceSpace(oxr.session, &create_info, &oxr.reference_space), + "Failed to create local reference space."); + } + else { + throw GHOST_XrException("Failed to create stage reference space.", result); + } + } + else { + /* Check if tracking bounds are valid. Tracking bounds may be invalid if the user did not + * define a tracking space via the XR runtime. */ + XrExtent2Df extents; + CHECK_XR(xrGetReferenceSpaceBoundsRect(oxr.session, XR_REFERENCE_SPACE_TYPE_STAGE, &extents), + "Failed to get stage reference space bounds."); + if (extents.width == 0.0f || extents.height == 0.0f) { + printf( + "Warning: Invalid stage reference space bounds, disabling absolute tracking. To enable " + "absolute tracking, please define a tracking space via the XR runtime.\n"); + + /* Fallback to local space. */ + if (oxr.reference_space != XR_NULL_HANDLE) { + CHECK_XR(xrDestroySpace(oxr.reference_space), "Failed to destroy stage reference space."); + } + + create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL; + CHECK_XR(xrCreateReferenceSpace(oxr.session, &create_info, &oxr.reference_space), + "Failed to create local reference space."); + } + } create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_VIEW; CHECK_XR(xrCreateReferenceSpace(oxr.session, &create_info, &oxr.view_space), @@ -370,6 +409,7 @@ void GHOST_XrSession::drawView(GHOST_XrSwapchain &swapchain, XrCompositionLayerProjectionView &r_proj_layer_view, XrSpaceLocation &view_location, XrView &view, + uint32_t view_idx, void *draw_customdata) { XrSwapchainImageBaseHeader *swapchain_image = swapchain.acquireDrawableSwapchainImage(); @@ -380,6 +420,8 @@ void GHOST_XrSession::drawView(GHOST_XrSwapchain &swapchain, r_proj_layer_view.fov = view.fov; swapchain.updateCompositionLayerProjectViewSubImage(r_proj_layer_view.subImage); + assert(view_idx < 256); + draw_view_info.view_idx = (char)view_idx; draw_view_info.expects_srgb_buffer = swapchain.isBufferSRGB(); draw_view_info.ofsx = r_proj_layer_view.subImage.imageRect.offset.x; draw_view_info.ofsy = r_proj_layer_view.subImage.imageRect.offset.y; @@ -429,6 +471,7 @@ XrCompositionLayerProjection GHOST_XrSession::drawLayer( r_proj_layer_views[view_idx], view_location, m_oxr->views[view_idx], + view_idx, draw_customdata); } diff --git a/intern/ghost/intern/GHOST_XrSession.h b/intern/ghost/intern/GHOST_XrSession.h index c871b98da46..d448585d14c 100644 --- a/intern/ghost/intern/GHOST_XrSession.h +++ b/intern/ghost/intern/GHOST_XrSession.h @@ -117,6 +117,7 @@ class GHOST_XrSession { XrCompositionLayerProjectionView &r_proj_layer_view, XrSpaceLocation &view_location, XrView &view, + uint32_t view_idx, void *draw_customdata); void beginFrameDrawing(); void endFrameDrawing(std::vector<XrCompositionLayerBaseHeader *> &layers); diff --git a/intern/libmv/CMakeLists.txt b/intern/libmv/CMakeLists.txt index 6fcf664d1f5..91ef1f4d038 100644 --- a/intern/libmv/CMakeLists.txt +++ b/intern/libmv/CMakeLists.txt @@ -217,39 +217,39 @@ if(WITH_LIBMV) if(WITH_GTESTS) include(GTestTesting) - blender_add_lib(libmv_test_dataset "./libmv/multiview/test_data_sets.cc" "" "" "") + blender_add_lib(libmv_test_dataset "./libmv/multiview/test_data_sets.cc" "${INC}" "${INC_SYS}" "") - BLENDER_SRC_GTEST("libmv_predict_tracks" "./libmv/autotrack/predict_tracks_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_tracks" "./libmv/autotrack/tracks_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_scoped_ptr" "./libmv/base/scoped_ptr_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_vector" "./libmv/base/vector_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_array_nd" "./libmv/image/array_nd_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_convolve" "./libmv/image/convolve_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_image" "./libmv/image/image_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_sample" "./libmv/image/sample_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_tuple" "./libmv/image/tuple_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_euclidean_resection" "./libmv/multiview/euclidean_resection_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_fundamental" "./libmv/multiview/fundamental_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_homography" "./libmv/multiview/homography_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_nviewtriangulation" "./libmv/multiview/nviewtriangulation_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_panography" "./libmv/multiview/panography_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_projection" "./libmv/multiview/projection_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_resection" "./libmv/multiview/resection_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_triangulation" "./libmv/multiview/triangulation_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_dogleg" "./libmv/numeric/dogleg_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_function_derivative" "./libmv/numeric/function_derivative_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_levenberg_marquardt" "./libmv/numeric/levenberg_marquardt_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_numeric" "./libmv/numeric/numeric_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_poly" "./libmv/numeric/poly_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_camera_intrinsics" "./libmv/simple_pipeline/camera_intrinsics_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_detect" "./libmv/simple_pipeline/detect_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_intersect" "./libmv/simple_pipeline/intersect_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_keyframe_selection" "./libmv/simple_pipeline/keyframe_selection_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_modal_solver" "./libmv/simple_pipeline/modal_solver_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_resect" "./libmv/simple_pipeline/resect_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_brute_region_tracker" "./libmv/tracking/brute_region_tracker_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_klt_region_tracker" "./libmv/tracking/klt_region_tracker_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_pyramid_region_tracker" "./libmv/tracking/pyramid_region_tracker_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_predict_tracks" "./libmv/autotrack/predict_tracks_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_tracks" "./libmv/autotrack/tracks_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_scoped_ptr" "./libmv/base/scoped_ptr_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_vector" "./libmv/base/vector_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_array_nd" "./libmv/image/array_nd_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_convolve" "./libmv/image/convolve_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_image" "./libmv/image/image_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_sample" "./libmv/image/sample_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_tuple" "./libmv/image/tuple_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_euclidean_resection" "./libmv/multiview/euclidean_resection_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_fundamental" "./libmv/multiview/fundamental_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_homography" "./libmv/multiview/homography_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_nviewtriangulation" "./libmv/multiview/nviewtriangulation_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_panography" "./libmv/multiview/panography_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_projection" "./libmv/multiview/projection_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_resection" "./libmv/multiview/resection_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_triangulation" "./libmv/multiview/triangulation_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_dogleg" "./libmv/numeric/dogleg_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_function_derivative" "./libmv/numeric/function_derivative_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_levenberg_marquardt" "./libmv/numeric/levenberg_marquardt_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_numeric" "./libmv/numeric/numeric_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_poly" "./libmv/numeric/poly_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_camera_intrinsics" "./libmv/simple_pipeline/camera_intrinsics_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_detect" "./libmv/simple_pipeline/detect_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_intersect" "./libmv/simple_pipeline/intersect_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_keyframe_selection" "./libmv/simple_pipeline/keyframe_selection_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_modal_solver" "./libmv/simple_pipeline/modal_solver_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_resect" "./libmv/simple_pipeline/resect_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_brute_region_tracker" "./libmv/tracking/brute_region_tracker_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_klt_region_tracker" "./libmv/tracking/klt_region_tracker_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") + blender_add_test_executable("libmv_pyramid_region_tracker" "./libmv/tracking/pyramid_region_tracker_test.cc" "${INC}" "${INC_SYS}" "libmv_test_dataset;bf_intern_libmv;extern_ceres") endif() else() list(APPEND SRC diff --git a/intern/memutil/MEM_Allocator.h b/intern/memutil/MEM_Allocator.h index 50a3e978197..1dbb2d5a9f7 100644 --- a/intern/memutil/MEM_Allocator.h +++ b/intern/memutil/MEM_Allocator.h @@ -62,8 +62,8 @@ template<typename _Tp> struct MEM_Allocator { return &__x; } - // NB: __n is permitted to be 0. The C++ standard says nothing - // about what the return value is when __n == 0. + /* NOTE: `__n` is permitted to be 0. + * The C++ standard says nothing about what the return value is when `__n == 0`. */ _Tp *allocate(size_type __n, const void * = 0) { _Tp *__ret = NULL; diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt index 16334a80761..bce8a8baa84 100644 --- a/intern/opensubdiv/CMakeLists.txt +++ b/intern/opensubdiv/CMakeLists.txt @@ -129,5 +129,5 @@ if(WITH_GTESTS AND WITH_OPENSUBDIV) add_definitions(${GLOG_DEFINES}) add_definitions(-DBLENDER_GFLAGS_NAMESPACE=${GFLAGS_NAMESPACE}) - BLENDER_SRC_GTEST(opensubdiv_mesh_topology_test "internal/topology/mesh_topology_test.cc" "${LIB};bf_intern_opensubdiv") + blender_add_test_executable(opensubdiv_mesh_topology_test "internal/topology/mesh_topology_test.cc" "${INC}" "${INC_SYS}" "${LIB};bf_intern_opensubdiv") endif() diff --git a/intern/rigidbody/RBI_api.h b/intern/rigidbody/RBI_api.h index 2e09f8952cb..f13f321a2c6 100644 --- a/intern/rigidbody/RBI_api.h +++ b/intern/rigidbody/RBI_api.h @@ -64,7 +64,7 @@ typedef struct rbConstraint rbConstraint; /* Setup ---------------------------- */ /* Create a new dynamics world instance */ -// TODO: add args to set the type of constraint solvers, etc. +/* TODO: add args to set the type of constraint solvers, etc. */ rbDynamicsWorld *RB_dworld_new(const float gravity[3]); /* Delete the given dynamics world, and free any extra data it may require */ diff --git a/release/datafiles/locale b/release/datafiles/locale -Subproject 4833954c0ac85cc407e1d5a153aa11b1d1823ec +Subproject 62e82958a760dad775d9b3387d7fb535fd6de4c diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index 6220edce28f..d51a82c482b 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -113,7 +113,7 @@ const UserDef U_default = { .gp_eraser = 25, .gp_settings = 0, - /** Initialized by: #BKE_studiolight_default . */ + /** Initialized by: #BKE_studiolight_default. */ .light_param = {{0}}, .light_ambient = {0, 0, 0}, diff --git a/release/scripts/addons b/release/scripts/addons -Subproject f86f25e62217264495d05f116ccb09d575fe984 +Subproject 1adb56d8b01cf1327f58c6fb8b1ccc8b7efd76a diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib -Subproject 5a82baad9f986722104280e8354a4427d8e9eab +Subproject 788441f2930465bbfba8f0797b12dcef1d46694 diff --git a/release/scripts/modules/bl_i18n_utils/utils_cli.py b/release/scripts/modules/bl_i18n_utils/utils_cli.py index e18491fa042..ea74ba832d9 100644 --- a/release/scripts/modules/bl_i18n_utils/utils_cli.py +++ b/release/scripts/modules/bl_i18n_utils/utils_cli.py @@ -71,7 +71,7 @@ def rtl_process_po(args, settings): po.write(kind="PO", dest=args.dst) -def language_menu(_args, settings): +def language_menu(args, settings): # 'DEFAULT' and en_US are always valid, fully-translated "languages"! stats = {"DEFAULT": 1.0, "en_US": 1.0} diff --git a/release/scripts/modules/nodeitems_utils.py b/release/scripts/modules/nodeitems_utils.py index a50997fab5f..a5c18cee463 100644 --- a/release/scripts/modules/nodeitems_utils.py +++ b/release/scripts/modules/nodeitems_utils.py @@ -77,7 +77,7 @@ class NodeItem: else: return bpy.app.translations.contexts.default - # NB: is a staticmethod because called with an explicit self argument + # NOTE: is a staticmethod because called with an explicit self argument # NodeItemCustom sets this as a variable attribute in __init__ @staticmethod def draw(self, layout, _context): diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py index 57fcd6f9752..f9756811bde 100644 --- a/release/scripts/modules/rna_manual_reference.py +++ b/release/scripts/modules/rna_manual_reference.py @@ -139,6 +139,7 @@ url_manual_mapping = ( ("bpy.types.fluiddomainsettings.use_resumable_cache*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-use-resumable-cache"), ("bpy.types.fluiddomainsettings.use_spray_particles*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-use-spray-particles"), ("bpy.types.fluiddomainsettings.vector_display_type*", "physics/fluid/type/domain/gas/viewport_display.html#bpy-types-fluiddomainsettings-vector-display-type"), + ("bpy.types.geometrynodecurveprimitivebeziersegment*", "modeling/geometry_nodes/curve_primitives/bezier_segment.html#bpy-types-geometrynodecurveprimitivebeziersegment"), ("bpy.types.linestylegeometrymodifier_perlinnoise1d*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/perlin_noise_1d.html#bpy-types-linestylegeometrymodifier-perlinnoise1d"), ("bpy.types.linestylegeometrymodifier_perlinnoise2d*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/perlin_noise_2d.html#bpy-types-linestylegeometrymodifier-perlinnoise2d"), ("bpy.types.materialgpencilstyle.use_stroke_holdout*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-use-stroke-holdout"), @@ -215,6 +216,7 @@ url_manual_mapping = ( ("bpy.types.spacesequenceeditor.proxy_render_size*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-proxy-render-size"), ("bpy.types.spacesequenceeditor.show_strip_offset*", "video_editing/sequencer/navigating.html#bpy-types-spacesequenceeditor-show-strip-offset"), ("bpy.types.spacesequenceeditor.show_strip_source*", "video_editing/sequencer/navigating.html#bpy-types-spacesequenceeditor-show-strip-source"), + ("bpy.types.spacespreadsheetrowfilter.column_name*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-column-name"), ("bpy.types.toolsettings.gpencil_stroke_placement*", "grease_pencil/modes/draw/stroke_placement.html#bpy-types-toolsettings-gpencil-stroke-placement"), ("bpy.types.toolsettings.use_keyframe_cycle_aware*", "editors/timeline.html#bpy-types-toolsettings-use-keyframe-cycle-aware"), ("bpy.types.toolsettings.use_keyframe_insert_auto*", "editors/timeline.html#bpy-types-toolsettings-use-keyframe-insert-auto"), @@ -233,6 +235,7 @@ url_manual_mapping = ( ("bpy.types.rendersettings.resolution_percentage*", "render/output/properties/dimensions.html#bpy-types-rendersettings-resolution-percentage"), ("bpy.types.rendersettings_simplify_gpencil_tint*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-tint"), ("bpy.types.spaceoutliner.use_filter_object_mesh*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-mesh"), + ("bpy.types.spaceoutliner.use_filter_view_layers*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-view-layers"), ("bpy.types.spacesequenceeditor.show_overexposed*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-show-overexposed"), ("bpy.types.toolsettings.use_gpencil_draw_onback*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-onback"), ("bpy.types.toolsettings.use_snap_align_rotation*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-align-rotation"), @@ -273,6 +276,8 @@ url_manual_mapping = ( ("bpy.types.spacesequenceeditor.show_safe_areas*", "video_editing/preview/introduction.html#bpy-types-spacesequenceeditor-show-safe-areas"), ("bpy.types.spacesequenceeditor.show_strip_name*", "video_editing/sequencer/navigating.html#bpy-types-spacesequenceeditor-show-strip-name"), ("bpy.types.spacespreadsheet.show_only_selected*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-show-only-selected"), + ("bpy.types.spacespreadsheetrowfilter.operation*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-operation"), + ("bpy.types.spacespreadsheetrowfilter.threshold*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-threshold"), ("bpy.types.toolsettings.use_snap_grid_absolute*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-grid-absolute"), ("bpy.types.view3doverlay.show_face_orientation*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-face-orientation"), ("bpy.ops.object.blenderkit_material_thumbnail*", "addons/3d_view/blenderkit.html#bpy-ops-object-blenderkit-material-thumbnail"), @@ -343,6 +348,7 @@ url_manual_mapping = ( ("bpy.types.spaceoutliner.use_filter_complete*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-complete"), ("bpy.types.spacesequenceeditor.show_metadata*", "video_editing/preview/introduction.html#bpy-types-spacesequenceeditor-show-metadata"), ("bpy.types.spacespreadsheet.attribute_domain*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-attribute-domain"), + ("bpy.types.spacespreadsheetrowfilter.enabled*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-enabled"), ("bpy.types.spaceview3d.transform_orientation*", "editors/3dview/controls/orientation.html#bpy-types-spaceview3d-transform-orientation"), ("bpy.types.spaceview3d.use_local_collections*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-use-local-collections"), ("bpy.types.toolsettings.use_snap_peel_object*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-peel-object"), @@ -350,7 +356,6 @@ url_manual_mapping = ( ("bpy.types.view3doverlay.wireframe_threshold*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-wireframe-threshold"), ("bpy.ops.object.constraint_add_with_targets*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-constraint-add-with-targets"), ("bpy.ops.object.material_slot_remove_unused*", "scene_layout/object/editing/cleanup.html#bpy-ops-object-material-slot-remove-unused"), - ("bpy.ops.object.vertex_group_copy_to_linked*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-copy-to-linked"), ("bpy.ops.outliner.collection_disable_render*", "editors/outliner/editing.html#bpy-ops-outliner-collection-disable-render"), ("bpy.types.brush.cloth_simulation_area_type*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-simulation-area-type"), ("bpy.types.brushgpencilsettings.fill_factor*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-factor"), @@ -372,6 +377,7 @@ url_manual_mapping = ( ("bpy.types.fluidflowsettings.use_plane_init*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-use-plane-init"), ("bpy.types.fluidflowsettings.velocity_coord*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-velocity-coord"), ("bpy.types.fluidflowsettings.volume_density*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-volume-density"), + ("bpy.types.geometrynodecurvequadraticbezier*", "modeling/geometry_nodes/curve_primitives/quadratic_bezier.html#bpy-types-geometrynodecurvequadraticbezier"), ("bpy.types.materialgpencilstyle.show_stroke*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-show-stroke"), ("bpy.types.movietrackingcamera.focal_length*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-focal-length"), ("bpy.types.movietrackingcamera.pixel_aspect*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-pixel-aspect"), @@ -471,6 +477,7 @@ url_manual_mapping = ( ("bpy.types.geometrynodeattributecolorramp*", "modeling/geometry_nodes/attribute/attribute_color_ramp.html#bpy-types-geometrynodeattributecolorramp"), ("bpy.types.geometrynodeattributeproximity*", "modeling/geometry_nodes/attribute/attribute_proximity.html#bpy-types-geometrynodeattributeproximity"), ("bpy.types.geometrynodeattributerandomize*", "modeling/geometry_nodes/attribute/attribute_randomize.html#bpy-types-geometrynodeattributerandomize"), + ("bpy.types.geometrynodecurvequadrilateral*", "modeling/geometry_nodes/curve_primitives/quadrilateral.html#bpy-types-geometrynodecurvequadrilateral"), ("bpy.types.geometrynodeseparatecomponents*", "modeling/geometry_nodes/geometry/separate_components.html#bpy-types-geometrynodeseparatecomponents"), ("bpy.types.geometrynodesubdivisionsurface*", "modeling/geometry_nodes/mesh/subdivision_surface.html#bpy-types-geometrynodesubdivisionsurface"), ("bpy.types.imageformatsettings.color_mode*", "render/output/properties/output.html#bpy-types-imageformatsettings-color-mode"), @@ -490,7 +497,7 @@ url_manual_mapping = ( ("bpy.types.rendersettings.use_compositing*", "render/output/properties/post_processing.html#bpy-types-rendersettings-use-compositing"), ("bpy.types.rendersettings.use_placeholder*", "render/output/properties/output.html#bpy-types-rendersettings-use-placeholder"), ("bpy.types.shadernodesubsurfacescattering*", "render/shader_nodes/shader/sss.html#bpy-types-shadernodesubsurfacescattering"), - ("bpy.types.spaceclipeditor.lock_selection*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-lock-selection"), + ("bpy.types.spaceclipeditor.lock_selection*", "editors/clip/introduction.html#bpy-types-spaceclipeditor-lock-selection"), ("bpy.types.spacedopesheeteditor.auto_snap*", "editors/dope_sheet/editing.html#bpy-types-spacedopesheeteditor-auto-snap"), ("bpy.types.spaceoutliner.show_mode_column*", "editors/outliner/interface.html#bpy-types-spaceoutliner-show-mode-column"), ("bpy.types.spacetexteditor.use_match_case*", "editors/text_editor.html#bpy-types-spacetexteditor-use-match-case"), @@ -508,6 +515,7 @@ url_manual_mapping = ( ("bpy.ops.outliner.collection_show_inside*", "editors/outliner/editing.html#bpy-ops-outliner-collection-show-inside"), ("bpy.ops.preferences.reset_default_theme*", "editors/preferences/themes.html#bpy-ops-preferences-reset-default-theme"), ("bpy.ops.sequencer.strip_transform_clear*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-strip-transform-clear"), + ("bpy.ops.spreadsheet.add_row_filter_rule*", "editors/spreadsheet.html#bpy-ops-spreadsheet-add-row-filter-rule"), ("bpy.types.animdata.action_extrapolation*", "editors/nla/sidebar.html#bpy-types-animdata-action-extrapolation"), ("bpy.types.bakesettings.max_ray_distance*", "render/cycles/baking.html#bpy-types-bakesettings-max-ray-distance"), ("bpy.types.brush.multiplane_scrape_angle*", "sculpt_paint/sculpting/tools/multiplane_scrape.html#bpy-types-brush-multiplane-scrape-angle"), @@ -695,6 +703,7 @@ url_manual_mapping = ( ("bpy.types.fmodifierfunctiongenerator*", "editors/graph_editor/fcurves/sidebar/modifiers.html#bpy-types-fmodifierfunctiongenerator"), ("bpy.types.geometrynodeattributeclamp*", "modeling/geometry_nodes/attribute/attribute_clamp.html#bpy-types-geometrynodeattributeclamp"), ("bpy.types.geometrynodecollectioninfo*", "modeling/geometry_nodes/input/collection_info.html#bpy-types-geometrynodecollectioninfo"), + ("bpy.types.geometrynodecurveendpoints*", "modeling/geometry_nodes/curve/curve_endpoints.html#bpy-types-geometrynodecurveendpoints"), ("bpy.types.geometrynodecurvesubdivide*", "modeling/geometry_nodes/curve/curve_subdivide.html#bpy-types-geometrynodecurvesubdivide"), ("bpy.types.geometrynodedeletegeometry*", "modeling/geometry_nodes/geometry/delete_geometry.html#bpy-types-geometrynodedeletegeometry"), ("bpy.types.geometrynodematerialassign*", "modeling/geometry_nodes/material/assign.html#bpy-types-geometrynodematerialassign"), @@ -765,6 +774,7 @@ url_manual_mapping = ( ("bpy.types.geometrynodecurvetopoints*", "modeling/geometry_nodes/curve/curve_to_points.html#bpy-types-geometrynodecurvetopoints"), ("bpy.types.geometrynodeinputmaterial*", "modeling/geometry_nodes/input/material.html#bpy-types-geometrynodeinputmaterial"), ("bpy.types.geometrynodemeshicosphere*", "modeling/geometry_nodes/mesh_primitives/icosphere.html#bpy-types-geometrynodemeshicosphere"), + ("bpy.types.geometrynodemeshsubdivide*", "modeling/geometry_nodes/mesh/subdivide.html#bpy-types-geometrynodemeshsubdivide"), ("bpy.types.geometrynodepointinstance*", "modeling/geometry_nodes/point/point_instance.html#bpy-types-geometrynodepointinstance"), ("bpy.types.geometrynodepointseparate*", "modeling/geometry_nodes/point/point_separate.html#bpy-types-geometrynodepointseparate"), ("bpy.types.geometrynoderesamplecurve*", "modeling/geometry_nodes/curve/resample_curve.html#bpy-types-geometrynoderesamplecurve"), @@ -795,6 +805,7 @@ url_manual_mapping = ( ("bpy.types.spline.tilt_interpolation*", "modeling/curves/properties/active_spline.html#bpy-types-spline-tilt-interpolation"), ("bpy.types.transformorientation.name*", "editors/3dview/controls/orientation.html#bpy-types-transformorientation-name"), ("bpy.types.volumedisplay.slice_depth*", "modeling/volumes/properties.html#bpy-types-volumedisplay-slice-depth"), + ("bpy.ops.clip.lock_selection_toggle*", "editors/clip/introduction.html#bpy-ops-clip-lock-selection-toggle"), ("bpy.ops.mesh.customdata_mask_clear*", "sculpt_paint/sculpting/editing/mask.html#bpy-ops-mesh-customdata-mask-clear"), ("bpy.ops.mesh.extrude_vertices_move*", "modeling/meshes/editing/vertex/extrude_vertices.html#bpy-ops-mesh-extrude-vertices-move"), ("bpy.ops.mesh.mod_weighted_strength*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-mesh-mod-weighted-strength"), @@ -802,7 +813,6 @@ url_manual_mapping = ( ("bpy.ops.mesh.select_interior_faces*", "modeling/meshes/selecting/all_by_trait.html#bpy-ops-mesh-select-interior-faces"), ("bpy.ops.mesh.select_similar_region*", "modeling/meshes/selecting/similar.html#bpy-ops-mesh-select-similar-region"), ("bpy.ops.mesh.tris_convert_to_quads*", "modeling/meshes/editing/face/triangles_quads.html#bpy-ops-mesh-tris-convert-to-quads"), - ("bpy.ops.node.active_preview_toggle*", "modeling/geometry_nodes/introduction.html#bpy-ops-node-active-preview-toggle"), ("bpy.ops.object.datalayout_transfer*", "scene_layout/object/editing/link_transfer/transfer_mesh_data_layout.html#bpy-ops-object-datalayout-transfer"), ("bpy.ops.object.multires_base_apply*", "modeling/modifiers/generate/multiresolution.html#bpy-ops-object-multires-base-apply"), ("bpy.ops.object.randomize_transform*", "scene_layout/object/editing/transform/randomize.html#bpy-ops-object-randomize-transform"), @@ -872,6 +882,7 @@ url_manual_mapping = ( ("bpy.types.volumedisplay.slice_axis*", "modeling/volumes/properties.html#bpy-types-volumedisplay-slice-axis"), ("bpy.ops.anim.channels_clean_empty*", "editors/nla/editing.html#bpy-ops-anim-channels-clean-empty"), ("bpy.ops.armature.select_hierarchy*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-hierarchy"), + ("bpy.ops.armature.switch_direction*", "animation/armatures/bones/editing/switch_direction.html#bpy-ops-armature-switch-direction"), ("bpy.ops.clip.apply_solution_scale*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-apply-solution-scale"), ("bpy.ops.clip.set_center_principal*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-set-center-principal"), ("bpy.ops.clip.setup_tracking_scene*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-setup-tracking-scene"), @@ -925,7 +936,9 @@ url_manual_mapping = ( ("bpy.types.functionnodeinputstring*", "modeling/geometry_nodes/input/string.html#bpy-types-functionnodeinputstring"), ("bpy.types.functionnodeinputvector*", "modeling/geometry_nodes/input/vector.html#bpy-types-functionnodeinputvector"), ("bpy.types.functionnoderandomfloat*", "modeling/geometry_nodes/input/random_float.html#bpy-types-functionnoderandomfloat"), + ("bpy.types.geometrynodecurvecircle*", "modeling/geometry_nodes/curve_primitives/circle.html#bpy-types-geometrynodecurvecircle"), ("bpy.types.geometrynodecurvelength*", "modeling/geometry_nodes/curve/curve_length.html#bpy-types-geometrynodecurvelength"), + ("bpy.types.geometrynodecurvespiral*", "modeling/geometry_nodes/curve_primitives/spiral.html#bpy-types-geometrynodecurvespiral"), ("bpy.types.geometrynodecurvetomesh*", "modeling/geometry_nodes/curve/curve_to_mesh.html#bpy-types-geometrynodecurvetomesh"), ("bpy.types.geometrynodemeshtocurve*", "modeling/geometry_nodes/curve/mesh_to_curve.html#bpy-types-geometrynodemeshtocurve"), ("bpy.types.geometrynodepointrotate*", "modeling/geometry_nodes/point/point_rotate.html#bpy-types-geometrynodepointrotate"), @@ -989,6 +1002,7 @@ url_manual_mapping = ( ("bpy.ops.sequencer.select_handles*", "video_editing/sequencer/selecting.html#bpy-ops-sequencer-select-handles"), ("bpy.ops.uv.average_islands_scale*", "modeling/meshes/uv/editing.html#bpy-ops-uv-average-islands-scale"), ("bpy.ops.view3d.blenderkit_search*", "addons/3d_view/blenderkit.html#bpy-ops-view3d-blenderkit-search"), + ("bpy.types.armature.axes_position*", "animation/armatures/properties/display.html#bpy-types-armature-axes-position"), ("bpy.types.armature.pose_position*", "animation/armatures/properties/skeleton.html#bpy-types-armature-pose-position"), ("bpy.types.bakesettings.use_clear*", "render/cycles/baking.html#bpy-types-bakesettings-use-clear"), ("bpy.types.bone.envelope_distance*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-envelope-distance"), @@ -1024,6 +1038,7 @@ url_manual_mapping = ( ("bpy.types.editbone.bbone_scalein*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-scalein"), ("bpy.types.editbone.inherit_scale*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-inherit-scale"), ("bpy.types.geometrynodeconvexhull*", "modeling/geometry_nodes/geometry/convex_hull.html#bpy-types-geometrynodeconvexhull"), + ("bpy.types.geometrynodefloattoint*", "modeling/geometry_nodes/utilities/float_to_int.html#bpy-types-geometrynodefloattoint"), ("bpy.types.geometrynodeisviewport*", "modeling/geometry_nodes/input/is_viewport.html#bpy-types-geometrynodeisviewport"), ("bpy.types.geometrynodemeshcircle*", "modeling/geometry_nodes/mesh_primitives/circle.html#bpy-types-geometrynodemeshcircle"), ("bpy.types.geometrynodeobjectinfo*", "modeling/geometry_nodes/input/object_info.html#bpy-types-geometrynodeobjectinfo"), @@ -1051,6 +1066,8 @@ url_manual_mapping = ( ("bpy.types.volumerender.step_size*", "modeling/volumes/properties.html#bpy-types-volumerender-step-size"), ("bpy.types.weightednormalmodifier*", "modeling/modifiers/modify/weighted_normal.html#bpy-types-weightednormalmodifier"), ("bpy.ops.armature.autoside_names*", "animation/armatures/bones/editing/naming.html#bpy-ops-armature-autoside-names"), + ("bpy.ops.armature.calculate_roll*", "animation/armatures/bones/editing/bone_roll.html#bpy-ops-armature-calculate-roll"), + ("bpy.ops.armature.duplicate_move*", "animation/armatures/bones/editing/duplicate.html#bpy-ops-armature-duplicate-move"), ("bpy.ops.armature.select_similar*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-similar"), ("bpy.ops.clip.create_plane_track*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-create-plane-track"), ("bpy.ops.curve.spline_weight_set*", "modeling/curves/editing/other.html#bpy-ops-curve-spline-weight-set"), @@ -1099,6 +1116,7 @@ url_manual_mapping = ( ("bpy.ops.wm.operator_cheat_sheet*", "advanced/operators.html#bpy-ops-wm-operator-cheat-sheet"), ("bpy.ops.wm.previews_batch_clear*", "files/blend/previews.html#bpy-ops-wm-previews-batch-clear"), ("bpy.ops.wm.recover_last_session*", "files/blend/open_save.html#bpy-ops-wm-recover-last-session"), + ("bpy.types.armature.display_type*", "animation/armatures/properties/display.html#bpy-types-armature-display-type"), ("bpy.types.armature.use_mirror_x*", "animation/armatures/bones/tools/tool_settings.html#bpy-types-armature-use-mirror-x"), ("bpy.types.bakesettings.normal_b*", "render/cycles/baking.html#bpy-types-bakesettings-normal-b"), ("bpy.types.bakesettings.normal_g*", "render/cycles/baking.html#bpy-types-bakesettings-normal-g"), @@ -1127,8 +1145,10 @@ url_manual_mapping = ( ("bpy.types.editbone.bbone_rollin*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-rollin"), ("bpy.types.fluideffectorsettings*", "physics/fluid/type/effector.html#bpy-types-fluideffectorsettings"), ("bpy.types.followtrackconstraint*", "animation/constraints/motion_tracking/follow_track.html#bpy-types-followtrackconstraint"), + ("bpy.types.geometrynodecurveline*", "modeling/geometry_nodes/curve_primitives/line.html#bpy-types-geometrynodecurveline"), + ("bpy.types.geometrynodecurvestar*", "modeling/geometry_nodes/curve_primitives/star.html#bpy-types-geometrynodecurvestar"), + ("bpy.types.geometrynodecurvetrim*", "modeling/geometry_nodes/curve/curve_trim.html#bpy-types-geometrynodecurvetrim"), ("bpy.types.geometrynodeedgesplit*", "modeling/geometry_nodes/mesh/edge_split.html#bpy-types-geometrynodeedgesplit"), - ("bpy.types.geometrynodesubdivide*", "modeling/geometry_nodes/mesh/subdivide.html#bpy-types-geometrynodesubdivide"), ("bpy.types.geometrynodetransform*", "modeling/geometry_nodes/geometry/transform.html#bpy-types-geometrynodetransform"), ("bpy.types.gpencilsculptsettings*", "grease_pencil/properties/index.html#bpy-types-gpencilsculptsettings"), ("bpy.types.light.cutoff_distance*", "render/eevee/lighting.html#bpy-types-light-cutoff-distance"), @@ -1247,6 +1267,8 @@ url_manual_mapping = ( ("bpy.types.volumetomeshmodifier*", "modeling/modifiers/generate/volume_to_mesh.html#bpy-types-volumetomeshmodifier"), ("bpy.types.whitebalancemodifier*", "video_editing/sequencer/sidebar/modifiers.html#bpy-types-whitebalancemodifier"), ("bpy.ops.anim.channels_ungroup*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-ungroup"), + ("bpy.ops.armature.extrude_move*", "animation/armatures/bones/editing/extrude.html#bpy-ops-armature-extrude-move"), + ("bpy.ops.armature.parent_clear*", "animation/armatures/bones/editing/parenting.html#bpy-ops-armature-parent-clear"), ("bpy.ops.clip.clear_track_path*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-clear-track-path"), ("bpy.ops.clip.set_scene_frames*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-set-scene-frames"), ("bpy.ops.curve.handle_type_set*", "modeling/curves/editing/control_points.html#bpy-ops-curve-handle-type-set"), @@ -1424,6 +1446,7 @@ url_manual_mapping = ( ("bpy.types.freestylelinestyle*", "render/freestyle/parameter_editor/line_style/index.html#bpy-types-freestylelinestyle"), ("bpy.types.gammacrosssequence*", "video_editing/sequencer/strips/transitions/gamma_cross.html#bpy-types-gammacrosssequence"), ("bpy.types.geometrynodeswitch*", "modeling/geometry_nodes/utilities/switch.html#bpy-types-geometrynodeswitch"), + ("bpy.types.geometrynodeviewer*", "modeling/geometry_nodes/output/viewer.html#bpy-types-geometrynodeviewer"), ("bpy.types.gpencilsculptguide*", "grease_pencil/modes/draw/guides.html#bpy-types-gpencilsculptguide"), ("bpy.types.huecorrectmodifier*", "video_editing/sequencer/sidebar/modifiers.html#bpy-types-huecorrectmodifier"), ("bpy.types.imagepaint.stencil*", "sculpt_paint/texture_paint/tool_settings/mask.html#bpy-types-imagepaint-stencil"), @@ -1462,7 +1485,9 @@ url_manual_mapping = ( ("bpy.ops.anim.channels_group*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-group"), ("bpy.ops.anim.keyframe_clear*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-clear"), ("bpy.ops.armature.flip_names*", "animation/armatures/bones/editing/naming.html#bpy-ops-armature-flip-names"), + ("bpy.ops.armature.parent_set*", "animation/armatures/bones/editing/parenting.html#bpy-ops-armature-parent-set"), ("bpy.ops.armature.select_all*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-all"), + ("bpy.ops.armature.symmetrize*", "animation/armatures/bones/editing/symmetrize.html#bpy-ops-armature-symmetrize"), ("bpy.ops.clip.average_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-average-tracks"), ("bpy.ops.clip.refine_markers*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-refine-markers"), ("bpy.ops.clip.select_grouped*", "movie_clip/tracking/clip/selecting.html#bpy-ops-clip-select-grouped"), @@ -1501,6 +1526,8 @@ url_manual_mapping = ( ("bpy.ops.object.shade_smooth*", "scene_layout/object/editing/shading.html#bpy-ops-object-shade-smooth"), ("bpy.ops.object.voxel_remesh*", "modeling/meshes/retopology.html#bpy-ops-object-voxel-remesh"), ("bpy.ops.pose.armature_apply*", "animation/armatures/posing/editing/apply.html#bpy-ops-pose-armature-apply"), + ("bpy.ops.pose.group_deselect*", "animation/armatures/properties/bone_groups.html#bpy-ops-pose-group-deselect"), + ("bpy.ops.pose.group_unassign*", "animation/armatures/properties/bone_groups.html#bpy-ops-pose-group-unassign"), ("bpy.ops.pose.select_grouped*", "animation/armatures/posing/selecting.html#bpy-ops-pose-select-grouped"), ("bpy.ops.poselib.pose_remove*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-pose-remove"), ("bpy.ops.poselib.pose_rename*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-pose-rename"), @@ -1574,6 +1601,7 @@ url_manual_mapping = ( ("bpy.types.wireframemodifier*", "modeling/modifiers/generate/wireframe.html#bpy-types-wireframemodifier"), ("bpy.types.worldmistsettings*", "render/cycles/world_settings.html#bpy-types-worldmistsettings"), ("bpy.ops.anim.channels_move*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-move"), + ("bpy.ops.armature.subdivide*", "animation/armatures/bones/editing/subdivide.html#bpy-ops-armature-subdivide"), ("bpy.ops.buttons.toggle_pin*", "editors/properties_editor.html#bpy-ops-buttons-toggle-pin"), ("bpy.ops.clip.filter_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-filter-tracks"), ("bpy.ops.clip.select_circle*", "movie_clip/tracking/clip/selecting.html#bpy-ops-clip-select-circle"), @@ -1675,6 +1703,8 @@ url_manual_mapping = ( ("bpy.types.texturenodegroup*", "editors/texture_node/types/groups.html#bpy-types-texturenodegroup"), ("bpy.types.texturenodeimage*", "editors/texture_node/types/input/image.html#bpy-types-texturenodeimage"), ("bpy.types.viewlayer.use_ao*", "render/layers/introduction.html#bpy-types-viewlayer-use-ao"), + ("bpy.ops.armature.dissolve*", "animation/armatures/bones/editing/delete.html#bpy-ops-armature-dissolve"), + ("bpy.ops.armature.separate*", "animation/armatures/bones/editing/separate_bones.html#bpy-ops-armature-separate"), ("bpy.ops.clip.clean_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-clean-tracks"), ("bpy.ops.clip.delete_track*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-delete-track"), ("bpy.ops.clip.solve_camera*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-solve-camera"), @@ -1703,6 +1733,8 @@ url_manual_mapping = ( ("bpy.ops.object.proxy_make*", "files/linked_libraries/library_proxies.html#bpy-ops-object-proxy-make"), ("bpy.ops.object.select_all*", "scene_layout/object/selecting.html#bpy-ops-object-select-all"), ("bpy.ops.object.shade_flat*", "scene_layout/object/editing/shading.html#bpy-ops-object-shade-flat"), + ("bpy.ops.pose.group_assign*", "animation/armatures/properties/bone_groups.html#bpy-ops-pose-group-assign"), + ("bpy.ops.pose.group_select*", "animation/armatures/properties/bone_groups.html#bpy-ops-pose-group-select"), ("bpy.ops.poselib.pose_move*", "animation/armatures/properties/pose_library.html#bpy-ops-poselib-pose-move"), ("bpy.ops.preferences.addon*", "editors/preferences/addons.html#bpy-ops-preferences-addon"), ("bpy.ops.scene.light_cache*", "render/eevee/render_settings/indirect_lighting.html#bpy-ops-scene-light-cache"), @@ -1872,6 +1904,7 @@ url_manual_mapping = ( ("bpy.ops.wm.owner_enable*", "interface/window_system/workspaces.html#bpy-ops-wm-owner-enable"), ("bpy.ops.wm.redraw_timer*", "advanced/operators.html#bpy-ops-wm-redraw-timer"), ("bpy.types.*light.shadow*", "render/eevee/lighting.html#bpy-types-light-shadow"), + ("bpy.types.armature.show*", "animation/armatures/properties/display.html#bpy-types-armature-show"), ("bpy.types.armaturebones*", "animation/armatures/bones/index.html#bpy-types-armaturebones"), ("bpy.types.arraymodifier*", "modeling/modifiers/generate/array.html#bpy-types-arraymodifier"), ("bpy.types.bevelmodifier*", "modeling/modifiers/generate/bevel.html#bpy-types-bevelmodifier"), @@ -1919,6 +1952,8 @@ url_manual_mapping = ( ("bpy.types.volumedisplay*", "modeling/volumes/properties.html#bpy-types-volumedisplay"), ("bpy.types.windowmanager*", "interface/index.html#bpy-types-windowmanager"), ("bpy.ops.*.select_lasso*", "interface/selecting.html#bpy-ops-select-lasso"), + ("bpy.ops.armature.align*", "animation/armatures/bones/editing/transform.html#bpy-ops-armature-align"), + ("bpy.ops.armature.split*", "animation/armatures/bones/editing/split.html#bpy-ops-armature-split"), ("bpy.ops.clip.set_plane*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-set-plane"), ("bpy.ops.clip.set_scale*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-set-scale"), ("bpy.ops.curve.decimate*", "modeling/curves/editing/curve.html#bpy-ops-curve-decimate"), @@ -1993,6 +2028,7 @@ url_manual_mapping = ( ("bpy.types.wavemodifier*", "modeling/modifiers/deform/wave.html#bpy-types-wavemodifier"), ("bpy.types.weldmodifier*", "modeling/modifiers/generate/weld.html#bpy-types-weldmodifier"), ("bpy.types.wipesequence*", "video_editing/sequencer/strips/transitions/wipe.html#bpy-types-wipesequence"), + ("bpy.ops.armature.fill*", "animation/armatures/bones/editing/fill_between_joints.html#bpy-ops-armature-fill"), ("bpy.ops.clip.prefetch*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-prefetch"), ("bpy.ops.clip.set_axis*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-set-axis"), ("bpy.ops.file.pack_all*", "files/blend/packed_data.html#bpy-ops-file-pack-all"), @@ -2064,6 +2100,7 @@ url_manual_mapping = ( ("bpy.ops.uv.mark_seam*", "modeling/meshes/uv/unwrapping/seams.html#bpy-ops-uv-mark-seam"), ("bpy.ops.view3d.ruler*", "editors/3dview/toolbar/measure.html#bpy-ops-view3d-ruler"), ("bpy.types.areaspaces*", "interface/window_system/areas.html#bpy-types-areaspaces"), + ("bpy.types.bonegroups*", "animation/armatures/properties/bone_groups.html#bpy-types-bonegroups"), ("bpy.types.bpy_struct*", "files/data_blocks.html#bpy-types-bpy-struct"), ("bpy.types.collection*", "scene_layout/collections/collections.html#bpy-types-collection"), ("bpy.types.compositor*", "compositing/index.html#bpy-types-compositor"), diff --git a/release/scripts/startup/bl_operators/assets.py b/release/scripts/startup/bl_operators/assets.py index d2655784afd..c782cd0646e 100644 --- a/release/scripts/startup/bl_operators/assets.py +++ b/release/scripts/startup/bl_operators/assets.py @@ -18,7 +18,6 @@ # <pep8 compliant> from __future__ import annotations -from pathlib import Path import bpy from bpy.types import Operator diff --git a/release/scripts/startup/bl_operators/geometry_nodes.py b/release/scripts/startup/bl_operators/geometry_nodes.py index 71ef89a066b..ec2887a1a74 100644 --- a/release/scripts/startup/bl_operators/geometry_nodes.py +++ b/release/scripts/startup/bl_operators/geometry_nodes.py @@ -81,7 +81,10 @@ class NewGeometryNodeTreeAssign(Operator): return geometry_modifier_poll(context) def execute(self, context): - modifier = context.object.modifiers.active + if context.area.type == 'PROPERTIES': + modifier = context.modifier + else: + modifier = context.object.modifiers.active if not modifier: return {'CANCELLED'} diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py index bc80500c888..7f5edac4dfb 100644 --- a/release/scripts/startup/bl_operators/rigidbody.py +++ b/release/scripts/startup/bl_operators/rigidbody.py @@ -60,17 +60,22 @@ class CopyRigidbodySettings(Operator): def execute(self, context): obj_act = context.object - view_layer = context.view_layer - # deselect all but mesh objects + # Deselect all non mesh objects and objects that + # already have a rigid body attached. + rb_objects = [] for o in context.selected_objects: - if o.type != 'MESH': + if o.type != 'MESH' or o.rigid_body is not None: o.select_set(False) - elif o.rigid_body is None: - # Add rigidbody to object! - view_layer.objects.active = o - bpy.ops.rigidbody.object_add() - view_layer.objects.active = obj_act + if o.rigid_body is not None: + rb_objects.append(o) + + bpy.ops.rigidbody.objects_add() + + # Ensure that the rigid body objects + # we've de-selected are selected again. + for o in rb_objects: + o.select_set(True) objects = context.selected_objects if objects: diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py index 48a02a4c5c6..8f678896e61 100644 --- a/release/scripts/startup/bl_operators/sequencer.py +++ b/release/scripts/startup/bl_operators/sequencer.py @@ -108,14 +108,13 @@ class SequencerSplitMulticam(Operator): if s.multicam_source == camera or camera >= s.channel: return {'FINISHED'} - if not s.select: - s.select = True - cfra = context.scene.frame_current - bpy.ops.sequencer.split(frame=cfra, type='SOFT', side='RIGHT') - for s in context.scene.sequence_editor.sequences_all: - if s.select and s.type == 'MULTICAM' and s.frame_final_start <= cfra and cfra < s.frame_final_end: - context.scene.sequence_editor.active_strip = s + right_strip = s.split(frame=cfra, split_method='SOFT') + + if right_strip: + s.select = False + right_strip.select = True + context.scene.sequence_editor.active_strip = right_strip context.scene.sequence_editor.active_strip.multicam_source = camera return {'FINISHED'} diff --git a/release/scripts/startup/bl_ui/properties_collection.py b/release/scripts/startup/bl_ui/properties_collection.py index b51d7157c06..3f7c0735eec 100644 --- a/release/scripts/startup/bl_ui/properties_collection.py +++ b/release/scripts/startup/bl_ui/properties_collection.py @@ -86,12 +86,15 @@ class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel): row = layout.row() row.prop(collection, "lineart_usage") - layout.prop(collection, "lineart_use_intersection_mask") + layout.prop(collection, "lineart_use_intersection_mask", text="Collection Mask") - row = layout.row(align=True, heading="Masks") - row.active = collection.lineart_use_intersection_mask + col = layout.column(align=True) + col.active = collection.lineart_use_intersection_mask + row = col.row(align=True, heading="Masks") for i in range(8): - row.prop(collection, "lineart_intersection_mask", index=i, text=str(i), toggle=True) + row.prop(collection, "lineart_intersection_mask", index=i, text=" ", toggle=True) + if i == 3: + row = col.row(align=True) classes = ( diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 7f4328bb25a..d9ad094ac4f 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -646,7 +646,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel): if len(colliding_names) == 0: return - layout.label(text="Name Collisions: {}".format(", ".join(colliding_names)), icon='INFO') + layout.label(text="Name collisions: {}".format(", ".join(colliding_names)), icon='ERROR') classes = ( diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index b217e33de12..1c7f3639f0a 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -291,18 +291,18 @@ class MATERIAL_PT_lineart(MaterialButtonsPanel, Panel): mat = context.material lineart = mat.lineart - layout.prop(lineart, "use_material_mask") + layout.prop(lineart, "use_material_mask", text="Material Mask") - row = layout.row(align=True, heading="Masks") - row.active = lineart.use_material_mask + col = layout.column(align=True) + col.active = lineart.use_material_mask + row = col.row(align=True, heading="Masks") for i in range(8): - row.prop(lineart, "use_material_mask_bits", text=str(i), index=i, toggle=True) + row.prop(lineart, "use_material_mask_bits", text=" ", index=i, toggle=True) + if i == 3: + row = col.row(align=True) row = layout.row(align=True, heading="Custom Occlusion") - row.prop(lineart, "use_mat_occlusion", text="") - sub = row.row(align=False) - sub.active = lineart.use_mat_occlusion - sub.prop(lineart, "mat_occlusion", slider=True, text="Levels") + row.prop(lineart, "mat_occlusion", text="Levels") classes = ( diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 55714e0b0a5..47b04f9cdbc 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -1156,14 +1156,19 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): flow.prop(strip, "use_only_boost") elif strip_type == 'SPEED': - layout.prop(strip, "use_default_fade", text="Stretch to Input Strip Length") - if not strip.use_default_fade: - layout.prop(strip, "use_as_speed") - if strip.use_as_speed: - layout.prop(strip, "speed_factor") - else: - layout.prop(strip, "speed_factor", text="Frame Number") - layout.prop(strip, "use_scale_to_length") + col = layout.column(align=True) + col.prop(strip, "speed_control", text="Speed Control") + if strip.speed_control == "MULTIPLY": + col.prop(strip, "speed_factor", text=" ") + elif strip.speed_control == "LENGTH": + col.prop(strip, "speed_length", text=" ") + elif strip.speed_control == "FRAME_NUMBER": + col.prop(strip, "speed_frame_number", text=" ") + + row = layout.row(align=True) + row.enabled = strip.speed_control != "STRETCH" + row = layout.row(align=True, heading="Interpolation") + row.prop(strip, "use_frame_interpolate", text="") elif strip_type == 'TRANSFORM': col = layout.column() @@ -1233,11 +1238,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): layout.prop(strip, "wrap_width", text="Wrap Width") col = layout.column(align=True) - if strip_type == 'SPEED': - col.prop(strip, "multiply_speed") - col.prop(strip, "use_frame_interpolate") - - elif strip_type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'ALPHA_OVER', 'ALPHA_UNDER', 'OVER_DROP'}: + if strip_type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'ALPHA_OVER', 'ALPHA_UNDER', 'OVER_DROP'}: col.prop(strip, "use_default_fade", text="Default Fade") if not strip.use_default_fade: col.prop(strip, "effect_fader", text="Effect Fader") diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 2b0ac6046bc..f130a79ede0 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -544,8 +544,10 @@ geometry_node_categories = [ NodeItem("GeometryNodeMeshToCurve"), NodeItem("GeometryNodeCurveToPoints"), NodeItem("GeometryNodeCurveEndpoints"), + NodeItem("GeometryNodeCurveTrim"), NodeItem("GeometryNodeCurveLength"), NodeItem("GeometryNodeCurveReverse"), + NodeItem("GeometryNodeCurveSetHandles"), ]), GeometryNodeCategory("GEO_PRIMITIVES_CURVE", "Curve Primitives", items=[ NodeItem("GeometryNodeCurvePrimitiveLine"), diff --git a/release/scripts/templates_py/custom_nodes.py b/release/scripts/templates_py/custom_nodes.py index ca9534e7cd3..fba94e23d0d 100644 --- a/release/scripts/templates_py/custom_nodes.py +++ b/release/scripts/templates_py/custom_nodes.py @@ -147,7 +147,7 @@ node_categories = [ MyNodeCategory('OTHERNODES', "Other Nodes", items=[ # the node item can have additional settings, # which are applied to new nodes - # NB: settings values are stored as string expressions, + # NOTE: settings values are stored as string expressions, # for this reason they should be converted to strings using repr() NodeItem("CustomNodeType", label="Node A", settings={ "my_string_prop": repr("Lorem ipsum dolor sit amet"), diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 904b7bb8718..e3954e134da 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -158,7 +158,7 @@ struct DerivedMesh { int (*getNumPolys)(DerivedMesh *dm); /** Copy a single vert/edge/tessellated face from the derived mesh into - * ``*r_{vert/edge/face}``. note that the current implementation + * `*r_{vert/edge/face}`. note that the current implementation * of this function can be quite slow, iterating over all * elements (editmesh) */ diff --git a/source/blender/blenkernel/BKE_action.hh b/source/blender/blenkernel/BKE_action.hh new file mode 100644 index 00000000000..b9f106d367e --- /dev/null +++ b/source/blender/blenkernel/BKE_action.hh @@ -0,0 +1,35 @@ +/* + * 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. + */ +#pragma once + +/** \file + * \ingroup bke + */ +#ifndef __cplusplus +# error This is a C++ only header. +#endif + +#include "BLI_function_ref.hh" + +struct bAction; +struct FCurve; + +namespace blender::bke { + +using FoundFCurveCallback = blender::FunctionRef<void(FCurve *fcurve, const char *bone_name)>; +void BKE_action_find_fcurves_with_bones(const bAction *action, FoundFCurveCallback callback); + +}; // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_armature.hh b/source/blender/blenkernel/BKE_armature.hh new file mode 100644 index 00000000000..e3f5b528156 --- /dev/null +++ b/source/blender/blenkernel/BKE_armature.hh @@ -0,0 +1,48 @@ +/* + * 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. + */ +#pragma once + +/** \file + * \ingroup bke + */ +#ifndef __cplusplus +# error This is a C++ only header. +#endif + +#include "BKE_armature.h" + +#include "BLI_function_ref.hh" +#include "BLI_set.hh" + +namespace blender::bke { + +struct SelectedBonesResult { + bool all_bones_selected = true; + bool no_bones_selected = true; +}; + +using SelectedBoneCallback = blender::FunctionRef<void(Bone *bone)>; +SelectedBonesResult BKE_armature_find_selected_bones(const bArmature *armature, + SelectedBoneCallback callback); + +using BoneNameSet = blender::Set<std::string>; +/** + * Return a set of names of the selected bones. An empty set means "ignore bone + * selection", which either means all bones are selected, or none are. + */ +BoneNameSet BKE_armature_find_selected_bone_names(const bArmature *armature); + +}; // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 28903c4787c..28be2c0f30d 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 12 +#define BLENDER_FILE_SUBVERSION 13 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index a0e3d5dc142..dbf285feb92 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -39,14 +39,14 @@ struct Scene; #define DO_INLINE MALWAYS_INLINE -/* goal defines */ +/* Goal defines. */ #define SOFTGOALSNAP 0.999f /* This is approximately the smallest number that can be * represented by a float, given its precision. */ #define ALMOST_ZERO FLT_EPSILON -/* Bits to or into the ClothVertex.flags. */ +/* Bits to or into the #ClothVertex.flags. */ typedef enum eClothVertexFlag { CLOTH_VERT_FLAG_PINNED = (1 << 0), CLOTH_VERT_FLAG_NOSELFCOLL = (1 << 1), /* vertex NOT used for self collisions */ @@ -150,7 +150,7 @@ typedef struct ClothSpring { float target[3]; } ClothSpring; -// some macro enhancements for vector treatment +/* Some macro enhancements for vector treatment. */ #define VECSUBADDSS(v1, v2, aS, v3, bS) \ { \ *(v1) -= *(v2)*aS + *(v3)*bS; \ @@ -211,9 +211,8 @@ typedef enum { CLOTH_SPRING_FLAG_NEEDED = (1 << 2), /* Springs has values to be applied. */ } CLOTH_SPRINGS_FLAGS; -///////////////////////////////////////////////// -// collision.c -//////////////////////////////////////////////// +/* -------------------------------------------------------------------- */ +/* collision.c */ struct CollPair; @@ -225,20 +224,17 @@ typedef struct ColliderContacts { int totcollisions; } ColliderContacts; -// needed for implicit.c +/* needed for implicit.c */ int cloth_bvh_collision(struct Depsgraph *depsgraph, struct Object *ob, struct ClothModifierData *clmd, float step, float dt); -//////////////////////////////////////////////// +/* -------------------------------------------------------------------- */ +/* cloth.c */ -///////////////////////////////////////////////// -// cloth.c -//////////////////////////////////////////////// - -// needed for modifier.c +/* Needed for modifier.c */ void cloth_free_modifier_extern(struct ClothModifierData *clmd); void cloth_free_modifier(struct ClothModifierData *clmd); void clothModifier_do(struct ClothModifierData *clmd, @@ -250,18 +246,16 @@ void clothModifier_do(struct ClothModifierData *clmd, int cloth_uses_vgroup(struct ClothModifierData *clmd); -// needed for collision.c +/* Needed for collision.c */ void bvhtree_update_from_cloth(struct ClothModifierData *clmd, bool moving, bool self); -// needed for button_object.c +/* Needed for button_object.c */ void cloth_clear_cache(struct Object *ob, struct ClothModifierData *clmd, float framenr); void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3], const float dir_new[3]); -//////////////////////////////////////////////// - #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index c7c5f59cab2..5e474c0c5ac 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -97,7 +97,6 @@ struct BoundBox *BKE_curve_boundbox_get(struct Object *ob); void BKE_curve_texspace_calc(struct Curve *cu); void BKE_curve_texspace_ensure(struct Curve *cu); -void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_size[3]); bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]); bool BKE_curve_center_median(struct Curve *cu, float cent[3]); diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index c4db8ee925e..7a44553c565 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -501,7 +501,7 @@ enum { CD_FAKE = 1 << 8, /* Vertices. */ - CD_FAKE_MDEFORMVERT = CD_FAKE | CD_MDEFORMVERT, /* *sigh* due to how vgroups are stored :( . */ + CD_FAKE_MDEFORMVERT = CD_FAKE | CD_MDEFORMVERT, /* *sigh* due to how vgroups are stored :(. */ CD_FAKE_SHAPEKEY = CD_FAKE | CD_SHAPEKEY, /* Not available as real CD layer in non-bmesh context. */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 12560ebed7b..e3be9cd8ef8 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -126,8 +126,8 @@ void BKE_mesh_eval_delete(struct Mesh *mesh_eval); struct Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference); /* These functions construct a new Mesh, - * contrary to BKE_mesh_from_nurbs which modifies ob itself. */ -struct Mesh *BKE_mesh_new_nomain_from_curve(struct Object *ob); + * contrary to BKE_mesh_to_curve_nurblist which modifies ob itself. */ +struct Mesh *BKE_mesh_new_nomain_from_curve(const struct Object *ob); struct Mesh *BKE_mesh_new_nomain_from_curve_displist(const struct Object *ob, const struct ListBase *dispbase); @@ -143,32 +143,11 @@ int BKE_mesh_mface_index_validate(struct MFace *mface, struct Mesh *BKE_mesh_from_object(struct Object *ob); void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me); void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me); -int BKE_mesh_nurbs_to_mdata(struct Object *ob, - struct MVert **r_allvert, - int *r_totvert, - struct MEdge **r_alledge, - int *r_totedge, - struct MLoop **r_allloop, - struct MPoly **r_allpoly, - int *r_totloop, - int *r_totpoly); -int BKE_mesh_nurbs_displist_to_mdata(const struct Object *ob, - const struct ListBase *dispbase, - struct MVert **r_allvert, - int *r_totvert, - struct MEdge **r_alledge, - int *r_totedge, - struct MLoop **r_allloop, - struct MPoly **r_allpoly, - struct MLoopUV **r_alluv, - int *r_totloop, - int *r_totpoly); void BKE_mesh_from_nurbs_displist(struct Main *bmain, struct Object *ob, struct ListBase *dispbase, const char *obdata_name, bool temporary); -void BKE_mesh_from_nurbs(struct Main *bmain, struct Object *ob); void BKE_mesh_to_curve_nurblist(const struct Mesh *me, struct ListBase *nurblist, const int edge_users_test); @@ -420,6 +399,12 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const char data_type); void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr); void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr); + +void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr, + MLoopNorSpaceArray *lnors_spacearr_tls); +void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr, + MLoopNorSpaceArray *lnors_spacearr_tls); + MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr); void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3], diff --git a/source/blender/blenkernel/BKE_mesh_iterators.h b/source/blender/blenkernel/BKE_mesh_iterators.h index 103e7b5b78f..a65f25ee182 100644 --- a/source/blender/blenkernel/BKE_mesh_iterators.h +++ b/source/blender/blenkernel/BKE_mesh_iterators.h @@ -41,6 +41,7 @@ void BKE_mesh_foreach_mapped_vert(struct Mesh *mesh, MeshForeachFlag flag); void BKE_mesh_foreach_mapped_edge( struct Mesh *mesh, + int tot_edges, void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]), void *userData); void BKE_mesh_foreach_mapped_loop(struct Mesh *mesh, diff --git a/source/blender/blenkernel/BKE_mesh_types.h b/source/blender/blenkernel/BKE_mesh_types.h index b223d3872ff..aed8c44a031 100644 --- a/source/blender/blenkernel/BKE_mesh_types.h +++ b/source/blender/blenkernel/BKE_mesh_types.h @@ -27,7 +27,6 @@ typedef enum eMeshBatchDirtyMode { BKE_MESH_BATCH_DIRTY_SELECT, BKE_MESH_BATCH_DIRTY_SELECT_PAINT, BKE_MESH_BATCH_DIRTY_SHADING, - BKE_MESH_BATCH_DIRTY_DEFORM, BKE_MESH_BATCH_DIRTY_UVEDIT_ALL, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT, } eMeshBatchDirtyMode; diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 63b11a194ff..cecb3118038 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1464,6 +1464,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_CURVE_PRIMITIVE_LINE 1068 #define GEO_NODE_CURVE_ENDPOINTS 1069 #define GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL 1070 +#define GEO_NODE_CURVE_TRIM 1071 +#define GEO_NODE_CURVE_SET_HANDLES 1072 /** \} */ diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index a16822fd7dd..4724e6dfab6 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -374,10 +374,6 @@ void BKE_object_runtime_free_data(struct Object *object); void BKE_object_batch_cache_dirty_tag(struct Object *ob); void BKE_object_data_batch_cache_dirty_tag(struct ID *object_data); -void BKE_object_data_eval_batch_cache_dirty_tag(struct Depsgraph *depsgraph, - struct ID *object_data); -void BKE_object_data_eval_batch_cache_deform_tag(struct Depsgraph *depsgraph, - struct ID *object_data); /* this function returns a superset of the scenes selection based on relationships */ diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index f85e62768f7..53485ecbd6b 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -306,6 +306,7 @@ class BezierSpline final : public Spline { blender::MutableSpan<HandleType> handle_types_right(); blender::Span<blender::float3> handle_positions_right() const; blender::MutableSpan<blender::float3> handle_positions_right(); + void ensure_auto_handles() const; void translate(const blender::float3 &translation) override; void transform(const blender::float4x4 &matrix) override; @@ -353,8 +354,6 @@ class BezierSpline final : public Spline { void correct_end_tangents() const final; void copy_settings(Spline &dst) const final; void copy_data(Spline &dst) const final; - - void ensure_auto_handles() const; }; /** @@ -544,6 +543,7 @@ struct CurveEval { blender::Span<SplinePtr> splines() const; blender::MutableSpan<SplinePtr> splines(); + bool has_spline_with_type(const Spline::Type type) const; void resize(const int size); void add_spline(SplinePtr spline); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 2c25b940578..e8f31ae72c0 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -69,6 +69,7 @@ set(SRC intern/CCGSubSurf_util.c intern/DerivedMesh.cc intern/action.c + intern/action_bones.cc intern/action_mirror.c intern/addon.c intern/anim_data.c @@ -77,6 +78,7 @@ set(SRC intern/anim_visualization.c intern/appdir.c intern/armature.c + intern/armature_selection.cc intern/armature_deform.c intern/armature_pose.cc intern/armature_update.c @@ -143,7 +145,7 @@ set(SRC intern/geometry_set_instances.cc intern/gpencil.c intern/gpencil_curve.c - intern/gpencil_geom.c + intern/gpencil_geom.cc intern/gpencil_modifier.c intern/hair.c intern/icons.cc @@ -287,6 +289,7 @@ set(SRC BKE_DerivedMesh.h BKE_action.h + BKE_action.hh BKE_addon.h BKE_anim_data.h BKE_anim_path.h @@ -294,6 +297,7 @@ set(SRC BKE_animsys.h BKE_appdir.h BKE_armature.h + BKE_armature.hh BKE_asset.h BKE_attribute.h BKE_attribute_access.hh diff --git a/source/blender/blenkernel/intern/action_bones.cc b/source/blender/blenkernel/intern/action_bones.cc new file mode 100644 index 00000000000..b8d185e6a81 --- /dev/null +++ b/source/blender/blenkernel/intern/action_bones.cc @@ -0,0 +1,48 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "BKE_action.hh" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "DNA_action_types.h" +#include "DNA_anim_types.h" + +#include "MEM_guardedalloc.h" + +namespace blender::bke { + +void BKE_action_find_fcurves_with_bones(const bAction *action, FoundFCurveCallback callback) +{ + LISTBASE_FOREACH (FCurve *, fcu, &action->curves) { + char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); + if (!bone_name) { + continue; + } + callback(fcu, bone_name); + MEM_freeN(bone_name); + } +} + +} // namespace blender::bke diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 2879a995ad6..ffc060bb64e 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1947,7 +1947,7 @@ static void nlaevalchan_blendOrcombine(NlaEvalChannelSnapshot *lower_necs, return; } default: - BLI_assert("Mix mode should've been handled"); + BLI_assert_msg(0, "Mix mode should've been handled"); } return; } @@ -1960,7 +1960,7 @@ static void nlaevalchan_blendOrcombine(NlaEvalChannelSnapshot *lower_necs, return; } default: - BLI_assert("Blend mode should've been handled"); + BLI_assert_msg(0, "Blend mode should've been handled"); } } @@ -2110,7 +2110,7 @@ static void nlaevalchan_blendOrcombine_get_inverted_upper_evalchan( return; } default: - BLI_assert("Mix mode should've been handled"); + BLI_assert_msg(0, "Mix mode should've been handled"); } return; } @@ -2123,7 +2123,7 @@ static void nlaevalchan_blendOrcombine_get_inverted_upper_evalchan( return; } default: - BLI_assert("Blend mode should've been handled"); + BLI_assert_msg(0, "Blend mode should've been handled"); } } diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c index 5e9259f05bb..5f721b49361 100644 --- a/source/blender/blenkernel/intern/armature_deform.c +++ b/source/blender/blenkernel/intern/armature_deform.c @@ -501,7 +501,7 @@ static void armature_deform_coords_impl(const Object *ob_arm, BLI_assert(0); } - if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { + if (BKE_object_supports_vertex_groups(ob_target)) { /* get the def_nr for the overall armature vertex group if present */ armature_def_nr = BKE_object_defgroup_name_index(ob_target, defgrp_name); @@ -529,11 +529,9 @@ static void armature_deform_coords_impl(const Object *ob_arm, dverts_len = gps_target->totpoints; } } - } - /* get a vertex-deform-index to posechannel array */ - if (deformflag & ARM_DEF_VGROUP) { - if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { + /* get a vertex-deform-index to posechannel array */ + if (deformflag & ARM_DEF_VGROUP) { /* if we have a Mesh, only use dverts if it has them */ if (em_target) { cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT); diff --git a/source/blender/blenkernel/intern/armature_pose.cc b/source/blender/blenkernel/intern/armature_pose.cc index 09e1c7d6615..a62a32d9633 100644 --- a/source/blender/blenkernel/intern/armature_pose.cc +++ b/source/blender/blenkernel/intern/armature_pose.cc @@ -23,8 +23,9 @@ * \ingroup bke */ +#include "BKE_action.hh" #include "BKE_animsys.h" -#include "BKE_armature.h" +#include "BKE_armature.hh" #include "BLI_function_ref.hh" #include "BLI_set.hh" @@ -36,14 +37,14 @@ #include "RNA_access.h" +using namespace blender::bke; + namespace { -using BoneNameSet = blender::Set<std::string>; using ActionApplier = blender::FunctionRef<void(PointerRNA *, bAction *, const AnimationEvalContext *)>; -// Forward declarations. -BoneNameSet pose_apply_find_selected_bones(const bArmature *armature, const bPose *pose); +/* Forward declarations. */ void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, const BoneNameSet &selected_bone_names); void pose_apply_restore_fcurves(bAction *action); @@ -102,7 +103,7 @@ void pose_apply(struct Object *ob, } const bArmature *armature = (bArmature *)ob->data; - const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(armature, pose); + const BoneNameSet selected_bone_names = BKE_armature_find_selected_bone_names(armature); const bool limit_to_selected_bones = !selected_bone_names.is_empty(); if (limit_to_selected_bones) { @@ -122,30 +123,6 @@ void pose_apply(struct Object *ob, } } -BoneNameSet pose_apply_find_selected_bones(const bArmature *armature, const bPose *pose) -{ - BoneNameSet selected_bone_names; - bool all_bones_selected = true; - bool no_bones_selected = true; - - LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { - const bool is_selected = PBONE_SELECTED(armature, pchan->bone); - all_bones_selected &= is_selected; - no_bones_selected &= !is_selected; - - if (is_selected) { - /* Bone names are unique, so no need to check for duplicates. */ - selected_bone_names.add_new(pchan->name); - } - } - - /* If no bones are selected, act as if all are. */ - if (all_bones_selected || no_bones_selected) { - return BoneNameSet(); /* An empty set means "ignore bone selection". */ - } - return selected_bone_names; -} - void pose_apply_restore_fcurves(bAction *action) { /* TODO(Sybren): Restore the FCurve flags, instead of just erasing the 'disabled' flag. */ @@ -157,24 +134,13 @@ void pose_apply_restore_fcurves(bAction *action) void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, const BoneNameSet &selected_bone_names) { - LISTBASE_FOREACH (FCurve *, fcu, &action->curves) { - if (!fcu->rna_path || !strstr(fcu->rna_path, "pose.bones[")) { - continue; - } - - /* Get bone name, and check if this bone is selected. */ - char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); - if (!bone_name) { - continue; - } - const bool is_selected = selected_bone_names.contains(bone_name); - MEM_freeN(bone_name); - if (is_selected) { - continue; + auto disable_unselected_fcurve = [&](FCurve *fcu, const char *bone_name) { + const bool is_bone_selected = selected_bone_names.contains(bone_name); + if (!is_bone_selected) { + fcu->flag |= FCURVE_DISABLED; } - - fcu->flag |= FCURVE_DISABLED; - } + }; + BKE_action_find_fcurves_with_bones(action, disable_unselected_fcurve); } } // namespace diff --git a/source/blender/blenkernel/intern/armature_selection.cc b/source/blender/blenkernel/intern/armature_selection.cc new file mode 100644 index 00000000000..c7dbc9d05b1 --- /dev/null +++ b/source/blender/blenkernel/intern/armature_selection.cc @@ -0,0 +1,78 @@ +/* + * 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. + */ + +/** \file + * \ingroup bke + */ + +#include "BKE_armature.hh" + +#include "BLI_listbase.h" + +#include "DNA_action_types.h" +#include "DNA_armature_types.h" + +namespace blender::bke { + +namespace { + +void find_selected_bones__visit_bone(const bArmature *armature, + SelectedBoneCallback callback, + SelectedBonesResult &result, + Bone *bone) +{ + const bool is_selected = PBONE_SELECTED(armature, bone); + result.all_bones_selected &= is_selected; + result.no_bones_selected &= !is_selected; + + if (is_selected) { + callback(bone); + } + + LISTBASE_FOREACH (Bone *, child_bone, &bone->childbase) { + find_selected_bones__visit_bone(armature, callback, result, child_bone); + } +} +} // namespace + +SelectedBonesResult BKE_armature_find_selected_bones(const bArmature *armature, + SelectedBoneCallback callback) +{ + SelectedBonesResult result; + LISTBASE_FOREACH (Bone *, root_bone, &armature->bonebase) { + find_selected_bones__visit_bone(armature, callback, result, root_bone); + } + + return result; +} + +BoneNameSet BKE_armature_find_selected_bone_names(const bArmature *armature) +{ + BoneNameSet selected_bone_names; + + /* Iterate over the selected bones to fill the set of bone names. */ + auto callback = [&](Bone *bone) { selected_bone_names.add(bone->name); }; + SelectedBonesResult result = BKE_armature_find_selected_bones(armature, callback); + + /* If no bones are selected, act as if all are. */ + if (result.all_bones_selected || result.no_bones_selected) { + return BoneNameSet(); + } + + return selected_bone_names; +} + +} // namespace blender::bke diff --git a/source/blender/blenkernel/intern/armature_test.cc b/source/blender/blenkernel/intern/armature_test.cc index 589337d9d01..47853deec3e 100644 --- a/source/blender/blenkernel/intern/armature_test.cc +++ b/source/blender/blenkernel/intern/armature_test.cc @@ -17,10 +17,13 @@ * All rights reserved. */ -#include "BKE_armature.h" +#include "BKE_armature.hh" +#include "BLI_listbase.h" #include "BLI_math.h" +#include "DNA_armature_types.h" + #include "testing/testing.h" namespace blender::bke::tests { @@ -157,4 +160,80 @@ TEST(vec_roll_to_mat3_normalized, Rotationmatrix) } } +class BKE_armature_find_selected_bones_test : public testing::Test { + protected: + bArmature arm; + Bone bone1, bone2, bone3; + + void SetUp() override + { + strcpy(bone1.name, "bone1"); + strcpy(bone2.name, "bone2"); + strcpy(bone3.name, "bone3"); + + arm.bonebase = {nullptr, nullptr}; + bone1.childbase = {nullptr, nullptr}; + bone2.childbase = {nullptr, nullptr}; + bone3.childbase = {nullptr, nullptr}; + + BLI_addtail(&arm.bonebase, &bone1); // bone1 is root bone + BLI_addtail(&arm.bonebase, &bone2); // bone2 is root bone + BLI_addtail(&bone2.childbase, &bone3); // bone3 has bone2 as parent + + // Make sure the armature & its bones are visible, to make them selectable. + arm.layer = bone1.layer = bone2.layer = bone3.layer = 1; + } +}; + +TEST_F(BKE_armature_find_selected_bones_test, some_bones_selected) +{ + bone1.flag = BONE_SELECTED; + bone2.flag = 0; + bone3.flag = BONE_SELECTED; + + std::vector<Bone *> seen_bones; + auto callback = [&](Bone *bone) { seen_bones.push_back(bone); }; + + SelectedBonesResult result = BKE_armature_find_selected_bones(&arm, callback); + + ASSERT_EQ(seen_bones.size(), 2) << "Expected 2 selected bones, got " << seen_bones.size(); + EXPECT_EQ(seen_bones[0], &bone1); + EXPECT_EQ(seen_bones[1], &bone3); + + EXPECT_FALSE(result.all_bones_selected); // Bone 2 was not selected. + EXPECT_FALSE(result.no_bones_selected); // Bones 1 and 3 were selected. +} + +TEST_F(BKE_armature_find_selected_bones_test, no_bones_selected) +{ + bone1.flag = bone2.flag = bone3.flag = 0; + + std::vector<Bone *> seen_bones; + auto callback = [&](Bone *bone) { seen_bones.push_back(bone); }; + + SelectedBonesResult result = BKE_armature_find_selected_bones(&arm, callback); + + EXPECT_TRUE(seen_bones.empty()) << "Expected no selected bones, got " << seen_bones.size(); + EXPECT_FALSE(result.all_bones_selected); + EXPECT_TRUE(result.no_bones_selected); +} + +TEST_F(BKE_armature_find_selected_bones_test, all_bones_selected) +{ + bone1.flag = bone2.flag = bone3.flag = BONE_SELECTED; + + std::vector<Bone *> seen_bones; + auto callback = [&](Bone *bone) { seen_bones.push_back(bone); }; + + SelectedBonesResult result = BKE_armature_find_selected_bones(&arm, callback); + + ASSERT_EQ(seen_bones.size(), 3) << "Expected 3 selected bones, got " << seen_bones.size(); + EXPECT_EQ(seen_bones[0], &bone1); + EXPECT_EQ(seen_bones[1], &bone2); + EXPECT_EQ(seen_bones[2], &bone3); + + EXPECT_TRUE(result.all_bones_selected); + EXPECT_FALSE(result.no_bones_selected); +} + } // namespace blender::bke::tests diff --git a/source/blender/blenkernel/intern/attribute.c b/source/blender/blenkernel/intern/attribute.c index ad2be4ffe30..e9444cf88a6 100644 --- a/source/blender/blenkernel/intern/attribute.c +++ b/source/blender/blenkernel/intern/attribute.c @@ -39,6 +39,7 @@ #include "BKE_attribute.h" #include "BKE_customdata.h" +#include "BKE_editmesh.h" #include "BKE_hair.h" #include "BKE_pointcloud.h" #include "BKE_report.h" @@ -63,14 +64,28 @@ static void get_domains(ID *id, DomainInfo info[ATTR_DOMAIN_NUM]) } case ID_ME: { Mesh *mesh = (Mesh *)id; - info[ATTR_DOMAIN_POINT].customdata = &mesh->vdata; - info[ATTR_DOMAIN_POINT].length = mesh->totvert; - info[ATTR_DOMAIN_EDGE].customdata = &mesh->edata; - info[ATTR_DOMAIN_EDGE].length = mesh->totedge; - info[ATTR_DOMAIN_CORNER].customdata = &mesh->ldata; - info[ATTR_DOMAIN_CORNER].length = mesh->totloop; - info[ATTR_DOMAIN_FACE].customdata = &mesh->pdata; - info[ATTR_DOMAIN_FACE].length = mesh->totpoly; + BMEditMesh *em = mesh->edit_mesh; + if (em != NULL) { + BMesh *bm = em->bm; + info[ATTR_DOMAIN_POINT].customdata = &bm->vdata; + info[ATTR_DOMAIN_POINT].length = bm->totvert; + info[ATTR_DOMAIN_EDGE].customdata = &bm->edata; + info[ATTR_DOMAIN_EDGE].length = bm->totedge; + info[ATTR_DOMAIN_CORNER].customdata = &bm->ldata; + info[ATTR_DOMAIN_CORNER].length = bm->totloop; + info[ATTR_DOMAIN_FACE].customdata = &bm->pdata; + info[ATTR_DOMAIN_FACE].length = bm->totface; + } + else { + info[ATTR_DOMAIN_POINT].customdata = &mesh->vdata; + info[ATTR_DOMAIN_POINT].length = mesh->totvert; + info[ATTR_DOMAIN_EDGE].customdata = &mesh->edata; + info[ATTR_DOMAIN_EDGE].length = mesh->totedge; + info[ATTR_DOMAIN_CORNER].customdata = &mesh->ldata; + info[ATTR_DOMAIN_CORNER].length = mesh->totloop; + info[ATTR_DOMAIN_FACE].customdata = &mesh->pdata; + info[ATTR_DOMAIN_FACE].length = mesh->totpoly; + } break; } case ID_HA: { @@ -146,7 +161,24 @@ CustomDataLayer *BKE_id_attribute_new( return NULL; } - CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name); + switch (GS(id->name)) { + case ID_ME: { + Mesh *me = (Mesh *)id; + BMEditMesh *em = me->edit_mesh; + if (em != NULL) { + BM_data_layer_add_named(em->bm, customdata, type, name); + } + else { + CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name); + } + break; + } + default: { + CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name); + break; + } + } + const int index = CustomData_get_named_layer_index(customdata, type, name); return (index == -1) ? NULL : &(customdata->layers[index]); } @@ -168,8 +200,26 @@ bool BKE_id_attribute_remove(ID *id, CustomDataLayer *layer, ReportList *reports return false; } - const int length = BKE_id_attribute_data_length(id, layer); - CustomData_free_layer(customdata, layer->type, length, index); + switch (GS(id->name)) { + case ID_ME: { + Mesh *me = (Mesh *)id; + BMEditMesh *em = me->edit_mesh; + if (em != NULL) { + BM_data_layer_free(em->bm, customdata, layer->type); + } + else { + const int length = BKE_id_attribute_data_length(id, layer); + CustomData_free_layer(customdata, layer->type, length, index); + } + break; + } + default: { + const int length = BKE_id_attribute_data_length(id, layer); + CustomData_free_layer(customdata, layer->type, length, index); + break; + } + } + return true; } @@ -316,7 +366,7 @@ CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *laye for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { CustomData *customdata = info[domain].customdata; - if (customdata && customdata->layers) { + if (customdata && customdata->layers && customdata->totlayer) { if (customdata->layers == layers) { use_next = true; } diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index e69173cc1d5..9caf416cd0c 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -231,7 +231,7 @@ static bool rule_avoid_collision(BoidRule *rule, int n, neighbors = 0, nearest = 0; bool ret = 0; - // check deflector objects first + /* Check deflector objects first. */ if (acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) { ParticleCollision col; BVHTreeRayHit hit; @@ -293,7 +293,7 @@ static bool rule_avoid_collision(BoidRule *rule, } } - // check boids in own system + /* Check boids in own system. */ if (acbr->options & BRULE_ACOLL_WITH_BOIDS) { neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(bbd->sim->psys->tree, pa->prev_state.co, @@ -823,11 +823,13 @@ static boid_rule_cb boid_rules[] = { rule_follow_leader, rule_average_speed, rule_fight, - // rule_help, - // rule_protect, - // rule_hide, - // rule_follow_path, - // rule_follow_wall, +#if 0 + rule_help, + rule_protect, + rule_hide, + rule_follow_path, + rule_follow_wall, +#endif }; static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa) @@ -1069,11 +1071,13 @@ static BoidState *get_boid_state(BoidSettings *boids, ParticleData *pa) return state; } -// static int boid_condition_is_true(BoidCondition *cond) -//{ -// /* TODO */ -// return 0; -//} + +#if 0 /* TODO */ +static int boid_condition_is_true(BoidCondition *cond) +{ + return 0; +} +#endif /* determines the velocity the boid wants to have */ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa) @@ -1085,7 +1089,6 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa) BoidParticle *bpa = pa->boid; ParticleSystem *psys = bbd->sim->psys; int rand; - // BoidCondition *cond; if (bpa->data.health <= 0.0f) { pa->alive = PARS_DYING; @@ -1093,15 +1096,17 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa) return; } - // planned for near future - // cond = state->conditions.first; - // for (; cond; cond=cond->next) { - // if (boid_condition_is_true(cond)) { - // pa->boid->state_id = cond->state_id; - // state = get_boid_state(boids, pa); - // break; /* only first true condition is used */ - // } - //} + /* Planned for near future. */ +#if 0 + BoidCondition *cond = state->conditions.first; + for (; cond; cond = cond->next) { + if (boid_condition_is_true(cond)) { + pa->boid->state_id = cond->state_id; + state = get_boid_state(boids, pa); + break; /* only first true condition is used */ + } + } +#endif zero_v3(bbd->wanted_co); bbd->wanted_speed = 0.0f; @@ -1507,20 +1512,22 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa) } case eBoidMode_Climbing: { boid_climb(boids, pa, ground_co, ground_nor); - // float nor[3]; - // copy_v3_v3(nor, ground_nor); - - ///* gather apparent gravity to r_ve */ - // madd_v3_v3fl(pa->r_ve, ground_nor, -1.0); - // normalize_v3(pa->r_ve); - - ///* raise boid it's size from surface */ - // mul_v3_fl(nor, pa->size * boids->height); - // add_v3_v3v3(pa->state.co, ground_co, nor); - - ///* remove normal component from velocity */ - // project_v3_v3v3(v, pa->state.vel, ground_nor); - // sub_v3_v3v3(pa->state.vel, pa->state.vel, v); +#if 0 + float nor[3]; + copy_v3_v3(nor, ground_nor); + + /* Gather apparent gravity to r_ve. */ + madd_v3_v3fl(pa->r_ve, ground_nor, -1.0); + normalize_v3(pa->r_ve); + + /* Raise boid it's size from surface. */ + mul_v3_fl(nor, pa->size * boids->height); + add_v3_v3v3(pa->state.co, ground_co, nor); + + /* Remove normal component from velocity. */ + project_v3_v3v3(v, pa->state.vel, ground_nor); + sub_v3_v3v3(pa->state.vel, pa->state.vel, v); +#endif break; } case eBoidMode_OnLand: { diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 24615dd8c2b..f1369254347 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -332,16 +332,6 @@ IDTypeInfo IDType_ID_CU = { .lib_override_apply_post = NULL, }; -static int cu_isectLL(const float v1[3], - const float v2[3], - const float v3[3], - const float v4[3], - short cox, - short coy, - float *lambda, - float *mu, - float vec[3]); - /* frees editcurve entirely */ void BKE_curve_editfont_free(Curve *cu) { @@ -566,18 +556,6 @@ void BKE_curve_texspace_ensure(Curve *cu) } } -void BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_size[3]) -{ - BKE_curve_texspace_ensure(cu); - - if (r_loc) { - copy_v3_v3(r_loc, cu->loc); - } - if (r_size) { - copy_v3_v3(r_size, cu->size); - } -} - bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3]) { int tot = 0; diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc index 8e1577ab072..5c18f6f3807 100644 --- a/source/blender/blenkernel/intern/curve_eval.cc +++ b/source/blender/blenkernel/intern/curve_eval.cc @@ -48,6 +48,22 @@ blender::MutableSpan<SplinePtr> CurveEval::splines() return splines_; } +/** + * \return True if the curve contains a spline with the given type. + * + * \note If you are looping over all of the splines in the same scope anyway, + * it's better to avoid calling this function, in case there are many splines. + */ +bool CurveEval::has_spline_with_type(const Spline::Type type) const +{ + for (const SplinePtr &spline : this->splines()) { + if (spline->type() == type) { + return true; + } + } + return false; +} + void CurveEval::resize(const int size) { splines_.resize(size); diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 9cae74e4e9a..83e03ef44f5 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -306,7 +306,7 @@ const float (*BKE_editmesh_vert_coords_when_deformed(struct Depsgraph *depsgraph } else if ((em->mesh_eval_final != NULL) && (em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) { - /* If this is an edit-mesh type, leave NULL as we can use the vertex coords. . */ + /* If this is an edit-mesh type, leave NULL as we can use the vertex coords. */ } else { /* Constructive modifiers have been used, we need to allocate coordinates. */ diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 1b628b16802..fc1721eaf3a 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -547,7 +547,7 @@ static float eff_calc_visibility(ListBase *colliders, return visibility; } -// noise function for wind e.g. +/* Noise function for wind e.g. */ static float wind_func(struct RNG *rng, float strength) { int random = (BLI_rng_get_int(rng) + 1) % 128; /* max 2357 */ diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 8f47a7e75d4..5decc7a1792 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -918,7 +918,7 @@ void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt) } /* The active keyframe should always be selected. */ - BLI_assert(BEZT_ISSEL_ANY(active_bezt) || !"active keyframe must be selected"); + BLI_assert_msg(BEZT_ISSEL_ANY(active_bezt), "active keyframe must be selected"); fcu->active_keyframe_index = (int)offset; } diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 2b48683a3a8..1d8dc97d2af 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -1545,7 +1545,7 @@ static void emit_from_particles(Object *flow_ob, float dt) { if (ffs && ffs->psys && ffs->psys->part && - ELEM(ffs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected + ELEM(ffs->psys->part->type, PART_EMITTER, PART_FLUID)) /* Is particle system selected. */ { ParticleSimulationData sim; ParticleSystem *psys = ffs->psys; diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index b5c49dbb8b2..0b6ba966974 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -854,17 +854,9 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo return {}; } - bool curve_has_bezier_spline = false; - for (SplinePtr &spline : curve->splines()) { - if (spline->type() == Spline::Type::Bezier) { - curve_has_bezier_spline = true; - break; - } - } - /* Use the regular position virtual array when there aren't any Bezier splines * to avoid the overhead of checking the spline type for every point. */ - if (!curve_has_bezier_spline) { + if (!curve->has_spline_with_type(Spline::Type::Bezier)) { return BuiltinPointAttributeProvider<float3>::try_get_for_write(component); } diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 47c8df03375..90a97264c8f 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -565,6 +565,7 @@ static PointCloud *join_pointcloud_position_attribute(Span<GeometryInstanceGroup } PointCloud *new_pointcloud = BKE_pointcloud_new_nomain(totpoint); + MutableSpan new_positions{(float3 *)new_pointcloud->co, new_pointcloud->totpoint}; /* Transform each instance's point locations into the new point cloud. */ int offset = 0; @@ -576,9 +577,7 @@ static PointCloud *join_pointcloud_position_attribute(Span<GeometryInstanceGroup } for (const float4x4 &transform : set_group.transforms) { for (const int i : IndexRange(pointcloud->totpoint)) { - const float3 old_position = pointcloud->co[i]; - const float3 new_position = transform * old_position; - copy_v3_v3(new_pointcloud->co[offset + i], new_position); + new_positions[offset + i] = transform * float3(pointcloud->co[i]); } offset += pointcloud->totpoint; } diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.cc index 4dcd94fdeec..f8a07939096 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.c +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -21,22 +21,24 @@ * \ingroup bke */ -#include <math.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include <cmath> +#include <cstddef> +#include <cstdio> +#include <cstdlib> +#include <cstring> #include "CLG_log.h" #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_float3.hh" #include "BLI_ghash.h" #include "BLI_hash.h" #include "BLI_heap.h" #include "BLI_math_vector.h" #include "BLI_polyfill_2d.h" +#include "BLI_span.hh" #include "BLT_translation.h" @@ -61,6 +63,9 @@ #include "DEG_depsgraph_query.h" +using blender::float3; +using blender::Span; + /* GP Object - Boundbox Support */ /** *Get min/max coordinate bounds for single stroke. @@ -75,20 +80,26 @@ bool BKE_gpencil_stroke_minmax(const bGPDstroke *gps, float r_min[3], float r_max[3]) { - const bGPDspoint *pt; - int i; - bool changed = false; - - if (ELEM(NULL, gps, r_min, r_max)) { + if (gps == nullptr) { return false; } - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) { - minmax_v3v3_v3(r_min, r_max, &pt->x); + bool changed = false; + if (use_select) { + for (const bGPDspoint &pt : Span(gps->points, gps->totpoints)) { + if (pt.flag & GP_SPOINT_SELECT) { + minmax_v3v3_v3(r_min, r_max, &pt.x); + changed = true; + } + } + } + else { + for (const bGPDspoint &pt : Span(gps->points, gps->totpoints)) { + minmax_v3v3_v3(r_min, r_max, &pt.x); changed = true; } } + return changed; } @@ -105,14 +116,14 @@ bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3]) INIT_MINMAX(r_min, r_max); - if (gpd == NULL) { + if (gpd == nullptr) { return changed; } LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { bGPDframe *gpf = gpl->actframe; - if (gpf != NULL) { + if (gpf != nullptr) { LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { changed |= BKE_gpencil_stroke_minmax(gps, false, r_min, r_max); } @@ -129,11 +140,11 @@ bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3]) */ void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3]) { - float min[3], max[3], tot[3]; - + float3 min; + float3 max; BKE_gpencil_data_minmax(gpd, min, max); - add_v3_v3v3(tot, min, max); + const float3 tot = min + max; mul_v3_v3fl(r_centroid, tot, 0.5f); } @@ -153,20 +164,18 @@ void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps) */ static void boundbox_gpencil(Object *ob) { - BoundBox *bb; - bGPdata *gpd; - float min[3], max[3]; - - if (ob->runtime.bb == NULL) { - ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox"); + if (ob->runtime.bb == nullptr) { + ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox"); } - bb = ob->runtime.bb; - gpd = ob->data; + BoundBox *bb = ob->runtime.bb; + bGPdata *gpd = (bGPdata *)ob->data; + float3 min; + float3 max; if (!BKE_gpencil_data_minmax(gpd, min, max)) { - min[0] = min[1] = min[2] = -1.0f; - max[0] = max[1] = max[2] = 1.0f; + min = float3(-1); + max = float3(1); } BKE_boundbox_init_from_minmax(bb, min, max); @@ -181,8 +190,8 @@ static void boundbox_gpencil(Object *ob) */ BoundBox *BKE_gpencil_boundbox_get(Object *ob) { - if (ELEM(NULL, ob, ob->data)) { - return NULL; + if (ELEM(nullptr, ob, ob->data)) { + return nullptr; } bGPdata *gpd = (bGPdata *)ob->data; @@ -196,9 +205,9 @@ BoundBox *BKE_gpencil_boundbox_get(Object *ob) /* Update orig object's boundbox with re-computed evaluated values. This function can be * called with the evaluated object and need update the original object bound box data * to keep both values synchronized. */ - if (!ELEM(ob_orig, NULL, ob)) { - if (ob_orig->runtime.bb == NULL) { - ob_orig->runtime.bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox"); + if (!ELEM(ob_orig, nullptr, ob)) { + if (ob_orig->runtime.bb == nullptr) { + ob_orig->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox"); } for (int i = 0; i < 8; i++) { copy_v3_v3(ob_orig->runtime.bb->vec[i], ob->runtime.bb->vec[i]); @@ -227,7 +236,7 @@ static int stroke_march_next_point(const bGPDstroke *gps, float step_start[3]; float point[3]; int next_point_index = index_next_pt; - bGPDspoint *pt = NULL; + bGPDspoint *pt = nullptr; if (!(next_point_index < gps->totpoints)) { return -1; @@ -295,7 +304,7 @@ static int stroke_march_next_point_no_interp(const bGPDstroke *gps, float step_start[3]; float point[3]; int next_point_index = index_next_pt; - bGPDspoint *pt = NULL; + bGPDspoint *pt = nullptr; if (!(next_point_index < gps->totpoints)) { return -1; @@ -336,7 +345,7 @@ static int stroke_march_count(const bGPDstroke *gps, const float dist) int point_count = 0; float point[3]; int next_point_index = 1; - bGPDspoint *pt = NULL; + bGPDspoint *pt = nullptr; pt = &gps->points[0]; copy_v3_v3(point, &pt->x); @@ -369,14 +378,14 @@ static void stroke_defvert_create_nr_list(MDeformVert *dv_list, for (j = 0; j < dv->totweight; j++) { bool found = false; dw = &dv->dw[j]; - for (ld = result->first; ld; ld = ld->next) { + for (ld = (LinkData *)result->first; ld; ld = ld->next) { if (ld->data == POINTER_FROM_INT(dw->def_nr)) { found = true; break; } } if (!found) { - ld = MEM_callocN(sizeof(LinkData), "def_nr_item"); + ld = (LinkData *)MEM_callocN(sizeof(LinkData), "def_nr_item"); ld->data = POINTER_FROM_INT(dw->def_nr); BLI_addtail(result, ld); tw++; @@ -391,14 +400,15 @@ static MDeformVert *stroke_defvert_new_count(int count, int totweight, ListBase { int i, j; LinkData *ld; - MDeformVert *dst = MEM_mallocN(count * sizeof(MDeformVert), "new_deformVert"); + MDeformVert *dst = (MDeformVert *)MEM_mallocN(count * sizeof(MDeformVert), "new_deformVert"); for (i = 0; i < count; i++) { - dst[i].dw = MEM_mallocN(sizeof(MDeformWeight) * totweight, "new_deformWeight"); + dst[i].dw = (MDeformWeight *)MEM_mallocN(sizeof(MDeformWeight) * totweight, + "new_deformWeight"); dst[i].totweight = totweight; j = 0; /* re-assign deform groups */ - for (ld = def_nr_list->first; ld; ld = ld->next) { + for (ld = (LinkData *)def_nr_list->first; ld; ld = ld->next) { dst[i].dw[j].def_nr = POINTER_AS_INT(ld->data); j++; } @@ -429,10 +439,10 @@ static void stroke_interpolate_deform_weights( bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist, const bool select) { bGPDspoint *pt = gps->points; - bGPDspoint *pt1 = NULL; - bGPDspoint *pt2 = NULL; + bGPDspoint *pt1 = nullptr; + bGPDspoint *pt2 = nullptr; LinkData *ld; - ListBase def_nr_list = {0}; + ListBase def_nr_list = {nullptr}; if (gps->totpoints < 2 || dist < FLT_EPSILON) { return false; @@ -440,12 +450,13 @@ bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist, /* TODO: Implement feature point preservation. */ int count = stroke_march_count(gps, dist); - bGPDspoint *new_pt = MEM_callocN(sizeof(bGPDspoint) * count, "gp_stroke_points_sampled"); - MDeformVert *new_dv = NULL; + bGPDspoint *new_pt = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * count, + "gp_stroke_points_sampled"); + MDeformVert *new_dv = nullptr; int result_totweight; - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { stroke_defvert_create_nr_list(gps->dvert, gps->totpoints, &def_nr_list, &result_totweight); new_dv = stroke_defvert_new_count(count, result_totweight, &def_nr_list); } @@ -513,7 +524,7 @@ bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist, /* Free original weight data. */ BKE_gpencil_free_stroke_weights(gps); MEM_freeN(gps->dvert); - while ((ld = BLI_pophead(&def_nr_list))) { + while ((ld = (LinkData *)BLI_pophead(&def_nr_list))) { MEM_freeN(ld); } @@ -610,26 +621,27 @@ bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const if (new_count == 1) { BKE_gpencil_free_stroke_weights(gps); MEM_freeN(gps->points); - gps->points = NULL; - gps->dvert = NULL; + gps->points = nullptr; + gps->dvert = nullptr; gps->totpoints = 0; return false; } - new_pt = MEM_callocN(sizeof(bGPDspoint) * new_count, "gp_stroke_points_trimmed"); + new_pt = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * new_count, "gp_stroke_points_trimmed"); for (int i = 0; i < new_count; i++) { memcpy(&new_pt[i], &pt[i + index_from], sizeof(bGPDspoint)); } if (gps->dvert) { - new_dv = MEM_callocN(sizeof(MDeformVert) * new_count, "gp_stroke_dverts_trimmed"); + new_dv = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * new_count, + "gp_stroke_dverts_trimmed"); for (int i = 0; i < new_count; i++) { dv = &gps->dvert[i + index_from]; new_dv[i].flag = dv->flag; new_dv[i].totweight = dv->totweight; - new_dv[i].dw = MEM_callocN(sizeof(MDeformWeight) * dv->totweight, - "gp_stroke_dverts_dw_trimmed"); + new_dv[i].dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dv->totweight, + "gp_stroke_dverts_dw_trimmed"); for (int j = 0; j < dv->totweight; j++) { new_dv[i].dw[j].weight = dv->dw[j].weight; new_dv[i].dw[j].def_nr = dv->dw[j].def_nr; @@ -685,14 +697,14 @@ bool BKE_gpencil_stroke_split(bGPdata *gpd, } if (gps->dvert) { - new_dv = MEM_callocN(sizeof(MDeformVert) * new_count, - "gp_stroke_dverts_remaining(MDeformVert)"); + new_dv = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * new_count, + "gp_stroke_dverts_remaining(MDeformVert)"); for (int i = 0; i < new_count; i++) { dv = &gps->dvert[i + before_index]; new_dv[i].flag = dv->flag; new_dv[i].totweight = dv->totweight; - new_dv[i].dw = MEM_callocN(sizeof(MDeformWeight) * dv->totweight, - "gp_stroke_dverts_dw_remaining(MDeformWeight)"); + new_dv[i].dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dv->totweight, + "gp_stroke_dverts_dw_remaining(MDeformWeight)"); for (int j = 0; j < dv->totweight; j++) { new_dv[i].dw[j].weight = dv->dw[j].weight; new_dv[i].dw[j].def_nr = dv->dw[j].def_nr; @@ -1301,11 +1313,12 @@ void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps) /* allocate memory for temporary areas */ gps->tot_triangles = gps->totpoints - 2; - uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, - "GP Stroke temp triangulation"); - float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, - "GP Stroke temp 2d points"); - float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data"); + uint(*tmp_triangles)[3] = (uint(*)[3])MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, + "GP Stroke temp triangulation"); + float(*points2d)[2] = (float(*)[2])MEM_mallocN(sizeof(*points2d) * gps->totpoints, + "GP Stroke temp 2d points"); + float(*uv)[2] = (float(*)[2])MEM_mallocN(sizeof(*uv) * gps->totpoints, + "GP Stroke temp 2d uv data"); int direction = 0; @@ -1326,8 +1339,8 @@ void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps) /* Save triangulation data. */ if (gps->tot_triangles > 0) { MEM_SAFE_FREE(gps->triangles); - gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, - "GP Stroke triangulation"); + gps->triangles = (bGPDtriangle *)MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, + "GP Stroke triangulation"); for (int i = 0; i < gps->tot_triangles; i++) { memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3])); @@ -1344,7 +1357,7 @@ void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps) MEM_freeN(gps->triangles); } - gps->triangles = NULL; + gps->triangles = nullptr; } /* clear memory */ @@ -1359,7 +1372,7 @@ void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps) */ void BKE_gpencil_stroke_uv_update(bGPDstroke *gps) { - if (gps == NULL || gps->totpoints == 0) { + if (gps == nullptr || gps->totpoints == 0) { return; } @@ -1379,11 +1392,11 @@ void BKE_gpencil_stroke_uv_update(bGPDstroke *gps) */ void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps) { - if (gps == NULL) { + if (gps == nullptr) { return; } - if (gps->editcurve != NULL) { + if (gps->editcurve != nullptr) { if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) { /* curve geometry was updated: stroke needs recalculation */ if (gps->flag & GP_STROKE_NEEDS_CURVE_UPDATE) { @@ -1519,20 +1532,20 @@ bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps) if (intersect) { /* save points */ - bGPDspoint *old_points = MEM_dupallocN(gps->points); - MDeformVert *old_dvert = NULL; - MDeformVert *dvert_src = NULL; + bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points); + MDeformVert *old_dvert = nullptr; + MDeformVert *dvert_src = nullptr; - if (gps->dvert != NULL) { - old_dvert = MEM_dupallocN(gps->dvert); + if (gps->dvert != nullptr) { + old_dvert = (MDeformVert *)MEM_dupallocN(gps->dvert); } /* resize gps */ int newtot = end - start + 1; - gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot); - if (gps->dvert != NULL) { - gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot); + gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(*gps->points) * newtot); + if (gps->dvert != nullptr) { + gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot); } for (int i = 0; i < newtot; i++) { @@ -1540,7 +1553,7 @@ bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps) bGPDspoint *pt_src = &old_points[idx]; bGPDspoint *pt_new = &gps->points[i]; memcpy(pt_new, pt_src, sizeof(bGPDspoint)); - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { dvert_src = &old_dvert[idx]; MDeformVert *dvert = &gps->dvert[i]; memcpy(dvert, dvert_src, sizeof(MDeformVert)); @@ -1570,8 +1583,8 @@ bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps) */ bool BKE_gpencil_stroke_close(bGPDstroke *gps) { - bGPDspoint *pt1 = NULL; - bGPDspoint *pt2 = NULL; + bGPDspoint *pt1 = nullptr; + bGPDspoint *pt2 = nullptr; /* Only can close a stroke with 3 points or more. */ if (gps->totpoints < 3) { @@ -1605,9 +1618,9 @@ bool BKE_gpencil_stroke_close(bGPDstroke *gps) /* Resize stroke array. */ int old_tot = gps->totpoints; gps->totpoints += tot_newpoints; - gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); - if (gps->dvert != NULL) { - gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); + gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); + if (gps->dvert != nullptr) { + gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); } /* Generate new points */ @@ -1629,7 +1642,7 @@ bool BKE_gpencil_stroke_close(bGPDstroke *gps) interp_v4_v4v4(pt->vert_color, pt1->vert_color, pt2->vert_color, step); /* Set weights. */ - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { MDeformVert *dvert1 = &gps->dvert[old_tot - 1]; MDeformWeight *dw1 = BKE_defvert_ensure_index(dvert1, 0); float weight_1 = dw1 ? dw1->weight : 0.0f; @@ -1663,7 +1676,7 @@ bool BKE_gpencil_stroke_close(bGPDstroke *gps) void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, const short tag) { bGPDspoint *pt; - MDeformVert *dvert = NULL; + MDeformVert *dvert = nullptr; int i; int tot = gps->totpoints; /* number of points in new buffer */ @@ -1693,30 +1706,32 @@ void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, } else { /* just copy all points to keep into a smaller buffer */ - bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy"); + bGPDspoint *new_points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * tot, + "new gp stroke points copy"); bGPDspoint *npt = new_points; - MDeformVert *new_dvert = NULL; - MDeformVert *ndvert = NULL; + MDeformVert *new_dvert = nullptr; + MDeformVert *ndvert = nullptr; - if (gps->dvert != NULL) { - new_dvert = MEM_callocN(sizeof(MDeformVert) * tot, "new gp stroke weights copy"); + if (gps->dvert != nullptr) { + new_dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * tot, + "new gp stroke weights copy"); ndvert = new_dvert; } - (gps->dvert != NULL) ? dvert = gps->dvert : NULL; + (gps->dvert != nullptr) ? dvert = gps->dvert : nullptr; for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if ((pt->flag & tag) == 0) { *npt = *pt; npt++; - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { *ndvert = *dvert; - ndvert->dw = MEM_dupallocN(dvert->dw); + ndvert->dw = (MDeformWeight *)MEM_dupallocN(dvert->dw); ndvert++; } } - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { dvert++; } } @@ -1789,15 +1804,15 @@ void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3]) */ void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float epsilon) { - bGPDspoint *old_points = MEM_dupallocN(gps->points); + bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points); int totpoints = gps->totpoints; - char *marked = NULL; + char *marked = nullptr; char work; int start = 0; int end = gps->totpoints - 1; - marked = MEM_callocN(totpoints, "GP marked array"); + marked = (char *)MEM_callocN(totpoints, "GP marked array"); marked[start] = 1; marked[end] = 1; @@ -1849,11 +1864,11 @@ void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float e } /* adding points marked */ - MDeformVert *old_dvert = NULL; - MDeformVert *dvert_src = NULL; + MDeformVert *old_dvert = nullptr; + MDeformVert *dvert_src = nullptr; - if (gps->dvert != NULL) { - old_dvert = MEM_dupallocN(gps->dvert); + if (gps->dvert != nullptr) { + old_dvert = (MDeformVert *)MEM_dupallocN(gps->dvert); } /* resize gps */ int j = 0; @@ -1863,7 +1878,7 @@ void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float e if ((marked[i]) || (i == 0) || (i == totpoints - 1)) { memcpy(pt, pt_src, sizeof(bGPDspoint)); - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { dvert_src = &old_dvert[i]; MDeformVert *dvert = &gps->dvert[j]; memcpy(dvert, dvert_src, sizeof(MDeformVert)); @@ -1874,7 +1889,7 @@ void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float e j++; } else { - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { dvert_src = &old_dvert[i]; BKE_gpencil_free_point_weights(dvert_src); } @@ -1903,12 +1918,12 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps) } /* save points */ - bGPDspoint *old_points = MEM_dupallocN(gps->points); - MDeformVert *old_dvert = NULL; - MDeformVert *dvert_src = NULL; + bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points); + MDeformVert *old_dvert = nullptr; + MDeformVert *dvert_src = nullptr; - if (gps->dvert != NULL) { - old_dvert = MEM_dupallocN(gps->dvert); + if (gps->dvert != nullptr) { + old_dvert = (MDeformVert *)MEM_dupallocN(gps->dvert); } /* resize gps */ @@ -1918,9 +1933,9 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps) } newtot += 2; - gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot); - if (gps->dvert != NULL) { - gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot); + gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(*gps->points) * newtot); + if (gps->dvert != nullptr) { + gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot); } int j = 0; @@ -1930,7 +1945,7 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps) if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) { memcpy(pt, pt_src, sizeof(bGPDspoint)); - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { dvert_src = &old_dvert[i]; MDeformVert *dvert = &gps->dvert[j]; memcpy(dvert, dvert_src, sizeof(MDeformVert)); @@ -1941,7 +1956,7 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps) j++; } else { - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { dvert_src = &old_dvert[i]; BKE_gpencil_free_point_weights(dvert_src); } @@ -1966,25 +1981,25 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps) void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int type) { bGPDspoint *temp_points; - MDeformVert *temp_dverts = NULL; - MDeformVert *dvert = NULL; - MDeformVert *dvert_final = NULL; - MDeformVert *dvert_next = NULL; + MDeformVert *temp_dverts = nullptr; + MDeformVert *dvert = nullptr; + MDeformVert *dvert_final = nullptr; + MDeformVert *dvert_next = nullptr; int totnewpoints, oldtotpoints; int i2; for (int s = 0; s < level; s++) { totnewpoints = gps->totpoints - 1; /* duplicate points in a temp area */ - temp_points = MEM_dupallocN(gps->points); + temp_points = (bGPDspoint *)MEM_dupallocN(gps->points); oldtotpoints = gps->totpoints; /* resize the points arrays */ gps->totpoints += totnewpoints; - gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); - if (gps->dvert != NULL) { - temp_dverts = MEM_dupallocN(gps->dvert); - gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); + gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); + if (gps->dvert != nullptr) { + temp_dverts = (MDeformVert *)MEM_dupallocN(gps->dvert); + gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); } /* move points from last to first to new place */ @@ -2002,7 +2017,7 @@ void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int pt_final->runtime.idx_orig = pt->runtime.idx_orig; copy_v4_v4(pt_final->vert_color, pt->vert_color); - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { dvert = &temp_dverts[i]; dvert_final = &gps->dvert[i2]; dvert_final->totweight = dvert->totweight; @@ -2023,17 +2038,17 @@ void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int pt_final->strength = interpf(pt->strength, next->strength, 0.5f); CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt_final->time = interpf(pt->time, next->time, 0.5f); - pt_final->runtime.pt_orig = NULL; + pt_final->runtime.pt_orig = nullptr; pt_final->flag = 0; interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f); - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { dvert = &temp_dverts[i]; dvert_next = &temp_dverts[i + 1]; dvert_final = &gps->dvert[i2]; dvert_final->totweight = dvert->totweight; - dvert_final->dw = MEM_dupallocN(dvert->dw); + dvert_final->dw = (MDeformWeight *)MEM_dupallocN(dvert->dw); /* interpolate weight values */ for (int d = 0; d < dvert->totweight; d++) { @@ -2055,7 +2070,7 @@ void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int /* Move points to smooth stroke (not simple type). */ if (type != GP_SUBDIV_SIMPLE) { /* duplicate points in a temp area with the new subdivide data */ - temp_points = MEM_dupallocN(gps->points); + temp_points = (bGPDspoint *)MEM_dupallocN(gps->points); /* extreme points are not changed */ for (int i = 0; i < gps->totpoints - 2; i++) { @@ -2079,13 +2094,14 @@ void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int /** * Reduce a series of points when the distance is below a threshold. - * Special case for first and last points (both are keeped) for other points, + * Special case for first and last points (both are kept) for other points, * the merge point always is at first point. - * \param gpd: Grease pencil data-block - * \param gpf: Grease Pencil frame - * \param gps: Grease Pencil stroke - * \param threshold: Distance between points - * \param use_unselected: Set to true to analyze all stroke and not only selected points + * + * \param gpd: Grease pencil data-block. + * \param gpf: Grease Pencil frame. + * \param gps: Grease Pencil stroke. + * \param threshold: Distance between points. + * \param use_unselected: Set to true to analyze all stroke and not only selected points. */ void BKE_gpencil_stroke_merge_distance(bGPdata *gpd, bGPDframe *gpf, @@ -2093,8 +2109,8 @@ void BKE_gpencil_stroke_merge_distance(bGPdata *gpd, const float threshold, const bool use_unselected) { - bGPDspoint *pt = NULL; - bGPDspoint *pt_next = NULL; + bGPDspoint *pt = nullptr; + bGPDspoint *pt_next = nullptr; float tagged = false; /* Use square distance to speed up loop */ const float th_square = threshold * threshold; @@ -2160,7 +2176,7 @@ void BKE_gpencil_stroke_merge_distance(bGPdata *gpd, BKE_gpencil_stroke_geometry_update(gpd, gps); } -typedef struct GpEdge { +struct GpEdge { uint v1, v2; /* Coordinates. */ float v1_co[3], v2_co[3]; @@ -2169,7 +2185,7 @@ typedef struct GpEdge { /* Direction of the segment. */ float vec[3]; int flag; -} GpEdge; +}; static int gpencil_next_edge( GpEdge *gp_edges, int totedges, GpEdge *gped_init, const float threshold, const bool reverse) @@ -2261,14 +2277,14 @@ static void gpencil_generate_edgeloops(Object *ob, } /* Arrays for all edge vertices (forward and backward) that form a edge loop. - * This is reused for each edgeloop to create gpencil stroke. */ - uint *stroke = MEM_callocN(sizeof(uint) * me->totedge * 2, __func__); - uint *stroke_fw = MEM_callocN(sizeof(uint) * me->totedge, __func__); - uint *stroke_bw = MEM_callocN(sizeof(uint) * me->totedge, __func__); + * This is reused for each edge-loop to create gpencil stroke. */ + uint *stroke = (uint *)MEM_callocN(sizeof(uint) * me->totedge * 2, __func__); + uint *stroke_fw = (uint *)MEM_callocN(sizeof(uint) * me->totedge, __func__); + uint *stroke_bw = (uint *)MEM_callocN(sizeof(uint) * me->totedge, __func__); /* Create array with all edges. */ - GpEdge *gp_edges = MEM_callocN(sizeof(GpEdge) * me->totedge, __func__); - GpEdge *gped = NULL; + GpEdge *gp_edges = (GpEdge *)MEM_callocN(sizeof(GpEdge) * me->totedge, __func__); + GpEdge *gped = nullptr; for (int i = 0; i < me->totedge; i++) { MEdge *ed = &me->medge[i]; gped = &gp_edges[i]; @@ -2321,7 +2337,7 @@ static void gpencil_generate_edgeloops(Object *ob, /* Look backward edges. */ int totbw = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_bw, e, angle, true); - BLI_ghash_free(v_table, NULL, NULL); + BLI_ghash_free(v_table, nullptr, nullptr); /* Join both arrays. */ int array_len = 0; @@ -2423,7 +2439,7 @@ static int gpencil_material_find_index_by_name(Object *ob, const char *name) { for (int i = 0; i < ob->totcol; i++) { Material *ma = BKE_object_material_get(ob, i + 1); - if ((ma != NULL) && (ma->gp_style != NULL) && (STREQ(ma->id.name + 2, name))) { + if ((ma != nullptr) && (ma->gp_style != nullptr) && (STREQ(ma->id.name + 2, name))) { return i; } } @@ -2453,7 +2469,7 @@ static void make_element_name(const char *obname, const char *name, const int ma * \param scene: Original scene. * \param ob_gp: Grease pencil object to add strokes. * \param ob_mesh: Mesh to convert. - * \param angle: Limit angle to consider a edgeloop ends. + * \param angle: Limit angle to consider a edge-loop ends. * \param thickness: Thickness of the strokes. * \param offset: Offset along the normals. * \param matrix: Transformation matrix. @@ -2474,7 +2490,7 @@ bool BKE_gpencil_convert_mesh(Main *bmain, const bool use_seams, const bool use_faces) { - if (ELEM(NULL, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) { + if (ELEM(nullptr, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == nullptr)) { return false; } @@ -2511,7 +2527,7 @@ bool BKE_gpencil_convert_mesh(Main *bmain, make_element_name(ob_mesh->id.name + 2, "Fills", 128, element_name); /* Create Layer and Frame. */ bGPDlayer *gpl_fill = BKE_gpencil_layer_named_get(gpd, element_name); - if (gpl_fill == NULL) { + if (gpl_fill == nullptr) { gpl_fill = BKE_gpencil_layer_addnew(gpd, element_name, true, false); } bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get( @@ -2524,11 +2540,11 @@ bool BKE_gpencil_convert_mesh(Main *bmain, int mat_idx = 0; Material *ma = BKE_object_material_get(ob_mesh, mp->mat_nr + 1); make_element_name( - ob_mesh->id.name + 2, (ma != NULL) ? ma->id.name + 2 : "Fill", 64, element_name); + ob_mesh->id.name + 2, (ma != nullptr) ? ma->id.name + 2 : "Fill", 64, element_name); mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob_gp, element_name); if (mat_idx == -1) { float color[4]; - if (ma != NULL) { + if (ma != nullptr) { copy_v3_v3(color, &ma->r); color[3] = 1.0f; } @@ -2567,7 +2583,7 @@ bool BKE_gpencil_convert_mesh(Main *bmain, /* Create Layer and Frame. */ bGPDlayer *gpl_stroke = BKE_gpencil_layer_named_get(gpd, element_name); - if (gpl_stroke == NULL) { + if (gpl_stroke == nullptr) { gpl_stroke = BKE_gpencil_layer_addnew(gpd, element_name, true, false); } bGPDframe *gpf_stroke = BKE_gpencil_layer_frame_get( @@ -2589,7 +2605,7 @@ bool BKE_gpencil_convert_mesh(Main *bmain, */ void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4]) { - if (gpd == NULL) { + if (gpd == nullptr) { return; } @@ -2625,7 +2641,7 @@ int BKE_gpencil_stroke_point_count(const bGPdata *gpd) { int total_points = 0; - if (gpd == NULL) { + if (gpd == nullptr) { return 0; } @@ -2650,7 +2666,7 @@ int BKE_gpencil_stroke_point_count(const bGPdata *gpd) /* Used for "move only origins" in object_data_transform.c */ void BKE_gpencil_point_coords_get(bGPdata *gpd, GPencilPointCoordinates *elem_data) { - if (gpd == NULL) { + if (gpd == nullptr) { return; } @@ -2681,7 +2697,7 @@ void BKE_gpencil_point_coords_get(bGPdata *gpd, GPencilPointCoordinates *elem_da /* Used for "move only origins" in object_data_transform.c */ void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates *elem_data) { - if (gpd == NULL) { + if (gpd == nullptr) { return; } @@ -2717,7 +2733,7 @@ void BKE_gpencil_point_coords_apply_with_mat4(bGPdata *gpd, const GPencilPointCoordinates *elem_data, const float mat[4][4]) { - if (gpd == NULL) { + if (gpd == nullptr) { return; } @@ -2818,24 +2834,24 @@ void BKE_gpencil_stroke_flip(bGPDstroke *gps) * that should be kept when splitting up a stroke. Used in: * gpencil_stroke_delete_tagged_points() */ -typedef struct tGPDeleteIsland { +struct tGPDeleteIsland { int start_idx; int end_idx; -} tGPDeleteIsland; +}; static void gpencil_stroke_join_islands(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps_first, bGPDstroke *gps_last) { - bGPDspoint *pt = NULL; - bGPDspoint *pt_final = NULL; + bGPDspoint *pt = nullptr; + bGPDspoint *pt_final = nullptr; const int totpoints = gps_first->totpoints + gps_last->totpoints; /* create new stroke */ bGPDstroke *join_stroke = BKE_gpencil_stroke_duplicate(gps_first, false, true); - join_stroke->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__); + join_stroke->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__); join_stroke->totpoints = totpoints; join_stroke->flag &= ~GP_STROKE_CYCLIC; @@ -2868,17 +2884,17 @@ static void gpencil_stroke_join_islands(bGPdata *gpd, } /* Copy over vertex weight data (if available) */ - if ((gps_first->dvert != NULL) || (gps_last->dvert != NULL)) { - join_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * totpoints, __func__); - MDeformVert *dvert_src = NULL; - MDeformVert *dvert_dst = NULL; + if ((gps_first->dvert != nullptr) || (gps_last->dvert != nullptr)) { + join_stroke->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * totpoints, __func__); + MDeformVert *dvert_src = nullptr; + MDeformVert *dvert_dst = nullptr; /* Copy weights (last before). */ e1 = 0; e2 = 0; for (int i = 0; i < totpoints; i++) { dvert_dst = &join_stroke->dvert[i]; - dvert_src = NULL; + dvert_src = nullptr; if (i < gps_last->totpoints) { if (gps_last->dvert) { dvert_src = &gps_last->dvert[e1]; @@ -2893,7 +2909,7 @@ static void gpencil_stroke_join_islands(bGPdata *gpd, } if ((dvert_src) && (dvert_src->dw)) { - dvert_dst->dw = MEM_dupallocN(dvert_src->dw); + dvert_dst->dw = (MDeformWeight *)MEM_dupallocN(dvert_src->dw); } } } @@ -2934,13 +2950,13 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, bool select, int limit) { - tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, - "gp_point_islands"); + tGPDeleteIsland *islands = (tGPDeleteIsland *)MEM_callocN( + sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands"); bool in_island = false; int num_islands = 0; - bGPDstroke *new_stroke = NULL; - bGPDstroke *gps_first = NULL; + bGPDstroke *new_stroke = nullptr; + bGPDstroke *gps_first = nullptr; const bool is_cyclic = (bool)(gps->flag & GP_STROKE_CYCLIC); /* First Pass: Identify start/end of islands */ @@ -2982,7 +2998,7 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, new_stroke = BKE_gpencil_stroke_duplicate(gps, false, true); /* if cyclic and first stroke, save to join later */ - if ((is_cyclic) && (gps_first == NULL)) { + if ((is_cyclic) && (gps_first == nullptr)) { gps_first = new_stroke; } @@ -2992,17 +3008,17 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, new_stroke->totpoints = island->end_idx - island->start_idx + 1; /* Copy over the relevant point data */ - new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, - "gp delete stroke fragment"); + new_stroke->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, + "gp delete stroke fragment"); memcpy(new_stroke->points, gps->points + island->start_idx, sizeof(bGPDspoint) * new_stroke->totpoints); /* Copy over vertex weight data (if available) */ - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { /* Copy over the relevant vertex-weight points */ - new_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints, - "gp delete stroke fragment weight"); + new_stroke->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints, + "gp delete stroke fragment weight"); memcpy(new_stroke->dvert, gps->dvert + island->start_idx, sizeof(MDeformVert) * new_stroke->totpoints); @@ -3013,7 +3029,7 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, MDeformVert *dvert_src = &gps->dvert[e]; MDeformVert *dvert_dst = &new_stroke->dvert[i]; if (dvert_src->dw) { - dvert_dst->dw = MEM_dupallocN(dvert_src->dw); + dvert_dst->dw = (MDeformWeight *)MEM_dupallocN(dvert_src->dw); } e++; } @@ -3047,7 +3063,7 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, /* Add new stroke to the frame or delete if below limit */ if ((limit > 0) && (new_stroke->totpoints <= limit)) { if (gps_first == new_stroke) { - gps_first = NULL; + gps_first = nullptr; } BKE_gpencil_free_stroke(new_stroke); } @@ -3064,7 +3080,7 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, } } /* if cyclic, need to join last stroke with first stroke */ - if ((is_cyclic) && (gps_first != NULL) && (gps_first != new_stroke)) { + if ((is_cyclic) && (gps_first != nullptr) && (gps_first != new_stroke)) { gpencil_stroke_join_islands(gpd, gpf, gps_first, new_stroke); } } @@ -3086,13 +3102,13 @@ void BKE_gpencil_curve_delete_tagged_points(bGPdata *gpd, bGPDcurve *gpc, int tag_flags) { - if (gpc == NULL) { + if (gpc == nullptr) { return; } const bool is_cyclic = gps->flag & GP_STROKE_CYCLIC; const int idx_last = gpc->tot_curve_points - 1; - bGPDstroke *gps_first = NULL; - bGPDstroke *gps_last = NULL; + bGPDstroke *gps_first = nullptr; + bGPDstroke *gps_last = nullptr; int idx_start = 0; int idx_end = 0; @@ -3123,11 +3139,11 @@ void BKE_gpencil_curve_delete_tagged_points(bGPdata *gpd, } bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, false, false); - new_stroke->points = NULL; + new_stroke->points = nullptr; new_stroke->flag &= ~GP_STROKE_CYCLIC; new_stroke->editcurve = BKE_gpencil_stroke_editcurve_new(island_length); - if (gps_first == NULL) { + if (gps_first == nullptr) { gps_first = new_stroke; } @@ -3155,15 +3171,15 @@ void BKE_gpencil_curve_delete_tagged_points(bGPdata *gpd, } /* join first and last stroke if cyclic */ - if (is_cyclic && gps_first != NULL && gps_last != NULL && gps_first != gps_last) { + if (is_cyclic && gps_first != nullptr && gps_last != nullptr && gps_first != gps_last) { bGPDcurve *gpc_first = gps_first->editcurve; bGPDcurve *gpc_last = gps_last->editcurve; int first_tot_points = gpc_first->tot_curve_points; int old_tot_points = gpc_last->tot_curve_points; gpc_last->tot_curve_points = first_tot_points + old_tot_points; - gpc_last->curve_points = MEM_recallocN(gpc_last->curve_points, - sizeof(bGPDcurve_point) * gpc_last->tot_curve_points); + gpc_last->curve_points = (bGPDcurve_point *)MEM_recallocN( + gpc_last->curve_points, sizeof(bGPDcurve_point) * gpc_last->tot_curve_points); /* copy data from first to last */ memcpy(gpc_last->curve_points + old_tot_points, gpc_first->curve_points, @@ -3196,14 +3212,16 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, { bGPDspoint *newpoint; - gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); - if (gps->dvert != NULL) { - gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1)); + gps->points = (bGPDspoint *)MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); + if (gps->dvert != nullptr) { + gps->dvert = (MDeformVert *)MEM_reallocN(gps->dvert, + sizeof(MDeformVert) * (gps->totpoints + 1)); } else { /* If destination has weight add weight to origin. */ - if (dvert != NULL) { - gps->dvert = MEM_callocN(sizeof(MDeformVert) * (gps->totpoints + 1), __func__); + if (dvert != nullptr) { + gps->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * (gps->totpoints + 1), + __func__); } } @@ -3219,16 +3237,16 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, newpoint->time = point->time + deltatime; copy_v4_v4(newpoint->vert_color, point->vert_color); - if (gps->dvert != NULL) { + if (gps->dvert != nullptr) { MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1]; - if (dvert != NULL) { + if (dvert != nullptr) { newdvert->totweight = dvert->totweight; - newdvert->dw = MEM_dupallocN(dvert->dw); + newdvert->dw = (MDeformWeight *)MEM_dupallocN(dvert->dw); } else { newdvert->totweight = 0; - newdvert->dw = NULL; + newdvert->dw = nullptr; } } } @@ -3246,7 +3264,7 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a, float deltatime = 0.0f; /* sanity checks */ - if (ELEM(NULL, gps_a, gps_b)) { + if (ELEM(nullptr, gps_a, gps_b)) { return; } @@ -3308,11 +3326,11 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a, point = gps_a->points[gps_a->totpoints - 1]; deltatime = point.time; - gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, 0.0f); + gpencil_stroke_copy_point(gps_a, nullptr, &point, delta, 0.0f, 0.0f, 0.0f); /* 2nd: add one head point to finish invisible area */ point = gps_b->points[0]; - gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, deltatime); + gpencil_stroke_copy_point(gps_a, nullptr, &point, delta, 0.0f, 0.0f, deltatime); } const float ratio = (fit_thickness && gps_a->thickness > 0.0f) ? @@ -3321,7 +3339,7 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a, /* 3rd: add all points */ for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) { - MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : NULL; + MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : nullptr; gpencil_stroke_copy_point( gps_a, dvert, pt, delta, pt->pressure * ratio, pt->strength, deltatime); } @@ -3340,16 +3358,16 @@ void BKE_gpencil_stroke_copy_to_keyframes( if (gpf->framenum != cfra) { bGPDframe *gpf_new = BKE_gpencil_layer_frame_find(gpl, cfra); - if (gpf_new == NULL) { + if (gpf_new == nullptr) { gpf_new = BKE_gpencil_frame_addnew(gpl, cfra); } - if (gpf_new == NULL) { + if (gpf_new == nullptr) { continue; } bGPDstroke *gps_new = BKE_gpencil_stroke_duplicate(gps, true, true); - if (gps_new == NULL) { + if (gps_new == nullptr) { continue; } @@ -3363,38 +3381,38 @@ void BKE_gpencil_stroke_copy_to_keyframes( } /* Free hash table. */ - BLI_ghash_free(frame_list, NULL, NULL); + BLI_ghash_free(frame_list, nullptr, nullptr); } /* Stroke Uniform Subdivide ------------------------------------- */ -typedef struct tSamplePoint { +struct tSamplePoint { struct tSamplePoint *next, *prev; float x, y, z; float pressure, strength, time; float vertex_color[4]; struct MDeformWeight *dw; int totweight; -} tSamplePoint; +}; -typedef struct tSampleEdge { +struct tSampleEdge { float length_sq; tSamplePoint *from; tSamplePoint *to; -} tSampleEdge; +}; /* Helper: creates a tSamplePoint from a bGPDspoint and (optionally) a MDeformVert. */ static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const MDeformVert *dvert) { - tSamplePoint *new_pt = MEM_callocN(sizeof(tSamplePoint), __func__); + tSamplePoint *new_pt = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__); copy_v3_v3(&new_pt->x, &pt->x); new_pt->pressure = pt->pressure; new_pt->strength = pt->strength; new_pt->time = pt->time; copy_v4_v4((float *)&new_pt->vertex_color, (float *)&pt->vert_color); - if (dvert != NULL) { + if (dvert != nullptr) { new_pt->totweight = dvert->totweight; - new_pt->dw = MEM_callocN(sizeof(MDeformWeight) * new_pt->totweight, __func__); + new_pt->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * new_pt->totweight, __func__); for (uint i = 0; i < new_pt->totweight; ++i) { MDeformWeight *dw = &new_pt->dw[i]; MDeformWeight *dw_from = &dvert->dw[i]; @@ -3409,7 +3427,7 @@ static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const * the edge. */ static tSampleEdge *new_sample_edge_from_sample_points(tSamplePoint *from, tSamplePoint *to) { - tSampleEdge *new_edge = MEM_callocN(sizeof(tSampleEdge), __func__); + tSampleEdge *new_edge = (tSampleEdge *)MEM_callocN(sizeof(tSampleEdge), __func__); new_edge->from = from; new_edge->to = to; new_edge->length_sq = len_squared_v3v3(&from->x, &to->x); @@ -3431,27 +3449,27 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, const bool select) { /* Stroke needs at least two points and strictly less points than the target number. */ - if (gps == NULL || gps->totpoints < 2 || gps->totpoints >= target_number) { + if (gps == nullptr || gps->totpoints < 2 || gps->totpoints >= target_number) { return; } const int totpoints = gps->totpoints; - const bool has_dverts = (gps->dvert != NULL); + const bool has_dverts = (gps->dvert != nullptr); const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC); - ListBase points = {NULL, NULL}; + ListBase points = {nullptr, nullptr}; Heap *edges = BLI_heap_new(); /* Add all points into list. */ for (uint32_t i = 0; i < totpoints; ++i) { bGPDspoint *pt = &gps->points[i]; - MDeformVert *dvert = has_dverts ? &gps->dvert[i] : NULL; + MDeformVert *dvert = has_dverts ? &gps->dvert[i] : nullptr; tSamplePoint *sp = new_sample_point_from_gp_point(pt, dvert); BLI_addtail(&points, sp); } /* Iterate over edges and insert them into the heap. */ - for (tSamplePoint *pt = ((tSamplePoint *)points.first)->next; pt != NULL; pt = pt->next) { + for (tSamplePoint *pt = ((tSamplePoint *)points.first)->next; pt != nullptr; pt = pt->next) { tSampleEdge *se = new_sample_edge_from_sample_points(pt->prev, pt); /* BLI_heap is a min-heap, but we need the largest key to be at the top, so we take the * negative of the squared length. */ @@ -3459,8 +3477,8 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, } if (is_cyclic) { - tSamplePoint *sp_first = points.first; - tSamplePoint *sp_last = points.last; + tSamplePoint *sp_first = (tSamplePoint *)points.first; + tSamplePoint *sp_last = (tSamplePoint *)points.last; tSampleEdge *se = new_sample_edge_from_sample_points(sp_last, sp_first); BLI_heap_insert(edges, -(se->length_sq), se); } @@ -3469,12 +3487,12 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, BLI_assert(num_points_needed > 0); while (num_points_needed > 0) { - tSampleEdge *se = BLI_heap_pop_min(edges); + tSampleEdge *se = (tSampleEdge *)BLI_heap_pop_min(edges); tSamplePoint *sp = se->from; tSamplePoint *sp_next = se->to; /* Subdivide the edge. */ - tSamplePoint *new_sp = MEM_callocN(sizeof(tSamplePoint), __func__); + tSamplePoint *new_sp = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__); interp_v3_v3v3(&new_sp->x, &sp->x, &sp_next->x, 0.5f); new_sp->pressure = interpf(sp->pressure, sp_next->pressure, 0.5f); new_sp->strength = interpf(sp->strength, sp_next->strength, 0.5f); @@ -3485,7 +3503,8 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, 0.5f); if (sp->dw && sp_next->dw) { new_sp->totweight = MIN2(sp->totweight, sp_next->totweight); - new_sp->dw = MEM_callocN(sizeof(MDeformWeight) * new_sp->totweight, __func__); + new_sp->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * new_sp->totweight, + __func__); for (uint32_t i = 0; i < new_sp->totweight; ++i) { MDeformWeight *dw = &new_sp->dw[i]; MDeformWeight *dw_from = &sp->dw[i]; @@ -3509,13 +3528,13 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, BLI_heap_free(edges, (HeapFreeFP)MEM_freeN); gps->totpoints = target_number; - gps->points = MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints); + gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints); if (has_dverts) { - gps->dvert = MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints); + gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints); } /* Convert list back to stroke point array. */ - tSamplePoint *sp = points.first; + tSamplePoint *sp = (tSamplePoint *)points.first; for (uint32_t i = 0; i < gps->totpoints && sp; ++i, sp = sp->next) { bGPDspoint *pt = &gps->points[i]; MDeformVert *dvert = &gps->dvert[i]; @@ -3528,7 +3547,7 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, if (sp->dw) { dvert->totweight = sp->totweight; - dvert->dw = MEM_callocN(sizeof(MDeformWeight) * dvert->totweight, __func__); + dvert->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dvert->totweight, __func__); for (uint32_t j = 0; j < dvert->totweight; ++j) { MDeformWeight *dw = &dvert->dw[j]; MDeformWeight *dw_from = &sp->dw[j]; @@ -3549,7 +3568,7 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, /* Free the sample points. Important to use the mutable loop here because we are erasing the list * elements. */ LISTBASE_FOREACH_MUTABLE (tSamplePoint *, temp, &points) { - if (temp->dw != NULL) { + if (temp->dw != nullptr) { MEM_freeN(temp->dw); } MEM_SAFE_FREE(temp); @@ -3601,14 +3620,14 @@ void BKE_gpencil_stroke_from_view_space(RegionView3D *rv3d, /* ----------------------------------------------------------------------------- */ /* Stroke to perimeter */ -typedef struct tPerimeterPoint { +struct tPerimeterPoint { struct tPerimeterPoint *next, *prev; float x, y, z; -} tPerimeterPoint; +}; static tPerimeterPoint *new_perimeter_point(const float pt[3]) { - tPerimeterPoint *new_pt = MEM_callocN(sizeof(tPerimeterPoint), __func__); + tPerimeterPoint *new_pt = (tPerimeterPoint *)MEM_callocN(sizeof(tPerimeterPoint), __func__); copy_v3_v3(&new_pt->x, pt); return new_pt; } @@ -3771,14 +3790,14 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd, { /* sanity check */ if (gps->totpoints < 1) { - return NULL; + return nullptr; } float defaultpixsize = 1000.0f / gpd->pixfactor; float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f; - ListBase *perimeter_right_side = MEM_callocN(sizeof(ListBase), __func__); - ListBase *perimeter_left_side = MEM_callocN(sizeof(ListBase), __func__); + ListBase *perimeter_right_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__); + ListBase *perimeter_left_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__); int num_perimeter_points = 0; bGPDspoint *first = &gps->points[0]; @@ -4018,7 +4037,7 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d, const float diff_mat[4][4]) { if (gps->totpoints == 0) { - return NULL; + return nullptr; } bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, true, false); const bool cyclic = ((gps_temp->flag & GP_STROKE_CYCLIC) != 0); @@ -4026,8 +4045,8 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d, /* If Cyclic, add a new point. */ if (cyclic && (gps_temp->totpoints > 1)) { gps_temp->totpoints++; - gps_temp->points = MEM_recallocN(gps_temp->points, - sizeof(*gps_temp->points) * gps_temp->totpoints); + gps_temp->points = (bGPDspoint *)MEM_recallocN( + gps_temp->points, sizeof(*gps_temp->points) * gps_temp->totpoints); bGPDspoint *pt_src = &gps_temp->points[0]; bGPDspoint *pt_dst = &gps_temp->points[gps_temp->totpoints - 1]; copy_v3_v3(&pt_dst->x, &pt_src->x); @@ -4043,7 +4062,7 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d, gpd, gpl, gps_temp, subdivisions, &num_perimeter_points); if (num_perimeter_points == 0) { - return NULL; + return nullptr; } /* Create new stroke. */ diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc index 7e9f81f9c83..12a0a1e3ae7 100644 --- a/source/blender/blenkernel/intern/icons.cc +++ b/source/blender/blenkernel/intern/icons.cc @@ -667,7 +667,7 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv) BKE_previewimg_finish(prv, i); } else { - /* Only for old files that didn't write the flag . */ + /* Only for old files that didn't write the flag. */ prv->flag[i] |= PRV_UNFINISHED; } } diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c index 9e3d5a162ae..360bad3e786 100644 --- a/source/blender/blenkernel/intern/image_save.c +++ b/source/blender/blenkernel/intern/image_save.c @@ -135,8 +135,8 @@ static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf) /** * \return success. - * \note ``ima->filepath`` and ``ibuf->name`` should end up the same. - * \note for multiview the first ``ibuf`` is important to get the settings. + * \note `ima->filepath` and `ibuf->name` should end up the same. + * \note for multi-view the first `ibuf` is important to get the settings. */ static bool image_save_single(ReportList *reports, Image *ima, diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 730c989abc9..28282aaa823 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -1237,7 +1237,7 @@ void BKE_layer_collection_isolate_global(Scene *scene, bool hide_it = extend && (lc->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER); if (!extend) { - /* Hide all collections . */ + /* Hide all collections. */ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) { layer_collection_flag_set_recursive(lc_iter, LAYER_COLLECTION_HIDE); } diff --git a/source/blender/blenkernel/intern/main_idmap.c b/source/blender/blenkernel/intern/main_idmap.c index 1d362db4432..1421d456883 100644 --- a/source/blender/blenkernel/intern/main_idmap.c +++ b/source/blender/blenkernel/intern/main_idmap.c @@ -49,9 +49,9 @@ * \{ */ struct IDNameLib_Key { - /** ``ID.name + 2``: without the ID type prefix, since each id type gets its own 'map' */ + /** `ID.name + 2`: without the ID type prefix, since each id type gets its own 'map'. */ const char *name; - /** ``ID.lib``: */ + /** `ID.lib`: */ const Library *lib; }; diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 760febaca91..9dd583b4c6b 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -305,7 +305,7 @@ static void build_bvh_spatial(PROCESS *process, /** * Computes density from given metaball at given position. - * Metaball equation is: ``(1 - r^2 / R^2)^3 * s`` + * Metaball equation is: `(1 - r^2 / R^2)^3 * s` * * r = distance from center * R = metaball radius diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index b463d903303..8d74002ad79 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -1874,6 +1874,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac } mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; + mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL; + mesh->runtime.cd_dirty_loop &= ~CD_MASK_NORMAL; } void BKE_mesh_calc_normals_split(Mesh *mesh) diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index e777eb7ffe9..0e4fe91e577 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -212,54 +212,19 @@ static void make_edges_mdata_extend( } /* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */ -/* return non-zero on error */ -int BKE_mesh_nurbs_to_mdata(Object *ob, - MVert **r_allvert, - int *r_totvert, - MEdge **r_alledge, - int *r_totedge, - MLoop **r_allloop, - MPoly **r_allpoly, - int *r_totloop, - int *r_totpoly) -{ - ListBase disp = {NULL, NULL}; - - if (ob->runtime.curve_cache) { - disp = ob->runtime.curve_cache->disp; - } - - return BKE_mesh_nurbs_displist_to_mdata(ob, - &disp, - r_allvert, - r_totvert, - r_alledge, - r_totedge, - r_allloop, - r_allpoly, - NULL, - r_totloop, - r_totpoly); -} - -/* BMESH: this doesn't calculate all edges from polygons, - * only free standing edges are calculated */ - -/* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */ /* use specified dispbase */ -int BKE_mesh_nurbs_displist_to_mdata(const Object *ob, - const ListBase *dispbase, - MVert **r_allvert, - int *r_totvert, - MEdge **r_alledge, - int *r_totedge, - MLoop **r_allloop, - MPoly **r_allpoly, - MLoopUV **r_alluv, - int *r_totloop, - int *r_totpoly) +static int mesh_nurbs_displist_to_mdata(const Curve *cu, + const ListBase *dispbase, + MVert **r_allvert, + int *r_totvert, + MEdge **r_alledge, + int *r_totedge, + MLoop **r_allloop, + MPoly **r_allpoly, + MLoopUV **r_alluv, + int *r_totloop, + int *r_totpoly) { - const Curve *cu = ob->data; MVert *mvert; MPoly *mpoly; MLoop *mloop; @@ -272,7 +237,7 @@ int BKE_mesh_nurbs_displist_to_mdata(const Object *ob, /* 2d polys are filled with DL_INDEX3 displists */ (CU_DO_2DFILL(cu) == false) || /* surf polys are never filled */ - (ob->type == OB_SURF)); + BKE_curve_type_get(cu) == OB_SURF); /* count */ LISTBASE_FOREACH (const DispList *, dl, dispbase) { @@ -527,17 +492,17 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(const Object *ob, const ListBase * MLoopUV *alluv = NULL; int totvert, totedge, totloop, totpoly; - if (BKE_mesh_nurbs_displist_to_mdata(ob, - dispbase, - &allvert, - &totvert, - &alledge, - &totedge, - &allloop, - &allpoly, - &alluv, - &totloop, - &totpoly) != 0) { + if (mesh_nurbs_displist_to_mdata(ob->data, + dispbase, + &allvert, + &totvert, + &alledge, + &totedge, + &allloop, + &allpoly, + &alluv, + &totloop, + &totpoly) != 0) { /* Error initializing mdata. This often happens when curve is empty */ return BKE_mesh_new_nomain(0, 0, 0, 0, 0); } @@ -571,7 +536,7 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(const Object *ob, const ListBase * return mesh; } -Mesh *BKE_mesh_new_nomain_from_curve(Object *ob) +Mesh *BKE_mesh_new_nomain_from_curve(const Object *ob) { ListBase disp = {NULL, NULL}; @@ -589,7 +554,6 @@ void BKE_mesh_from_nurbs_displist( Object *ob1; Mesh *me_eval = (Mesh *)ob->runtime.data_eval; Mesh *me; - Curve *cu; MVert *allvert = NULL; MEdge *alledge = NULL; MLoop *allloop = NULL; @@ -597,20 +561,20 @@ void BKE_mesh_from_nurbs_displist( MPoly *allpoly = NULL; int totvert, totedge, totloop, totpoly; - cu = ob->data; + Curve *cu = ob->data; if (me_eval == NULL) { - if (BKE_mesh_nurbs_displist_to_mdata(ob, - dispbase, - &allvert, - &totvert, - &alledge, - &totedge, - &allloop, - &allpoly, - &alluv, - &totloop, - &totpoly) != 0) { + if (mesh_nurbs_displist_to_mdata(cu, + dispbase, + &allvert, + &totvert, + &alledge, + &totedge, + &allloop, + &allpoly, + &alluv, + &totloop, + &totpoly) != 0) { /* Error initializing */ return; } @@ -702,18 +666,6 @@ void BKE_mesh_from_nurbs_displist( } } -void BKE_mesh_from_nurbs(Main *bmain, Object *ob) -{ - Curve *cu = (Curve *)ob->data; - ListBase disp = {NULL, NULL}; - - if (ob->runtime.curve_cache) { - disp = ob->runtime.curve_cache->disp; - } - - BKE_mesh_from_nurbs_displist(bmain, ob, &disp, cu->id.name, false); -} - typedef struct EdgeLink { struct EdgeLink *next, *prev; void *edge; @@ -1152,8 +1104,8 @@ static Mesh *mesh_new_from_curve_type_object(Object *object) BKE_mesh_from_nurbs_displist( NULL, temp_object, &temp_object->runtime.curve_cache->disp, curve->id.name + 2, true); - /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. If it didn't the curve did - * not have any segments or otherwise would have generated an empty mesh. */ + /* BKE_mesh_from_nurbs_displist changes the type to a mesh, check it worked. If it didn't + * the curve did not have any segments or otherwise would have generated an empty mesh. */ if (temp_object->type != OB_MESH) { BKE_id_free(NULL, temp_object->data); BKE_id_free(NULL, temp_object); diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c index 5ecf5ae316d..7a776b0ecb7 100644 --- a/source/blender/blenkernel/intern/mesh_iterators.c +++ b/source/blender/blenkernel/intern/mesh_iterators.c @@ -95,9 +95,14 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh, } } -/* Copied from cdDM_foreachMappedEdge */ +/** + * Copied from #cdDM_foreachMappedEdge. + * \param tot_edges: Number of original edges. Used to avoid calling the callback with invalid + * edge indices. + */ void BKE_mesh_foreach_mapped_edge( Mesh *mesh, + const int tot_edges, void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]), void *userData) { @@ -138,7 +143,7 @@ void BKE_mesh_foreach_mapped_edge( func(userData, orig, mv[med->v1].co, mv[med->v2].co); } } - else { + else if (mesh->totedge == tot_edges) { for (int i = 0; i < mesh->totedge; i++, med++) { func(userData, i, mv[med->v1].co, mv[med->v2].co); } diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c index ca6c60557a6..d28bb9c0744 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.c +++ b/source/blender/blenkernel/intern/mesh_mapping.c @@ -539,8 +539,8 @@ void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, * \param totfinal: The size of \a final_origindex * \param final_origindex: The size of the final array. * - * \note ``totsource`` could be ``totpoly``, - * ``totfinal`` could be ``tottessface`` and ``final_origindex`` its ORIGINDEX customdata. + * \note `totsource` could be `totpoly`, + * `totfinal` could be `tottessface` and `final_origindex` its ORIGINDEX custom-data. * This would allow an MPoly to loop over its tessfaces. */ void BKE_mesh_origindex_map_create(MeshElemMap **r_map, diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 2fe132fc684..f496d6eada1 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -530,6 +530,36 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, lnors_spacearr->data_type = data_type; } +/** + * Utility for multi-threaded calculation that ensures + * `lnors_spacearr_tls` doesn't share memory with `lnors_spacearr` + * that would cause it not to be thread safe. + * + * \note This works as long as threads never operate on the same loops at once. + */ +void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr, + MLoopNorSpaceArray *lnors_spacearr_tls) +{ + *lnors_spacearr_tls = *lnors_spacearr; + lnors_spacearr_tls->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); +} + +/** + * Utility for multi-threaded calculation + * that merges `lnors_spacearr_tls` into `lnors_spacearr`. + */ +void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr, + MLoopNorSpaceArray *lnors_spacearr_tls) +{ + BLI_assert(lnors_spacearr->data_type == lnors_spacearr_tls->data_type); + BLI_assert(lnors_spacearr->mem != lnors_spacearr_tls->mem); + lnors_spacearr->num_spaces += lnors_spacearr_tls->num_spaces; + BLI_memarena_merge(lnors_spacearr->mem, lnors_spacearr_tls->mem); + BLI_memarena_free(lnors_spacearr_tls->mem); + lnors_spacearr_tls->mem = nullptr; + BKE_lnor_spacearr_clear(lnors_spacearr_tls); +} + void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr) { lnors_spacearr->num_spaces = 0; diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 85d30fc8c8b..e9608457896 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -1212,10 +1212,12 @@ static void update_typeinfo(Main *bmain, FOREACH_NODETREE_END; } -/* Try to initialize all typeinfo in a node tree. - * NB: In general undefined typeinfo is a perfectly valid case, +/** + * Try to initialize all type-info in a node tree. + * + * \note In general undefined type-info is a perfectly valid case, * the type may just be registered later. - * In that case the update_typeinfo function will set typeinfo on registration + * In that case the update_typeinfo function will set type-info on registration * and do necessary updates. */ void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree) @@ -5117,9 +5119,11 @@ static void registerGeometryNodes() register_node_type_geo_curve_primitive_star(); register_node_type_geo_curve_resample(); register_node_type_geo_curve_reverse(); + register_node_type_geo_curve_set_handles(); register_node_type_geo_curve_subdivide(); register_node_type_geo_curve_to_mesh(); register_node_type_geo_curve_to_points(); + register_node_type_geo_curve_trim(); register_node_type_geo_delete_geometry(); register_node_type_geo_edge_split(); register_node_type_geo_input_material(); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 941db80b76c..89de37d6e4b 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1653,7 +1653,7 @@ static void object_update_from_subsurf_ccg(Object *object) * * All this is defeating all the designs we need to follow to allow safe * threaded evaluation, but this is as good as we can make it within the - * current sculpt//evaluated mesh design. This is also how we've survived + * current sculpt/evaluated mesh design. This is also how we've survived * with old DerivedMesh based solutions. So, while this is all wrong and * needs reconsideration, doesn't seem to be a big stopper for real * production artists. diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 7cdea14e9bd..7e15ac5de5d 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -388,31 +388,12 @@ void BKE_object_batch_cache_dirty_tag(Object *ob) BKE_object_data_batch_cache_dirty_tag(ob->data); } -void BKE_object_data_eval_batch_cache_dirty_tag(Depsgraph *depsgraph, ID *object_data) -{ - DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data); - BKE_object_data_batch_cache_dirty_tag(object_data); -} - -void BKE_object_data_eval_batch_cache_deform_tag(Depsgraph *depsgraph, ID *object_data) -{ - DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data); - switch (GS(object_data->name)) { - case ID_ME: - BKE_mesh_batch_cache_dirty_tag((Mesh *)object_data, BKE_MESH_BATCH_DIRTY_DEFORM); - break; - default: - /* Only mesh is currently supported. Fallback to dirty all for other datablocks types. */ - BKE_object_data_batch_cache_dirty_tag(object_data); - break; - } -} - void BKE_object_eval_uber_data(Depsgraph *depsgraph, Scene *scene, Object *ob) { DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); BLI_assert(ob->type != OB_ARMATURE); BKE_object_handle_data_update(depsgraph, scene, ob); + BKE_object_batch_cache_dirty_tag(ob); } void BKE_object_eval_ptcache_reset(Depsgraph *depsgraph, Scene *scene, Object *object) diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 1af66fa090b..a1fa6aae1ce 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -880,7 +880,7 @@ static int palettecolor_compare_luminance(const void *a1, const void *a2) void BKE_palette_sort_hsv(tPaletteColorHSV *color_array, const int totcol) { - /* Sort by Hue , Saturation and Value. */ + /* Sort by Hue, Saturation and Value. */ qsort(color_array, totcol, sizeof(tPaletteColorHSV), palettecolor_compare_hsv); } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index db1fbb56125..f2f3c5d4ca6 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -4418,12 +4418,12 @@ void psys_get_texture( if ((event & mtex->mapto) & PAMAP_TIME) { /* the first time has to set the base value for time regardless of blend mode */ - if ((setvars & MAP_PA_TIME) == 0) { + if ((setvars & PAMAP_TIME) == 0) { int flip = (mtex->timefac < 0.0f); float timefac = fabsf(mtex->timefac); ptex->time *= 1.0f - timefac; ptex->time += timefac * ((flip) ? 1.0f - value : value); - setvars |= MAP_PA_TIME; + setvars |= PAMAP_TIME; } else { ptex->time = texture_value_blend(def, ptex->time, value, mtex->timefac, blend); diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index d3d7f02ecad..93cffcf7164 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -1168,12 +1168,12 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, } /** - * The 2 new faces created and assigned to ``f_new`` have their + * The 2 new faces created and assigned to `f_new` have their * verts & edges shuffled around. * * - faces wind anticlockwise in this example. - * - original edge is ``(v1, v2)`` - * - original face is ``(v1, v2, v3)`` + * - original edge is `(v1, v2)` + * - original face is `(v1, v2, v3)` * * <pre> * + v3(v_opp) @@ -1189,8 +1189,8 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, * (first) (second) * </pre> * - * - f_new (first): ``v_tri=(v1, v4, v3), e_tri=(e1, e5, e4)`` - * - f_new (second): ``v_tri=(v4, v2, v3), e_tri=(e2, e3, e5)`` + * - f_new (first): `v_tri=(v1, v4, v3), e_tri=(e1, e5, e4)` + * - f_new (second): `v_tri=(v4, v2, v3), e_tri=(e2, e3, e5)` */ /* Create two new faces */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index cc5a8536a5a..a3a0ce0060b 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -2105,7 +2105,7 @@ Object *BKE_scene_object_find_by_name(const Scene *scene, const char *name) /** * Sets the active scene, mainly used when running in background mode - * (``--scene`` command line argument). + * (`--scene` command line argument). * This is also called to set the scene directly, bypassing windowing code. * Otherwise #WM_window_set_active_scene is used when changing scenes by the user. */ @@ -3242,9 +3242,9 @@ void BKE_scene_multiview_filepath_get(SceneRenderView *srv, const char *filepath } /** - * When multiview is not used the filepath is as usual (e.g., ``Image.jpg``). + * When multiview is not used the filepath is as usual (e.g., `Image.jpg`). * When multiview is on, even if only one view is enabled the view is incorporated - * into the file name (e.g., ``Image_L.jpg``). That allows for the user to re-render + * into the file name (e.g., `Image_L.jpg`). That allows for the user to re-render * individual views. */ void BKE_scene_multiview_view_filepath_get(const RenderData *rd, diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc index 6234cdf87e2..a7caae967f6 100644 --- a/source/blender/blenkernel/intern/spline_base.cc +++ b/source/blender/blenkernel/intern/spline_base.cc @@ -410,7 +410,7 @@ Spline::LookupResult Spline::lookup_evaluated_length(const float length) const const float *offset = std::lower_bound(lengths.begin(), lengths.end(), length); const int index = offset - lengths.begin(); - const int next_index = (index == this->size() - 1) ? 0 : index + 1; + const int next_index = (index == this->evaluated_points_size() - 1) ? 0 : index + 1; const float previous_length = (index == 0) ? 0.0f : lengths[index - 1]; const float factor = (length - previous_length) / (lengths[index] - previous_length); diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index cff2c5cc562..a1b45c2ac7d 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -423,7 +423,7 @@ static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh * /* get some info from CCGSubSurf */ totface = ccgSubSurf_getNumFaces(uvss); - /* edgeSize = ccgSubSurf_getEdgeSize(uvss); */ /*UNUSED*/ + // edgeSize = ccgSubSurf_getEdgeSize(uvss); /* UNUSED */ gridSize = ccgSubSurf_getGridSize(uvss); gridFaces = gridSize - 1; diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index d9f02ce4c75..4581d410444 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -1303,7 +1303,7 @@ const char *BKE_unit_identifier_get(const void *usys_pt, int index) { const bUnitDef *unit = ((const bUnitCollection *)usys_pt)->units + index; if (unit->identifier == NULL) { - BLI_assert(false && "identifier for this unit is not specified yet"); + BLI_assert_msg(0, "identifier for this unit is not specified yet"); } return unit->identifier; } diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 5cac149c503..059dc68b1dc 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -58,7 +58,7 @@ static void workspace_init_data(ID *id) { WorkSpace *workspace = (WorkSpace *)id; - BKE_asset_library_reference_init_default(&workspace->active_asset_library); + BKE_asset_library_reference_init_default(&workspace->asset_library); } static void workspace_free_data(ID *id) diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 560ae30967f..9b3103a638b 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -1747,9 +1747,10 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset) rd->ffcodecdata.type = FFMPEG_MPEG2; rd->ffcodecdata.video_bitrate = 6000; - /* Don't set resolution, see T21351. - * rd->xsch = 720; - * rd->ysch = isntsc ? 480 : 576; */ +# if 0 /* Don't set resolution, see T21351. */ + rd->xsch = 720; + rd->ysch = isntsc ? 480 : 576; +# endif rd->ffcodecdata.gop_size = isntsc ? 18 : 15; rd->ffcodecdata.rc_max_rate = 9000; diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h index e40a79dad21..6bf29a6168f 100644 --- a/source/blender/blenlib/BLI_array.h +++ b/source/blender/blenlib/BLI_array.h @@ -58,7 +58,7 @@ void _bli_array_grow_func(void **arr_p, /** \name Public defines * \{ */ -/** use ``sizeof(*(arr))`` to ensure the array exists and is an array */ +/** use `sizeof(*(arr))` to ensure the array exists and is an array */ #define BLI_array_declare(arr) \ int _##arr##_len = ((void)(sizeof(*(arr))), 0); \ void *_##arr##_static = NULL diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh index 76dfcf0b57d..d93bd7f6f76 100644 --- a/source/blender/blenlib/BLI_color.hh +++ b/source/blender/blenlib/BLI_color.hh @@ -34,11 +34,11 @@ namespace blender { * Usage: * * Convert a theme byte color to a linearrgb premultiplied. - * ``` + * \code{.cc} * ColorTheme4b theme_color; * ColorSceneLinear4f<eAlpha::Premultiplied> linearrgb_color = * BLI_color_convert_to_scene_linear(theme_color).premultiply_alpha(); - * ``` + * \endcode * * The API is structured to make most use of inlining. Most notable are space * conversions done via `BLI_color_convert_to*` functions. diff --git a/source/blender/blenlib/BLI_compiler_typecheck.h b/source/blender/blenlib/BLI_compiler_typecheck.h index d9c2bfc1d58..18be2190c1b 100644 --- a/source/blender/blenlib/BLI_compiler_typecheck.h +++ b/source/blender/blenlib/BLI_compiler_typecheck.h @@ -86,7 +86,7 @@ /** * CHECK_TYPE_ANY: handy macro, eg: - * ``CHECK_TYPE_ANY(var, Foo *, Bar *, Baz *)`` + * `CHECK_TYPE_ANY(var, Foo *, Bar *, Baz *)` * * excuse ridiculously long generated args. * \code{.py} diff --git a/source/blender/blenlib/BLI_delaunay_2d.h b/source/blender/blenlib/BLI_delaunay_2d.h index d42bd6af637..658dcadadce 100644 --- a/source/blender/blenlib/BLI_delaunay_2d.h +++ b/source/blender/blenlib/BLI_delaunay_2d.h @@ -110,6 +110,10 @@ extern "C" { * If zero is supplied for epsilon, an internal value of 1e-8 used * instead, since this code will not work correctly if it is not allowed * to merge "too near" vertices. + * + * Normally the output will contain mappings from outputs to inputs. + * If this is not needed, set need_ids to false and the execution may be much + * faster in some circumstances. */ typedef struct CDT_input { int verts_len; @@ -121,6 +125,7 @@ typedef struct CDT_input { int *faces_start_table; int *faces_len_table; float epsilon; + bool need_ids; } CDT_input; /** @@ -140,6 +145,7 @@ typedef struct CDT_input { * a run-together array and a "start" and "len" extra array, * similar triples are used to represent the output to input * mapping of vertices, edges, and faces. + * These are only set if need_ids is true in the input. * * Those triples are: * - verts_orig, verts_orig_start_table, verts_orig_len_table @@ -236,6 +242,7 @@ template<typename Arith_t> class CDT_input { Array<std::pair<int, int>> edge; Array<Vector<int>> face; Arith_t epsilon{0}; + bool need_ids{true}; }; template<typename Arith_t> class CDT_result { @@ -243,6 +250,7 @@ template<typename Arith_t> class CDT_result { Array<vec2<Arith_t>> vert; Array<std::pair<int, int>> edge; Array<Vector<int>> face; + /* The orig vectors are only populated if the need_ids input field is true. */ /** For each output vert, which input verts correspond to it? */ Array<Vector<int>> vert_orig; /** diff --git a/source/blender/blenlib/BLI_dlrbTree.h b/source/blender/blenlib/BLI_dlrbTree.h index 8c20e3d3988..03aab8d2895 100644 --- a/source/blender/blenlib/BLI_dlrbTree.h +++ b/source/blender/blenlib/BLI_dlrbTree.h @@ -111,20 +111,22 @@ void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree); /* Searching ------------------------------------ */ /* Find the node which matches or is the closest to the requested node */ -DLRBT_Node *BLI_dlrbTree_search(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data); +DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree, + DLRBT_Comparator_FP cmp_cb, + void *search_data); /* Find the node which exactly matches the required data */ -DLRBT_Node *BLI_dlrbTree_search_exact(DLRBT_Tree *tree, +DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data); /* Find the node which occurs immediately before the best matching node */ -DLRBT_Node *BLI_dlrbTree_search_prev(DLRBT_Tree *tree, +DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data); /* Find the node which occurs immediately after the best matching node */ -DLRBT_Node *BLI_dlrbTree_search_next(DLRBT_Tree *tree, +DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data); @@ -137,7 +139,8 @@ short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void * */ /* Add the given data to the tree, and return the node added */ -// NOTE: for duplicates, the update_cb is called (if available), and the existing node is returned +/* NOTE: for duplicates, the update_cb is called (if available), + * and the existing node is returned. */ DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, DLRBT_NAlloc_FP new_cb, @@ -145,7 +148,7 @@ DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree, void *data); /* Remove the given element from the tree and balance again */ -// FIXME: this is not implemented yet... +/* FIXME: this is not implemented yet... */ // void BLI_dlrbTree_remove(DLRBT_Tree *tree, DLRBT_Node *node); /* Node Operations (Manual) --------------------- */ diff --git a/source/blender/blenlib/BLI_float4x4.hh b/source/blender/blenlib/BLI_float4x4.hh index 396b0b1bd21..8ff4f94f95c 100644 --- a/source/blender/blenlib/BLI_float4x4.hh +++ b/source/blender/blenlib/BLI_float4x4.hh @@ -51,8 +51,14 @@ struct float4x4 { { BLI_ASSERT_UNIT_V3(forward); BLI_ASSERT_UNIT_V3(up); + + /* Negate the cross product so that the resulting matrix has determinant 1 (instead of -1). + * Without the negation, the result would be a so called improper rotation. That means it + * contains a reflection. Such an improper rotation matrix could not be converted to another + * representation of a rotation such as euler angles. */ + const float3 cross = -float3::cross(forward, up); + float4x4 matrix; - const float3 cross = float3::cross(forward, up); matrix.values[0][0] = forward.x; matrix.values[1][0] = cross.x; matrix.values[2][0] = up.x; diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index e708b327bd4..a2c5c6349a5 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -77,7 +77,7 @@ enum { /* -------------------------------------------------------------------- */ /** \name GHash API * - * Defined in ``BLI_ghash.c`` + * Defined in `BLI_ghash.c` * \{ */ GHash *BLI_ghash_new_ex(GHashHashFP hashfp, @@ -333,11 +333,11 @@ double BLI_gset_calc_quality(GSet *gs); /* -------------------------------------------------------------------- */ /** \name GHash/GSet Utils * - * Defined in ``BLI_ghash_utils.c`` + * Defined in `BLI_ghash_utils.c` * \{ */ /** - * Callbacks for GHash (``BLI_ghashutil_``) + * Callbacks for GHash (`BLI_ghashutil_`) * * \note '_p' suffix denotes void pointer arg, * so we can have functions that take correctly typed args too. diff --git a/source/blender/blenlib/BLI_link_utils.h b/source/blender/blenlib/BLI_link_utils.h index e1e4a8dbd4a..7aa7300da16 100644 --- a/source/blender/blenlib/BLI_link_utils.h +++ b/source/blender/blenlib/BLI_link_utils.h @@ -20,7 +20,7 @@ * \ingroup bli * \brief Single link-list utility macros. (header only api). * - * Use this api when the structure defines its own ``next`` pointer + * Use this api when the structure defines its own `next` pointer * and a double linked list such as #ListBase isn't needed. */ diff --git a/source/blender/blenlib/BLI_linklist_stack.h b/source/blender/blenlib/BLI_linklist_stack.h index 8a5e94a7b56..d07bc40c923 100644 --- a/source/blender/blenlib/BLI_linklist_stack.h +++ b/source/blender/blenlib/BLI_linklist_stack.h @@ -28,7 +28,7 @@ * \note These macros follow STACK_* macros defined in 'BLI_utildefines.h' * and should be kept (mostly) interchangeable. * - * \note ``_##var##_type`` is a dummy variable only used for typechecks. + * \note `_##var##_type` is a dummy variable only used for type-checks. */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenlib/BLI_math.h b/source/blender/blenlib/BLI_math.h index 3b61c0feb51..5768b098d2f 100644 --- a/source/blender/blenlib/BLI_math.h +++ b/source/blender/blenlib/BLI_math.h @@ -26,32 +26,32 @@ * * \section mathabbrev Abbreviations * - * - ``fl`` = float - * - ``db`` = double - * - ``v2`` = vec2 = vector 2 - * - ``v3`` = vec3 = vector 3 - * - ``v4`` = vec4 = vector 4 - * - ``vn`` = vec4 = vector N dimensions, *passed as an arg, after the vector*. - * - ``qt`` = quat = quaternion - * - ``dq`` = dquat = dual quaternion - * - ``m2`` = mat2 = matrix 2x2 - * - ``m3`` = mat3 = matrix 3x3 - * - ``m4`` = mat4 = matrix 4x4 - * - ``eul`` = euler rotation - * - ``eulO`` = euler with order - * - ``plane`` = plane 4, (vec3, distance) - * - ``plane3`` = plane 3 (same as a ``plane`` with a zero 4th component) + * - `fl` = float + * - `db` = double + * - `v2` = vec2 = vector 2 + * - `v3` = vec3 = vector 3 + * - `v4` = vec4 = vector 4 + * - `vn` = vec4 = vector N dimensions, *passed as an arg, after the vector*. + * - `qt` = quat = quaternion + * - `dq` = dquat = dual quaternion + * - `m2` = mat2 = matrix 2x2 + * - `m3` = mat3 = matrix 3x3 + * - `m4` = mat4 = matrix 4x4 + * - `eul` = euler rotation + * - `eulO` = euler with order + * - `plane` = plane 4, (vec3, distance) + * - `plane3` = plane 3 (same as a `plane` with a zero 4th component) * * \subsection mathabbrev_all Function Type Abbreviations * * For non float versions of functions (which typically operate on floats), * use single suffix abbreviations. * - * - ``_d`` = double - * - ``_i`` = int - * - ``_u`` = unsigned int - * - ``_char`` = char - * - ``_uchar`` = unsigned char + * - `_d` = double + * - `_i` = int + * - `_u` = unsigned int + * - `_char` = char + * - `_uchar` = unsigned char * * \section mathvarnames Variable Names * diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c index 86784557b25..8f7f722c71b 100644 --- a/source/blender/blenlib/intern/BLI_dynstr.c +++ b/source/blender/blenlib/intern/BLI_dynstr.c @@ -291,7 +291,7 @@ int BLI_dynstr_get_len(const DynStr *ds) /** * Get a DynStr's contents as a c-string. * The \a rets argument must be allocated to be at - * least the size of ``BLI_dynstr_get_len(ds) + 1``. + * least the size of `BLI_dynstr_get_len(ds) + 1`. * * \param ds: The DynStr of interest. * \param rets: The string to fill. diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 46e599b7cf3..2c9285e418a 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -1270,7 +1270,7 @@ void BLI_gset_flag_clear(GSet *gs, uint flag) /* -------------------------------------------------------------------- */ /** \name GSet Combined Key/Value Usage * - * \note Not typical ``set`` use, only use when the pointer identity matters. + * \note Not typical `set` use, only use when the pointer identity matters. * This can be useful when the key references data stored outside the GSet. * \{ */ diff --git a/source/blender/blenlib/intern/BLI_ghash_utils.c b/source/blender/blenlib/intern/BLI_ghash_utils.c index 182c27aed6d..b9144009304 100644 --- a/source/blender/blenlib/intern/BLI_ghash_utils.c +++ b/source/blender/blenlib/intern/BLI_ghash_utils.c @@ -138,8 +138,8 @@ size_t BLI_ghashutil_combine_hash(size_t hash_a, size_t hash_b) * This function implements the widely used "djb" hash apparently posted * by Daniel Bernstein to comp.lang.c some time ago. The 32 bit * unsigned hash value starts at 5381 and for each byte 'c' in the - * string, is updated: ``hash = hash * 33 + c``. This - * function uses the signed value of each byte. + * string, is updated: `hash = hash * 33 + c`. + * This function uses the signed value of each byte. * * NOTE: this is the same hash method that glib 2.34.0 uses. */ diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 25939323b73..674654c99a8 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -22,7 +22,7 @@ * \brief BVH-tree implementation. * * k-DOP BVH (Discrete Oriented Polytope, Bounding Volume Hierarchy). - * A k-DOP is represented as k/2 pairs of min , max values for k/2 directions (intervals, "slabs"). + * A k-DOP is represented as k/2 pairs of min, max values for k/2 directions (intervals, "slabs"). * * See: http://www.gris.uni-tuebingen.de/people/staff/jmezger/papers/bvh.pdf * @@ -868,7 +868,7 @@ static void non_recursive_bvh_div_nodes(const BVHTree *tree, * \{ */ /** - * \note many callers don't check for ``NULL`` return. + * \note many callers don't check for `NULL` return. */ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) { diff --git a/source/blender/blenlib/intern/BLI_memiter.c b/source/blender/blenlib/intern/BLI_memiter.c index 3f255ce0e16..effbe5da5c4 100644 --- a/source/blender/blenlib/intern/BLI_memiter.c +++ b/source/blender/blenlib/intern/BLI_memiter.c @@ -73,7 +73,7 @@ typedef struct BLI_memiter_chunk { struct BLI_memiter_chunk *next; /** * internal format is: - * ``[next_pointer, size:data, size:data, ..., negative_offset]`` + * `[next_pointer, size:data, size:data, ..., negative_offset]` * * Where negative offset rewinds to the start. */ diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c index 5263af2ae56..f968799326a 100644 --- a/source/blender/blenlib/intern/BLI_mempool.c +++ b/source/blender/blenlib/intern/BLI_mempool.c @@ -63,9 +63,9 @@ #endif /** - * Important that this value is an is _not_ aligned with ``sizeof(void *)``. + * Important that this value is an is _not_ aligned with `sizeof(void *)`. * So having a pointer to 2/4/8... aligned memory is enough to ensure - * the freeword will never be used. + * the `freeword` will never be used. * To be safe, use a word that's the same in both directions. */ #define FREEWORD \ diff --git a/source/blender/blenlib/intern/BLI_mmap.c b/source/blender/blenlib/intern/BLI_mmap.c index 71510b62ba1..c25e89df818 100644 --- a/source/blender/blenlib/intern/BLI_mmap.c +++ b/source/blender/blenlib/intern/BLI_mmap.c @@ -31,11 +31,11 @@ #ifndef WIN32 # include <signal.h> # include <stdlib.h> -# include <sys/mman.h> // for mmap -# include <unistd.h> // for read close +# include <sys/mman.h> /* For mmap. */ +# include <unistd.h> /* For read close. */ #else # include "BLI_winstuff.h" -# include <io.h> // for open close read +# include <io.h> /* For open close read. */ #endif struct BLI_mmap_file { diff --git a/source/blender/blenlib/intern/DLRB_tree.c b/source/blender/blenlib/intern/DLRB_tree.c index 09234dcfa26..436b9b8d782 100644 --- a/source/blender/blenlib/intern/DLRB_tree.c +++ b/source/blender/blenlib/intern/DLRB_tree.c @@ -128,7 +128,9 @@ void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree) /* Tree Search Utilities */ /* Find the node which matches or is the closest to the requested node */ -DLRBT_Node *BLI_dlrbTree_search(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data) +DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree, + DLRBT_Comparator_FP cmp_cb, + void *search_data) { DLRBT_Node *node = (tree) ? tree->root : NULL; short found = 0; @@ -174,7 +176,7 @@ DLRBT_Node *BLI_dlrbTree_search(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, vo } /* Find the node which exactly matches the required data */ -DLRBT_Node *BLI_dlrbTree_search_exact(DLRBT_Tree *tree, +DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data) { @@ -222,7 +224,7 @@ DLRBT_Node *BLI_dlrbTree_search_exact(DLRBT_Tree *tree, } /* Find the node which occurs immediately before the best matching node */ -DLRBT_Node *BLI_dlrbTree_search_prev(DLRBT_Tree *tree, +DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data) { @@ -253,7 +255,7 @@ DLRBT_Node *BLI_dlrbTree_search_prev(DLRBT_Tree *tree, } /* Find the node which occurs immediately after the best matching node */ -DLRBT_Node *BLI_dlrbTree_search_next(DLRBT_Tree *tree, +DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data) { diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c index e1a7ee98ce5..5ad57a7bec8 100644 --- a/source/blender/blenlib/intern/array_store.c +++ b/source/blender/blenlib/intern/array_store.c @@ -1403,16 +1403,16 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info, * Create a new array store, which can store any number of arrays * as long as their stride matches. * - * \param stride: ``sizeof()`` each element, + * \param stride: `sizeof()` each element, * - * \note while a stride of ``1`` will always work, + * \note while a stride of `1` will always work, * its less efficient since duplicate chunks of memory will be searched * at positions unaligned with the array data. * * \param chunk_count: Number of elements to split each chunk into. * - A small value increases the ability to de-duplicate chunks, * but adds overhead by increasing the number of chunks to look up when searching for duplicates, - * as well as some overhead constructing the original array again, with more calls to ``memcpy``. + * as well as some overhead constructing the original array again, with more calls to `memcpy`. * - Larger values reduce the *book keeping* overhead, * but increase the chance a small, * isolated change will cause a larger amount of data to be duplicated. diff --git a/source/blender/blenlib/intern/convexhull_2d.c b/source/blender/blenlib/intern/convexhull_2d.c index cb4ef54bfb7..233a1430fe7 100644 --- a/source/blender/blenlib/intern/convexhull_2d.c +++ b/source/blender/blenlib/intern/convexhull_2d.c @@ -188,7 +188,7 @@ static int pointref_cmp_yx(const void *a_, const void *b_) * \param points: An array of 2D points. * \param n: The number of points in points. * \param r_points: An array of the convex hull vertex indices (max is n). - * _must_ be allocated as ``n * 2`` because of how its used internally, + * _must_ be allocated as `n * 2` because of how its used internally, * even though the final result will be no more than \a n in size. * \returns the number of points in r_points. */ diff --git a/source/blender/blenlib/intern/delaunay_2d.cc b/source/blender/blenlib/intern/delaunay_2d.cc index 24a58103a10..4582ea69d9b 100644 --- a/source/blender/blenlib/intern/delaunay_2d.cc +++ b/source/blender/blenlib/intern/delaunay_2d.cc @@ -19,6 +19,7 @@ */ #include <algorithm> +#include <atomic> #include <fstream> #include <iostream> #include <sstream> @@ -29,6 +30,8 @@ #include "BLI_math_boolean.hh" #include "BLI_math_mpq.hh" #include "BLI_mpq2.hh" +#include "BLI_set.hh" +#include "BLI_task.hh" #include "BLI_vector.hh" #include "BLI_delaunay_2d.h" @@ -77,8 +80,8 @@ template<> double math_to_double<double>(const double v) * Define a templated 2D arrangement of vertices, edges, and faces. * The #SymEdge data structure is the basis for a structure that allows * easy traversal to neighboring (by topology) geometric elements. - * Each of #CDTVert, #CDTEdge, and #CDTFace have an input_id linked list, - * whose nodes contain integers that keep track of which input verts, edges, + * Each of #CDTVert, #CDTEdge, and #CDTFace have an input_id set, + * which contain integers that keep track of which input verts, edges, * and faces, respectively, that the element was derived from. * * While this could be cleaned up some, it is usable by other routines in Blender @@ -195,8 +198,8 @@ template<typename T> struct CDTVert { FatCo<T> co; /** Some edge attached to it. */ SymEdge<T> *symedge{nullptr}; - /** List of corresponding vertex input ids. */ - LinkNode *input_ids{nullptr}; + /** Set of corresponding vertex input ids. Not used if don't need_ids. */ + blender::Set<int> input_ids; /** Index into array that #CDTArrangement keeps. */ int index{-1}; /** Index of a CDTVert that this has merged to. -1 if no merge. */ @@ -209,8 +212,10 @@ template<typename T> struct CDTVert { }; template<typename Arith_t> struct CDTEdge { - /** List of input edge ids that this is part of. */ - LinkNode *input_ids{nullptr}; + /** Set of input edge ids that this is part of. + * If don't need_ids, then should contain 0 if it is a constrained edge, + * else empty. */ + blender::Set<int> input_ids; /** The directed edges for this edge. */ SymEdge<Arith_t> symedges[2]{SymEdge<Arith_t>(), SymEdge<Arith_t>()}; @@ -220,8 +225,10 @@ template<typename Arith_t> struct CDTEdge { template<typename Arith_t> struct CDTFace { /** A symedge in face; only used during output, so only valid then. */ SymEdge<Arith_t> *symedge{nullptr}; - /** List of input face ids that this is part of. */ - LinkNode *input_ids{nullptr}; + /** Set of input face ids that this is part of. + * If don't need_ids, then should contain 0 if it is part of a constrained face, + * else empty. */ + blender::Set<int> input_ids; /** Used by algorithms operating on CDT structures. */ int visit_index{0}; /** Marks this face no longer used. */ @@ -334,27 +341,30 @@ template<typename T> class CDT_state { int face_edge_offset; /** How close before coords considered equal. */ T epsilon; + /** Do we need to track ids? */ + bool need_ids; - explicit CDT_state(int num_input_verts, int num_input_edges, int num_input_faces, T epsilon); + explicit CDT_state( + int num_input_verts, int num_input_edges, int num_input_faces, T epsilon, bool need_ids); }; template<typename T> CDTArrangement<T>::~CDTArrangement() { for (int i : this->verts.index_range()) { CDTVert<T> *v = this->verts[i]; - BLI_linklist_free(v->input_ids, nullptr); + v->input_ids.clear(); delete v; this->verts[i] = nullptr; } for (int i : this->edges.index_range()) { CDTEdge<T> *e = this->edges[i]; - BLI_linklist_free(e->input_ids, nullptr); + e->input_ids.clear(); delete e; this->edges[i] = nullptr; } for (int i : this->faces.index_range()) { CDTFace<T> *f = this->faces[i]; - BLI_linklist_free(f->input_ids, nullptr); + f->input_ids.clear(); delete f; this->faces[i] = nullptr; } @@ -431,11 +441,11 @@ template<typename T> std::ostream &operator<<(std::ostream &os, const CDT_state< if (se) { os << " edges out:\n"; do { - if (se->next == NULL) { + if (se->next == nullptr) { os << " [NULL] next/rot symedge, se=" << trunc_ptr(se) << "\n"; break; } - if (se->next->next == NULL) { + if (se->next->next == nullptr) { os << " [NULL] next-next/rot symedge, se=" << trunc_ptr(se) << "\n"; break; } @@ -495,6 +505,7 @@ template<typename T> void cdt_draw(const std::string &label, const CDTArrangemen constexpr int vert_radius = 3; constexpr bool draw_vert_labels = true; constexpr bool draw_edge_labels = false; + constexpr bool draw_face_labels = false; if (cdt.verts.size() == 0) { return; @@ -559,7 +570,7 @@ template<typename T> void cdt_draw(const std::string &label, const CDTArrangemen const CDTVert<T> *v = e->symedges[1].vert; const vec2<double> &uco = u->co.approx; const vec2<double> &vco = v->co.approx; - int strokew = e->input_ids == nullptr ? thin_line : thick_line; + int strokew = e->input_ids.size() == 0 ? thin_line : thick_line; f << R"(<line fill="none" stroke="black" stroke-width=")" << strokew << "\" x1=\"" << SX(uco[0]) << "\" y1=\"" << SY(uco[1]) << "\" x2=\"" << SX(vco[0]) << "\" y2=\"" << SY(vco[1]) << "\">\n"; @@ -586,6 +597,54 @@ template<typename T> void cdt_draw(const std::string &label, const CDTArrangemen ++i; } + if (draw_face_labels) { + for (const CDTFace<T> *face : cdt.faces) { + if (!face->deleted) { + /* Since may not have prepared output yet, need a slow find of a SymEdge for this face. */ + const SymEdge<T> *se_face_start = nullptr; + for (const CDTEdge<T> *e : cdt.edges) { + if (e->symedges[0].face == face) { + se_face_start = &e->symedges[0]; + break; + } + if (e->symedges[1].face == face) { + se_face_start = &e->symedges[1]; + } + } + if (se_face_start != nullptr) { + /* Find center of face. */ + int face_nverts = 0; + vec2<double> cen(0.0, 0.0); + if (face == cdt.outer_face) { + cen.x = minx; + cen.y = miny; + } + else { + const SymEdge<T> *se = se_face_start; + do { + if (se->face == face) { + cen = cen + se->vert->co.approx; + face_nverts++; + } + } while ((se = se->next) != se_face_start); + if (face_nverts > 0) { + cen = cen / double(face_nverts); + } + } + f << "<text x=\"" << SX(cen[0]) << "\" y=\"" << SY(cen[1]) << "\"" + << " font-size=\"small\">["; + f << trunc_ptr(face); + if (face->input_ids.size() > 0) { + for (int id : face->input_ids) { + f << " " << id; + } + } + f << "]</text>\n"; + } + } + } + } + append = true; # undef SX # undef SY @@ -754,7 +813,6 @@ template<> CDTVert<double>::CDTVert(const vec2<double> &pt) this->co.exact = pt; this->co.approx = pt; this->co.abs_approx = pt; /* Not used, so doesn't matter. */ - this->input_ids = nullptr; this->symedge = nullptr; this->index = -1; this->merge_to_index = -1; @@ -767,7 +825,6 @@ template<> CDTVert<mpq_class>::CDTVert(const vec2<mpq_class> &pt) this->co.exact = pt; this->co.approx = double2(pt.x.get_d(), pt.y.get_d()); this->co.abs_approx = double2(fabs(this->co.approx.x), fabs(this->co.approx.y)); - this->input_ids = nullptr; this->symedge = nullptr; this->index = -1; this->merge_to_index = -1; @@ -824,35 +881,21 @@ template<typename T> void CDTArrangement<T>::reserve(int num_verts, int num_edge } template<typename T> -CDT_state<T>::CDT_state(int num_input_verts, int num_input_edges, int num_input_faces, T epsilon) +CDT_state<T>::CDT_state( + int num_input_verts, int num_input_edges, int num_input_faces, T epsilon, bool need_ids) { this->input_vert_tot = num_input_verts; this->cdt.reserve(num_input_verts, num_input_edges, num_input_faces); this->cdt.outer_face = this->cdt.add_face(); this->epsilon = epsilon; + this->need_ids = need_ids; this->visit_count = 0; } -static bool id_in_list(const LinkNode *id_list, int id) -{ - const LinkNode *ln; - - for (ln = id_list; ln != nullptr; ln = ln->next) { - if (POINTER_AS_INT(ln->link) == id) { - return true; - } - } - return false; -} - /* Is any id in (range_start, range_start+1, ... , range_end) in id_list? */ -static bool id_range_in_list(const LinkNode *id_list, int range_start, int range_end) +static bool id_range_in_list(const blender::Set<int> &id_list, int range_start, int range_end) { - const LinkNode *ln; - int id; - - for (ln = id_list; ln != nullptr; ln = ln->next) { - id = POINTER_AS_INT(ln->link); + for (int id : id_list) { if (id >= range_start && id <= range_end) { return true; } @@ -860,19 +903,15 @@ static bool id_range_in_list(const LinkNode *id_list, int range_start, int range return false; } -static void add_to_input_ids(LinkNode **dst, int input_id) +static void add_to_input_ids(blender::Set<int> &dst, int input_id) { - if (!id_in_list(*dst, input_id)) { - BLI_linklist_prepend(dst, POINTER_FROM_INT(input_id)); - } + dst.add(input_id); } -static void add_list_to_input_ids(LinkNode **dst, const LinkNode *src) +static void add_list_to_input_ids(blender::Set<int> &dst, const blender::Set<int> &src) { - const LinkNode *ln; - - for (ln = src; ln != nullptr; ln = ln->next) { - add_to_input_ids(dst, POINTER_AS_INT(ln->link)); + for (int value : src) { + dst.add(value); } } @@ -883,7 +922,7 @@ template<typename T> inline bool is_border_edge(const CDTEdge<T> *e, const CDT_s template<typename T> inline bool is_constrained_edge(const CDTEdge<T> *e) { - return e->input_ids != nullptr; + return e->input_ids.size() > 0; } template<typename T> inline bool is_deleted_edge(const CDTEdge<T> *e) @@ -979,7 +1018,7 @@ template<typename T> CDTEdge<T> *CDTArrangement<T>::add_diagonal(SymEdge<T> *s1, for (SymEdge<T> *se = s2; se != sdiag; se = se->next) { se->face = fnew; } - add_list_to_input_ids(&fnew->input_ids, fold->input_ids); + add_list_to_input_ids(fnew->input_ids, fold->input_ids); return ediag; } @@ -1058,7 +1097,7 @@ template<typename T> CDTEdge<T> *CDTArrangement<T>::split_edge(SymEdge<T> *se, T if (newsesym->vert->symedge == sesym) { newsesym->vert->symedge = newsesym; } - add_list_to_input_ids(&e->input_ids, se->edge->input_ids); + add_list_to_input_ids(e->input_ids, se->edge->input_ids); return e; } @@ -1880,7 +1919,7 @@ void add_edge_constraint( SymEdge<T> *t = find_symedge_between_verts(v1, v2); if (t != nullptr) { /* Segment already there. */ - add_to_input_ids(&t->edge->input_ids, input_id); + add_to_input_ids(t->edge->input_ids, input_id); if (r_edges != nullptr) { BLI_linklist_append(&edge_list, t->edge); *r_edges = edge_list.list; @@ -2041,7 +2080,7 @@ void add_edge_constraint( BLI_assert(cd_prev->lambda == 0.0); BLI_assert(cd_prev->out->next->vert == cd->vert); edge = cd_prev->out->edge; - add_to_input_ids(&edge->input_ids, input_id); + add_to_input_ids(edge->input_ids, input_id); if (r_edges != nullptr) { BLI_linklist_append(&edge_list, edge); } @@ -2054,7 +2093,7 @@ void add_edge_constraint( else { edge = cdt_state->cdt.add_diagonal(tstart, t); } - add_to_input_ids(&edge->input_ids, input_id); + add_to_input_ids(edge->input_ids, input_id); if (r_edges != nullptr) { BLI_linklist_append(&edge_list, edge); } @@ -2093,7 +2132,8 @@ template<typename T> void add_edge_constraints(CDT_state<T> *cdt_state, const CD } CDTVert<T> *v1 = cdt_state->cdt.get_vert_resolve_merge(iv1); CDTVert<T> *v2 = cdt_state->cdt.get_vert_resolve_merge(iv2); - add_edge_constraint(cdt_state, v1, v2, i, nullptr); + int id = cdt_state->need_ids ? i : 0; + add_edge_constraint(cdt_state, v1, v2, id, nullptr); } cdt_state->face_edge_offset = ne; } @@ -2132,7 +2172,7 @@ void add_face_ids( continue; } face->visit_index = visit; - add_to_input_ids(&face->input_ids, face_id); + add_to_input_ids(face->input_ids, face_id); SymEdge<T> *se_start = se; for (se = se->next; se != se_start; se = se->next) { if (!id_range_in_list(se->edge->input_ids, fedge_start, fedge_end)) { @@ -2168,7 +2208,10 @@ static int power_of_10_greater_equal_to(int x) * order around each face in turn. And then the next face starts at * cdt->face_edge_offset beyond the start for the previous face. */ -template<typename T> void add_face_constraints(CDT_state<T> *cdt_state, const CDT_input<T> &input) +template<typename T> +void add_face_constraints(CDT_state<T> *cdt_state, + const CDT_input<T> &input, + CDT_output_type output_type) { int nv = input.vert.size(); int nf = input.face.size(); @@ -2206,7 +2249,8 @@ template<typename T> void add_face_constraints(CDT_state<T> *cdt_state, const CD CDTVert<T> *v1 = cdt->get_vert_resolve_merge(iv1); CDTVert<T> *v2 = cdt->get_vert_resolve_merge(iv2); LinkNode *edge_list; - add_edge_constraint(cdt_state, v1, v2, face_edge_id, &edge_list); + int id = cdt_state->need_ids ? face_edge_id : 0; + add_edge_constraint(cdt_state, v1, v2, id, &edge_list); /* Set a new face_symedge0 each time since earlier ones may not * survive later symedge splits. Really, just want the one when * i == flen -1, but this code guards against that one somehow @@ -2224,7 +2268,16 @@ template<typename T> void add_face_constraints(CDT_state<T> *cdt_state, const CD } int fedge_end = fedge_start + flen - 1; if (face_symedge0 != nullptr) { - add_face_ids(cdt_state, face_symedge0, f, fedge_start, fedge_end); + /* We need to propagate face ids to all faces that represent #f, if #need_ids. + * Even if `need_ids == false`, we need to propagate at least the fact that + * the face ids set would be non-empty if the output type is one of the ones + * making valid BMesh faces. */ + int id = cdt_state->need_ids ? f : 0; + add_face_ids(cdt_state, face_symedge0, id, fedge_start, fedge_end); + if (cdt_state->need_ids || (output_type == CDT_CONSTRAINTS_VALID_BMESH || + output_type == CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES)) { + add_face_ids(cdt_state, face_symedge0, f, fedge_start, fedge_end); + } } fstart += flen; } @@ -2349,7 +2402,7 @@ template<typename T> void remove_non_constraint_edges_leave_valid_bmesh(CDT_stat CDTFace<T> *fleft = se->face; CDTFace<T> *fright = sym(se)->face; if (fleft != cdt->outer_face && fright != cdt->outer_face && - (fleft->input_ids != nullptr || fright->input_ids != nullptr)) { + (fleft->input_ids.size() > 0 || fright->input_ids.size() > 0)) { /* Is there another #SymEdge with same left and right faces? * Or is there a vertex not part of e touching the same left and right faces? */ for (SymEdge<T> *se2 = se->next; dissolve && se2 != se; se2 = se2->next) { @@ -2507,30 +2560,33 @@ template<typename T> void detect_holes(CDT_state<T> *cdt_state) mid.exact[1] = (f->symedge->vert->co.exact[1] + f->symedge->next->vert->co.exact[1] + f->symedge->next->next->vert->co.exact[1]) / 3; - int hits = 0; + std::atomic<int> hits = 0; /* TODO: Use CDT data structure here to greatly reduce search for intersections! */ - for (const CDTEdge<T> *e : cdt->edges) { - if (!is_deleted_edge(e) && is_constrained_edge(e)) { - if (e->symedges[0].face->visit_index == e->symedges[1].face->visit_index) { - continue; /* Don't count hits on edges between faces in same region. */ - } - auto isect = vec2<T>::isect_seg_seg(ray_end.exact, - mid.exact, - e->symedges[0].vert->co.exact, - e->symedges[1].vert->co.exact); - switch (isect.kind) { - case vec2<T>::isect_result::LINE_LINE_CROSS: { - hits++; - break; + threading::parallel_for(cdt->edges.index_range(), 256, [&](IndexRange range) { + for (const int i : range) { + const CDTEdge<T> *e = cdt->edges[i]; + if (!is_deleted_edge(e) && is_constrained_edge(e)) { + if (e->symedges[0].face->visit_index == e->symedges[1].face->visit_index) { + continue; /* Don't count hits on edges between faces in same region. */ + } + auto isect = vec2<T>::isect_seg_seg(ray_end.exact, + mid.exact, + e->symedges[0].vert->co.exact, + e->symedges[1].vert->co.exact); + switch (isect.kind) { + case vec2<T>::isect_result::LINE_LINE_CROSS: { + hits++; + break; + } + case vec2<T>::isect_result::LINE_LINE_EXACT: + case vec2<T>::isect_result::LINE_LINE_NONE: + case vec2<T>::isect_result::LINE_LINE_COLINEAR: + break; } - case vec2<T>::isect_result::LINE_LINE_EXACT: - case vec2<T>::isect_result::LINE_LINE_NONE: - case vec2<T>::isect_result::LINE_LINE_COLINEAR: - break; } } - } - f->hole = (hits % 2) == 0; + }); + f->hole = (hits.load() % 2) == 0; } /* Finally, propagate hole status to all holes of a region. */ @@ -2631,25 +2687,31 @@ CDT_result<T> get_cdt_output(CDT_state<T> *cdt_state, for (int i = 0; i < verts_size; ++i) { CDTVert<T> *v = cdt->verts[i]; if (v->merge_to_index != -1) { - if (i < cdt_state->input_vert_tot) { - add_to_input_ids(&cdt->verts[v->merge_to_index]->input_ids, i); + if (cdt_state->need_ids) { + if (i < cdt_state->input_vert_tot) { + add_to_input_ids(cdt->verts[v->merge_to_index]->input_ids, i); + } } vert_to_output_map[i] = vert_to_output_map[v->merge_to_index]; } } } result.vert = Array<vec2<T>>(nv); - result.vert_orig = Array<Vector<int>>(nv); + if (cdt_state->need_ids) { + result.vert_orig = Array<Vector<int>>(nv); + } int i_out = 0; for (int i = 0; i < verts_size; ++i) { CDTVert<T> *v = cdt->verts[i]; if (v->merge_to_index == -1) { result.vert[i_out] = v->co.exact; - if (i < cdt_state->input_vert_tot) { - result.vert_orig[i_out].append(i); - } - for (LinkNode *ln = v->input_ids; ln; ln = ln->next) { - result.vert_orig[i_out].append(POINTER_AS_INT(ln->link)); + if (cdt_state->need_ids) { + if (i < cdt_state->input_vert_tot) { + result.vert_orig[i_out].append(i); + } + for (int vert : v->input_ids) { + result.vert_orig[i_out].append(vert); + } } ++i_out; } @@ -2660,15 +2722,19 @@ CDT_result<T> get_cdt_output(CDT_state<T> *cdt_state, return !is_deleted_edge(e); }); result.edge = Array<std::pair<int, int>>(ne); - result.edge_orig = Array<Vector<int>>(ne); + if (cdt_state->need_ids) { + result.edge_orig = Array<Vector<int>>(ne); + } int e_out = 0; for (const CDTEdge<T> *e : cdt->edges) { if (!is_deleted_edge(e)) { int vo1 = vert_to_output_map[e->symedges[0].vert->index]; int vo2 = vert_to_output_map[e->symedges[1].vert->index]; result.edge[e_out] = std::pair<int, int>(vo1, vo2); - for (LinkNode *ln = e->input_ids; ln; ln = ln->next) { - result.edge_orig[e_out].append(POINTER_AS_INT(ln->link)); + if (cdt_state->need_ids) { + for (int edge : e->input_ids) { + result.edge_orig[e_out].append(edge); + } } ++e_out; } @@ -2679,7 +2745,9 @@ CDT_result<T> get_cdt_output(CDT_state<T> *cdt_state, return !f->deleted && f != cdt->outer_face; }); result.face = Array<Vector<int>>(nf); - result.face_orig = Array<Vector<int>>(nf); + if (cdt_state->need_ids) { + result.face_orig = Array<Vector<int>>(nf); + } int f_out = 0; for (const CDTFace<T> *f : cdt->faces) { if (!f->deleted && f != cdt->outer_face) { @@ -2690,8 +2758,10 @@ CDT_result<T> get_cdt_output(CDT_state<T> *cdt_state, result.face[f_out].append(vert_to_output_map[se->vert->index]); se = se->next; } while (se != se_start); - for (LinkNode *ln = f->input_ids; ln; ln = ln->next) { - result.face_orig[f_out].append(POINTER_AS_INT(ln->link)); + if (cdt_state->need_ids) { + for (int face : f->input_ids) { + result.face_orig[f_out].append(face); + } } ++f_out; } @@ -2716,11 +2786,11 @@ CDT_result<T> delaunay_calc(const CDT_input<T> &input, CDT_output_type output_ty int nv = input.vert.size(); int ne = input.edge.size(); int nf = input.face.size(); - CDT_state<T> cdt_state(nv, ne, nf, input.epsilon); + CDT_state<T> cdt_state(nv, ne, nf, input.epsilon, input.need_ids); add_input_verts(&cdt_state, input); initial_triangulation(&cdt_state.cdt); add_edge_constraints(&cdt_state, input); - add_face_constraints(&cdt_state, input); + add_face_constraints(&cdt_state, input, output_type); return get_cdt_output(&cdt_state, input, output_type); } @@ -2772,6 +2842,7 @@ extern "C" ::CDT_result *BLI_delaunay_2d_cdt_calc(const ::CDT_input *input, } } in.epsilon = static_cast<double>(input->epsilon); + in.need_ids = input->need_ids; blender::meshintersect::CDT_result<double> res = blender::meshintersect::delaunay_2d_calc( in, output_type); @@ -2784,74 +2855,101 @@ extern "C" ::CDT_result *BLI_delaunay_2d_cdt_calc(const ::CDT_input *input, int tot_e_orig = 0; int tot_f_orig = 0; int tot_f_lens = 0; - for (int v = 0; v < nv; ++v) { - tot_v_orig += res.vert_orig[v].size(); - } - for (int e = 0; e < ne; ++e) { - tot_e_orig += res.edge_orig[e].size(); + if (input->need_ids) { + for (int v = 0; v < nv; ++v) { + tot_v_orig += res.vert_orig[v].size(); + } + for (int e = 0; e < ne; ++e) { + tot_e_orig += res.edge_orig[e].size(); + } } for (int f = 0; f < nf; ++f) { - tot_f_orig += res.face_orig[f].size(); + if (input->need_ids) { + tot_f_orig += res.face_orig[f].size(); + } tot_f_lens += res.face[f].size(); } output->vert_coords = static_cast<decltype(output->vert_coords)>( MEM_malloc_arrayN(nv, sizeof(output->vert_coords[0]), __func__)); - output->verts_orig = static_cast<int *>(MEM_malloc_arrayN(tot_v_orig, sizeof(int), __func__)); - output->verts_orig_start_table = static_cast<int *>( - MEM_malloc_arrayN(nv, sizeof(int), __func__)); - output->verts_orig_len_table = static_cast<int *>(MEM_malloc_arrayN(nv, sizeof(int), __func__)); output->edges = static_cast<decltype(output->edges)>( MEM_malloc_arrayN(ne, sizeof(output->edges[0]), __func__)); - output->edges_orig = static_cast<int *>(MEM_malloc_arrayN(tot_e_orig, sizeof(int), __func__)); - output->edges_orig_start_table = static_cast<int *>( - MEM_malloc_arrayN(ne, sizeof(int), __func__)); - output->edges_orig_len_table = static_cast<int *>(MEM_malloc_arrayN(ne, sizeof(int), __func__)); output->faces = static_cast<int *>(MEM_malloc_arrayN(tot_f_lens, sizeof(int), __func__)); output->faces_start_table = static_cast<int *>(MEM_malloc_arrayN(nf, sizeof(int), __func__)); output->faces_len_table = static_cast<int *>(MEM_malloc_arrayN(nf, sizeof(int), __func__)); - output->faces_orig = static_cast<int *>(MEM_malloc_arrayN(tot_f_orig, sizeof(int), __func__)); - output->faces_orig_start_table = static_cast<int *>( - MEM_malloc_arrayN(nf, sizeof(int), __func__)); - output->faces_orig_len_table = static_cast<int *>(MEM_malloc_arrayN(nf, sizeof(int), __func__)); + if (input->need_ids) { + output->verts_orig = static_cast<int *>(MEM_malloc_arrayN(tot_v_orig, sizeof(int), __func__)); + output->verts_orig_start_table = static_cast<int *>( + MEM_malloc_arrayN(nv, sizeof(int), __func__)); + output->verts_orig_len_table = static_cast<int *>( + MEM_malloc_arrayN(nv, sizeof(int), __func__)); + output->edges_orig = static_cast<int *>(MEM_malloc_arrayN(tot_e_orig, sizeof(int), __func__)); + output->edges_orig_start_table = static_cast<int *>( + MEM_malloc_arrayN(ne, sizeof(int), __func__)); + output->edges_orig_len_table = static_cast<int *>( + MEM_malloc_arrayN(ne, sizeof(int), __func__)); + output->faces_orig = static_cast<int *>(MEM_malloc_arrayN(tot_f_orig, sizeof(int), __func__)); + output->faces_orig_start_table = static_cast<int *>( + MEM_malloc_arrayN(nf, sizeof(int), __func__)); + output->faces_orig_len_table = static_cast<int *>( + MEM_malloc_arrayN(nf, sizeof(int), __func__)); + } + else { + output->verts_orig = nullptr; + output->verts_orig_start_table = nullptr; + output->verts_orig_len_table = nullptr; + output->edges_orig = nullptr; + output->edges_orig_start_table = nullptr; + output->edges_orig_len_table = nullptr; + output->faces_orig = nullptr; + output->faces_orig_start_table = nullptr; + output->faces_orig_len_table = nullptr; + } int v_orig_index = 0; for (int v = 0; v < nv; ++v) { output->vert_coords[v][0] = static_cast<float>(res.vert[v][0]); output->vert_coords[v][1] = static_cast<float>(res.vert[v][1]); - int this_start = v_orig_index; - output->verts_orig_start_table[v] = this_start; - for (int j : res.vert_orig[v].index_range()) { - output->verts_orig[v_orig_index++] = res.vert_orig[v][j]; + if (input->need_ids) { + int this_start = v_orig_index; + output->verts_orig_start_table[v] = this_start; + for (int j : res.vert_orig[v].index_range()) { + output->verts_orig[v_orig_index++] = res.vert_orig[v][j]; + } + output->verts_orig_len_table[v] = v_orig_index - this_start; } - output->verts_orig_len_table[v] = v_orig_index - this_start; } int e_orig_index = 0; for (int e = 0; e < ne; ++e) { output->edges[e][0] = res.edge[e].first; output->edges[e][1] = res.edge[e].second; - int this_start = e_orig_index; - output->edges_orig_start_table[e] = this_start; - for (int j : res.edge_orig[e].index_range()) { - output->edges_orig[e_orig_index++] = res.edge_orig[e][j]; + if (input->need_ids) { + int this_start = e_orig_index; + output->edges_orig_start_table[e] = this_start; + for (int j : res.edge_orig[e].index_range()) { + output->edges_orig[e_orig_index++] = res.edge_orig[e][j]; + } + output->edges_orig_len_table[e] = e_orig_index - this_start; } - output->edges_orig_len_table[e] = e_orig_index - this_start; } int f_orig_index = 0; int f_index = 0; for (int f = 0; f < nf; ++f) { + output->faces_start_table[f] = f_index; int flen = res.face[f].size(); output->faces_len_table[f] = flen; for (int j = 0; j < flen; ++j) { output->faces[f_index++] = res.face[f][j]; } - int this_start = f_orig_index; - output->faces_orig_start_table[f] = this_start; - for (int k : res.face_orig[f].index_range()) { - output->faces_orig[f_orig_index++] = res.face_orig[f][k]; + if (input->need_ids) { + int this_start = f_orig_index; + output->faces_orig_start_table[f] = this_start; + for (int k : res.face_orig[f].index_range()) { + output->faces_orig[f_orig_index++] = res.face_orig[f][k]; + } + output->faces_orig_len_table[f] = f_orig_index - this_start; } - output->faces_orig_len_table[f] = f_orig_index - this_start; } return output; } @@ -2863,14 +2961,16 @@ extern "C" void BLI_delaunay_2d_cdt_free(::CDT_result *result) MEM_freeN(result->faces); MEM_freeN(result->faces_start_table); MEM_freeN(result->faces_len_table); - MEM_freeN(result->verts_orig); - MEM_freeN(result->verts_orig_start_table); - MEM_freeN(result->verts_orig_len_table); - MEM_freeN(result->edges_orig); - MEM_freeN(result->edges_orig_start_table); - MEM_freeN(result->edges_orig_len_table); - MEM_freeN(result->faces_orig); - MEM_freeN(result->faces_orig_start_table); - MEM_freeN(result->faces_orig_len_table); + if (result->verts_orig) { + MEM_freeN(result->verts_orig); + MEM_freeN(result->verts_orig_start_table); + MEM_freeN(result->verts_orig_len_table); + MEM_freeN(result->edges_orig); + MEM_freeN(result->edges_orig_start_table); + MEM_freeN(result->edges_orig_len_table); + MEM_freeN(result->faces_orig); + MEM_freeN(result->faces_orig_start_table); + MEM_freeN(result->faces_orig_len_table); + } MEM_freeN(result); } diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 58b109eca10..0a213fa8696 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -410,7 +410,7 @@ MINLINE float pingpongf(float value, float scale) return fabsf(fractf((value - scale) / (scale * 2.0f)) * scale * 2.0f - scale); } -// Square. +/* Square. */ MINLINE int square_s(short a) { @@ -442,7 +442,7 @@ MINLINE double square_d(double a) return a * a; } -// Cube. +/* Cube. */ MINLINE int cube_s(short a) { @@ -474,7 +474,7 @@ MINLINE double cube_d(double a) return a * a * a; } -// Min/max +/* Min/max */ MINLINE float min_ff(float a, float b) { diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c index 4c50c1c7af8..a5a687ef9fe 100644 --- a/source/blender/blenlib/intern/math_color_inline.c +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -276,14 +276,14 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack) * https://en.wikipedia.org/wiki/Relative_luminance * * Real values are: - * ``Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`` + * `Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)` * according to: "Derivation of Basic Television Color Equations", RP 177-1993 * * As this sums slightly above 1.0, the document recommends to use: - * ``0.2126(R) + 0.7152(G) + 0.0722(B)``, as used here. + * `0.2126(R) + 0.7152(G) + 0.0722(B)`, as used here. * * The high precision values are used to calculate the rounded byte weights so they add up to 255: - * ``54(R) + 182(G) + 19(B)`` + * `54(R) + 182(G) + 19(B)` */ MINLINE float rgb_to_grayscale(const float rgb[3]) { diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 80f0008c7eb..803291e4a3b 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -165,7 +165,7 @@ float area_squared_poly_v3(const float verts[][3], unsigned int nr) /** * Scalar cross product of a 2d polygon. * - * - equivalent to ``area * 2`` + * - equivalent to `area * 2` * - useful for checking polygon winding (a positive value is clockwise). */ float cross_poly_v2(const float verts[][2], unsigned int nr) @@ -518,7 +518,7 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]) } /** - * Check if \a p is inside the 2x planes defined by ``(v1, v2, v3)`` + * Check if \a p is inside the 2x planes defined by `(v1, v2, v3)` * where the 3x points define 2x planes. * * \param axis_ref: used when v1,v2,v3 form a line and to check if the corner is concave/convex. @@ -527,7 +527,7 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]) * (it just defines the planes). * * \return the lowest squared distance to either of the planes. - * where ``(return < 0.0)`` is outside. + * where `(return < 0.0)` is outside. * * <pre> * v1 @@ -1421,7 +1421,7 @@ int isect_seg_seg_v2_lambda_mu_db(const double v1[2], * \return r_p1, r_p2: Intersection coordinates. * * \note The order of assignment for intersection points (\a r_p1, \a r_p2) is predictable, - * based on the direction defined by ``l2 - l1``, + * based on the direction defined by `l2 - l1`, * this direction compared with the normal of each point on the sphere: * \a r_p1 always has a >= 0.0 dot product. * \a r_p2 always has a <= 0.0 dot product. @@ -3426,7 +3426,7 @@ float ray_point_factor_v3(const float p[3], /** * A simplified version of #closest_to_line_v3 - * we only need to return the ``lambda`` + * we only need to return the `lambda` * * \param epsilon: avoid approaching divide-by-zero. * Passing a zero will just check for nonzero division. diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c index 655d3fcc4c0..1757b0dd525 100644 --- a/source/blender/blenlib/intern/math_geom_inline.c +++ b/source/blender/blenlib/intern/math_geom_inline.c @@ -272,7 +272,7 @@ MINLINE float shell_angle_to_dist(const float angle) return (UNLIKELY(angle < SMALL_NUMBER)) ? 1.0f : fabsf(1.0f / cosf(angle)); } /** - * equivalent to ``shell_angle_to_dist(angle_normalized_v3v3(a, b))`` + * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b))`. */ MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3]) { @@ -282,7 +282,7 @@ MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3]) return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos); } /** - * equivalent to ``shell_angle_to_dist(angle_normalized_v2v2(a, b))`` + * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b))`. */ MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2]) { @@ -293,7 +293,7 @@ MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2]) } /** - * equivalent to ``shell_angle_to_dist(angle_normalized_v3v3(a, b) / 2)`` + * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b) / 2)`. */ MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3]) { @@ -307,7 +307,7 @@ MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[ } /** - * equivalent to ``shell_angle_to_dist(angle_normalized_v2v2(a, b) / 2)`` + * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b) / 2)`. */ MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2]) { diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c index 04fae6a0e68..bd48edf70c0 100644 --- a/source/blender/blenlib/intern/math_interp.c +++ b/source/blender/blenlib/intern/math_interp.c @@ -625,7 +625,7 @@ void BLI_ewa_filter(const int width, * Use a different radius based on interpolation switch, * just enough to anti-alias when interpolation is off, * and slightly larger to make result a bit smoother than bilinear interpolation when - * interpolation is on (minimum values: const float rmin = intpol ? 1.0f : 0.5f;) */ + * interpolation is on (minimum values: `const float rmin = intpol ? 1.0f : 0.5f;`) */ const float rmin = (intpol ? 1.5625f : 0.765625f) / ff2; BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc); if ((b2 = b * b) < rmin) { diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 5920788821c..b605c3eeead 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -276,7 +276,7 @@ void mul_m4_m4m4_uniq(float R[4][4], const float A[4][4], const float B[4][4]) { BLI_assert(!ELEM(R, A, B)); - /* matrix product: R[j][k] = A[j][i] . B[i][k] */ + /* Matrix product: `R[j][k] = A[j][i] . B[i][k]`. */ #ifdef BLI_HAVE_SSE2 __m128 A0 = _mm_loadu_ps(A[0]); __m128 A1 = _mm_loadu_ps(A[1]); @@ -321,7 +321,7 @@ void mul_m4_m4m4_db_uniq(double R[4][4], const double A[4][4], const double B[4] { BLI_assert(!ELEM(R, A, B)); - /* matrix product: R[j][k] = A[j][i] . B[i][k] */ + /* Matrix product: `R[j][k] = A[j][i] . B[i][k]`. */ R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0] + B[0][3] * A[3][0]; R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1] + B[0][3] * A[3][1]; @@ -349,7 +349,7 @@ void mul_m4db_m4db_m4fl_uniq(double R[4][4], const double A[4][4], const float B /* Remove second check since types don't match. */ BLI_assert(!ELEM(R, A /*, B */)); - /* matrix product: R[j][k] = A[j][i] . B[i][k] */ + /* Matrix product: `R[j][k] = A[j][i] . B[i][k]`. */ R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0] + B[0][3] * A[3][0]; R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1] + B[0][3] * A[3][1]; diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index db9ece81c59..55f7a152b83 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -1312,7 +1312,7 @@ MINLINE bool is_one_v3(const float v[3]) /* -------------------------------------------------------------------- */ /** \name Vector Comparison * - * \note use ``value <= limit``, so a limit of zero doesn't fail on an exact match. + * \note use `value <= limit`, so a limit of zero doesn't fail on an exact match. * \{ */ MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) diff --git a/source/blender/blenlib/intern/memory_utils.c b/source/blender/blenlib/intern/memory_utils.c index 5ca7b96c136..4bb93877401 100644 --- a/source/blender/blenlib/intern/memory_utils.c +++ b/source/blender/blenlib/intern/memory_utils.c @@ -19,7 +19,7 @@ * \brief Generic memory manipulation API. * * This is to extend on existing functions - * such as ``memcpy`` & ``memcmp``. + * such as `memcpy` & `memcmp`. */ #include <string.h> diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc index 8b8850c7cdb..90ffebdb422 100644 --- a/source/blender/blenlib/intern/mesh_boolean.cc +++ b/source/blender/blenlib/intern/mesh_boolean.cc @@ -151,7 +151,7 @@ class TriMeshTopology : NonCopyable { * Else return NO_INDEX. */ int other_tri_if_manifold(Edge e, int t) const { - auto p = edge_tri_.lookup_ptr(e); + const auto *p = edge_tri_.lookup_ptr(e); if (p != nullptr && (*p)->size() == 2) { return ((**p)[0] == t) ? (**p)[1] : (**p)[0]; } @@ -204,7 +204,7 @@ TriMeshTopology::TriMeshTopology(const IMesh &tm) } edges->append_non_duplicates(e); - auto p = edge_tri_.lookup_ptr(Edge(v, vnext)); + auto *p = edge_tri_.lookup_ptr(Edge(v, vnext)); if (p == nullptr) { edge_tri_.add_new(e, new Vector<int>{t}); } @@ -238,7 +238,7 @@ TriMeshTopology::~TriMeshTopology() Vector<Vector<int> *> values; /* Deconstructing is faster in parallel, so it is worth building an array of things to delete. */ - for (auto item : edge_tri_.values()) { + for (auto *item : edge_tri_.values()) { values.append(item); } diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc index f91dd762e70..dcd432a88d5 100644 --- a/source/blender/blenlib/intern/mesh_intersect.cc +++ b/source/blender/blenlib/intern/mesh_intersect.cc @@ -1875,6 +1875,16 @@ static void do_cdt(CDT_data &cd) } } +/* Find an original edge index that goes with the edge that the CDT output edge + * that goes between verts i0 and i1 (in the CDT output vert indexing scheme). + * There may be more than one: if so, prefer one that was originally a face edge. + * The input to CDT for a triangle with some intersecting segments from other triangles + * will have both edges and a face constraint for the main triangle (this is redundant + * but allows us to discover which face edge goes with which output edges). + * If there is any face edge, return one of those as the original. + * If there is no face edge but there is another edge in the input problem, then that + * edge must have come from intersection with another triangle, so set *r_is_intersect + * to true in that case. */ static int get_cdt_edge_orig( int i0, int i1, const CDT_data &cd, const IMesh &in_tm, bool *r_is_intersect) { @@ -1900,35 +1910,50 @@ static int get_cdt_edge_orig( } /* Pick an arbitrary orig, but not one equal to NO_INDEX, if we can help it. */ - /* TODO: if edge has origs from more than on part of the nary input, + /* TODO: if edge has origs from more than one part of the nary input, * then want to set *r_is_intersect to true. */ + int face_eorig = NO_INDEX; + bool have_non_face_eorig = false; for (int orig_index : cd.cdt_out.edge_orig[e]) { /* orig_index encodes the triangle and pos within the triangle of the input edge. */ if (orig_index >= foff) { - int in_face_index = (orig_index / foff) - 1; - int pos = orig_index % foff; - /* We need to retrieve the edge orig field from the Face used to populate the - * in_face_index'th face of the CDT, at the pos'th position of the face. */ - int in_tm_face_index = cd.input_face[in_face_index]; - BLI_assert(in_tm_face_index < in_tm.face_size()); - const Face *facep = in_tm.face(in_tm_face_index); - BLI_assert(pos < facep->size()); - bool is_rev = cd.is_reversed[in_face_index]; - int eorig = is_rev ? facep->edge_orig[2 - pos] : facep->edge_orig[pos]; - if (eorig != NO_INDEX) { - return eorig; + if (face_eorig == NO_INDEX) { + int in_face_index = (orig_index / foff) - 1; + int pos = orig_index % foff; + /* We need to retrieve the edge orig field from the Face used to populate the + * in_face_index'th face of the CDT, at the pos'th position of the face. */ + int in_tm_face_index = cd.input_face[in_face_index]; + BLI_assert(in_tm_face_index < in_tm.face_size()); + const Face *facep = in_tm.face(in_tm_face_index); + BLI_assert(pos < facep->size()); + bool is_rev = cd.is_reversed[in_face_index]; + int eorig = is_rev ? facep->edge_orig[2 - pos] : facep->edge_orig[pos]; + if (eorig != NO_INDEX) { + face_eorig = eorig; + } } } else { - /* This edge came from an edge input to the CDT problem, - * so it is an intersect edge. */ - *r_is_intersect = true; - /* TODO: maybe there is an orig index: - * This happens if an input edge was formed by an input face having - * an edge that is co-planar with the cluster, while the face as a whole is not. */ - return NO_INDEX; + if (!have_non_face_eorig) { + have_non_face_eorig = true; + } + if (face_eorig != NO_INDEX && have_non_face_eorig) { + /* Only need at most one orig for each type. */ + break; + } } } + if (face_eorig != NO_INDEX) { + return face_eorig; + } + if (have_non_face_eorig) { + /* This must have been an input to the CDT problem that was an intersection edge. */ + /* TODO: maybe there is an orig index: + * This happens if an input edge was formed by an input face having + * an edge that is co-planar with the cluster, while the face as a whole is not. */ + *r_is_intersect = true; + return NO_INDEX; + } return NO_INDEX; } diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c index 01aad5b078f..9850de69b5a 100644 --- a/source/blender/blenlib/intern/noise.c +++ b/source/blender/blenlib/intern/noise.c @@ -1294,13 +1294,12 @@ float BLI_noise_generic_turbulence( * source code in the book "Texturing and Modeling: A procedural approach" */ -/* - * Procedural fBm evaluated at "point"; returns value stored in "value". +/** + * Procedural `fBm` evaluated at "point"; returns value stored in "value". * - * Parameters: - * ``H'' is the fractal increment parameter - * ``lacunarity'' is the gap between successive frequencies - * ``octaves'' is the number of frequencies in the fBm + * \param H: is the fractal increment parameter. + * \param lacunarity: is the gap between successive frequencies. + * \param octaves: is the number of frequencies in the `fBm`. */ float BLI_noise_mg_fbm( float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis) @@ -1359,15 +1358,16 @@ float BLI_noise_mg_fbm( } /* fBm() */ -/* - * Procedural multifractal evaluated at "point"; +/** + * Procedural multi-fractal evaluated at "point"; * returns value stored in "value". * - * Parameters: - * ``H'' determines the highest fractal dimension - * ``lacunarity'' is gap between successive frequencies - * ``octaves'' is the number of frequencies in the fBm - * ``offset'' is the zero offset, which determines multifractality (NOT USED??) + * \param H: determines the highest fractal dimension. + * \param lacunarity: is gap between successive frequencies. + * \param octaves: is the number of frequencies in the `fBm`. + * + * \note There used to be a parameter called `offset`, old docs read: + * is the zero offset, which determines multi-fractality. */ /* this one is in fact rather confusing, @@ -1429,15 +1429,14 @@ float BLI_noise_mg_multi_fractal( } /* multifractal() */ -/* +/** * Heterogeneous procedural terrain function: stats by altitude method. * Evaluated at "point"; returns value stored in "value". * - * Parameters: - * ``H'' determines the fractal dimension of the roughest areas - * ``lacunarity'' is the gap between successive frequencies - * ``octaves'' is the number of frequencies in the fBm - * ``offset'' raises the terrain from `sea level' + * \param H: Determines the fractal dimension of the roughest areas. + * \param lacunarity: Is the gap between successive frequencies. + * \param octaves: Is the number of frequencies in the `fBm`. + * \param offset: Raises the terrain from `sea level`. */ float BLI_noise_mg_hetero_terrain(float x, float y, diff --git a/source/blender/blenlib/intern/polyfill_2d.c b/source/blender/blenlib/intern/polyfill_2d.c index 817572ba85c..9af98359199 100644 --- a/source/blender/blenlib/intern/polyfill_2d.c +++ b/source/blender/blenlib/intern/polyfill_2d.c @@ -77,9 +77,9 @@ typedef signed char eSign; #ifdef USE_KDTREE /** * Spatial optimization for point-in-triangle intersection checks. - * The simple version of this algorithm is ``O(n^2)`` complexity + * The simple version of this algorithm is `O(n^2)` complexity * (every point needing to check the triangle defined by every other point), - * Using a binary-tree reduces the complexity to ``O(n log n)`` + * Using a binary-tree reduces the complexity to `O(n log n)` * plus some overhead of creating the tree. * * This is a single purpose KDTree based on BLI_kdtree with some modifications @@ -898,7 +898,7 @@ void BLI_polyfill_calc_arena(const float (*coords)[2], * \param coords_sign: Pass this when we know the sign in advance to avoid extra calculations. * * \param r_tris: This array is filled in with triangle indices in clockwise order. - * The length of the array must be ``coords_tot - 2``. + * The length of the array must be `coords_tot - 2`. * Indices are guaranteed to be assigned to unique triangles, with valid indices, * even in the case of degenerate input (self intersecting polygons, zero area ears... etc). */ diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c index 6e5a3e961a5..006a3798dcd 100644 --- a/source/blender/blenlib/intern/smallhash.c +++ b/source/blender/blenlib/intern/smallhash.c @@ -34,11 +34,11 @@ * Otherwise #GHash should be used instead. * * #SmallHashEntry.key - * - ``SMHASH_KEY_UNUSED`` means the key in the cell has not been initialized. + * - `SMHASH_KEY_UNUSED` means the key in the cell has not been initialized. * * #SmallHashEntry.val - * - ``SMHASH_CELL_UNUSED`` means this cell is inside a key series. - * - ``SMHASH_CELL_FREE`` means this cell terminates a key series. + * - `SMHASH_CELL_UNUSED` means this cell is inside a key series. + * - `SMHASH_CELL_FREE` means this cell terminates a key series. * * Note that the values and keys are often pointers or index values, * use the maximum values to avoid real pointers colliding with magic numbers. diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 61d095658a3..5541d75bc73 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -232,7 +232,7 @@ size_t BLI_vsnprintf(char *__restrict buffer, } /** - * A version of #BLI_vsnprintf that returns ``strlen(buffer)`` + * A version of #BLI_vsnprintf that returns `strlen(buffer)` */ size_t BLI_vsnprintf_rlen(char *__restrict buffer, size_t maxncpy, @@ -278,7 +278,7 @@ size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict } /** - * A version of #BLI_snprintf that returns ``strlen(dst)`` + * A version of #BLI_snprintf that returns `strlen(dst)` */ size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...) { diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c index 6a2ed8fac2c..d2666c6fe63 100644 --- a/source/blender/blenlib/intern/string_utils.c +++ b/source/blender/blenlib/intern/string_utils.c @@ -182,8 +182,8 @@ void BLI_string_flip_side_name(char *r_name, /* We first check the case with a .### extension, let's find the last period */ if (isdigit(r_name[len - 1])) { - index = strrchr(r_name, '.'); /* last occurrence. */ - if (index && isdigit(index[1])) { /* doesn't handle case bone.1abc2 correct..., whatever! */ + index = strrchr(r_name, '.'); /* Last occurrence. */ + if (index && isdigit(index[1])) { /* Doesn't handle case `bone.1abc2` correct..., whatever! */ if (strip_number == false) { BLI_strncpy(number, index, name_len); } @@ -194,7 +194,7 @@ void BLI_string_flip_side_name(char *r_name, BLI_strncpy(prefix, r_name, name_len); - /* first case; separator . - _ with extensions r R l L. */ + /* First case; separator (`.` or `_`) with extensions in `r R l L`. */ if ((len > 1) && is_char_sep(r_name[len - 2])) { is_set = true; switch (r_name[len - 1]) { diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc index 6250c1b9986..cbb5bf34477 100644 --- a/source/blender/blenlib/intern/task_pool.cc +++ b/source/blender/blenlib/intern/task_pool.cc @@ -532,7 +532,7 @@ bool BLI_task_pool_current_canceled(TaskPool *pool) case TASK_POOL_BACKGROUND_SERIAL: return background_task_pool_canceled(pool); } - BLI_assert("BLI_task_pool_canceled: Control flow should not come here!"); + BLI_assert_msg(0, "BLI_task_pool_canceled: Control flow should not come here!"); return false; } diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c index 7d7436411ac..a9665c0a9c2 100644 --- a/source/blender/blenlib/intern/timecode.c +++ b/source/blender/blenlib/intern/timecode.c @@ -39,7 +39,7 @@ * Generate time-code/frame number string and store in \a str * * \param str: destination string - * \param maxncpy: maximum number of characters to copy ``sizeof(str)`` + * \param maxncpy: maximum number of characters to copy `sizeof(str)` * \param brevity_level: special setting for #View2D grid drawing, * used to specify how detailed we need to be * \param time_seconds: time total time in seconds @@ -199,7 +199,7 @@ size_t BLI_timecode_string_from_time(char *str, * Generate time string and store in \a str * * \param str: destination string - * \param maxncpy: maximum number of characters to copy ``sizeof(str)`` + * \param maxncpy: maximum number of characters to copy `sizeof(str)` * \param time_seconds: time total time in seconds * \return length of \a str */ @@ -229,7 +229,7 @@ size_t BLI_timecode_string_from_time_simple(char *str, * Generate time string and store in \a str * * \param str: destination string - * \param maxncpy: maximum number of characters to copy ``sizeof(str)`` + * \param maxncpy: maximum number of characters to copy `sizeof(str)` * \param brevity_level: special setting for #View2D grid drawing, * used to specify how detailed we need to be * \param time_seconds: time total time in seconds diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c index beeae175869..d5c9c5cd5e6 100644 --- a/source/blender/blenlib/intern/winstuff.c +++ b/source/blender/blenlib/intern/winstuff.c @@ -30,7 +30,7 @@ # include "MEM_guardedalloc.h" -# define WIN32_SKIP_HKEY_PROTECTION // need to use HKEY +# define WIN32_SKIP_HKEY_PROTECTION /* Need to use HKEY. */ # include "BLI_path_util.h" # include "BLI_string.h" # include "BLI_utildefines.h" diff --git a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc index 08a3818e18f..f221036419e 100644 --- a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc +++ b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc @@ -241,7 +241,7 @@ template<typename T> std::ostream &operator<<(std::ostream &os, const CDT_result for (int i : r.edge.index_range()) { os << "e" << i << " = (" << r.edge[i].first << ", " << r.edge[i].second << ")\n"; os << " orig: "; - for (int j : r.edge_orig[i].size()) { + for (int j : r.edge_orig[i].index_range()) { os << r.edge_orig[i][j] << " "; } os << "\n"; @@ -797,6 +797,55 @@ template<typename T> void crosssegs_test() } } +template<typename T> void cutacrosstri_test() +{ + /* Right triangle with horizontal segment exactly crossing in the middle. */ + const char *spec = R"(5 1 1 + 0.0 0.0 + 1.0 0.0 + 0.0 1.0 + 0.0 0.5 + 0.5 0.5 + 3 4 + 0 1 2 + )"; + + CDT_input<T> in = fill_input_from_string<T>(spec); + CDT_result<T> out = delaunay_2d_calc(in, CDT_FULL); + EXPECT_EQ(out.vert.size(), 5); + EXPECT_EQ(out.edge.size(), 7); + EXPECT_EQ(out.face.size(), 3); + int v0_out = get_orig_index(out.vert_orig, 0); + int v1_out = get_orig_index(out.vert_orig, 1); + int v2_out = get_orig_index(out.vert_orig, 2); + int v3_out = get_orig_index(out.vert_orig, 3); + int v4_out = get_orig_index(out.vert_orig, 4); + EXPECT_TRUE(v0_out != -1 && v1_out != -1 && v2_out != -1 && v3_out != -1 && v4_out != -1); + if (out.face.size() == 3) { + int e0_out = get_orig_index(out.edge_orig, 0); + EXPECT_NE(e0_out, -1); + int fe0_out = get_output_edge_index(out, v0_out, v1_out); + EXPECT_NE(fe0_out, -1); + int fe1a_out = get_output_edge_index(out, v1_out, v4_out); + EXPECT_NE(fe1a_out, -1); + int fe1b_out = get_output_edge_index(out, v4_out, v2_out); + EXPECT_NE(fe1b_out, -1); + if (fe1a_out != 0 && fe1b_out != 0) { + EXPECT_EQ(e0_out, get_orig_index(out.edge_orig, 0)); + EXPECT_TRUE(out.edge_orig[fe1a_out].size() == 1 && out.edge_orig[fe1a_out][0] == 11); + EXPECT_TRUE(out.edge_orig[fe1b_out].size() == 1 && out.edge_orig[fe1b_out][0] == 11); + } + int e_diag = get_output_edge_index(out, v0_out, v4_out); + EXPECT_NE(e_diag, -1); + if (e_diag != -1) { + EXPECT_EQ(out.edge_orig[e_diag].size(), 0); + } + } + if (DO_DRAW) { + graph_draw<T>("CutAcrossTri", out.vert, out.edge, out.face); + } +} + template<typename T> void diamondcross_test() { /* Diamond with constraint edge from top to bottom. Some dup verts. */ @@ -1470,6 +1519,11 @@ TEST(delaunay_d, CrossSegs) crosssegs_test<double>(); } +TEST(delaunay_d, CutAcrossTri) +{ + cutacrosstri_test<double>(); +} + TEST(delaunay_d, DiamondCross) { diamondcross_test<double>(); @@ -1610,6 +1664,11 @@ TEST(delaunay_m, CrossSegs) crosssegs_test<mpq_class>(); } +TEST(delaunay_m, CutAcrossTri) +{ + cutacrosstri_test<mpq_class>(); +} + TEST(delaunay_m, DiamondCross) { diamondcross_test<mpq_class>(); @@ -1697,14 +1756,40 @@ TEST(delaunay_d, CintTwoFace) input.faces_len_table = faces_len; input.faces_start_table = faces_start; input.epsilon = 1e-5f; + input.need_ids = false; ::CDT_result *output = BLI_delaunay_2d_cdt_calc(&input, CDT_FULL); BLI_delaunay_2d_cdt_free(output); } + +TEST(delaunay_d, CintTwoFaceNoIds) +{ + float vert_coords[][2] = { + {0.0, 0.0}, {1.0, 0.0}, {0.5, 1.0}, {1.1, 1.0}, {1.1, 0.0}, {1.6, 1.0}}; + int faces[] = {0, 1, 2, 3, 4, 5}; + int faces_len[] = {3, 3}; + int faces_start[] = {0, 3}; + + ::CDT_input input; + input.verts_len = 6; + input.edges_len = 0; + input.faces_len = 2; + input.vert_coords = vert_coords; + input.edges = nullptr; + input.faces = faces; + input.faces_len_table = faces_len; + input.faces_start_table = faces_start; + input.epsilon = 1e-5f; + input.need_ids = true; + ::CDT_result *output = BLI_delaunay_2d_cdt_calc(&input, CDT_FULL); + BLI_delaunay_2d_cdt_free(output); +} + #endif #if DO_TEXT_TESTS template<typename T> -void text_test(int num_arc_points, int num_lets_per_line, int num_lines, CDT_output_type otype) +void text_test( + int num_arc_points, int num_lets_per_line, int num_lines, CDT_output_type otype, bool need_ids) { constexpr bool print_timing = true; /* @@ -1789,7 +1874,7 @@ void text_test(int num_arc_points, int num_lets_per_line, int num_lines, CDT_out vec2<T> start_co = b_vert[arc_origin_vert]; vec2<T> end_co = b_vert[arc_terminal_vert]; vec2<T> center_co = 0.5 * (start_co + end_co); - BLI_assert(start_co[0] == end_co[2]); + BLI_assert(start_co[0] == end_co[0]); double radius = abs(math_to_double<T>(end_co[1] - center_co[1])); double angle_delta = M_PI / (num_arc_points + 1); int start_vert = b_before_arcs_in.vert.size() + arc * num_arc_points; @@ -1843,12 +1928,18 @@ void text_test(int num_arc_points, int num_lets_per_line, int num_lines, CDT_out } } in.epsilon = b_before_arcs_in.epsilon; + in.need_ids = need_ids; double tstart = PIL_check_seconds_timer(); CDT_result<T> out = delaunay_2d_calc(in, otype); double tend = PIL_check_seconds_timer(); if (print_timing) { std::cout << "time = " << tend - tstart << "\n"; } + if (!need_ids) { + EXPECT_EQ(out.vert_orig.size(), 0); + EXPECT_EQ(out.edge_orig.size(), 0); + EXPECT_EQ(out.face_orig.size(), 0); + } if (DO_DRAW) { std::string label = "Text arcpts=" + std::to_string(num_arc_points); if (num_lets_per_line > 1) { @@ -1857,25 +1948,103 @@ void text_test(int num_arc_points, int num_lets_per_line, int num_lines, CDT_out if (num_lines > 1) { label += " lines=" + std::to_string(num_lines); } + if (!need_ids) { + label += " no_ids"; + } + if (otype != CDT_INSIDE_WITH_HOLES) { + label += " otype=" + std::to_string(otype); + } graph_draw<T>(label, out.vert, out.edge, out.face); } } TEST(delaunay_d, TextB10) { - text_test<double>(10, 1, 1, CDT_INSIDE_WITH_HOLES); + text_test<double>(10, 1, 1, CDT_INSIDE_WITH_HOLES, true); +} + +TEST(delaunay_d, TextB10_noids) +{ + text_test<double>(10, 1, 1, CDT_INSIDE_WITH_HOLES, false); +} + +TEST(delaunay_d, TextB10_inside) +{ + text_test<double>(10, 1, 1, CDT_INSIDE, true); +} + +TEST(delaunay_d, TextB10_inside_noids) +{ + text_test<double>(10, 1, 1, CDT_INSIDE, false); +} + +TEST(delaunay_d, TextB10_constraints) +{ + text_test<double>(10, 1, 1, CDT_CONSTRAINTS, true); +} + +TEST(delaunay_d, TextB10_constraints_noids) +{ + text_test<double>(10, 1, 1, CDT_CONSTRAINTS, false); +} + +TEST(delaunay_d, TextB10_constraints_valid_bmesh) +{ + text_test<double>(10, 1, 1, CDT_CONSTRAINTS_VALID_BMESH, true); +} + +TEST(delaunay_d, TextB10_constraints_valid_bmesh_noids) +{ + text_test<double>(10, 1, 1, CDT_CONSTRAINTS_VALID_BMESH, false); +} + +TEST(delaunay_d, TextB10_constraints_valid_bmesh_with_holes) +{ + text_test<double>(10, 1, 1, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES, true); +} + +TEST(delaunay_d, TextB10_constraints_valid_bmesh_with_holes_noids) +{ + text_test<double>(10, 1, 1, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES, false); } TEST(delaunay_d, TextB200) { - text_test<double>(200, 1, 1, CDT_INSIDE_WITH_HOLES); + text_test<double>(200, 1, 1, CDT_INSIDE_WITH_HOLES, true); } TEST(delaunay_d, TextB10_10_10) { - text_test<double>(10, 10, 10, CDT_INSIDE_WITH_HOLES); + text_test<double>(10, 10, 10, CDT_INSIDE_WITH_HOLES, true); +} + +TEST(delaunay_d, TextB10_10_10_noids) +{ + text_test<double>(10, 10, 10, CDT_INSIDE_WITH_HOLES, false); } +# ifdef WITH_GMP +TEST(delaunay_m, TextB10) +{ + text_test<mpq_class>(10, 1, 1, CDT_INSIDE_WITH_HOLES, true); +} + +TEST(delaunay_m, TextB200) +{ + text_test<mpq_class>(200, 1, 1, CDT_INSIDE_WITH_HOLES, true); +} + +TEST(delaunay_m, TextB10_10_10) +{ + text_test<mpq_class>(10, 10, 10, CDT_INSIDE_WITH_HOLES, true); +} + +TEST(delaunay_m, TextB10_10_10_noids) +{ + text_test<mpq_class>(10, 10, 10, CDT_INSIDE_WITH_HOLES, false); +} +# endif + #endif #if DO_RANDOM_TESTS diff --git a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc index 24fa7f1a476..0329fc156c0 100644 --- a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc +++ b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc @@ -866,11 +866,11 @@ static void fill_sphere_data(int nrings, }; Array<int> eid = {0, 0, 0, 0}; /* Don't care about edge ids. */ /* - * (x, y , z) is given from inclination theta and azimuth phi, - * where 0 <= theta <= pi; 0 <= phi <= 2pi. - * x = radius * sin(theta) cos(phi) - * y = radius * sin(theta) sin(phi) - * z = radius * cos(theta) + * (x, y, z) is given from inclination theta and azimuth phi, + * where: `0 <= theta <= pi; 0 <= phi <= 2pi`. + * `x = radius * sin(theta) cos(phi)` + * `y = radius * sin(theta) sin(phi)` + * `z = radius * cos(theta)` */ for (int s = 0; s < nsegs; ++s) { double phi = s * delta_phi; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 03fb4149d7b..11986f11fea 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2444,7 +2444,7 @@ static void direct_link_id_common( BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int tag) { if (!BLO_read_data_is_undo(reader)) { - /* When actually reading a file , we do want to reset/re-generate session uuids. + /* When actually reading a file, we do want to reset/re-generate session uuids. * In undo case, we want to re-use existing ones. */ id->session_uuid = MAIN_ID_SESSION_UUID_UNSET; } diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 8a7bc375ea9..e56c1995363 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -132,7 +132,7 @@ static void sequencer_init_preview_region(ARegion *region) region->v2d.max[0] = 12000.0f; region->v2d.max[1] = 12000.0f; region->v2d.cur = region->v2d.tot; - region->v2d.align = V2D_ALIGN_FREE; // (V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_NEG_Y); + region->v2d.align = V2D_ALIGN_FREE; /* `(V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_NEG_Y)` */ region->v2d.keeptot = V2D_KEEPTOT_FREE; } @@ -655,8 +655,10 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) Tex *tx; ParticleSettings *part; Object *ob; - // PTCacheID *pid; - // ListBase pidlist; +#if 0 + PTCacheID *pid; + ListBase pidlist; +#endif bSound *sound; Sequence *seq; @@ -766,12 +768,15 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) /* set old pointcaches to have disk cache flag */ for (ob = bmain->objects.first; ob; ob = ob->id.next) { - // BKE_ptcache_ids_from_object(&pidlist, ob); +#if 0 + BKE_ptcache_ids_from_object(&pidlist, ob); - // for (pid = pidlist.first; pid; pid = pid->next) - // pid->cache->flag |= PTCACHE_DISK_CACHE; + for (pid = pidlist.first; pid; pid = pid->next) { + pid->cache->flag |= PTCACHE_DISK_CACHE; + } - // BLI_freelistN(&pidlist); + BLI_freelistN(&pidlist); +#endif } /* type was a mixed flag & enum. move the 2d flag elsewhere */ @@ -789,18 +794,23 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) Tex *tex; Scene *sce; ToolSettings *ts; - // PTCacheID *pid; - // ListBase pidlist; +#if 0 + PTCacheID *pid; + ListBase pidlist; +#endif for (ob = bmain->objects.first; ob; ob = ob->id.next) { - // BKE_ptcache_ids_from_object(&pidlist, ob); +#if 0 + BKE_ptcache_ids_from_object(&pidlist, ob); - // for (pid = pidlist.first; pid; pid = pid->next) { - // if (BLI_listbase_is_empty(pid->ptcaches)) - // pid->ptcaches->first = pid->ptcaches->last = pid->cache; - //} + for (pid = pidlist.first; pid; pid = pid->next) { + if (BLI_listbase_is_empty(pid->ptcaches)) { + pid->ptcaches->first = pid->ptcaches->last = pid->cache; + } + } - // BLI_freelistN(&pidlist); + BLI_freelistN(&pidlist); +#endif if (ob->totcol && ob->matbits == NULL) { int a; @@ -842,7 +852,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) Object *ob; for (ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ob->flag & 8192) { // OB_POSEMODE = 8192 + if (ob->flag & 8192) { /* OB_POSEMODE = 8192. */ ob->mode |= OB_MODE_POSE; } } @@ -1395,7 +1405,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) } if ((sce->r.ffcodecdata.flags & FFMPEG_MULTIPLEX_AUDIO) == 0) { - sce->r.ffcodecdata.audio_codec = 0x0; // CODEC_ID_NONE + sce->r.ffcodecdata.audio_codec = 0x0; /* `CODEC_ID_NONE` */ } SEQ_ALL_BEGIN (sce->ed, seq) { @@ -1735,7 +1745,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) /* New Settings */ if (!MAIN_VERSION_ATLEAST(bmain, 252, 5)) { - brush->flag |= BRUSH_SPACE_ATTEN; // explicitly enable adaptive space + brush->flag |= BRUSH_SPACE_ATTEN; /* Explicitly enable adaptive space. */ /* spacing was originally in pixels, convert it to percentage for new version * size should not be zero due to sanity check above diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 5bf4d3b68b5..858f5d85a90 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -2149,7 +2149,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) } for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - /* NB: scene->nodetree is a local ID block, has been direct_link'ed */ + /* NOTE: `scene->nodetree` is a local ID block, has been direct_link'ed. */ if (scene->nodetree) { scene->nodetree->active_viewer_key = active_viewer_key; } diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index d36c622c572..4dcb7414bb4 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -29,8 +29,10 @@ #include "DNA_armature_types.h" #include "DNA_brush_types.h" #include "DNA_collection_types.h" +#include "DNA_curve_types.h" #include "DNA_genfile.h" #include "DNA_listBase.h" +#include "DNA_material_types.h" #include "DNA_modifier_types.h" #include "DNA_text_types.h" #include "DNA_workspace_types.h" @@ -40,6 +42,7 @@ #include "BKE_asset.h" #include "BKE_collection.h" #include "BKE_deform.h" +#include "BKE_fcurve.h" #include "BKE_fcurve_driver.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -48,11 +51,10 @@ #include "BLO_readfile.h" #include "MEM_guardedalloc.h" #include "readfile.h" -#include "versioning_common.h" #include "SEQ_sequencer.h" -#include "MEM_guardedalloc.h" +#include "RNA_access.h" #include "versioning_common.h" @@ -99,13 +101,87 @@ static void move_vertex_group_names_to_object_data(Main *bmain) if (ELEM(object->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { ListBase *new_defbase = BKE_object_defgroup_list_mutable(object); - /* Clear the list in case the it was already assigned from another object. */ - BLI_freelistN(new_defbase); - *new_defbase = object->defbase; + /* Choose the longest vertex group name list among all linked duplicates. */ + if (BLI_listbase_count(&object->defbase) < BLI_listbase_count(new_defbase)) { + BLI_freelistN(&object->defbase); + } + else { + /* Clear the list in case the it was already assigned from another object. */ + BLI_freelistN(new_defbase); + *new_defbase = object->defbase; + } } } } +static void do_versions_sequencer_speed_effect_recursive(Scene *scene, const ListBase *seqbase) +{ + /* Old SpeedControlVars->flags. */ +#define SEQ_SPEED_INTEGRATE (1 << 0) +#define SEQ_SPEED_COMPRESS_IPO_Y (1 << 2) + + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if (seq->type == SEQ_TYPE_SPEED) { + SpeedControlVars *v = (SpeedControlVars *)seq->effectdata; + const char *substr = NULL; + float globalSpeed = v->globalSpeed; + if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) { + if (globalSpeed == 1.0f) { + v->speed_control_type = SEQ_SPEED_STRETCH; + } + else { + v->speed_control_type = SEQ_SPEED_MULTIPLY; + v->speed_fader = globalSpeed * + ((float)seq->seq1->len / + max_ff((float)(seq->seq1->enddisp - seq->seq1->start), 1.0f)); + } + } + else if (v->flags & SEQ_SPEED_INTEGRATE) { + v->speed_control_type = SEQ_SPEED_MULTIPLY; + v->speed_fader = seq->speed_fader * globalSpeed; + } + else if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) { + globalSpeed *= 100.0f; + v->speed_control_type = SEQ_SPEED_LENGTH; + v->speed_fader_length = seq->speed_fader * globalSpeed; + substr = "speed_length"; + } + else { + v->speed_control_type = SEQ_SPEED_FRAME_NUMBER; + v->speed_fader_frame_number = (int)(seq->speed_fader * globalSpeed); + substr = "speed_frame_number"; + } + + v->flags &= ~(SEQ_SPEED_INTEGRATE | SEQ_SPEED_COMPRESS_IPO_Y); + + if (substr || globalSpeed != 1.0f) { + FCurve *fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL); + if (fcu) { + if (globalSpeed != 1.0f) { + for (int i = 0; i < fcu->totvert; i++) { + BezTriple *bezt = &fcu->bezt[i]; + bezt->vec[0][1] *= globalSpeed; + bezt->vec[1][1] *= globalSpeed; + bezt->vec[2][1] *= globalSpeed; + } + } + if (substr) { + char *new_path = BLI_str_replaceN(fcu->rna_path, "speed_factor", substr); + MEM_freeN(fcu->rna_path); + fcu->rna_path = new_path; + } + } + } + } + else if (seq->type == SEQ_TYPE_META) { + do_versions_sequencer_speed_effect_recursive(scene, &seq->seqbase); + } + } + +#undef SEQ_SPEED_INTEGRATE +#undef SEQ_SPEED_COMPRESS_IPO_Y +} + void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports)) { if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) { @@ -154,6 +230,14 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports)) move_vertex_group_names_to_object_data(bmain); } + if (!MAIN_VERSION_ATLEAST(bmain, 300, 13)) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->ed != NULL) { + do_versions_sequencer_speed_effect_recursive(scene, &scene->ed->seqbase); + } + } + } + /** * Versioning code until next subversion bump goes here. * @@ -499,6 +583,11 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) sizeof(scene->master_collection->id.name) - 2); } } + LISTBASE_FOREACH (Material *, mat, &bmain->materials) { + if (!(mat->lineart.flags & LRT_MATERIAL_CUSTOM_OCCLUSION_EFFECTIVENESS)) { + mat->lineart.mat_occlusion = 1; + } + } } if (!MAIN_VERSION_ATLEAST(bmain, 300, 9)) { @@ -519,15 +608,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } FOREACH_NODETREE_END; - - { - if (!DNA_struct_elem_find( - fd->filesdna, "WorkSpace", "AssetLibraryReference", "active_asset_library")) { - LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) { - BKE_asset_library_reference_init_default(&workspace->active_asset_library); - } - } - } } if (!MAIN_VERSION_ATLEAST(bmain, 300, 10)) { @@ -540,6 +620,51 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 300, 13)) { + /* Convert Surface Deform to sparse-capable bind structure. */ + if (!DNA_struct_elem_find( + fd->filesdna, "SurfaceDeformModifierData", "int", "num_mesh_verts")) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_SurfaceDeform) { + SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; + if (smd->num_bind_verts && smd->verts) { + smd->num_mesh_verts = smd->num_bind_verts; + + for (unsigned int i = 0; i < smd->num_bind_verts; i++) { + smd->verts[i].vertex_idx = i; + } + } + } + } + } + } + + if (!DNA_struct_elem_find( + fd->filesdna, "WorkSpace", "AssetLibraryReference", "asset_library")) { + LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) { + BKE_asset_library_reference_init_default(&workspace->asset_library); + } + } + + if (!DNA_struct_elem_find( + fd->filesdna, "FileAssetSelectParams", "AssetLibraryReference", "asset_library")) { + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) { + if (space->spacetype == SPACE_FILE) { + SpaceFile *sfile = (SpaceFile *)space; + if (sfile->browse_mode != FILE_BROWSE_MODE_ASSETS) { + continue; + } + BKE_asset_library_reference_init_default(&sfile->asset_params->asset_library); + } + } + } + } + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 30587418f84..152dcbed6a4 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -883,6 +883,10 @@ void blo_do_versions_userdef(UserDef *userdef) userdef->sequencer_proxy_setup = USER_SEQ_PROXY_SETUP_AUTOMATIC; } + if (!USER_VERSION_ATLEAST(293, 13)) { + BKE_addon_ensure(&userdef->addons, "pose_library"); + } + /** * Versioning code until next subversion bump goes here. * @@ -894,7 +898,6 @@ void blo_do_versions_userdef(UserDef *userdef) */ { /* Keep this block, even when empty. */ - BKE_addon_ensure(&userdef->addons, "pose_library"); } LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index fc29b1d8915..12839a155e4 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -69,7 +69,7 @@ * - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional). * - write #GLOB (#FileGlobal struct) (some global vars). * - write #DNA1 (#SDNA struct) - * - write #USER (#UserDef struct) if filename is ``~/.config/blender/X.XX/config/startup.blend``. + * - write #USER (#UserDef struct) if filename is `~/.config/blender/X.XX/config/startup.blend`. */ #include <fcntl.h> diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h index a5241f6b36d..40db423ba2f 100644 --- a/source/blender/bmesh/bmesh.h +++ b/source/blender/bmesh/bmesh.h @@ -37,7 +37,7 @@ * * BMHeader flags should **never** be read or written to by bmesh operators (see Operators below). * - * Access to header flags is done with ``BM_elem_flag_*()`` functions. + * Access to header flags is done with `BM_elem_flag_*()` functions. * \subsection bm_faces Faces * * Faces in BMesh are stored as a circular linked list of loops. Loops store per-face-vertex data @@ -55,7 +55,7 @@ * * - BMLoop#v - pointer to the vertex associated with this loop. * - BMLoop#e - pointer to the edge associated with this loop, - * between verts ``(loop->v, loop->next->v)`` + * between verts `(loop->v, loop->next->v)` * - BMLoop#f - pointer to the face associated with this loop. * \subsection bm_two_side_face 2-Sided Faces * @@ -113,7 +113,7 @@ * * These slots are identified by name, using strings. * - * Access to slots is done with ``BMO_slot_***()`` functions. + * Access to slots is done with `BMO_slot_***()` functions. * \subsection bm_tool_flags Tool Flags * * The BMesh API provides a set of flags for faces, edges and vertices, @@ -126,7 +126,7 @@ * These flags should not be confused with header flags, which are used to store persistent flags * (e.g. selection, hide status, etc). * - * Access to tool flags is done with ``BMO_elem_flag_***()`` functions. + * Access to tool flags is done with `BMO_elem_flag_***()` functions. * * \warning Operators are **never** allowed to read or write to header flags. * They act entirely on the data inside their input slots. @@ -162,14 +162,14 @@ * * These conventions should be used throughout the bmesh module. * - * - ``bmesh_kernel_*()`` - Low level API, for primitive functions that others are built ontop of. - * - ``bmesh_***()`` - Low level API function. - * - ``bm_***()`` - 'static' functions, not a part of the API at all, + * - `bmesh_kernel_*()` - Low level API, for primitive functions that others are built ontop of. + * - `bmesh_***()` - Low level API function. + * - `bm_***()` - 'static' functions, not a part of the API at all, * but use prefix since they operate on BMesh data. - * - ``BM_***()`` - High level BMesh API function for use anywhere. - * - ``BMO_***()`` - High level operator API function for use anywhere. - * - ``bmo_***()`` - Low level / internal operator API functions. - * - ``_bm_***()`` - Functions which are called via macros only. + * - `BM_***()` - High level BMesh API function for use anywhere. + * - `BMO_***()` - High level operator API function for use anywhere. + * - `bmo_***()` - Low level / internal operator API functions. + * - `_bm_***()` - Functions which are called via macros only. * * \section bm_todo BMesh TODO's * diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index 423d64ba62c..82c76c8ae4f 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -185,7 +185,7 @@ typedef struct BMLoop { struct BMFace *f; /** - * Other loops connected to this edge,. + * Other loops connected to this edge. * * This is typically use for accessing an edges faces, * however this is done by stepping over it's loops. diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c index dea6561fe9a..6dfaa0ca688 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_normals.c +++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c @@ -40,6 +40,16 @@ #include "intern/bmesh_private.h" +/* Smooth angle to use when tagging edges is disabled entirely. */ +#define EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS -FLT_MAX + +static void bm_edge_tag_from_smooth_and_set_sharp(const float (*fnos)[3], + BMEdge *e, + const float split_angle_cos); +static void bm_edge_tag_from_smooth(const float (*fnos)[3], + BMEdge *e, + const float split_angle_cos); + /* -------------------------------------------------------------------- */ /** \name Update Vertex & Face Normals * \{ */ @@ -394,9 +404,7 @@ void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges) * Helpers for #BM_mesh_loop_normals_update and #BM_loops_calc_normal_vcos */ static void bm_mesh_edges_sharp_tag(BMesh *bm, - const float (*vnos)[3], const float (*fnos)[3], - float (*r_lnos)[3], const float split_angle, const bool do_sharp_edges_tag) { @@ -407,58 +415,23 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm, const bool check_angle = (split_angle < (float)M_PI); const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f; - { - char htype = BM_VERT | BM_LOOP; - if (fnos) { - htype |= BM_FACE; - } - BM_mesh_elem_index_ensure(bm, htype); + if (fnos) { + BM_mesh_elem_index_ensure(bm, BM_FACE); } - /* This first loop checks which edges are actually smooth, - * and pre-populate lnos with vnos (as if they were all smooth). */ - BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) { - BMLoop *l_a, *l_b; - - BM_elem_index_set(e, i); /* set_inline */ - BM_elem_flag_disable(e, BM_ELEM_TAG); /* Clear tag (means edge is sharp). */ - - /* An edge with only two loops, might be smooth... */ - if (BM_edge_loop_pair(e, &l_a, &l_b)) { - bool is_angle_smooth = true; - if (check_angle) { - const float *no_a = fnos ? fnos[BM_elem_index_get(l_a->f)] : l_a->f->no; - const float *no_b = fnos ? fnos[BM_elem_index_get(l_b->f)] : l_b->f->no; - is_angle_smooth = (dot_v3v3(no_a, no_b) >= split_angle_cos); + if (do_sharp_edges_tag) { + BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) { + BM_elem_index_set(e, i); /* set_inline */ + if (e->l != NULL) { + bm_edge_tag_from_smooth_and_set_sharp(fnos, e, split_angle_cos); } - - /* We only tag edges that are *really* smooth: - * If the angle between both its polys' normals is below split_angle value, - * and it is tagged as such, - * and both its faces are smooth, - * and both its faces have compatible (non-flipped) normals, - * i.e. both loops on the same edge do not share the same vertex. - */ - if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) && BM_elem_flag_test(l_a->f, BM_ELEM_SMOOTH) && - BM_elem_flag_test(l_b->f, BM_ELEM_SMOOTH) && l_a->v != l_b->v) { - if (is_angle_smooth) { - const float *no; - BM_elem_flag_enable(e, BM_ELEM_TAG); - - /* linked vertices might be fully smooth, copy their normals to loop ones. */ - if (r_lnos) { - no = vnos ? vnos[BM_elem_index_get(l_a->v)] : l_a->v->no; - copy_v3_v3(r_lnos[BM_elem_index_get(l_a)], no); - no = vnos ? vnos[BM_elem_index_get(l_b->v)] : l_b->v->no; - copy_v3_v3(r_lnos[BM_elem_index_get(l_b)], no); - } - } - else if (do_sharp_edges_tag) { - /* Note that we do not care about the other sharp-edge cases - * (sharp poly, non-manifold edge, etc.), - * only tag edge as sharp when it is due to angle threshold. */ - BM_elem_flag_disable(e, BM_ELEM_SMOOTH); - } + } + } + else { + BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) { + BM_elem_index_set(e, i); /* set_inline */ + if (e->l != NULL) { + bm_edge_tag_from_smooth(fnos, e, split_angle_cos); } } } @@ -479,7 +452,7 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle) return; } - bm_mesh_edges_sharp_tag(bm, NULL, NULL, NULL, split_angle, true); + bm_mesh_edges_sharp_tag(bm, NULL, split_angle, true); } /** \} */ @@ -526,6 +499,600 @@ bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr) } /** + * Called for all faces loops. + * + * - All loops must have #BM_ELEM_TAG cleared. + * - Loop indices must be valid. + * + * \note When custom normals are present, the order of loops can be important. + * Loops with lower indices must be passed before loops with higher indices (for each vertex). + * This is needed since the first loop sets the reference point for the custom normal offsets. + * + * \return The number of loops that were handled (for early exit when all have been handled). + */ +static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm, + const float (*vcos)[3], + const float (*fnos)[3], + const short (*clnors_data)[2], + const int cd_loop_clnors_offset, + const bool has_clnors, + /* Cache. */ + BLI_Stack *edge_vectors, + /* Iterate. */ + BMLoop *l_curr, + /* Result. */ + float (*r_lnos)[3], + MLoopNorSpaceArray *r_lnors_spacearr) +{ + BLI_assert((bm->elem_index_dirty & (BM_FACE | BM_LOOP)) == 0); + BLI_assert((vcos == NULL) || ((bm->elem_index_dirty & BM_VERT) == 0)); + UNUSED_VARS_NDEBUG(bm); + + int handled = 0; + + /* Temp normal stack. */ + BLI_SMALLSTACK_DECLARE(normal, float *); + /* Temp clnors stack. */ + BLI_SMALLSTACK_DECLARE(clnors, short *); + /* Temp edge vectors stack, only used when computing lnor spacearr. */ + + /* A smooth edge, we have to check for cyclic smooth fan case. + * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge + * as 'entry point', otherwise we can skip it. */ + + /* NOTE: In theory, we could make bm_mesh_loop_check_cyclic_smooth_fan() store + * mlfan_pivot's in a stack, to avoid having to fan again around + * the vert during actual computation of clnor & clnorspace. However, this would complicate + * the code, add more memory usage, and + * BM_vert_step_fan_loop() is quite cheap in term of CPU cycles, + * so really think it's not worth it. */ + if (BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && + (BM_elem_flag_test(l_curr, BM_ELEM_TAG) || !BM_loop_check_cyclic_smooth_fan(l_curr))) { + } + else if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && + !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) { + /* Simple case (both edges around that vertex are sharp in related polygon), + * this vertex just takes its poly normal. + */ + const int l_curr_index = BM_elem_index_get(l_curr); + const float *no = fnos ? fnos[BM_elem_index_get(l_curr->f)] : l_curr->f->no; + copy_v3_v3(r_lnos[l_curr_index], no); + + /* If needed, generate this (simple!) lnor space. */ + if (r_lnors_spacearr) { + float vec_curr[3], vec_prev[3]; + MLoopNorSpace *lnor_space = BKE_lnor_space_create(r_lnors_spacearr); + + { + const BMVert *v_pivot = l_curr->v; + const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co; + const BMVert *v_1 = l_curr->next->v; + const float *co_1 = vcos ? vcos[BM_elem_index_get(v_1)] : v_1->co; + const BMVert *v_2 = l_curr->prev->v; + const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co; + + BLI_assert(v_1 == BM_edge_other_vert(l_curr->e, v_pivot)); + BLI_assert(v_2 == BM_edge_other_vert(l_curr->prev->e, v_pivot)); + + sub_v3_v3v3(vec_curr, co_1, co_pivot); + normalize_v3(vec_curr); + sub_v3_v3v3(vec_prev, co_2, co_pivot); + normalize_v3(vec_prev); + } + + BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, NULL); + /* We know there is only one loop in this space, + * no need to create a linklist in this case... */ + BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, l_curr, true); + + if (has_clnors) { + const short(*clnor)[2] = clnors_data ? &clnors_data[l_curr_index] : + (const void *)BM_ELEM_CD_GET_VOID_P( + l_curr, cd_loop_clnors_offset); + BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor, r_lnos[l_curr_index]); + } + } + handled = 1; + } + /* We *do not need* to check/tag loops as already computed! + * Due to the fact a loop only links to one of its two edges, + * a same fan *will never be walked more than once!* + * Since we consider edges having neighbor faces with inverted (flipped) normals as sharp, + * we are sure that no fan will be skipped, even only considering the case + * (sharp curr_edge, smooth prev_edge), and not the alternative + * (smooth curr_edge, sharp prev_edge). + * All this due/thanks to link between normals and loop ordering. + */ + else { + /* We have to fan around current vertex, until we find the other non-smooth edge, + * and accumulate face normals into the vertex! + * Note in case this vertex has only one sharp edge, + * this is a waste because the normal is the same as the vertex normal, + * but I do not see any easy way to detect that (would need to count number of sharp edges + * per vertex, I doubt the additional memory usage would be worth it, especially as it + * should not be a common case in real-life meshes anyway). + */ + BMVert *v_pivot = l_curr->v; + BMEdge *e_next; + const BMEdge *e_org = l_curr->e; + BMLoop *lfan_pivot, *lfan_pivot_next; + int lfan_pivot_index; + float lnor[3] = {0.0f, 0.0f, 0.0f}; + float vec_curr[3], vec_next[3], vec_org[3]; + + /* We validate clnors data on the fly - cheapest way to do! */ + int clnors_avg[2] = {0, 0}; + const short(*clnor_ref)[2] = NULL; + int clnors_nbr = 0; + bool clnors_invalid = false; + + const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co; + + MLoopNorSpace *lnor_space = r_lnors_spacearr ? BKE_lnor_space_create(r_lnors_spacearr) : NULL; + + BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors)); + + lfan_pivot = l_curr; + lfan_pivot_index = BM_elem_index_get(lfan_pivot); + e_next = lfan_pivot->e; /* Current edge here, actually! */ + + /* Only need to compute previous edge's vector once, + * then we can just reuse old current one! */ + { + const BMVert *v_2 = lfan_pivot->next->v; + const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co; + + BLI_assert(v_2 == BM_edge_other_vert(e_next, v_pivot)); + + sub_v3_v3v3(vec_org, co_2, co_pivot); + normalize_v3(vec_org); + copy_v3_v3(vec_curr, vec_org); + + if (r_lnors_spacearr) { + BLI_stack_push(edge_vectors, vec_org); + } + } + + while (true) { + /* Much simpler than in sibling code with basic Mesh data! */ + lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); + if (lfan_pivot_next) { + BLI_assert(lfan_pivot_next->v == v_pivot); + } + else { + /* next edge is non-manifold, we have to find it ourselves! */ + e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; + } + + /* Compute edge vector. + * NOTE: We could pre-compute those into an array, in the first iteration, + * instead of computing them twice (or more) here. + * However, time gained is not worth memory and time lost, + * given the fact that this code should not be called that much in real-life meshes. + */ + { + const BMVert *v_2 = BM_edge_other_vert(e_next, v_pivot); + const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co; + + sub_v3_v3v3(vec_next, co_2, co_pivot); + normalize_v3(vec_next); + } + + { + /* Code similar to accumulate_vertex_normals_poly_v3. */ + /* Calculate angle between the two poly edges incident on this vertex. */ + const BMFace *f = lfan_pivot->f; + const float fac = saacos(dot_v3v3(vec_next, vec_curr)); + const float *no = fnos ? fnos[BM_elem_index_get(f)] : f->no; + /* Accumulate */ + madd_v3_v3fl(lnor, no, fac); + + if (has_clnors) { + /* Accumulate all clnors, if they are not all equal we have to fix that! */ + const short(*clnor)[2] = clnors_data ? &clnors_data[lfan_pivot_index] : + (const void *)BM_ELEM_CD_GET_VOID_P( + lfan_pivot, cd_loop_clnors_offset); + if (clnors_nbr) { + clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]); + } + else { + clnor_ref = clnor; + } + clnors_avg[0] += (*clnor)[0]; + clnors_avg[1] += (*clnor)[1]; + clnors_nbr++; + /* We store here a pointer to all custom lnors processed. */ + BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor); + } + } + + /* We store here a pointer to all loop-normals processed. */ + BLI_SMALLSTACK_PUSH(normal, (float *)r_lnos[lfan_pivot_index]); + + if (r_lnors_spacearr) { + /* Assign current lnor space to current 'vertex' loop. */ + BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, lfan_pivot_index, lfan_pivot, false); + if (e_next != e_org) { + /* We store here all edges-normalized vectors processed. */ + BLI_stack_push(edge_vectors, vec_next); + } + } + + handled += 1; + + if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { + /* Next edge is sharp, we have finished with this fan of faces around this vert! */ + break; + } + + /* Copy next edge vector to current one. */ + copy_v3_v3(vec_curr, vec_next); + /* Next pivot loop to current one. */ + lfan_pivot = lfan_pivot_next; + lfan_pivot_index = BM_elem_index_get(lfan_pivot); + } + + { + float lnor_len = normalize_v3(lnor); + + /* If we are generating lnor spacearr, we can now define the one for this fan. */ + if (r_lnors_spacearr) { + if (UNLIKELY(lnor_len == 0.0f)) { + /* Use vertex normal as fallback! */ + copy_v3_v3(lnor, r_lnos[lfan_pivot_index]); + lnor_len = 1.0f; + } + + BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_next, edge_vectors); + + if (has_clnors) { + if (clnors_invalid) { + short *clnor; + + clnors_avg[0] /= clnors_nbr; + clnors_avg[1] /= clnors_nbr; + /* Fix/update all clnors of this fan with computed average value. */ + + /* Prints continuously when merge custom normals, so commenting. */ + /* printf("Invalid clnors in this fan!\n"); */ + + while ((clnor = BLI_SMALLSTACK_POP(clnors))) { + // print_v2("org clnor", clnor); + clnor[0] = (short)clnors_avg[0]; + clnor[1] = (short)clnors_avg[1]; + } + // print_v2("new clnors", clnors_avg); + } + else { + /* We still have to consume the stack! */ + while (BLI_SMALLSTACK_POP(clnors)) { + /* pass */ + } + } + BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor); + } + } + + /* In case we get a zero normal here, just use vertex normal already set! */ + if (LIKELY(lnor_len != 0.0f)) { + /* Copy back the final computed normal into all related loop-normals. */ + float *nor; + + while ((nor = BLI_SMALLSTACK_POP(normal))) { + copy_v3_v3(nor, lnor); + } + } + else { + /* We still have to consume the stack! */ + while (BLI_SMALLSTACK_POP(normal)) { + /* pass */ + } + } + } + + /* Tag related vertex as sharp, to avoid fanning around it again + * (in case it was a smooth one). */ + if (r_lnors_spacearr) { + BM_elem_flag_enable(l_curr->v, BM_ELEM_TAG); + } + } + return handled; +} + +static int bm_loop_index_cmp(const void *a, const void *b) +{ + BLI_assert(BM_elem_index_get((BMLoop *)a) != BM_elem_index_get((BMLoop *)b)); + if (BM_elem_index_get((BMLoop *)a) < BM_elem_index_get((BMLoop *)b)) { + return -1; + } + return 1; +} + +/** + * We only tag edges that are *really* smooth when the following conditions are met: + * - The angle between both its polygons normals is below split_angle value. + * - The edge is tagged as smooth. + * - The faces of the edge are tagged as smooth. + * - The faces of the edge have compatible (non-flipped) topological normal (winding), + * i.e. both loops on the same edge do not share the same vertex. + */ +BLI_INLINE bool bm_edge_is_smooth_no_angle_test(const BMEdge *e, + const BMLoop *l_a, + const BMLoop *l_b) +{ + return ( + /* The face is manifold. */ + (l_a->radial_next == l_b) && + /* Faces have winding that faces the same way. */ + (l_a->v != l_b->v) && + /* The edge is smooth. */ + BM_elem_flag_test(e, BM_ELEM_SMOOTH) && + /* Both faces are smooth. */ + BM_elem_flag_test(l_a->f, BM_ELEM_SMOOTH) && BM_elem_flag_test(l_b->f, BM_ELEM_SMOOTH)); +} + +static void bm_edge_tag_from_smooth(const float (*fnos)[3], BMEdge *e, const float split_angle_cos) +{ + BLI_assert(e->l != NULL); + BMLoop *l_a = e->l, *l_b = l_a->radial_next; + bool is_smooth = false; + if (bm_edge_is_smooth_no_angle_test(e, l_a, l_b)) { + if (split_angle_cos != -1.0f) { + const float dot = (fnos == NULL) ? dot_v3v3(l_a->f->no, l_b->f->no) : + dot_v3v3(fnos[BM_elem_index_get(l_a->f)], + fnos[BM_elem_index_get(l_b->f)]); + if (dot >= split_angle_cos) { + is_smooth = true; + } + } + else { + is_smooth = true; + } + } + + /* Perform `BM_elem_flag_set(e, BM_ELEM_TAG, is_smooth)` + * NOTE: This will be set by multiple threads however it will be set to the same value. */ + + /* No need for atomics here as this is a single byte. */ + char *hflag_p = &e->head.hflag; + if (is_smooth) { + *hflag_p = *hflag_p | BM_ELEM_TAG; + } + else { + *hflag_p = *hflag_p & ~BM_ELEM_TAG; + } +} + +/** + * A version of #bm_edge_tag_from_smooth that sets sharp edges + * when they would be considered smooth but exceed the split angle . + * + * \note This doesn't have the same atomic requirement as #bm_edge_tag_from_smooth + * since it isn't run from multiple threads at once. + */ +static void bm_edge_tag_from_smooth_and_set_sharp(const float (*fnos)[3], + BMEdge *e, + const float split_angle_cos) +{ + BLI_assert(e->l != NULL); + BMLoop *l_a = e->l, *l_b = l_a->radial_next; + bool is_smooth = false; + if (bm_edge_is_smooth_no_angle_test(e, l_a, l_b)) { + if (split_angle_cos != -1.0f) { + const float dot = (fnos == NULL) ? dot_v3v3(l_a->f->no, l_b->f->no) : + dot_v3v3(fnos[BM_elem_index_get(l_a->f)], + fnos[BM_elem_index_get(l_b->f)]); + if (dot >= split_angle_cos) { + is_smooth = true; + } + else { + /* Note that we do not care about the other sharp-edge cases + * (sharp poly, non-manifold edge, etc.), + * only tag edge as sharp when it is due to angle threshold. */ + BM_elem_flag_disable(e, BM_ELEM_SMOOTH); + } + } + else { + is_smooth = true; + } + } + + BM_elem_flag_set(e, BM_ELEM_TAG, is_smooth); +} + +/** + * Operate on all vertices loops. + * operating on vertices this is needed for multi-threading + * so there is a guarantee that each thread has isolated loops. + */ +static void bm_mesh_loops_calc_normals_for_vert_with_clnors(BMesh *bm, + const float (*vcos)[3], + const float (*fnos)[3], + float (*r_lnos)[3], + const short (*clnors_data)[2], + const int cd_loop_clnors_offset, + const bool do_rebuild, + const float split_angle_cos, + /* TLS */ + MLoopNorSpaceArray *r_lnors_spacearr, + BLI_Stack *edge_vectors, + /* Iterate over. */ + BMVert *v) +{ + /* Respecting face order is necessary so the initial starting loop is consistent + * with looping over loops of all faces. + * + * Logically we could sort the loops by their index & loop over them + * however it's faster to use the lowest index of an un-ordered list + * since it's common that smooth vertices only ever need to pick one loop + * which then handles all the others. + * + * Sorting is only performed when multiple fans are found. */ + const bool has_clnors = true; + LinkNode *loops_of_vert = NULL; + int loops_of_vert_count = 0; + const bool do_edge_tag = (split_angle_cos != EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); + + /* The loop with the lowest index. */ + { + LinkNode *link_best; + uint index_best = UINT_MAX; + BMEdge *e_curr_iter = v->e; + do { /* Edges of vertex. */ + BMLoop *l_curr = e_curr_iter->l; + if (l_curr == NULL) { + continue; + } + + if (do_edge_tag) { + bm_edge_tag_from_smooth(fnos, e_curr_iter, split_angle_cos); + } + + do { /* Radial loops. */ + if (l_curr->v != v) { + continue; + } + if (do_rebuild && !BM_ELEM_API_FLAG_TEST(l_curr, BM_LNORSPACE_UPDATE) && + !(bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL)) { + continue; + } + BM_elem_flag_disable(l_curr, BM_ELEM_TAG); + BLI_linklist_prepend_alloca(&loops_of_vert, l_curr); + loops_of_vert_count += 1; + + const uint index_test = (uint)BM_elem_index_get(l_curr); + if (index_best > index_test) { + index_best = index_test; + link_best = loops_of_vert; + } + } while ((l_curr = l_curr->radial_next) != e_curr_iter->l); + } while ((e_curr_iter = BM_DISK_EDGE_NEXT(e_curr_iter, v)) != v->e); + + if (UNLIKELY(loops_of_vert == NULL)) { + return; + } + + /* Immediately pop the best element. + * The order doesn't matter, so swap the links as it's simpler than tracking + * reference to `link_best`. */ + if (link_best != loops_of_vert) { + SWAP(void *, link_best->link, loops_of_vert->link); + } + } + + bool loops_of_vert_is_sorted = false; + + /* Keep track of the number of loops that have been assigned. */ + int loops_of_vert_handled = 0; + + while (loops_of_vert != NULL) { + BMLoop *l_best = loops_of_vert->link; + loops_of_vert = loops_of_vert->next; + + BLI_assert(l_best->v == v); + loops_of_vert_handled += bm_mesh_loops_calc_normals_for_loop(bm, + vcos, + fnos, + clnors_data, + cd_loop_clnors_offset, + has_clnors, + edge_vectors, + l_best, + r_lnos, + r_lnors_spacearr); + + /* Check if an early exit is possible without an exhaustive inspection of every loop + * where 1 loop's fan extends out to all remaining loops. + * This is a common case for smooth vertices. */ + BLI_assert(loops_of_vert_handled <= loops_of_vert_count); + if (loops_of_vert_handled == loops_of_vert_count) { + break; + } + + /* Note on sorting, in some cases it will be faster to scan for the lowest index each time. + * However in the worst case this is `O(N^2)`, so use a single sort call instead. */ + if (!loops_of_vert_is_sorted) { + if (loops_of_vert && loops_of_vert->next) { + loops_of_vert = BLI_linklist_sort(loops_of_vert, bm_loop_index_cmp); + loops_of_vert_is_sorted = true; + } + } + } +} + +/** + * A simplified version of #bm_mesh_loops_calc_normals_for_vert_with_clnors + * that can operate on loops in any order. + */ +static void bm_mesh_loops_calc_normals_for_vert_without_clnors( + BMesh *bm, + const float (*vcos)[3], + const float (*fnos)[3], + float (*r_lnos)[3], + const bool do_rebuild, + const float split_angle_cos, + /* TLS */ + MLoopNorSpaceArray *r_lnors_spacearr, + BLI_Stack *edge_vectors, + /* Iterate over. */ + BMVert *v) +{ + const bool has_clnors = false; + const short(*clnors_data)[2] = NULL; + const bool do_edge_tag = (split_angle_cos != EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); + const int cd_loop_clnors_offset = -1; + + BMEdge *e_curr_iter; + + /* Unfortunately a loop is needed just to clear loop-tags. */ + e_curr_iter = v->e; + do { /* Edges of vertex. */ + BMLoop *l_curr = e_curr_iter->l; + if (l_curr == NULL) { + continue; + } + + if (do_edge_tag) { + bm_edge_tag_from_smooth(fnos, e_curr_iter, split_angle_cos); + } + + do { /* Radial loops. */ + if (l_curr->v != v) { + continue; + } + BM_elem_flag_disable(l_curr, BM_ELEM_TAG); + } while ((l_curr = l_curr->radial_next) != e_curr_iter->l); + } while ((e_curr_iter = BM_DISK_EDGE_NEXT(e_curr_iter, v)) != v->e); + + e_curr_iter = v->e; + do { /* Edges of vertex. */ + BMLoop *l_curr = e_curr_iter->l; + if (l_curr == NULL) { + continue; + } + do { /* Radial loops. */ + if (l_curr->v != v) { + continue; + } + if (do_rebuild && !BM_ELEM_API_FLAG_TEST(l_curr, BM_LNORSPACE_UPDATE) && + !(bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL)) { + continue; + } + bm_mesh_loops_calc_normals_for_loop(bm, + vcos, + fnos, + clnors_data, + cd_loop_clnors_offset, + has_clnors, + edge_vectors, + l_curr, + r_lnos, + r_lnors_spacearr); + } while ((l_curr = l_curr->radial_next) != e_curr_iter->l); + } while ((e_curr_iter = BM_DISK_EDGE_NEXT(e_curr_iter, v)) != v->e); +} + +/** * BMesh version of BKE_mesh_normals_loop_split() in `mesh_evaluate.cc` * Will use first clnors_data array, and fallback to cd_loop_clnors_offset * (use NULL and -1 to not use clnors). @@ -533,26 +1100,24 @@ bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr) * \note This sets #BM_ELEM_TAG which is used in tool code (e.g. T84426). * we could add a low-level API flag for this, see #BM_ELEM_API_FLAG_ENABLE and friends. */ -static void bm_mesh_loops_calc_normals(BMesh *bm, - const float (*vcos)[3], - const float (*fnos)[3], - float (*r_lnos)[3], - MLoopNorSpaceArray *r_lnors_spacearr, - const short (*clnors_data)[2], - const int cd_loop_clnors_offset, - const bool do_rebuild) +static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm, + const float (*vcos)[3], + const float (*fnos)[3], + float (*r_lnos)[3], + MLoopNorSpaceArray *r_lnors_spacearr, + const short (*clnors_data)[2], + const int cd_loop_clnors_offset, + const bool do_rebuild, + const float split_angle) { BMIter fiter; BMFace *f_curr; const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1); + const bool check_angle = (split_angle < (float)M_PI); + const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f; MLoopNorSpaceArray _lnors_spacearr = {NULL}; - /* Temp normal stack. */ - BLI_SMALLSTACK_DECLARE(normal, float *); - /* Temp clnors stack. */ - BLI_SMALLSTACK_DECLARE(clnors, short *); - /* Temp edge vectors stack, only used when computing lnor spacearr. */ BLI_Stack *edge_vectors = NULL; { @@ -573,6 +1138,10 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, edge_vectors = BLI_stack_new(sizeof(float[3]), __func__); } + if (split_angle_cos != -1.0f) { + bm_mesh_edges_sharp_tag(bm, fnos, has_clnors ? (float)M_PI : split_angle, false); + } + /* Clear all loops' tags (means none are to be skipped for now). */ int index_face, index_loop = 0; BM_ITER_MESH_INDEX (f_curr, &fiter, bm, BM_FACES_OF_MESH, index_face) { @@ -601,277 +1170,249 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, !(bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL)) { continue; } - /* A smooth edge, we have to check for cyclic smooth fan case. - * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge - * as 'entry point', otherwise we can skip it. */ - - /* NOTE: In theory, we could make bm_mesh_loop_check_cyclic_smooth_fan() store - * mlfan_pivot's in a stack, to avoid having to fan again around - * the vert during actual computation of clnor & clnorspace. However, this would complicate - * the code, add more memory usage, and - * BM_vert_step_fan_loop() is quite cheap in term of CPU cycles, - * so really think it's not worth it. */ - if (BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && - (BM_elem_flag_test(l_curr, BM_ELEM_TAG) || !BM_loop_check_cyclic_smooth_fan(l_curr))) { - } - else if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && - !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) { - /* Simple case (both edges around that vertex are sharp in related polygon), - * this vertex just takes its poly normal. - */ - const int l_curr_index = BM_elem_index_get(l_curr); - const float *no = fnos ? fnos[BM_elem_index_get(f_curr)] : f_curr->no; - copy_v3_v3(r_lnos[l_curr_index], no); - - /* If needed, generate this (simple!) lnor space. */ - if (r_lnors_spacearr) { - float vec_curr[3], vec_prev[3]; - MLoopNorSpace *lnor_space = BKE_lnor_space_create(r_lnors_spacearr); - - { - const BMVert *v_pivot = l_curr->v; - const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co; - const BMVert *v_1 = l_curr->next->v; - const float *co_1 = vcos ? vcos[BM_elem_index_get(v_1)] : v_1->co; - const BMVert *v_2 = l_curr->prev->v; - const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co; - - BLI_assert(v_1 == BM_edge_other_vert(l_curr->e, v_pivot)); - BLI_assert(v_2 == BM_edge_other_vert(l_curr->prev->e, v_pivot)); - - sub_v3_v3v3(vec_curr, co_1, co_pivot); - normalize_v3(vec_curr); - sub_v3_v3v3(vec_prev, co_2, co_pivot); - normalize_v3(vec_prev); - } - - BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, NULL); - /* We know there is only one loop in this space, - * no need to create a linklist in this case... */ - BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, l_curr, true); - - if (has_clnors) { - const short(*clnor)[2] = clnors_data ? &clnors_data[l_curr_index] : - (const void *)BM_ELEM_CD_GET_VOID_P( - l_curr, cd_loop_clnors_offset); - BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor, r_lnos[l_curr_index]); - } - } - } - /* We *do not need* to check/tag loops as already computed! - * Due to the fact a loop only links to one of its two edges, - * a same fan *will never be walked more than once!* - * Since we consider edges having neighbor faces with inverted (flipped) normals as sharp, - * we are sure that no fan will be skipped, even only considering the case - * (sharp curr_edge, smooth prev_edge), and not the alternative - * (smooth curr_edge, sharp prev_edge). - * All this due/thanks to link between normals and loop ordering. - */ - else { - /* We have to fan around current vertex, until we find the other non-smooth edge, - * and accumulate face normals into the vertex! - * Note in case this vertex has only one sharp edge, - * this is a waste because the normal is the same as the vertex normal, - * but I do not see any easy way to detect that (would need to count number of sharp edges - * per vertex, I doubt the additional memory usage would be worth it, especially as it - * should not be a common case in real-life meshes anyway). - */ - BMVert *v_pivot = l_curr->v; - BMEdge *e_next; - const BMEdge *e_org = l_curr->e; - BMLoop *lfan_pivot, *lfan_pivot_next; - int lfan_pivot_index; - float lnor[3] = {0.0f, 0.0f, 0.0f}; - float vec_curr[3], vec_next[3], vec_org[3]; - - /* We validate clnors data on the fly - cheapest way to do! */ - int clnors_avg[2] = {0, 0}; - const short(*clnor_ref)[2] = NULL; - int clnors_nbr = 0; - bool clnors_invalid = false; - - const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co; - - MLoopNorSpace *lnor_space = r_lnors_spacearr ? BKE_lnor_space_create(r_lnors_spacearr) : - NULL; - - BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors)); - - lfan_pivot = l_curr; - lfan_pivot_index = BM_elem_index_get(lfan_pivot); - e_next = lfan_pivot->e; /* Current edge here, actually! */ - - /* Only need to compute previous edge's vector once, - * then we can just reuse old current one! */ - { - const BMVert *v_2 = lfan_pivot->next->v; - const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co; - - BLI_assert(v_2 == BM_edge_other_vert(e_next, v_pivot)); - - sub_v3_v3v3(vec_org, co_2, co_pivot); - normalize_v3(vec_org); - copy_v3_v3(vec_curr, vec_org); + bm_mesh_loops_calc_normals_for_loop(bm, + vcos, + fnos, + clnors_data, + cd_loop_clnors_offset, + has_clnors, + edge_vectors, + l_curr, + r_lnos, + r_lnors_spacearr); + } while ((l_curr = l_curr->next) != l_first); + } - if (r_lnors_spacearr) { - BLI_stack_push(edge_vectors, vec_org); - } - } + if (r_lnors_spacearr) { + BLI_stack_free(edge_vectors); + if (r_lnors_spacearr == &_lnors_spacearr) { + BKE_lnor_spacearr_free(r_lnors_spacearr); + } + } +} - while (true) { - /* Much simpler than in sibling code with basic Mesh data! */ - lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); - if (lfan_pivot_next) { - BLI_assert(lfan_pivot_next->v == v_pivot); - } - else { - /* next edge is non-manifold, we have to find it ourselves! */ - e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; - } +typedef struct BMLoopsCalcNormalsWithCoordsData { + /* Read-only data. */ + const float (*fnos)[3]; + const float (*vcos)[3]; + BMesh *bm; + const short (*clnors_data)[2]; + const int cd_loop_clnors_offset; + const bool do_rebuild; + const float split_angle_cos; + + /* Output. */ + float (*r_lnos)[3]; + MLoopNorSpaceArray *r_lnors_spacearr; +} BMLoopsCalcNormalsWithCoordsData; + +typedef struct BMLoopsCalcNormalsWithCoords_TLS { + BLI_Stack *edge_vectors; + + /** Copied from #BMLoopsCalcNormalsWithCoordsData.r_lnors_spacearr when it's not NULL. */ + MLoopNorSpaceArray *lnors_spacearr; + MLoopNorSpaceArray lnors_spacearr_buf; +} BMLoopsCalcNormalsWithCoords_TLS; + +static void bm_mesh_loops_calc_normals_for_vert_init_fn(const void *__restrict userdata, + void *__restrict chunk) +{ + const BMLoopsCalcNormalsWithCoordsData *data = userdata; + BMLoopsCalcNormalsWithCoords_TLS *tls_data = chunk; + if (data->r_lnors_spacearr) { + tls_data->edge_vectors = BLI_stack_new(sizeof(float[3]), __func__); + BKE_lnor_spacearr_tls_init(data->r_lnors_spacearr, &tls_data->lnors_spacearr_buf); + tls_data->lnors_spacearr = &tls_data->lnors_spacearr_buf; + } + else { + tls_data->lnors_spacearr = NULL; + } +} - /* Compute edge vector. - * NOTE: We could pre-compute those into an array, in the first iteration, - * instead of computing them twice (or more) here. - * However, time gained is not worth memory and time lost, - * given the fact that this code should not be called that much in real-life meshes. - */ - { - const BMVert *v_2 = BM_edge_other_vert(e_next, v_pivot); - const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co; +static void bm_mesh_loops_calc_normals_for_vert_reduce_fn(const void *__restrict userdata, + void *__restrict UNUSED(chunk_join), + void *__restrict chunk) +{ + const BMLoopsCalcNormalsWithCoordsData *data = userdata; + BMLoopsCalcNormalsWithCoords_TLS *tls_data = chunk; - sub_v3_v3v3(vec_next, co_2, co_pivot); - normalize_v3(vec_next); - } + if (data->r_lnors_spacearr) { + BKE_lnor_spacearr_tls_join(data->r_lnors_spacearr, tls_data->lnors_spacearr); + } +} - { - /* Code similar to accumulate_vertex_normals_poly_v3. */ - /* Calculate angle between the two poly edges incident on this vertex. */ - const BMFace *f = lfan_pivot->f; - const float fac = saacos(dot_v3v3(vec_next, vec_curr)); - const float *no = fnos ? fnos[BM_elem_index_get(f)] : f->no; - /* Accumulate */ - madd_v3_v3fl(lnor, no, fac); - - if (has_clnors) { - /* Accumulate all clnors, if they are not all equal we have to fix that! */ - const short(*clnor)[2] = clnors_data ? &clnors_data[lfan_pivot_index] : - (const void *)BM_ELEM_CD_GET_VOID_P( - lfan_pivot, cd_loop_clnors_offset); - if (clnors_nbr) { - clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || - (*clnor_ref)[1] != (*clnor)[1]); - } - else { - clnor_ref = clnor; - } - clnors_avg[0] += (*clnor)[0]; - clnors_avg[1] += (*clnor)[1]; - clnors_nbr++; - /* We store here a pointer to all custom lnors processed. */ - BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor); - } - } +static void bm_mesh_loops_calc_normals_for_vert_free_fn(const void *__restrict userdata, + void *__restrict chunk) +{ + const BMLoopsCalcNormalsWithCoordsData *data = userdata; + BMLoopsCalcNormalsWithCoords_TLS *tls_data = chunk; - /* We store here a pointer to all loop-normals processed. */ - BLI_SMALLSTACK_PUSH(normal, (float *)r_lnos[lfan_pivot_index]); + if (data->r_lnors_spacearr) { + BLI_stack_free(tls_data->edge_vectors); + } +} - if (r_lnors_spacearr) { - /* Assign current lnor space to current 'vertex' loop. */ - BKE_lnor_space_add_loop( - r_lnors_spacearr, lnor_space, lfan_pivot_index, lfan_pivot, false); - if (e_next != e_org) { - /* We store here all edges-normalized vectors processed. */ - BLI_stack_push(edge_vectors, vec_next); - } - } +static void bm_mesh_loops_calc_normals_for_vert_with_clnors_fn( + void *userdata, MempoolIterData *mp_v, const TaskParallelTLS *__restrict tls) +{ + BMVert *v = (BMVert *)mp_v; + if (v->e == NULL) { + return; + } + BMLoopsCalcNormalsWithCoordsData *data = userdata; + BMLoopsCalcNormalsWithCoords_TLS *tls_data = tls->userdata_chunk; + bm_mesh_loops_calc_normals_for_vert_with_clnors(data->bm, + data->vcos, + data->fnos, + data->r_lnos, + + data->clnors_data, + data->cd_loop_clnors_offset, + data->do_rebuild, + data->split_angle_cos, + /* Thread local. */ + tls_data->lnors_spacearr, + tls_data->edge_vectors, + /* Iterate over. */ + v); +} - if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { - /* Next edge is sharp, we have finished with this fan of faces around this vert! */ - break; - } +static void bm_mesh_loops_calc_normals_for_vert_without_clnors_fn( + void *userdata, MempoolIterData *mp_v, const TaskParallelTLS *__restrict tls) +{ + BMVert *v = (BMVert *)mp_v; + if (v->e == NULL) { + return; + } + BMLoopsCalcNormalsWithCoordsData *data = userdata; + BMLoopsCalcNormalsWithCoords_TLS *tls_data = tls->userdata_chunk; + bm_mesh_loops_calc_normals_for_vert_without_clnors(data->bm, + data->vcos, + data->fnos, + data->r_lnos, + + data->do_rebuild, + data->split_angle_cos, + /* Thread local. */ + tls_data->lnors_spacearr, + tls_data->edge_vectors, + /* Iterate over. */ + v); +} - /* Copy next edge vector to current one. */ - copy_v3_v3(vec_curr, vec_next); - /* Next pivot loop to current one. */ - lfan_pivot = lfan_pivot_next; - lfan_pivot_index = BM_elem_index_get(lfan_pivot); - } +static void bm_mesh_loops_calc_normals__multi_threaded(BMesh *bm, + const float (*vcos)[3], + const float (*fnos)[3], + float (*r_lnos)[3], + MLoopNorSpaceArray *r_lnors_spacearr, + const short (*clnors_data)[2], + const int cd_loop_clnors_offset, + const bool do_rebuild, + const float split_angle) +{ + const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1); + const bool check_angle = (split_angle < (float)M_PI); + const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f; - { - float lnor_len = normalize_v3(lnor); + MLoopNorSpaceArray _lnors_spacearr = {NULL}; - /* If we are generating lnor spacearr, we can now define the one for this fan. */ - if (r_lnors_spacearr) { - if (UNLIKELY(lnor_len == 0.0f)) { - /* Use vertex normal as fallback! */ - copy_v3_v3(lnor, r_lnos[lfan_pivot_index]); - lnor_len = 1.0f; - } + { + char htype = BM_LOOP; + if (vcos) { + htype |= BM_VERT; + } + if (fnos) { + htype |= BM_FACE; + } + /* Face/Loop indices are set inline below. */ + BM_mesh_elem_index_ensure(bm, htype); + } - BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_next, edge_vectors); - - if (has_clnors) { - if (clnors_invalid) { - short *clnor; - - clnors_avg[0] /= clnors_nbr; - clnors_avg[1] /= clnors_nbr; - /* Fix/update all clnors of this fan with computed average value. */ - - /* Prints continuously when merge custom normals, so commenting. */ - /* printf("Invalid clnors in this fan!\n"); */ - - while ((clnor = BLI_SMALLSTACK_POP(clnors))) { - // print_v2("org clnor", clnor); - clnor[0] = (short)clnors_avg[0]; - clnor[1] = (short)clnors_avg[1]; - } - // print_v2("new clnors", clnors_avg); - } - else { - /* We still have to consume the stack! */ - while (BLI_SMALLSTACK_POP(clnors)) { - /* pass */ - } - } - BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor); - } - } + if (!r_lnors_spacearr && has_clnors) { + /* We need to compute lnor spacearr if some custom lnor data are given to us! */ + r_lnors_spacearr = &_lnors_spacearr; + } + if (r_lnors_spacearr) { + BKE_lnor_spacearr_init(r_lnors_spacearr, bm->totloop, MLNOR_SPACEARR_BMLOOP_PTR); + } - /* In case we get a zero normal here, just use vertex normal already set! */ - if (LIKELY(lnor_len != 0.0f)) { - /* Copy back the final computed normal into all related loop-normals. */ - float *nor; + /* We now know edges that can be smoothed (they are tagged), + * and edges that will be hard (they aren't). + * Now, time to generate the normals. + */ - while ((nor = BLI_SMALLSTACK_POP(normal))) { - copy_v3_v3(nor, lnor); - } - } - else { - /* We still have to consume the stack! */ - while (BLI_SMALLSTACK_POP(normal)) { - /* pass */ - } - } - } + TaskParallelSettings settings; + BLI_parallel_mempool_settings_defaults(&settings); - /* Tag related vertex as sharp, to avoid fanning around it again - * (in case it was a smooth one). */ - if (r_lnors_spacearr) { - BM_elem_flag_enable(l_curr->v, BM_ELEM_TAG); - } - } - } while ((l_curr = l_curr->next) != l_first); - } + BMLoopsCalcNormalsWithCoords_TLS tls = {NULL}; + + settings.userdata_chunk = &tls; + settings.userdata_chunk_size = sizeof(tls); + + settings.func_init = bm_mesh_loops_calc_normals_for_vert_init_fn; + settings.func_reduce = bm_mesh_loops_calc_normals_for_vert_reduce_fn; + settings.func_free = bm_mesh_loops_calc_normals_for_vert_free_fn; + + BMLoopsCalcNormalsWithCoordsData data = { + .bm = bm, + .vcos = vcos, + .fnos = fnos, + .r_lnos = r_lnos, + .r_lnors_spacearr = r_lnors_spacearr, + .clnors_data = clnors_data, + .cd_loop_clnors_offset = cd_loop_clnors_offset, + .do_rebuild = do_rebuild, + .split_angle_cos = split_angle_cos, + }; + + BM_iter_parallel(bm, + BM_VERTS_OF_MESH, + has_clnors ? bm_mesh_loops_calc_normals_for_vert_with_clnors_fn : + bm_mesh_loops_calc_normals_for_vert_without_clnors_fn, + &data, + &settings); if (r_lnors_spacearr) { - BLI_stack_free(edge_vectors); if (r_lnors_spacearr == &_lnors_spacearr) { BKE_lnor_spacearr_free(r_lnors_spacearr); } } } +static void bm_mesh_loops_calc_normals(BMesh *bm, + const float (*vcos)[3], + const float (*fnos)[3], + float (*r_lnos)[3], + MLoopNorSpaceArray *r_lnors_spacearr, + const short (*clnors_data)[2], + const int cd_loop_clnors_offset, + const bool do_rebuild, + const float split_angle) +{ + if (bm->totloop < BM_OMP_LIMIT) { + bm_mesh_loops_calc_normals__single_threaded(bm, + vcos, + fnos, + r_lnos, + r_lnors_spacearr, + clnors_data, + cd_loop_clnors_offset, + do_rebuild, + split_angle); + } + else { + bm_mesh_loops_calc_normals__multi_threaded(bm, + vcos, + fnos, + r_lnos, + r_lnors_spacearr, + clnors_data, + cd_loop_clnors_offset, + do_rebuild, + split_angle); + } +} + /* This threshold is a bit touchy (usual float precision issue), this value seems OK. */ #define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f) @@ -1062,7 +1603,6 @@ static void bm_mesh_loops_assign_normal_data(BMesh *bm, */ static void bm_mesh_loops_custom_normals_set(BMesh *bm, const float (*vcos)[3], - const float (*vnos)[3], const float (*fnos)[3], MLoopNorSpaceArray *r_lnors_spacearr, short (*r_clnors_data)[2], @@ -1080,12 +1620,19 @@ static void bm_mesh_loops_custom_normals_set(BMesh *bm, /* Tag smooth edges and set lnos from vnos when they might be completely smooth... * When using custom loop normals, disable the angle feature! */ - bm_mesh_edges_sharp_tag(bm, vnos, fnos, cur_lnors, (float)M_PI, false); + bm_mesh_edges_sharp_tag(bm, fnos, (float)M_PI, false); /* Finish computing lnos by accumulating face normals * in each fan of faces defined by sharp edges. */ - bm_mesh_loops_calc_normals( - bm, vcos, fnos, cur_lnors, r_lnors_spacearr, r_clnors_data, cd_loop_clnors_offset, false); + bm_mesh_loops_calc_normals(bm, + vcos, + fnos, + cur_lnors, + r_lnors_spacearr, + r_clnors_data, + cd_loop_clnors_offset, + false, + EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); /* Extract new normals from the data layer if necessary. */ float(*custom_lnors)[3] = new_lnors; @@ -1118,8 +1665,15 @@ static void bm_mesh_loops_custom_normals_set(BMesh *bm, * spacearr/smooth fans matching the given custom lnors. */ BKE_lnor_spacearr_clear(r_lnors_spacearr); - bm_mesh_loops_calc_normals( - bm, vcos, fnos, cur_lnors, r_lnors_spacearr, r_clnors_data, cd_loop_clnors_offset, false); + bm_mesh_loops_calc_normals(bm, + vcos, + fnos, + cur_lnors, + r_lnors_spacearr, + r_clnors_data, + cd_loop_clnors_offset, + false, + EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); } /* And we just have to convert plain object-space custom normals to our @@ -1167,40 +1721,6 @@ static void bm_mesh_loops_calc_normals_no_autosmooth(BMesh *bm, } } -#if 0 /* Unused currently */ -/** - * \brief BMesh Compute Loop Normals - * - * Updates the loop normals of a mesh. - * Assumes vertex and face normals are valid (else call BM_mesh_normals_update() first)! - */ -void BM_mesh_loop_normals_update(BMesh *bm, - const bool use_split_normals, - const float split_angle, - float (*r_lnos)[3], - MLoopNorSpaceArray *r_lnors_spacearr, - const short (*clnors_data)[2], - const int cd_loop_clnors_offset) -{ - const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1); - - if (use_split_normals) { - /* Tag smooth edges and set lnos from vnos when they might be completely smooth... - * When using custom loop normals, disable the angle feature! */ - bm_mesh_edges_sharp_tag(bm, NULL, NULL, has_clnors ? (float)M_PI : split_angle, r_lnos); - - /* Finish computing lnos by accumulating face normals - * in each fan of faces defined by sharp edges. */ - bm_mesh_loops_calc_normals( - bm, NULL, NULL, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset); - } - else { - BLI_assert(!r_lnors_spacearr); - bm_mesh_loops_calc_normals_no_autosmooth(bm, NULL, NULL, r_lnos); - } -} -#endif - /** * \brief BMesh Compute Loop Normals from/to external data. * @@ -1223,14 +1743,15 @@ void BM_loops_calc_normal_vcos(BMesh *bm, const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1); if (use_split_normals) { - /* Tag smooth edges and set lnos from vnos when they might be completely smooth... - * When using custom loop normals, disable the angle feature! */ - bm_mesh_edges_sharp_tag(bm, vnos, fnos, r_lnos, has_clnors ? (float)M_PI : split_angle, false); - - /* Finish computing lnos by accumulating face normals - * in each fan of faces defined by sharp edges. */ - bm_mesh_loops_calc_normals( - bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset, do_rebuild); + bm_mesh_loops_calc_normals(bm, + vcos, + fnos, + r_lnos, + r_lnors_spacearr, + clnors_data, + cd_loop_clnors_offset, + do_rebuild, + has_clnors ? (float)M_PI : split_angle); } else { BLI_assert(!r_lnors_spacearr); @@ -1788,7 +2309,6 @@ void BM_custom_loop_normals_from_vector_layer(BMesh *bm, bool add_sharp_edges) bm_mesh_loops_custom_normals_set(bm, NULL, NULL, - NULL, bm->lnor_spacearr, NULL, cd_custom_normal_offset, diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 3978959a425..b63a09a97a6 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -245,7 +245,7 @@ static BMOpDefine bmo_region_extend_def = { * Edge Rotate. * * Rotates edges topologically. Also known as "spin edge" to some people. - * Simple example: ``[/] becomes [|] then [\]``. + * Simple example: `[/] becomes [|] then [\]`. */ static BMOpDefine bmo_rotate_edges_def = { "rotate_edges", @@ -1942,7 +1942,7 @@ static BMOpDefine bmo_inset_region_def = { }; /* - * Edgeloop Offset. + * Edge-loop Offset. * * Creates edge loops based on simple edge-outset method. */ diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index 0aab10e7b1a..51ae47adacc 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -316,7 +316,7 @@ float BM_face_calc_perimeter_with_mat3(const BMFace *f, const float mat3[3][3]) /** * Utility function to calculate the edge which is most different from the other two. * - * \return The first edge index, where the second vertex is ``(index + 1) % 3``. + * \return The first edge index, where the second vertex is `(index + 1) % 3`. */ static int bm_vert_tri_find_unique_edge(BMVert *verts[3]) { diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c index bc881040e4e..cb5764b1c91 100644 --- a/source/blender/bmesh/intern/bmesh_query.c +++ b/source/blender/bmesh/intern/bmesh_query.c @@ -766,7 +766,7 @@ bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb) } /** - * Fast alternative to ``(BM_vert_edge_count(v) == 2)`` + * Fast alternative to `(BM_vert_edge_count(v) == 2)`. */ bool BM_vert_is_edge_pair(const BMVert *v) { @@ -779,7 +779,7 @@ bool BM_vert_is_edge_pair(const BMVert *v) } /** - * Fast alternative to ``(BM_vert_edge_count(v) == 2)`` + * Fast alternative to `(BM_vert_edge_count(v) == 2)` * that checks both edges connect to the same faces. */ bool BM_vert_is_edge_pair_manifold(const BMVert *v) @@ -896,7 +896,7 @@ int BM_vert_face_count_at_most(const BMVert *v, int count_max) /** * Return true if the vertex is connected to _any_ faces. * - * same as ``BM_vert_face_count(v) != 0`` or ``BM_vert_find_first_loop(v) == NULL`` + * same as `BM_vert_face_count(v) != 0` or `BM_vert_find_first_loop(v) == NULL`. */ bool BM_vert_face_check(const BMVert *v) { diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h index 5627f3820c2..021358f81ad 100644 --- a/source/blender/bmesh/intern/bmesh_query.h +++ b/source/blender/bmesh/intern/bmesh_query.h @@ -272,7 +272,7 @@ int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm, int (**r_groups)[3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3, 4, 5); -/* not really any good place to put this */ +/* Not really any good place to put this. */ float bmesh_subd_falloff_calc(const int falloff, float val) ATTR_WARN_UNUSED_RESULT; #include "bmesh_query_inline.h" diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c index cfdce0b749b..d5d72cd4ba3 100644 --- a/source/blender/bmesh/intern/bmesh_structure.c +++ b/source/blender/bmesh/intern/bmesh_structure.c @@ -592,7 +592,7 @@ int bmesh_radial_facevert_count_at_most(const BMLoop *l, const BMVert *v, const /** * \brief RADIAL CHECK FACE VERT * - * Quicker check for ``bmesh_radial_facevert_count(...) != 0`` + * Quicker check for `bmesh_radial_facevert_count(...) != 0`. */ bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v) { diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c index 4ae5bfb7fb2..924538490ad 100644 --- a/source/blender/bmesh/tools/bmesh_region_match.c +++ b/source/blender/bmesh/tools/bmesh_region_match.c @@ -1336,7 +1336,7 @@ static void bm_vert_fasthash_destroy(UUIDFashMatch *fm) * Take a face-region and return a list of matching face-regions. * * \param faces_region: A single, contiguous face-region. - * \return A list of matching null-terminated face-region arrays. + * \return A list of matching null-terminated face-region arrays. */ int BM_mesh_region_match(BMesh *bm, BMFace **faces_region, diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index 20b56ceb55f..830792a2a48 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -49,8 +49,11 @@ set(SRC COM_compositor.h COM_defines.h + intern/COM_BufferArea.h intern/COM_BufferOperation.cc intern/COM_BufferOperation.h + intern/COM_BufferRange.h + intern/COM_BuffersIterator.h intern/COM_CPUDevice.cc intern/COM_CPUDevice.h intern/COM_ChunkOrder.cc diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h index 9f8e6f10215..900f29db44c 100644 --- a/source/blender/compositor/COM_defines.h +++ b/source/blender/compositor/COM_defines.h @@ -18,6 +18,9 @@ #pragma once +#include "BLI_index_range.hh" +#include "BLI_rect.h" + namespace blender::compositor { enum class eExecutionModel { @@ -63,6 +66,7 @@ constexpr int COM_DATA_TYPE_VALUE_CHANNELS = COM_data_type_num_channels(DataType constexpr int COM_DATA_TYPE_VECTOR_CHANNELS = COM_data_type_num_channels(DataType::Vector); constexpr int COM_DATA_TYPE_COLOR_CHANNELS = COM_data_type_num_channels(DataType::Color); +constexpr float COM_COLOR_TRANSPARENT[4] = {0.0f, 0.0f, 0.0f, 0.0f}; constexpr float COM_VECTOR_ZERO[3] = {0.0f, 0.0f, 0.0f}; constexpr float COM_VALUE_ZERO[1] = {0.0f}; constexpr float COM_VALUE_ONE[1] = {1.0f}; @@ -109,4 +113,24 @@ constexpr float COM_PREVIEW_SIZE = 140.f; constexpr float COM_RULE_OF_THIRDS_DIVIDER = 100.0f; constexpr float COM_BLUR_BOKEH_PIXELS = 512; +constexpr IndexRange XRange(const rcti &area) +{ + return IndexRange(area.xmin, area.xmax - area.xmin); +} + +constexpr IndexRange YRange(const rcti &area) +{ + return IndexRange(area.ymin, area.ymax - area.ymin); +} + +constexpr IndexRange XRange(const rcti *area) +{ + return XRange(*area); +} + +constexpr IndexRange YRange(const rcti *area) +{ + return YRange(*area); +} + } // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_BufferArea.h b/source/blender/compositor/intern/COM_BufferArea.h new file mode 100644 index 00000000000..6f7756ecbfc --- /dev/null +++ b/source/blender/compositor/intern/COM_BufferArea.h @@ -0,0 +1,215 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#pragma once + +#include "BLI_assert.h" +#include "BLI_rect.h" +#include <iterator> + +namespace blender::compositor { + +/* Forward declarations. */ +template<typename T> class BufferAreaIterator; + +/** + * A rectangle area of buffer elements. + */ +template<typename T> class BufferArea : rcti { + public: + using Iterator = BufferAreaIterator<T>; + using ConstIterator = BufferAreaIterator<const T>; + + private: + T *buffer_; + /* Number of elements in a buffer row. */ + int buffer_width_; + /* Buffer element stride. */ + int elem_stride_; + + public: + constexpr BufferArea() = default; + + /** + * Create a buffer area containing given rectangle area. + */ + constexpr BufferArea(T *buffer, int buffer_width, const rcti &area, int elem_stride = 1) + : rcti(area), buffer_(buffer), buffer_width_(buffer_width), elem_stride_(elem_stride) + { + } + + /** + * Create a buffer area containing whole buffer with no offsets. + */ + constexpr BufferArea(T *buffer, int buffer_width, int buffer_height, int elem_stride = 1) + : buffer_(buffer), buffer_width_(buffer_width), elem_stride_(elem_stride) + { + BLI_rcti_init(this, 0, buffer_width, 0, buffer_height); + } + + constexpr friend bool operator==(const BufferArea &a, const BufferArea &b) + { + return a.buffer_ == b.buffer_ && BLI_rcti_compare(&a, &b) && a.elem_stride_ == b.elem_stride_; + } + + constexpr const rcti &get_rect() const + { + return *this; + } + + /** + * Number of elements in a row. + */ + constexpr int width() const + { + return BLI_rcti_size_x(this); + } + + /** + * Number of elements in a column. + */ + constexpr int height() const + { + return BLI_rcti_size_y(this); + } + + constexpr Iterator begin() + { + return begin_iterator<Iterator>(); + } + + constexpr Iterator end() + { + return end_iterator<Iterator>(); + } + + constexpr ConstIterator begin() const + { + return begin_iterator<ConstIterator>(); + } + + constexpr ConstIterator end() const + { + return end_iterator<ConstIterator>(); + } + + private: + template<typename TIterator> constexpr TIterator begin_iterator() const + { + T *end_ptr = get_end_ptr(); + if (elem_stride_ == 0) { + /* Iterate a single element. */ + return TIterator(buffer_, end_ptr, 1, 1, 1); + } + + T *begin_ptr = buffer_ + (intptr_t)this->ymin * buffer_width_ * elem_stride_ + + (intptr_t)this->xmin * elem_stride_; + return TIterator(begin_ptr, end_ptr, buffer_width_, BLI_rcti_size_x(this), elem_stride_); + } + + template<typename TIterator> constexpr TIterator end_iterator() const + { + T *end_ptr = get_end_ptr(); + if (elem_stride_ == 0) { + /* Iterate a single element. */ + return TIterator(end_ptr, end_ptr, 1, 1, 1); + } + + return TIterator(end_ptr, end_ptr, buffer_width_, BLI_rcti_size_x(this), elem_stride_); + } + + T *get_end_ptr() const + { + if (elem_stride_ == 0) { + return buffer_ + 1; + } + return buffer_ + (intptr_t)(this->ymax - 1) * buffer_width_ * elem_stride_ + + (intptr_t)this->xmax * elem_stride_; + } +}; + +template<typename T> class BufferAreaIterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = T *; + using pointer = T *const *; + using reference = T *const &; + using difference_type = std::ptrdiff_t; + + private: + int elem_stride_; + int row_stride_; + /* Stride between a row end and the next row start. */ + int rows_gap_; + T *current_; + const T *row_end_; + const T *end_; + + public: + constexpr BufferAreaIterator() = default; + + constexpr BufferAreaIterator( + T *current, const T *end, int buffer_width, int area_width, int elem_stride = 1) + : elem_stride_(elem_stride), + row_stride_(buffer_width * elem_stride), + rows_gap_(row_stride_ - area_width * elem_stride), + current_(current), + row_end_(current + area_width * elem_stride), + end_(end) + { + } + + constexpr BufferAreaIterator &operator++() + { + current_ += elem_stride_; + BLI_assert(current_ <= row_end_); + if (current_ == row_end_) { + BLI_assert(current_ <= end_); + if (current_ == end_) { + return *this; + } + current_ += rows_gap_; + row_end_ += row_stride_; + } + return *this; + } + + constexpr BufferAreaIterator operator++(int) const + { + BufferAreaIterator copied_iterator = *this; + ++copied_iterator; + return copied_iterator; + } + + constexpr friend bool operator!=(const BufferAreaIterator &a, const BufferAreaIterator &b) + { + return a.current_ != b.current_; + } + + constexpr friend bool operator==(const BufferAreaIterator &a, const BufferAreaIterator &b) + { + return a.current_ == b.current_; + } + + constexpr T *operator*() const + { + return current_; + } +}; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_BufferRange.h b/source/blender/compositor/intern/COM_BufferRange.h new file mode 100644 index 00000000000..ffdf1f2f1e5 --- /dev/null +++ b/source/blender/compositor/intern/COM_BufferRange.h @@ -0,0 +1,171 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#pragma once + +#include "BLI_assert.h" +#include "BLI_rect.h" + +#include <iterator> + +namespace blender::compositor { + +/* Forward declarations. */ +template<typename T> class BufferRangeIterator; + +/** + * A range of buffer elements. + */ +template<typename T> class BufferRange { + public: + using Iterator = BufferRangeIterator<T>; + using ConstIterator = BufferRangeIterator<const T>; + + private: + T *start_; + /* Number of elements in the range. */ + int64_t size_; + /* Buffer element stride. */ + int elem_stride_; + + public: + constexpr BufferRange() = default; + + /** + * Create a buffer range of elements from a given element index. + */ + constexpr BufferRange(T *buffer, int64_t start_elem_index, int64_t size, int elem_stride = 1) + : start_(buffer + start_elem_index * elem_stride), size_(size), elem_stride_(elem_stride) + { + } + + constexpr friend bool operator==(const BufferRange &a, const BufferRange &b) + { + return a.start_ == b.start_ && a.size_ == b.size_ && a.elem_stride_ == b.elem_stride_; + } + + /** + * Access an element in the range. Index is relative to range start. + */ + constexpr T *operator[](int64_t index) const + { + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + return start_ + index * elem_stride_; + } + + /** + * Get the number of elements in the range. + */ + constexpr int64_t size() const + { + return size_; + } + + constexpr Iterator begin() + { + return begin_iterator<Iterator>(); + } + + constexpr Iterator end() + { + return end_iterator<Iterator>(); + } + + constexpr ConstIterator begin() const + { + return begin_iterator<ConstIterator>(); + } + + constexpr ConstIterator end() const + { + return end_iterator<ConstIterator>(); + } + + private: + template<typename TIterator> constexpr TIterator begin_iterator() const + { + if (elem_stride_ == 0) { + /* Iterate a single element. */ + return TIterator(start_, 1); + } + + return TIterator(start_, elem_stride_); + } + + template<typename TIterator> constexpr TIterator end_iterator() const + { + if (elem_stride_ == 0) { + /* Iterate a single element. */ + return TIterator(start_ + 1, 1); + } + + return TIterator(start_ + size_ * elem_stride_, elem_stride_); + } +}; + +template<typename T> class BufferRangeIterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = T *; + using pointer = T *const *; + using reference = T *const &; + using difference_type = std::ptrdiff_t; + + private: + T *current_; + int elem_stride_; + + public: + constexpr BufferRangeIterator() = default; + + constexpr BufferRangeIterator(T *current, int elem_stride = 1) + : current_(current), elem_stride_(elem_stride) + { + } + + constexpr BufferRangeIterator &operator++() + { + current_ += elem_stride_; + return *this; + } + + constexpr BufferRangeIterator operator++(int) const + { + BufferRangeIterator copied_iterator = *this; + ++copied_iterator; + return copied_iterator; + } + + constexpr friend bool operator!=(const BufferRangeIterator &a, const BufferRangeIterator &b) + { + return a.current_ != b.current_; + } + + constexpr friend bool operator==(const BufferRangeIterator &a, const BufferRangeIterator &b) + { + return a.current_ == b.current_; + } + + constexpr T *operator*() const + { + return current_; + } +}; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_BuffersIterator.h b/source/blender/compositor/intern/COM_BuffersIterator.h new file mode 100644 index 00000000000..bfe0b7a3d45 --- /dev/null +++ b/source/blender/compositor/intern/COM_BuffersIterator.h @@ -0,0 +1,195 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#pragma once + +#include "BLI_rect.h" +#include "BLI_vector.hh" + +namespace blender::compositor { + +/** + * Builds an iterator for simultaneously iterating an area of elements in an output buffer and any + * number of input buffers. It's not a standard C++ iterator and it does not support neither + * deference, equality or postfix increment operators. + */ +template<typename T> class BuffersIteratorBuilder { + public: + class Iterator { + int x_start_; + int x_end_; + const T *out_end_; + int out_elem_stride_; + /* Stride between an output row end and the next row start. */ + int out_rows_gap_; + + struct In { + int elem_stride; + int rows_gap; + const T *in; + }; + Vector<In, 6> ins_; + + friend class BuffersIteratorBuilder; + + public: + int x; + int y; + /** Current output element. */ + T *out; + + public: + /** + * Get current element from an input. + */ + const T *in(int input_index) const + { + BLI_assert(input_index < ins_.size()); + return ins_[input_index].in; + } + + int get_num_inputs() const + { + return ins_.size(); + } + + /** + * Has the end of the area been reached. + */ + bool is_end() const + { + return out >= out_end_; + } + + /** + * Go to the next element in the area. + */ + void next() + { + out += out_elem_stride_; + for (In &in : ins_) { + in.in += in.elem_stride; + } + x++; + if (x == x_end_) { + x = x_start_; + y++; + out += out_rows_gap_; + for (In &in : ins_) { + in.in += in.rows_gap; + } + } + } + + Iterator &operator++() + { + this->next(); + return *this; + } + }; + + private: + Iterator iterator_; + rcti area_; + bool is_built_; + + public: + /** + * Create a buffers iterator builder to iterate given output buffer area. + * \param output: Output buffer. + * \param buffer_area: Whole output buffer area (may have offset position). + * \param iterated_area: Area to be iterated in all buffers. + * \param elem_stride: Output buffer element stride. + */ + BuffersIteratorBuilder(T *output, + const rcti &buffer_area, + const rcti &iterated_area, + int elem_stride = 1) + : area_(iterated_area), is_built_(false) + { + BLI_assert(BLI_rcti_inside_rcti(&buffer_area, &iterated_area)); + iterator_.x = iterated_area.xmin; + iterator_.y = iterated_area.ymin; + iterator_.x_start_ = iterated_area.xmin; + iterator_.x_end_ = iterated_area.xmax; + + iterator_.out_elem_stride_ = elem_stride; + const int buffer_width = BLI_rcti_size_x(&buffer_area); + intptr_t out_row_stride = buffer_width * elem_stride; + iterator_.out_rows_gap_ = out_row_stride - BLI_rcti_size_x(&iterated_area) * elem_stride; + const int out_start_x = iterated_area.xmin - buffer_area.xmin; + const int out_start_y = iterated_area.ymin - buffer_area.ymin; + iterator_.out = output + (intptr_t)out_start_y * out_row_stride + + (intptr_t)out_start_x * elem_stride; + const T *out_row_end_ = iterator_.out + + (intptr_t)BLI_rcti_size_x(&iterated_area) * elem_stride; + iterator_.out_end_ = out_row_end_ + + (intptr_t)out_row_stride * (BLI_rcti_size_y(&iterated_area) - 1); + } + + /** + * Create a buffers iterator builder to iterate given output buffer with no offsets. + */ + BuffersIteratorBuilder(T *output, int buffer_width, int buffer_height, int elem_stride = 1) + : BuffersIteratorBuilder(output, + {0, buffer_width, 0, buffer_height}, + {0, buffer_width, 0, buffer_height}, + elem_stride) + { + } + + /** + * Add an input buffer to be iterated. It must contain iterated area. + */ + void add_input(const T *input, const rcti &buffer_area, int elem_stride = 1) + { + BLI_assert(!is_built_); + BLI_assert(BLI_rcti_inside_rcti(&buffer_area, &area_)); + typename Iterator::In in; + in.elem_stride = elem_stride; + const int buffer_width = BLI_rcti_size_x(&buffer_area); + in.rows_gap = buffer_width * elem_stride - BLI_rcti_size_x(&area_) * elem_stride; + const int in_start_x = area_.xmin - buffer_area.xmin; + const int in_start_y = area_.ymin - buffer_area.ymin; + in.in = input + in_start_y * buffer_width * elem_stride + in_start_x * elem_stride; + iterator_.ins_.append(std::move(in)); + } + + /** + * Add an input buffer to be iterated with no offsets. It must contain iterated area. + */ + void add_input(const T *input, int buffer_width, int elem_stride = 1) + { + rcti buffer_area; + BLI_rcti_init(&buffer_area, 0, buffer_width, 0, area_.ymax); + add_input(input, buffer_area, elem_stride); + } + + /** + * Build the iterator. + */ + BuffersIteratorBuilder::Iterator build() + { + is_built_ = true; + return iterator_; + } +}; + +template<typename T> using BuffersIterator = typename BuffersIteratorBuilder<T>::Iterator; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_ConstantFolder.cc b/source/blender/compositor/intern/COM_ConstantFolder.cc index f20324de342..15450572958 100644 --- a/source/blender/compositor/intern/COM_ConstantFolder.cc +++ b/source/blender/compositor/intern/COM_ConstantFolder.cc @@ -53,12 +53,12 @@ static bool is_constant_foldable(NodeOperation *operation) return false; } -static Vector<NodeOperation *> find_constant_foldable_operations(Span<NodeOperation *> operations) +static Set<NodeOperation *> find_constant_foldable_operations(Span<NodeOperation *> operations) { - Vector<NodeOperation *> foldable_ops; + Set<NodeOperation *> foldable_ops; for (NodeOperation *op : operations) { if (is_constant_foldable(op)) { - foldable_ops.append(op); + foldable_ops.add(op); } } return foldable_ops; @@ -132,7 +132,7 @@ Vector<MemoryBuffer *> ConstantFolder::get_constant_input_buffers(NodeOperation /** Returns constant operations resulted from folded operations. */ Vector<ConstantOperation *> ConstantFolder::try_fold_operations(Span<NodeOperation *> operations) { - Vector<NodeOperation *> foldable_ops = find_constant_foldable_operations(operations); + Set<NodeOperation *> foldable_ops = find_constant_foldable_operations(operations); if (foldable_ops.size() == 0) { return Vector<ConstantOperation *>(); } diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc index abef4517b3e..c0460aed4a4 100644 --- a/source/blender/compositor/intern/COM_Debug.cc +++ b/source/blender/compositor/intern/COM_Debug.cc @@ -31,6 +31,8 @@ extern "C" { #include "BKE_appdir.h" #include "BKE_node.h" #include "DNA_node_types.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" } #include "COM_ExecutionSystem.h" @@ -50,7 +52,7 @@ std::string DebugInfo::m_current_node_name; std::string DebugInfo::m_current_op_name; DebugInfo::GroupStateMap DebugInfo::m_group_states; -static std::string operation_class_name(NodeOperation *op) +static std::string operation_class_name(const NodeOperation *op) { std::string full_name = typeid(*op).name(); /* Remove name-spaces. */ @@ -452,4 +454,45 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name) } } +static std::string get_operations_export_dir() +{ + return std::string(BKE_tempdir_session()) + "COM_operations" + SEP_STR; +} + +void DebugInfo::export_operation(const NodeOperation *op, MemoryBuffer *render) +{ + ImBuf *ibuf = IMB_allocFromBuffer(nullptr, + render->getBuffer(), + render->getWidth(), + render->getHeight(), + render->get_num_channels()); + + const std::string file_name = operation_class_name(op) + "_" + std::to_string(op->get_id()) + + ".png"; + const std::string path = get_operations_export_dir() + file_name; + BLI_make_existing_file(path.c_str()); + IMB_saveiff(ibuf, path.c_str(), ibuf->flags); + IMB_freeImBuf(ibuf); +} + +void DebugInfo::delete_operation_exports() +{ + const std::string dir = get_operations_export_dir(); + if (BLI_exists(dir.c_str())) { + struct direntry *file_list; + int num_files = BLI_filelist_dir_contents(dir.c_str(), &file_list); + for (int i = 0; i < num_files; i++) { + direntry *file = &file_list[i]; + const eFileAttributes file_attrs = BLI_file_attributes(file->path); + if (file_attrs & FILE_ATTR_ANY_LINK) { + continue; + } + + if (BLI_is_file(file->path) && BLI_path_extension_check(file->path, ".png")) { + BLI_delete(file->path, false, false); + } + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_Debug.h b/source/blender/compositor/intern/COM_Debug.h index 53461e13f48..23d99c7e529 100644 --- a/source/blender/compositor/intern/COM_Debug.h +++ b/source/blender/compositor/intern/COM_Debug.h @@ -30,6 +30,9 @@ namespace blender::compositor { static constexpr bool COM_EXPORT_GRAPHVIZ = false; static constexpr bool COM_GRAPHVIZ_SHOW_NODE_NAME = false; +/* Saves operations results to image files. */ +static constexpr bool COM_EXPORT_OPERATION_BUFFERS = false; + class Node; class ExecutionSystem; class ExecutionGroup; @@ -75,6 +78,9 @@ class DebugInfo { m_group_states[execution_group] = EG_WAIT; } } + if (COM_EXPORT_OPERATION_BUFFERS) { + delete_operation_exports(); + } }; static void node_added(const Node *node) @@ -118,6 +124,14 @@ class DebugInfo { } }; + static void operation_rendered(const NodeOperation *op, MemoryBuffer *render) + { + /* Don't export constant operations as there are too many and it's rarely useful. */ + if (COM_EXPORT_OPERATION_BUFFERS && render && !render->is_a_single_elem()) { + export_operation(op, render); + } + } + static void graphviz(const ExecutionSystem *system, StringRefNull name = ""); protected: @@ -133,6 +147,9 @@ class DebugInfo { const char *name, const char *color, const char *style, char *str, int maxlen); static int graphviz_legend(char *str, int maxlen, bool has_execution_groups); static bool graphviz_system(const ExecutionSystem *system, char *str, int maxlen); + + static void export_operation(const NodeOperation *op, MemoryBuffer *render); + static void delete_operation_exports(); }; } // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc index 3b0a9172871..bd3a481d691 100644 --- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc +++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc @@ -20,6 +20,7 @@ #include "COM_Debug.h" #include "COM_ExecutionGroup.h" #include "COM_ReadBufferOperation.h" +#include "COM_ViewerOperation.h" #include "COM_WorkScheduler.h" #include "BLT_translation.h" @@ -100,8 +101,13 @@ void FullFrameExecutionModel::render_operation(NodeOperation *op) const bool has_outputs = op->getNumberOfOutputSockets() > 0; MemoryBuffer *op_buf = has_outputs ? create_operation_buffer(op) : nullptr; - Span<rcti> areas = active_buffers_.get_areas_to_render(op); - op->render(op_buf, areas, input_bufs); + if (op->getWidth() > 0 && op->getHeight() > 0) { + Span<rcti> areas = active_buffers_.get_areas_to_render(op); + op->render(op_buf, areas, input_bufs); + DebugInfo::operation_rendered(op, op_buf); + } + /* Even if operation has no resolution set the empty buffer. It will be clipped with a + * TranslateOperation from convert resolutions if linked to an operation with resolution. */ active_buffers_.set_rendered_buffer(op, std::unique_ptr<MemoryBuffer>(op_buf)); operation_finished(op); @@ -117,10 +123,16 @@ void FullFrameExecutionModel::render_operations() WorkScheduler::start(this->context_); for (eCompositorPriority priority : priorities_) { for (NodeOperation *op : operations_) { - if (op->isOutputOperation(is_rendering) && op->getRenderPriority() == priority) { + const bool has_size = op->getWidth() > 0 && op->getHeight() > 0; + const bool is_priority_output = op->isOutputOperation(is_rendering) && + op->getRenderPriority() == priority; + if (is_priority_output && has_size) { render_output_dependencies(op); render_operation(op); } + else if (is_priority_output && !has_size && op->isActiveViewerOutput()) { + static_cast<ViewerOperation *>(op)->clear_display_buffer(); + } } } WorkScheduler::stop(); diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc index c7bddddd0e6..6b954072a9a 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.cc +++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc @@ -129,6 +129,20 @@ void MemoryBuffer::clear() memset(m_buffer, 0, buffer_len() * m_num_channels * sizeof(float)); } +BuffersIterator<float> MemoryBuffer::iterate_with(Span<MemoryBuffer *> inputs) +{ + return iterate_with(inputs, m_rect); +} + +BuffersIterator<float> MemoryBuffer::iterate_with(Span<MemoryBuffer *> inputs, const rcti &area) +{ + BuffersIteratorBuilder<float> builder(m_buffer, m_rect, area, elem_stride); + for (MemoryBuffer *input : inputs) { + builder.add_input(input->getBuffer(), input->get_rect(), input->elem_stride); + } + return builder.build(); +} + /** * Converts a single elem buffer to a full size buffer (allocates memory for all * elements in resolution). diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h index 4ad0872b0b7..048ed4c5d6e 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.h +++ b/source/blender/compositor/intern/COM_MemoryBuffer.h @@ -18,6 +18,9 @@ #pragma once +#include "COM_BufferArea.h" +#include "COM_BufferRange.h" +#include "COM_BuffersIterator.h" #include "COM_ExecutionGroup.h" #include "COM_MemoryProxy.h" @@ -239,6 +242,32 @@ class MemoryBuffer { } /** + * Get all buffer elements as a range with no offsets. + */ + BufferRange<float> as_range() + { + return BufferRange<float>(m_buffer, 0, buffer_len(), elem_stride); + } + + BufferRange<const float> as_range() const + { + return BufferRange<const float>(m_buffer, 0, buffer_len(), elem_stride); + } + + BufferArea<float> get_buffer_area(const rcti &area) + { + return BufferArea<float>(m_buffer, getWidth(), area, elem_stride); + } + + BufferArea<const float> get_buffer_area(const rcti &area) const + { + return BufferArea<const float>(m_buffer, getWidth(), area, elem_stride); + } + + BuffersIterator<float> iterate_with(Span<MemoryBuffer *> inputs); + BuffersIterator<float> iterate_with(Span<MemoryBuffer *> inputs, const rcti &area); + + /** * \brief get the data of this MemoryBuffer * \note buffer should already be available in memory */ diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cc b/source/blender/compositor/nodes/COM_RenderLayersNode.cc index 253ca542c04..6744e98ecdb 100644 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.cc +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cc @@ -143,7 +143,7 @@ void RenderLayersNode::missingSocketLink(NodeConverter &converter, NodeOutput *o break; } default: { - BLI_assert("!Unexpected data type"); + BLI_assert_msg(0, "Unexpected data type"); return; } } diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.cc b/source/blender/compositor/operations/COM_BrightnessOperation.cc index 92cab47318a..7878eca2bbd 100644 --- a/source/blender/compositor/operations/COM_BrightnessOperation.cc +++ b/source/blender/compositor/operations/COM_BrightnessOperation.cc @@ -28,6 +28,7 @@ BrightnessOperation::BrightnessOperation() this->addOutputSocket(DataType::Color); this->m_inputProgram = nullptr; this->m_use_premultiply = false; + flags.can_be_constant = true; } void BrightnessOperation::setUsePremultiply(bool use_premultiply) @@ -85,6 +86,50 @@ void BrightnessOperation::executePixelSampled(float output[4], } } +void BrightnessOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + float tmp_color[4]; + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *in_color = it.in(0); + const float brightness = *it.in(1) / 100.0f; + const float contrast = *it.in(2); + float delta = contrast / 200.0f; + /* + * The algorithm is by Werner D. Streidt + * (http://visca.com/ffactory/archives/5-99/msg00021.html) + * Extracted of OpenCV demhist.c + */ + float a, b; + if (contrast > 0) { + a = 1.0f - delta * 2.0f; + a = 1.0f / max_ff(a, FLT_EPSILON); + b = a * (brightness - delta); + } + else { + delta *= -1; + a = max_ff(1.0f - delta * 2.0f, 0.0f); + b = a * brightness + delta; + } + const float *color; + if (this->m_use_premultiply) { + premul_to_straight_v4_v4(tmp_color, in_color); + color = tmp_color; + } + else { + color = in_color; + } + it.out[0] = a * color[0] + b; + it.out[1] = a * color[1] + b; + it.out[2] = a * color[2] + b; + it.out[3] = color[3]; + if (this->m_use_premultiply) { + straight_to_premul_v4(it.out); + } + } +} + void BrightnessOperation::deinitExecution() { this->m_inputProgram = nullptr; diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.h b/source/blender/compositor/operations/COM_BrightnessOperation.h index 7c33e0b35ec..64b4fa0dbe2 100644 --- a/source/blender/compositor/operations/COM_BrightnessOperation.h +++ b/source/blender/compositor/operations/COM_BrightnessOperation.h @@ -18,11 +18,11 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class BrightnessOperation : public NodeOperation { +class BrightnessOperation : public MultiThreadedOperation { private: /** * Cached reference to the inputProgram @@ -52,6 +52,10 @@ class BrightnessOperation : public NodeOperation { void deinitExecution() override; void setUsePremultiply(bool use_premultiply); + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc index c4099a6d33d..55ae19ad194 100644 --- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc +++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc @@ -25,7 +25,7 @@ namespace blender::compositor { -// this part has been copied from the double edge mask +/* This part has been copied from the double edge mask. */ static void do_adjacentKeepBorders(unsigned int t, unsigned int rw, const unsigned int *limask, @@ -35,163 +35,163 @@ static void do_adjacentKeepBorders(unsigned int t, unsigned int *rsize) { int x; - unsigned int isz = 0; // inner edge size - unsigned int osz = 0; // outer edge size - unsigned int gsz = 0; // gradient fill area size + unsigned int isz = 0; /* Inner edge size. */ + unsigned int osz = 0; /* Outer edge size. */ + unsigned int gsz = 0; /* Gradient fill area size. */ /* Test the four corners */ - /* upper left corner */ + /* Upper left corner. */ x = t - rw + 1; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel underneath, or to the right, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel underneath, or to the right, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } - /* upper right corner */ + /* Upper right corner. */ x = t; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel underneath, or to the left, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel underneath, or to the left, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x - 1] && lomask[x - 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } - /* lower left corner */ + /* Lower left corner. */ x = 0; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel above, or to the right, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel above, or to the right, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } - /* lower right corner */ + /* Lower right corner. */ x = rw - 1; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel above, or to the left, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel above, or to the left, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x - 1] && lomask[x - 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } /* Test the TOP row of pixels in buffer, except corners */ for (x = t - 1; x >= (t - rw) + 2; x--) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel to the right, or to the left, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel to the right, or to the left, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } } /* Test the BOTTOM row of pixels in buffer, except corners */ for (x = rw - 2; x; x--) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel to the right, or to the left, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel to the right, or to the left, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } } /* Test the LEFT edge of pixels in buffer, except corners */ for (x = t - (rw << 1) + 1; x >= rw; x -= rw) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel underneath, or above, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel underneath, or above, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } } /* Test the RIGHT edge of pixels in buffer, except corners */ for (x = t - rw; x > rw; x -= rw) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel underneath, or above, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel underneath, or above, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } } - rsize[0] = isz; // fill in our return sizes for edges + fill + rsize[0] = isz; /* Fill in our return sizes for edges + fill. */ rsize[1] = osz; rsize[2] = gsz; } @@ -205,214 +205,218 @@ static void do_adjacentBleedBorders(unsigned int t, unsigned int *rsize) { int x; - unsigned int isz = 0; // inner edge size - unsigned int osz = 0; // outer edge size - unsigned int gsz = 0; // gradient fill area size + unsigned int isz = 0; /* Inner edge size. */ + unsigned int osz = 0; /* Outer edge size. */ + unsigned int gsz = 0; /* Gradient fill area size. */ /* Test the four corners */ - /* upper left corner */ + /* Upper left corner. */ x = t - rw + 1; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel underneath, or to the right, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel underneath, or to the right, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ if (!lomask[x - rw] || - !lomask[x + 1]) { // test if outer mask is empty underneath or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + !lomask[x + 1]) { /* Test if outer mask is empty underneath or to the right. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } - /* upper right corner */ + /* Upper right corner. */ x = t; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel underneath, or to the left, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel underneath, or to the left, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x - 1] && lomask[x - 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ if (!lomask[x - rw] || - !lomask[x - 1]) { // test if outer mask is empty underneath or to the left - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + !lomask[x - 1]) { /* Test if outer mask is empty underneath or to the left. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } - /* lower left corner */ + /* Lower left corner. */ x = 0; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel above, or to the right, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel above, or to the right, are empty in the inner mask, + * But filled in the outer mask. */ if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x + rw] || !lomask[x + 1]) { // test if outer mask is empty above or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + if (!lomask[x + rw] || + !lomask[x + 1]) { /* Test if outer mask is empty above or to the right. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } - /* lower right corner */ + /* Lower right corner. */ x = rw - 1; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel above, or to the left, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel above, or to the left, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x - 1] && lomask[x - 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x + rw] || !lomask[x - 1]) { // test if outer mask is empty above or to the left - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + if (!lomask[x + rw] || + !lomask[x - 1]) { /* Test if outer mask is empty above or to the left. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } /* Test the TOP row of pixels in buffer, except corners */ for (x = t - 1; x >= (t - rw) + 2; x--) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel to the left, or to the right, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel to the left, or to the right, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ if (!lomask[x - 1] || - !lomask[x + 1]) { // test if outer mask is empty to the left or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + !lomask[x + 1]) { /* Test if outer mask is empty to the left or to the right. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } } /* Test the BOTTOM row of pixels in buffer, except corners */ for (x = rw - 2; x; x--) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel to the left, or to the right, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel to the left, or to the right, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ if (!lomask[x - 1] || - !lomask[x + 1]) { // test if outer mask is empty to the left or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + !lomask[x + 1]) { /* Test if outer mask is empty to the left or to the right. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } } /* Test the LEFT edge of pixels in buffer, except corners */ for (x = t - (rw << 1) + 1; x >= rw; x -= rw) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel underneath, or above, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel underneath, or above, are empty in the inner mask, + * but filled in the outer mask. */ if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + if (!lomask[x - rw] || + !lomask[x + rw]) { /* Test if outer mask is empty underneath or above. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } } /* Test the RIGHT edge of pixels in buffer, except corners */ for (x = t - rw; x > rw; x -= rw) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if pixel underneath, or above, are empty in the inner mask, - // but filled in the outer mask + /* Test if pixel underneath, or above, are empty in the inner mask, + * But filled in the outer mask. */ if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + if (!lomask[x - rw] || + !lomask[x + rw]) { /* Test if outer mask is empty underneath or above. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } } - rsize[0] = isz; // fill in our return sizes for edges + fill + rsize[0] = isz; /* Fill in our return sizes for edges + fill. */ rsize[1] = osz; rsize[2] = gsz; } @@ -426,155 +430,155 @@ static void do_allKeepBorders(unsigned int t, unsigned int *rsize) { int x; - unsigned int isz = 0; // inner edge size - unsigned int osz = 0; // outer edge size - unsigned int gsz = 0; // gradient fill area size - /* Test the four corners */ - /* upper left corner */ + unsigned int isz = 0; /* Inner edge size. */ + unsigned int osz = 0; /* Outer edge size. */ + unsigned int gsz = 0; /* Gradient fill area size. */ + /* Test the four corners. */ + /* Upper left corner. */ x = t - rw + 1; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if the inner mask is empty underneath or to the right + /* Test if the inner mask is empty underneath or to the right. */ if (!limask[x - rw] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } - /* upper right corner */ + /* Upper right corner. */ x = t; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if the inner mask is empty underneath or to the left + /* Test if the inner mask is empty underneath or to the left. */ if (!limask[x - rw] || !limask[x - 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } - /* lower left corner */ + /* Lower left corner. */ x = 0; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if inner mask is empty above or to the right + /* Test if inner mask is empty above or to the right. */ if (!limask[x + rw] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } - /* lower right corner */ + /* Lower right corner. */ x = rw - 1; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if inner mask is empty above or to the left + /* Test if inner mask is empty above or to the left. */ if (!limask[x + rw] || !limask[x - 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } /* Test the TOP row of pixels in buffer, except corners */ for (x = t - 1; x >= (t - rw) + 2; x--) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if inner mask is empty to the left or to the right + /* Test if inner mask is empty to the left or to the right. */ if (!limask[x - 1] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } } /* Test the BOTTOM row of pixels in buffer, except corners */ for (x = rw - 2; x; x--) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if inner mask is empty to the left or to the right + /* Test if inner mask is empty to the left or to the right. */ if (!limask[x - 1] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } } /* Test the LEFT edge of pixels in buffer, except corners */ for (x = t - (rw << 1) + 1; x >= rw; x -= rw) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if inner mask is empty underneath or above + /* Test if inner mask is empty underneath or above. */ if (!limask[x - rw] || !limask[x + rw]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } } /* Test the RIGHT edge of pixels in buffer, except corners */ for (x = t - rw; x > rw; x -= rw) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if inner mask is empty underneath or above + /* Test if inner mask is empty underneath or above. */ if (!limask[x - rw] || !limask[x + rw]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } } - rsize[0] = isz; // fill in our return sizes for edges + fill + rsize[0] = isz; /* Fill in our return sizes for edges + fill. */ rsize[1] = osz; rsize[2] = gsz; } @@ -588,207 +592,210 @@ static void do_allBleedBorders(unsigned int t, unsigned int *rsize) { int x; - unsigned int isz = 0; // inner edge size - unsigned int osz = 0; // outer edge size - unsigned int gsz = 0; // gradient fill area size + unsigned int isz = 0; /* Inner edge size. */ + unsigned int osz = 0; /* Outer edge size. */ + unsigned int gsz = 0; /* Gradient fill area size. */ /* Test the four corners */ - /* upper left corner */ + /* Upper left corner. */ x = t - rw + 1; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if the inner mask is empty underneath or to the right + /* Test if the inner mask is empty underneath or to the right. */ if (!limask[x - rw] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ if (!lomask[x - rw] || - !lomask[x + 1]) { // test if outer mask is empty underneath or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + !lomask[x + 1]) { /* Test if outer mask is empty underneath or to the right. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } - /* upper right corner */ + /* Upper right corner. */ x = t; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if the inner mask is empty underneath or to the left + /* Test if the inner mask is empty underneath or to the left. */ if (!limask[x - rw] || !limask[x - 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || !lomask[x - 1]) { // test if outer mask is empty above or to the left - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + if (!lomask[x - rw] || + !lomask[x - 1]) { /* Test if outer mask is empty above or to the left. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } - /* lower left corner */ + /* Lower left corner. */ x = 0; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if inner mask is empty above or to the right + /* Test if inner mask is empty above or to the right. */ if (!limask[x + rw] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ if (!lomask[x + rw] || - !lomask[x + 1]) { // test if outer mask is empty underneath or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + !lomask[x + 1]) { /* Test if outer mask is empty underneath or to the right. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } - /* lower right corner */ + /* Lower right corner. */ x = rw - 1; - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if inner mask is empty above or to the left + /* Test if inner mask is empty above or to the left. */ if (!limask[x + rw] || !limask[x - 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ if (!lomask[x + rw] || - !lomask[x - 1]) { // test if outer mask is empty underneath or to the left - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + !lomask[x - 1]) { /* Test if outer mask is empty underneath or to the left. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } /* Test the TOP row of pixels in buffer, except corners */ for (x = t - 1; x >= (t - rw) + 2; x--) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if inner mask is empty to the left or to the right + /* Test if inner mask is empty to the left or to the right. */ if (!limask[x - 1] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ if (!lomask[x - 1] || - !lomask[x + 1]) { // test if outer mask is empty to the left or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + !lomask[x + 1]) { /* Test if outer mask is empty to the left or to the right. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } } /* Test the BOTTOM row of pixels in buffer, except corners */ for (x = rw - 2; x; x--) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if inner mask is empty to the left or to the right + /* Test if inner mask is empty to the left or to the right. */ if (!limask[x - 1] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ if (!lomask[x - 1] || - !lomask[x + 1]) { // test if outer mask is empty to the left or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + !lomask[x + 1]) { /* Test if outer mask is empty to the left or to the right. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } } /* Test the LEFT edge of pixels in buffer, except corners */ for (x = t - (rw << 1) + 1; x >= rw; x -= rw) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if inner mask is empty underneath or above + /* Test if inner mask is empty underneath or above. */ if (!limask[x - rw] || !limask[x + rw]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + if (!lomask[x - rw] || + !lomask[x + rw]) { /* Test if outer mask is empty underneath or above. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } } /* Test the RIGHT edge of pixels in buffer, except corners */ for (x = t - rw; x > rw; x -= rw) { - // test if inner mask is filled + /* Test if inner mask is filled. */ if (limask[x]) { - // test if inner mask is empty underneath or above + /* Test if inner mask is empty underneath or above. */ if (!limask[x - rw] || !limask[x + rw]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge + isz++; /* Increment inner edge size. */ + lres[x] = 4; /* Flag pixel as inner edge. */ } else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + res[x] = 1.0f; /* Pixel is just part of inner mask, and it's not an edge. */ } } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge + else if (lomask[x]) { /* Inner mask was empty, test if outer mask is filled. */ + if (!lomask[x - rw] || + !lomask[x + rw]) { /* Test if outer mask is empty underneath or above. */ + osz++; /* Increment outer edge size. */ + lres[x] = 3; /* Flag pixel as outer edge. */ } else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient + gsz++; /* Increment the gradient pixel count. */ + lres[x] = 2; /* Flag pixel as gradient. */ } } } - rsize[0] = isz; // fill in our return sizes for edges + fill + rsize[0] = isz; /* Fill in our return sizes for edges + fill. */ rsize[1] = osz; rsize[2] = gsz; } @@ -804,13 +811,14 @@ static void do_allEdgeDetection(unsigned int t, unsigned int in_osz, unsigned int in_gsz) { - int x; // x = pixel loop counter - int a; // a = pixel loop counter - int dx; // dx = delta x - int pix_prevRow; // pix_prevRow = pixel one row behind the one we are testing in a loop - int pix_nextRow; // pix_nextRow = pixel one row in front of the one we are testing in a loop - int pix_prevCol; // pix_prevCol = pixel one column behind the one we are testing in a loop - int pix_nextCol; // pix_nextCol = pixel one column in front of the one we are testing in a loop + int x; /* Pixel loop counter. */ + int a; /* Pixel loop counter. */ + int dx; /* Delta x. */ + int pix_prevRow; /* Pixel one row behind the one we are testing in a loop. */ + int pix_nextRow; /* Pixel one row in front of the one we are testing in a loop. */ + int pix_prevCol; /* Pixel one column behind the one we are testing in a loop. */ + int pix_nextCol; /* Pixel one column in front of the one we are testing in a loop. */ + /* Test all rows between the FIRST and LAST rows, excluding left and right edges */ for (x = (t - rw) + 1, dx = x - (rw - 2); dx > rw; x -= rw, dx -= rw) { a = x - 2; @@ -819,8 +827,8 @@ static void do_allEdgeDetection(unsigned int t, pix_prevCol = a + 1; pix_nextCol = a - 1; while (a > dx - 2) { - if (!limask[a]) { // if the inner mask is empty - if (lomask[a]) { // if the outer mask is full + if (!limask[a]) { /* If the inner mask is empty. */ + if (lomask[a]) { /* If the outer mask is full. */ /* * Next we test all 4 directions around the current pixel: next/prev/up/down * The test ensures that the outer mask is empty and that the inner mask @@ -831,23 +839,23 @@ static void do_allEdgeDetection(unsigned int t, (!lomask[pix_prevCol] && !limask[pix_prevCol]) || (!lomask[pix_nextRow] && !limask[pix_nextRow]) || (!lomask[pix_prevRow] && !limask[pix_prevRow])) { - in_osz++; // increment the outer boundary pixel count - lres[a] = 3; // flag pixel as part of outer edge + in_osz++; /* Increment the outer boundary pixel count. */ + lres[a] = 3; /* Flag pixel as part of outer edge. */ } - else { // it's not a boundary pixel, but it is a gradient pixel - in_gsz++; // increment the gradient pixel count - lres[a] = 2; // flag pixel as gradient + else { /* It's not a boundary pixel, but it is a gradient pixel. */ + in_gsz++; /* Increment the gradient pixel count. */ + lres[a] = 2; /* Flag pixel as gradient. */ } } } else { if (!limask[pix_nextCol] || !limask[pix_prevCol] || !limask[pix_nextRow] || !limask[pix_prevRow]) { - in_isz++; // increment the inner boundary pixel count - lres[a] = 4; // flag pixel as part of inner edge + in_isz++; /* Increment the inner boundary pixel count. */ + lres[a] = 4; /* Flag pixel as part of inner edge. */ } else { - res[a] = 1.0f; // pixel is part of inner mask, but not at an edge + res[a] = 1.0f; /* Pixel is part of inner mask, but not at an edge. */ } } a--; @@ -858,7 +866,7 @@ static void do_allEdgeDetection(unsigned int t, } } - rsize[0] = in_isz; // fill in our return sizes for edges + fill + rsize[0] = in_isz; /* Fill in our return sizes for edges + fill. */ rsize[1] = in_osz; rsize[2] = in_gsz; } @@ -874,13 +882,13 @@ static void do_adjacentEdgeDetection(unsigned int t, unsigned int in_osz, unsigned int in_gsz) { - int x; // x = pixel loop counter - int a; // a = pixel loop counter - int dx; // dx = delta x - int pix_prevRow; // pix_prevRow = pixel one row behind the one we are testing in a loop - int pix_nextRow; // pix_nextRow = pixel one row in front of the one we are testing in a loop - int pix_prevCol; // pix_prevCol = pixel one column behind the one we are testing in a loop - int pix_nextCol; // pix_nextCol = pixel one column in front of the one we are testing in a loop + int x; /* Pixel loop counter. */ + int a; /* Pixel loop counter. */ + int dx; /* Delta x. */ + int pix_prevRow; /* Pixel one row behind the one we are testing in a loop. */ + int pix_nextRow; /* Pixel one row in front of the one we are testing in a loop. */ + int pix_prevCol; /* Pixel one column behind the one we are testing in a loop. */ + int pix_nextCol; /* Pixel one column in front of the one we are testing in a loop. */ /* Test all rows between the FIRST and LAST rows, excluding left and right edges */ for (x = (t - rw) + 1, dx = x - (rw - 2); dx > rw; x -= rw, dx -= rw) { a = x - 2; @@ -889,8 +897,8 @@ static void do_adjacentEdgeDetection(unsigned int t, pix_prevCol = a + 1; pix_nextCol = a - 1; while (a > dx - 2) { - if (!limask[a]) { // if the inner mask is empty - if (lomask[a]) { // if the outer mask is full + if (!limask[a]) { /* If the inner mask is empty. */ + if (lomask[a]) { /* If the outer mask is full. */ /* * Next we test all 4 directions around the current pixel: next/prev/up/down * The test ensures that the outer mask is empty and that the inner mask @@ -901,12 +909,12 @@ static void do_adjacentEdgeDetection(unsigned int t, (!lomask[pix_prevCol] && !limask[pix_prevCol]) || (!lomask[pix_nextRow] && !limask[pix_nextRow]) || (!lomask[pix_prevRow] && !limask[pix_prevRow])) { - in_osz++; // increment the outer boundary pixel count - lres[a] = 3; // flag pixel as part of outer edge + in_osz++; /* Increment the outer boundary pixel count. */ + lres[a] = 3; /* Flag pixel as part of outer edge. */ } - else { // it's not a boundary pixel, but it is a gradient pixel - in_gsz++; // increment the gradient pixel count - lres[a] = 2; // flag pixel as gradient + else { /* It's not a boundary pixel, but it is a gradient pixel. */ + in_gsz++; /* Increment the gradient pixel count. */ + lres[a] = 2; /* Flag pixel as gradient. */ } } } @@ -915,22 +923,22 @@ static void do_adjacentEdgeDetection(unsigned int t, (!limask[pix_prevCol] && lomask[pix_prevCol]) || (!limask[pix_nextRow] && lomask[pix_nextRow]) || (!limask[pix_prevRow] && lomask[pix_prevRow])) { - in_isz++; // increment the inner boundary pixel count - lres[a] = 4; // flag pixel as part of inner edge + in_isz++; /* Increment the inner boundary pixel count. */ + lres[a] = 4; /* Flag pixel as part of inner edge. */ } else { - res[a] = 1.0f; // pixel is part of inner mask, but not at an edge + res[a] = 1.0f; /* Pixel is part of inner mask, but not at an edge. */ } } a--; - pix_prevRow--; // advance all four "surrounding" pixel pointers + pix_prevRow--; /* Advance all four "surrounding" pixel pointers. */ pix_nextRow--; pix_prevCol--; pix_nextCol--; } } - rsize[0] = in_isz; // fill in our return sizes for edges + fill + rsize[0] = in_isz; /* Fill in our return sizes for edges + fill. */ rsize[1] = in_osz; rsize[2] = in_gsz; } @@ -945,12 +953,12 @@ static void do_createEdgeLocationBuffer(unsigned int t, unsigned int isz, unsigned int gsz) { - int x; // x = pixel loop counter - int a; // a = temporary pixel index buffer loop counter - unsigned int ud; // ud = unscaled edge distance - unsigned int dmin; // dmin = minimum edge distance + int x; /* Pixel loop counter. */ + int a; /* Temporary pixel index buffer loop counter. */ + unsigned int ud; /* Unscaled edge distance. */ + unsigned int dmin; /* Minimum edge distance. */ - unsigned int rsl; // long used for finding fast 1.0/sqrt + unsigned int rsl; /* Long used for finding fast `1.0/sqrt`. */ unsigned int gradientFillOffset; /* For looping inner edge pixel indexes, represents current position from offset. */ @@ -980,11 +988,11 @@ static void do_createEdgeLocationBuffer(unsigned int t, * * Example: 9 by 9 pixel block * - * . = pixel non-white in both outer and inner mask - * o = pixel white in outer, but not inner mask, adjacent to "." pixel - * g = pixel white in outer, but not inner mask, not adjacent to "." pixel - * i = pixel white in inner mask, adjacent to "g" or "." pixel - * F = pixel white in inner mask, only adjacent to other pixels white in the inner mask + * `.` = Pixel non-white in both outer and inner mask. + * `o` = Pixel white in outer, but not inner mask, adjacent to "." pixel. + * `g` = Pixel white in outer, but not inner mask, not adjacent to "." pixel. + * `i` = Pixel white in inner mask, adjacent to "g" or "." pixel. + * `F` = Pixel white in inner mask, only adjacent to other pixels white in the inner mask. * * * ......... <----- pixel #80 @@ -1025,36 +1033,37 @@ static void do_createEdgeLocationBuffer(unsigned int t, */ /* clang-format on */ - gradientFillOffset = 0; // since there are likely "more" of these, put it first. :) - *innerEdgeOffset = gradientFillOffset + gsz; // set start of inner edge indexes - *outerEdgeOffset = (*innerEdgeOffset) + isz; // set start of outer edge indexes - /* set the accumulators to correct positions */ // set up some accumulator variables for loops - gradientAccum = gradientFillOffset; // each accumulator variable starts at its respective - innerAccum = *innerEdgeOffset; // section's offset so when we start filling, each - outerAccum = *outerEdgeOffset; // section fills up its allocated space in gbuf - // uses dmin=row, rsl=col + gradientFillOffset = 0; /* Since there are likely "more" of these, put it first. :). */ + *innerEdgeOffset = gradientFillOffset + gsz; /* Set start of inner edge indexes. */ + *outerEdgeOffset = (*innerEdgeOffset) + isz; /* Set start of outer edge indexes. */ + /* Set the accumulators to correct positions */ /* Set up some accumulator variables for loops. + */ + gradientAccum = gradientFillOffset; /* Each accumulator variable starts at its respective. */ + innerAccum = *innerEdgeOffset; /* Section's offset so when we start filling, each. */ + outerAccum = *outerEdgeOffset; /* Section fills up its allocated space in gbuf. */ + /* Uses `dmin=row`, `rsl=col`. */ for (x = 0, dmin = 0; x < t; x += rw, dmin++) { for (rsl = 0; rsl < rw; rsl++) { a = x + rsl; - if (lres[a] == 2) { // it is a gradient pixel flagged by 2 - ud = gradientAccum << 1; // double the index to reach correct unsigned short location - gbuf[ud] = dmin; // insert pixel's row into gradient pixel location buffer - gbuf[ud + 1] = rsl; // insert pixel's column into gradient pixel location buffer - gradientAccum++; // increment gradient index buffer pointer + if (lres[a] == 2) { /* It is a gradient pixel flagged by 2. */ + ud = gradientAccum << 1; /* Double the index to reach correct unsigned short location. */ + gbuf[ud] = dmin; /* Insert pixel's row into gradient pixel location buffer. */ + gbuf[ud + 1] = rsl; /* Insert pixel's column into gradient pixel location buffer. */ + gradientAccum++; /* Increment gradient index buffer pointer. */ } - else if (lres[a] == 3) { // it is an outer edge pixel flagged by 3 - ud = outerAccum << 1; // double the index to reach correct unsigned short location - gbuf[ud] = dmin; // insert pixel's row into outer edge pixel location buffer - gbuf[ud + 1] = rsl; // insert pixel's column into outer edge pixel location buffer - outerAccum++; // increment outer edge index buffer pointer - res[a] = 0.0f; // set output pixel intensity now since it won't change later + else if (lres[a] == 3) { /* It is an outer edge pixel flagged by 3. */ + ud = outerAccum << 1; /* Double the index to reach correct unsigned short location. */ + gbuf[ud] = dmin; /* Insert pixel's row into outer edge pixel location buffer. */ + gbuf[ud + 1] = rsl; /* Insert pixel's column into outer edge pixel location buffer. */ + outerAccum++; /* Increment outer edge index buffer pointer. */ + res[a] = 0.0f; /* Set output pixel intensity now since it won't change later. */ } - else if (lres[a] == 4) { // it is an inner edge pixel flagged by 4 - ud = innerAccum << 1; // double int index to reach correct unsigned short location - gbuf[ud] = dmin; // insert pixel's row into inner edge pixel location buffer - gbuf[ud + 1] = rsl; // insert pixel's column into inner edge pixel location buffer - innerAccum++; // increment inner edge index buffer pointer - res[a] = 1.0f; // set output pixel intensity now since it won't change later + else if (lres[a] == 4) { /* It is an inner edge pixel flagged by 4. */ + ud = innerAccum << 1; /* Double int index to reach correct unsigned short location. */ + gbuf[ud] = dmin; /* Insert pixel's row into inner edge pixel location buffer. */ + gbuf[ud + 1] = rsl; /* Insert pixel's column into inner edge pixel location buffer. */ + innerAccum++; /* Increment inner edge index buffer pointer. */ + res[a] = 1.0f; /* Set output pixel intensity now since it won't change later. */ } } } @@ -1069,21 +1078,21 @@ static void do_fillGradientBuffer(unsigned int rw, unsigned int innerEdgeOffset, unsigned int outerEdgeOffset) { - int x; // x = pixel loop counter - int a; // a = temporary pixel index buffer loop counter - int fsz; // size of the frame - unsigned int rsl; // long used for finding fast 1.0/sqrt - float rsf; // float used for finding fast 1.0/sqrt - const float rsopf = 1.5f; // constant float used for finding fast 1.0/sqrt + int x; /* Pixel loop counter. */ + int a; /* Temporary pixel index buffer loop counter. */ + int fsz; /* Size of the frame. */ + unsigned int rsl; /* Long used for finding fast `1.0/sqrt`. */ + float rsf; /* Float used for finding fast `1.0/sqrt`. */ + const float rsopf = 1.5f; /* Constant float used for finding fast `1.0/sqrt`. */ unsigned int gradientFillOffset; unsigned int t; - unsigned int ud; // ud = unscaled edge distance - unsigned int dmin; // dmin = minimum edge distance - float odist; // odist = current outer edge distance - float idist; // idist = current inner edge distance - int dx; // dx = X-delta (used for distance proportion calculation) - int dy; // dy = Y-delta (used for distance proportion calculation) + unsigned int ud; /* Unscaled edge distance. */ + unsigned int dmin; /* Minimum edge distance. */ + float odist; /* Current outer edge distance. */ + float idist; /* Current inner edge distance. */ + int dx; /* X-delta (used for distance proportion calculation) */ + int dy; /* Y-delta (used for distance proportion calculation) */ /* * The general algorithm used to color each gradient pixel is: @@ -1099,9 +1108,9 @@ static void do_fillGradientBuffer(unsigned int rw, * outside edge. * * In an image where: - * . = blank (black) pixels, not covered by inner mask or outer mask - * + = desired gradient pixels, covered only by outer mask - * * = white full mask pixels, covered by at least inner mask + * `.` = Blank (black) pixels, not covered by inner mask or outer mask. + * `+` = Desired gradient pixels, covered only by outer mask. + * `*` = White full mask pixels, covered by at least inner mask. * * ............................... * ...............+++++++++++..... @@ -1146,92 +1155,95 @@ static void do_fillGradientBuffer(unsigned int rw, for (x = gsz - 1; x >= 0; x--) { gradientFillOffset = x << 1; - t = gbuf[gradientFillOffset]; // calculate column of pixel indexed by gbuf[x] - fsz = gbuf[gradientFillOffset + 1]; // calculate row of pixel indexed by gbuf[x] - dmin = 0xffffffff; // reset min distance to edge pixel + t = gbuf[gradientFillOffset]; /* Calculate column of pixel indexed by `gbuf[x]`. */ + fsz = gbuf[gradientFillOffset + 1]; /* Calculate row of pixel indexed by `gbuf[x]`. */ + dmin = 0xffffffff; /* Reset min distance to edge pixel. */ for (a = outerEdgeOffset + osz - 1; a >= outerEdgeOffset; - a--) { // loop through all outer edge buffer pixels + a--) { /* Loop through all outer edge buffer pixels. */ ud = a << 1; - dy = t - gbuf[ud]; // set dx to gradient pixel column - outer edge pixel row - dx = fsz - gbuf[ud + 1]; // set dy to gradient pixel row - outer edge pixel column - ud = dx * dx + dy * dy; // compute sum of squares - if (ud < dmin) { // if our new sum of squares is less than the current minimum - dmin = ud; // set a new minimum equal to the new lower value + dy = t - gbuf[ud]; /* Set dx to gradient pixel column - outer edge pixel row. */ + dx = fsz - gbuf[ud + 1]; /* Set dy to gradient pixel row - outer edge pixel column. */ + ud = dx * dx + dy * dy; /* Compute sum of squares. */ + if (ud < dmin) { /* If our new sum of squares is less than the current minimum. */ + dmin = ud; /* Set a new minimum equal to the new lower value. */ } } - odist = (float)(dmin); // cast outer min to a float - rsf = odist * 0.5f; // - rsl = *(unsigned int *)&odist; // use some peculiar properties of the way bits are stored - rsl = 0x5f3759df - (rsl >> 1); // in floats vs. unsigned ints to compute an approximate - odist = *(float *)&rsl; // reciprocal square root + odist = (float)(dmin); /* Cast outer min to a float. */ + rsf = odist * 0.5f; + rsl = *(unsigned int *)&odist; /* Use some peculiar properties of the way bits are stored. */ + rsl = 0x5f3759df - (rsl >> 1); /* In floats vs. unsigned ints to compute an approximate. */ + odist = *(float *)&rsl; /* Reciprocal square root. */ odist = odist * (rsopf - (rsf * odist * - odist)); // -- ** this line can be iterated for more accuracy ** -- - dmin = 0xffffffff; // reset min distance to edge pixel + odist)); /* -- This line can be iterated for more accuracy. -- */ + dmin = 0xffffffff; /* Reset min distance to edge pixel. */ for (a = innerEdgeOffset + isz - 1; a >= innerEdgeOffset; - a--) { // loop through all inside edge pixels + a--) { /* Loop through all inside edge pixels. */ ud = a << 1; - dy = t - gbuf[ud]; // compute delta in Y from gradient pixel to inside edge pixel - dx = fsz - gbuf[ud + 1]; // compute delta in X from gradient pixel to inside edge pixel - ud = dx * dx + dy * dy; // compute sum of squares - if (ud < dmin) { // if our new sum of squares is less than the current minimum we've found - dmin = ud; // set a new minimum equal to the new lower value + dy = t - gbuf[ud]; /* Compute delta in Y from gradient pixel to inside edge pixel. */ + dx = fsz - gbuf[ud + 1]; /* Compute delta in X from gradient pixel to inside edge pixel. */ + ud = dx * dx + dy * dy; /* Compute sum of squares. */ + if (ud < + dmin) { /* If our new sum of squares is less than the current minimum we've found. */ + dmin = ud; /* Set a new minimum equal to the new lower value. */ } } - idist = (float)(dmin); // cast inner min to a float - rsf = idist * 0.5f; // - rsl = *(unsigned int *)&idist; // - rsl = 0x5f3759df - (rsl >> 1); // see notes above - idist = *(float *)&rsl; // - idist = idist * (rsopf - (rsf * idist * idist)); // - /* - * Note once again that since we are using reciprocals of distance values our + + /* Cast inner min to a float. */ + idist = (float)(dmin); + rsf = idist * 0.5f; + rsl = *(unsigned int *)&idist; + + /* See notes above. */ + rsl = 0x5f3759df - (rsl >> 1); + idist = *(float *)&rsl; + idist = idist * (rsopf - (rsf * idist * idist)); + + /* NOTE: once again that since we are using reciprocals of distance values our * proportion is already the correct intensity, and does not need to be - * subtracted from 1.0 like it would have if we used real distances. - */ + * subtracted from 1.0 like it would have if we used real distances. */ - /* - * Here we reconstruct the pixel's memory location in the CompBuf by - * Pixel Index = Pixel Column + ( Pixel Row * Row Width ) - */ + /* Here we reconstruct the pixel's memory location in the CompBuf by + * `Pixel Index = Pixel Column + ( Pixel Row * Row Width )`. */ res[gbuf[gradientFillOffset + 1] + (gbuf[gradientFillOffset] * rw)] = - (idist / (idist + odist)); // set intensity + (idist / (idist + odist)); /* Set intensity. */ } } -// end of copy +/* End of copy. */ void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float *res) { - unsigned int *lres; // lres = unsigned int pointer to output pixel buffer (for bit operations) - unsigned int *limask; // limask = unsigned int pointer to inner mask (for bit operations) - unsigned int *lomask; // lomask = unsigned int pointer to outer mask (for bit operations) - - int rw; // rw = pixel row width - int t; // t = total number of pixels in buffer - 1 (used for loop starts) - int fsz; // size of the frame - - unsigned int isz = 0; // size (in pixels) of inside edge pixel index buffer - unsigned int osz = 0; // size (in pixels) of outside edge pixel index buffer - unsigned int gsz = 0; // size (in pixels) of gradient pixel index buffer - unsigned int rsize[3]; // size storage to pass to helper functions + unsigned int *lres; /* Pointer to output pixel buffer (for bit operations). */ + unsigned int *limask; /* Pointer to inner mask (for bit operations). */ + unsigned int *lomask; /* Pointer to outer mask (for bit operations). */ + + int rw; /* Pixel row width. */ + int t; /* Total number of pixels in buffer - 1 (used for loop starts). */ + int fsz; /* Size of the frame. */ + + unsigned int isz = 0; /* Size (in pixels) of inside edge pixel index buffer. */ + unsigned int osz = 0; /* Size (in pixels) of outside edge pixel index buffer. */ + unsigned int gsz = 0; /* Size (in pixels) of gradient pixel index buffer. */ + unsigned int rsize[3]; /* Size storage to pass to helper functions. */ unsigned int innerEdgeOffset = - 0; // offset into final buffer where inner edge pixel indexes start + 0; /* Offset into final buffer where inner edge pixel indexes start. */ unsigned int outerEdgeOffset = - 0; // offset into final buffer where outer edge pixel indexes start + 0; /* Offset into final buffer where outer edge pixel indexes start. */ - unsigned short *gbuf; // gradient/inner/outer pixel location index buffer + unsigned short *gbuf; /* Gradient/inner/outer pixel location index buffer. */ - if (true) { // if both input sockets have some data coming in... + if (true) { /* If both input sockets have some data coming in... */ - rw = this->getWidth(); // width of a row of pixels - t = (rw * this->getHeight()) - 1; // determine size of the frame + rw = this->getWidth(); /* Width of a row of pixels. */ + t = (rw * this->getHeight()) - 1; /* Determine size of the frame. */ memset(res, 0, - sizeof(float) * (t + 1)); // clear output buffer (not all pixels will be written later) + sizeof(float) * + (t + 1)); /* Clear output buffer (not all pixels will be written later). */ - lres = (unsigned int *)res; // unsigned int pointer to output buffer (for bit level ops) - limask = (unsigned int *)imask; // unsigned int pointer to input mask (for bit level ops) - lomask = (unsigned int *)omask; // unsigned int pointer to output mask (for bit level ops) + lres = (unsigned int *)res; /* Pointer to output buffer (for bit level ops).. */ + limask = (unsigned int *)imask; /* Pointer to input mask (for bit level ops).. */ + lomask = (unsigned int *)omask; /* Pointer to output mask (for bit level ops).. */ /* * The whole buffer is broken up into 4 parts. The four CORNERS, the FIRST and LAST rows, the @@ -1258,52 +1270,52 @@ void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float * * Each version has slightly different criteria for detecting an edge pixel. */ - if (this->m_adjacentOnly) { // if "adjacent only" inner edge mode is turned on - if (this->m_keepInside) { // if "keep inside" buffer edge mode is turned on + if (this->m_adjacentOnly) { /* If "adjacent only" inner edge mode is turned on. */ + if (this->m_keepInside) { /* If "keep inside" buffer edge mode is turned on. */ do_adjacentKeepBorders(t, rw, limask, lomask, lres, res, rsize); } - else { // "bleed out" buffer edge mode is turned on + else { /* "bleed out" buffer edge mode is turned on. */ do_adjacentBleedBorders(t, rw, limask, lomask, lres, res, rsize); } - // set up inner edge, outer edge, and gradient buffer sizes after border pass + /* Set up inner edge, outer edge, and gradient buffer sizes after border pass. */ isz = rsize[0]; osz = rsize[1]; gsz = rsize[2]; - // detect edges in all non-border pixels in the buffer + /* Detect edges in all non-border pixels in the buffer. */ do_adjacentEdgeDetection(t, rw, limask, lomask, lres, res, rsize, isz, osz, gsz); } - else { // "all" inner edge mode is turned on - if (this->m_keepInside) { // if "keep inside" buffer edge mode is turned on + else { /* "all" inner edge mode is turned on. */ + if (this->m_keepInside) { /* If "keep inside" buffer edge mode is turned on. */ do_allKeepBorders(t, rw, limask, lomask, lres, res, rsize); } - else { // "bleed out" buffer edge mode is turned on + else { /* "bleed out" buffer edge mode is turned on. */ do_allBleedBorders(t, rw, limask, lomask, lres, res, rsize); } - // set up inner edge, outer edge, and gradient buffer sizes after border pass + /* Set up inner edge, outer edge, and gradient buffer sizes after border pass. */ isz = rsize[0]; osz = rsize[1]; gsz = rsize[2]; - // detect edges in all non-border pixels in the buffer + /* Detect edges in all non-border pixels in the buffer. */ do_allEdgeDetection(t, rw, limask, lomask, lres, res, rsize, isz, osz, gsz); } - // set edge and gradient buffer sizes once again... - // the sizes in rsize[] may have been modified - // by the do_*EdgeDetection() function. + /* Set edge and gradient buffer sizes once again... + * the sizes in rsize[] may have been modified + * by the `do_*EdgeDetection()` function. */ isz = rsize[0]; osz = rsize[1]; gsz = rsize[2]; - // calculate size of pixel index buffer needed + /* Calculate size of pixel index buffer needed. */ fsz = gsz + isz + osz; - // allocate edge/gradient pixel index buffer + /* Allocate edge/gradient pixel index buffer. */ gbuf = (unsigned short *)MEM_callocN(sizeof(unsigned short) * fsz * 2, "DEM"); do_createEdgeLocationBuffer( t, rw, lres, res, gbuf, &innerEdgeOffset, &outerEdgeOffset, isz, gsz); do_fillGradientBuffer(rw, res, gbuf, isz, osz, gsz, innerEdgeOffset, outerEdgeOffset); - // free the gradient index buffer + /* Free the gradient index buffer. */ MEM_freeN(gbuf); } } @@ -1318,6 +1330,7 @@ DoubleEdgeMaskOperation::DoubleEdgeMaskOperation() this->m_adjacentOnly = false; this->m_keepInside = false; this->flags.complex = true; + is_output_rendered_ = false; } bool DoubleEdgeMaskOperation::determineDependingAreaOfInterest(rcti * /*input*/, @@ -1382,4 +1395,43 @@ void DoubleEdgeMaskOperation::deinitExecution() } } +void DoubleEdgeMaskOperation::get_area_of_interest(int UNUSED(input_idx), + const rcti &UNUSED(output_area), + rcti &r_input_area) +{ + r_input_area.xmax = this->getWidth(); + r_input_area.xmin = 0; + r_input_area.ymax = this->getHeight(); + r_input_area.ymin = 0; +} + +void DoubleEdgeMaskOperation::update_memory_buffer(MemoryBuffer *output, + const rcti &UNUSED(area), + Span<MemoryBuffer *> inputs) +{ + if (!is_output_rendered_) { + /* Ensure full buffers to work with no strides. */ + MemoryBuffer *input_inner_mask = inputs[0]; + MemoryBuffer *inner_mask = input_inner_mask->is_a_single_elem() ? input_inner_mask->inflate() : + input_inner_mask; + MemoryBuffer *input_outer_mask = inputs[1]; + MemoryBuffer *outer_mask = input_outer_mask->is_a_single_elem() ? input_outer_mask->inflate() : + input_outer_mask; + + BLI_assert(output->getWidth() == this->getWidth()); + BLI_assert(output->getHeight() == this->getHeight()); + /* TODO(manzanilla): Once tiled implementation is removed, use execution system to run + * multi-threaded where possible. */ + doDoubleEdgeMask(inner_mask->getBuffer(), outer_mask->getBuffer(), output->getBuffer()); + is_output_rendered_ = true; + + if (inner_mask != input_inner_mask) { + delete inner_mask; + } + if (outer_mask != input_outer_mask) { + delete outer_mask; + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h index e956e8edc3e..45a80bbbbf0 100644 --- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h +++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { @@ -31,8 +31,12 @@ class DoubleEdgeMaskOperation : public NodeOperation { SocketReader *m_inputInnerMask; bool m_adjacentOnly; bool m_keepInside; + + /* TODO(manzanilla): To be removed with tiled implementation. */ float *m_cachedInstance; + bool is_output_rendered_; + public: DoubleEdgeMaskOperation(); @@ -66,6 +70,12 @@ class DoubleEdgeMaskOperation : public NodeOperation { { this->m_keepInside = keepInside; } + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + + void update_memory_buffer(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc index 5a4503fecec..eb1fd98a590 100644 --- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc +++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc @@ -20,6 +20,8 @@ #include "BLI_math.h" #include "DNA_node_types.h" +#include <functional> + namespace blender::compositor { EllipseMaskOperation::EllipseMaskOperation() @@ -114,6 +116,77 @@ void EllipseMaskOperation::executePixelSampled(float output[4], } } +void EllipseMaskOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + MaskFunc mask_func; + switch (m_maskType) { + case CMP_NODE_MASKTYPE_ADD: + mask_func = [](const bool is_inside, const float *mask, const float *value) { + return is_inside ? MAX2(mask[0], value[0]) : mask[0]; + }; + break; + case CMP_NODE_MASKTYPE_SUBTRACT: + mask_func = [](const bool is_inside, const float *mask, const float *value) { + return is_inside ? CLAMPIS(mask[0] - value[0], 0, 1) : mask[0]; + }; + break; + case CMP_NODE_MASKTYPE_MULTIPLY: + mask_func = [](const bool is_inside, const float *mask, const float *value) { + return is_inside ? mask[0] * value[0] : 0; + }; + break; + case CMP_NODE_MASKTYPE_NOT: + mask_func = [](const bool is_inside, const float *mask, const float *value) { + if (is_inside) { + return mask[0] > 0.0f ? 0.0f : value[0]; + } + return mask[0]; + }; + break; + } + apply_mask(output, area, inputs, mask_func); +} + +void EllipseMaskOperation::apply_mask(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs, + MaskFunc mask_func) +{ + const MemoryBuffer *input_mask = inputs[0]; + const MemoryBuffer *input_value = inputs[1]; + const float op_w = this->getWidth(); + const float op_h = this->getHeight(); + const float half_w = this->m_data->width / 2.0f; + const float half_h = this->m_data->height / 2.0f; + const float tx = half_w * half_w; + const float ty = half_h * half_h; + for (const int y : YRange(area)) { + const float op_ry = y / op_h; + const float dy = (op_ry - this->m_data->y) / m_aspectRatio; + float *out = output->get_elem(area.xmin, y); + const float *mask = input_mask->get_elem(area.xmin, y); + const float *value = input_value->get_elem(area.xmin, y); + for (const int x : XRange(area)) { + const float op_rx = x / op_w; + const float dx = op_rx - this->m_data->x; + const float rx = this->m_data->x + (m_cosine * dx + m_sine * dy); + const float ry = this->m_data->y + (-m_sine * dx + m_cosine * dy); + float sx = rx - this->m_data->x; + sx *= sx; + float sy = ry - this->m_data->y; + sy *= sy; + const bool inside = ((sx / tx) + (sy / ty)) < 1.0f; + out[0] = mask_func(inside, mask, value); + + mask += input_mask->elem_stride; + value += input_value->elem_stride; + out += output->elem_stride; + } + } +} + void EllipseMaskOperation::deinitExecution() { this->m_inputMask = nullptr; diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.h b/source/blender/compositor/operations/COM_EllipseMaskOperation.h index 64afe0145cf..fba3f979d26 100644 --- a/source/blender/compositor/operations/COM_EllipseMaskOperation.h +++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.h @@ -18,12 +18,14 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class EllipseMaskOperation : public NodeOperation { +class EllipseMaskOperation : public MultiThreadedOperation { private: + using MaskFunc = std::function<float(bool is_inside, const float *mask, const float *value)>; + /** * Cached reference to the inputProgram */ @@ -64,6 +66,16 @@ class EllipseMaskOperation : public NodeOperation { { this->m_maskType = maskType; } + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + + private: + void apply_mask(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs, + MaskFunc mask_func); }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc index 2be6e4d1be7..3804e6ec646 100644 --- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc +++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc @@ -126,7 +126,7 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, float *buffer = src->getBuffer(); const uint8_t num_channels = src->get_num_channels(); - // <0.5 not valid, though can have a possibly useful sort of sharpening effect + /* <0.5 not valid, though can have a possibly useful sort of sharpening effect. */ if (sigma < 0.5f) { return; } @@ -135,8 +135,8 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, xy = 3; } - // XXX The YVV macro defined below explicitly expects sources of at least 3x3 pixels, - // so just skipping blur along faulty direction if src's def is below that limit! + /* XXX The YVV macro defined below explicitly expects sources of at least 3x3 pixels, + * so just skipping blur along faulty direction if src's def is below that limit! */ if (src_width < 3) { xy &= ~1; } @@ -147,32 +147,32 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, return; } - // see "Recursive Gabor Filtering" by Young/VanVliet - // all factors here in double.prec. - // Required, because for single.prec it seems to blow up if sigma > ~200 + /* See "Recursive Gabor Filtering" by Young/VanVliet + * all factors here in double-precision. + * Required, because for single-precision floating point seems to blow up if `sigma > ~200`. */ if (sigma >= 3.556f) { q = 0.9804f * (sigma - 3.556f) + 2.5091f; } - else { // sigma >= 0.5 + else { /* `sigma >= 0.5`. */ q = (0.0561f * sigma + 0.5784f) * sigma - 0.2568f; } q2 = q * q; sc = (1.1668 + q) * (3.203729649 + (2.21566 + q) * q); - // no gabor filtering here, so no complex multiplies, just the regular coefs. - // all negated here, so as not to have to recalc Triggs/Sdika matrix + /* No gabor filtering here, so no complex multiplies, just the regular coefficients. + * all negated here, so as not to have to recalc Triggs/Sdika matrix. */ cf[1] = q * (5.788961737 + (6.76492 + 3.0 * q) * q) / sc; cf[2] = -q2 * (3.38246 + 3.0 * q) / sc; - // 0 & 3 unchanged + /* 0 & 3 unchanged. */ cf[3] = q2 * q / sc; cf[0] = 1.0 - cf[1] - cf[2] - cf[3]; - // Triggs/Sdika border corrections, - // it seems to work, not entirely sure if it is actually totally correct, - // Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark), - // found one other implementation by Cristoph Lampert, - // but neither seem to be quite the same, result seems to be ok so far anyway. - // Extra scale factor here to not have to do it in filter, - // though maybe this had something to with the precision errors + /* Triggs/Sdika border corrections, + * it seems to work, not entirely sure if it is actually totally correct, + * Besides J.M.Geusebroek's `anigauss.c` (see http://www.science.uva.nl/~mark), + * found one other implementation by Cristoph Lampert, + * but neither seem to be quite the same, result seems to be ok so far anyway. + * Extra scale factor here to not have to do it in filter, + * though maybe this had something to with the precision errors */ sc = cf[0] / ((1.0 + cf[1] - cf[2] + cf[3]) * (1.0 - cf[1] - cf[2] - cf[3]) * (1.0 + cf[2] + (cf[1] - cf[3]) * cf[3])); tsM[0] = sc * (-cf[3] * cf[1] + 1.0 - cf[3] * cf[3] - cf[2]); @@ -210,12 +210,12 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, } \ (void)0 - // intermediate buffers + /* Intermediate buffers. */ sz = MAX2(src_width, src_height); X = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss X buf"); Y = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss Y buf"); W = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss W buf"); - if (xy & 1) { // H + if (xy & 1) { /* H. */ int offset; for (y = 0; y < src_height; y++) { const int yx = y * src_width; @@ -232,7 +232,7 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, } } } - if (xy & 2) { // V + if (xy & 2) { /* V. */ int offset; const int add = src_width * num_channels; @@ -257,7 +257,6 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, #undef YVV } -/// FastGaussianBlurValueOperation::FastGaussianBlurValueOperation() { this->addInputSocket(DataType::Value); @@ -336,8 +335,6 @@ void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect) } } - // newBuf-> - this->m_iirgaus = copy; } unlockMutex(); diff --git a/source/blender/compositor/operations/COM_MixOperation.cc b/source/blender/compositor/operations/COM_MixOperation.cc index 58fa09fa2a8..77ecbf60356 100644 --- a/source/blender/compositor/operations/COM_MixOperation.cc +++ b/source/blender/compositor/operations/COM_MixOperation.cc @@ -35,6 +35,7 @@ MixBaseOperation::MixBaseOperation() this->m_inputColor2Operation = nullptr; this->setUseValueAlphaMultiply(false); this->setUseClamp(false); + flags.can_be_constant = true; } void MixBaseOperation::initExecution() @@ -97,6 +98,45 @@ void MixBaseOperation::deinitExecution() this->m_inputColor2Operation = nullptr; } +void MixBaseOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_value = inputs[0]; + const MemoryBuffer *input_color1 = inputs[1]; + const MemoryBuffer *input_color2 = inputs[2]; + const int width = BLI_rcti_size_x(&area); + PixelCursor p; + p.out_stride = output->elem_stride; + p.value_stride = input_value->elem_stride; + p.color1_stride = input_color1->elem_stride; + p.color2_stride = input_color2->elem_stride; + for (const int y : YRange(area)) { + p.out = output->get_elem(area.xmin, y); + p.row_end = p.out + width * output->elem_stride; + p.value = input_value->get_elem(area.xmin, y); + p.color1 = input_color1->get_elem(area.xmin, y); + p.color2 = input_color2->get_elem(area.xmin, y); + update_memory_buffer_row(p); + } +} + +void MixBaseOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + const float value_m = 1.0f - value; + p.out[0] = value_m * p.color1[0] + value * p.color2[0]; + p.out[1] = value_m * p.color1[1] + value * p.color2[1]; + p.out[2] = value_m * p.color1[2] + value * p.color2[2]; + p.out[3] = p.color1[3]; + p.next(); + } +} + /* ******** Mix Add Operation ******** */ void MixAddOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) @@ -121,6 +161,23 @@ void MixAddOperation::executePixelSampled(float output[4], float x, float y, Pix clampIfNeeded(output); } +void MixAddOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + p.out[0] = p.color1[0] + value * p.color2[0]; + p.out[1] = p.color1[1] + value * p.color2[1]; + p.out[2] = p.color1[2] + value * p.color2[2]; + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Blend Operation ******** */ void MixBlendOperation::executePixelSampled(float output[4], @@ -150,6 +207,24 @@ void MixBlendOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixBlendOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + float value_m = 1.0f - value; + p.out[0] = value_m * p.color1[0] + value * p.color2[0]; + p.out[1] = value_m * p.color1[1] + value * p.color2[1]; + p.out[2] = value_m * p.color1[2] + value * p.color2[2]; + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Burn Operation ******** */ void MixColorBurnOperation::executePixelSampled(float output[4], @@ -228,6 +303,48 @@ void MixColorBurnOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixColorBurnOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + const float value_m = 1.0f - value; + + float tmp = value_m + value * p.color2[0]; + if (tmp <= 0.0f) { + p.out[0] = 0.0f; + } + else { + tmp = 1.0f - (1.0f - p.color1[0]) / tmp; + p.out[0] = CLAMPIS(tmp, 0.0f, 1.0f); + } + + tmp = value_m + value * p.color2[1]; + if (tmp <= 0.0f) { + p.out[1] = 0.0f; + } + else { + tmp = 1.0f - (1.0f - p.color1[1]) / tmp; + p.out[1] = CLAMPIS(tmp, 0.0f, 1.0f); + } + + tmp = value_m + value * p.color2[2]; + if (tmp <= 0.0f) { + p.out[2] = 0.0f; + } + else { + tmp = 1.0f - (1.0f - p.color1[2]) / tmp; + p.out[2] = CLAMPIS(tmp, 0.0f, 1.0f); + } + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Color Operation ******** */ void MixColorOperation::executePixelSampled(float output[4], @@ -268,6 +385,36 @@ void MixColorOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixColorOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + const float value_m = 1.0f - value; + + float colH, colS, colV; + rgb_to_hsv(p.color2[0], p.color2[1], p.color2[2], &colH, &colS, &colV); + if (colS != 0.0f) { + float rH, rS, rV; + float tmpr, tmpg, tmpb; + rgb_to_hsv(p.color1[0], p.color1[1], p.color1[2], &rH, &rS, &rV); + hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb); + p.out[0] = (value_m * p.color1[0]) + (value * tmpr); + p.out[1] = (value_m * p.color1[1]) + (value * tmpg); + p.out[2] = (value_m * p.color1[2]) + (value * tmpb); + } + else { + copy_v3_v3(p.out, p.color1); + } + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Darken Operation ******** */ void MixDarkenOperation::executePixelSampled(float output[4], @@ -296,6 +443,24 @@ void MixDarkenOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixDarkenOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + float value_m = 1.0f - value; + p.out[0] = min_ff(p.color1[0], p.color2[0]) * value + p.color1[0] * value_m; + p.out[1] = min_ff(p.color1[1], p.color2[1]) * value + p.color1[1] * value_m; + p.out[2] = min_ff(p.color1[2], p.color2[2]) * value + p.color1[2] * value_m; + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Difference Operation ******** */ void MixDifferenceOperation::executePixelSampled(float output[4], @@ -324,6 +489,24 @@ void MixDifferenceOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixDifferenceOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + const float value_m = 1.0f - value; + p.out[0] = value_m * p.color1[0] + value * fabsf(p.color1[0] - p.color2[0]); + p.out[1] = value_m * p.color1[1] + value * fabsf(p.color1[1] - p.color2[1]); + p.out[2] = value_m * p.color1[2] + value * fabsf(p.color1[2] - p.color2[2]); + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Difference Operation ******** */ void MixDivideOperation::executePixelSampled(float output[4], @@ -369,6 +552,41 @@ void MixDivideOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixDivideOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + const float value_m = 1.0f - value; + + if (p.color2[0] != 0.0f) { + p.out[0] = value_m * (p.color1[0]) + value * (p.color1[0]) / p.color2[0]; + } + else { + p.out[0] = 0.0f; + } + if (p.color2[1] != 0.0f) { + p.out[1] = value_m * (p.color1[1]) + value * (p.color1[1]) / p.color2[1]; + } + else { + p.out[1] = 0.0f; + } + if (p.color2[2] != 0.0f) { + p.out[2] = value_m * (p.color1[2]) + value * (p.color1[2]) / p.color2[2]; + } + else { + p.out[2] = 0.0f; + } + + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Dodge Operation ******** */ void MixDodgeOperation::executePixelSampled(float output[4], @@ -452,6 +670,64 @@ void MixDodgeOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixDodgeOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + + float tmp; + if (p.color1[0] != 0.0f) { + tmp = 1.0f - value * p.color2[0]; + if (tmp <= 0.0f) { + p.out[0] = 1.0f; + } + else { + p.out[0] = p.color1[0] / tmp; + CLAMP_MAX(p.out[0], 1.0f); + } + } + else { + p.out[0] = 0.0f; + } + + if (p.color1[1] != 0.0f) { + tmp = 1.0f - value * p.color2[1]; + if (tmp <= 0.0f) { + p.out[1] = 1.0f; + } + else { + p.out[1] = p.color1[1] / tmp; + CLAMP_MAX(p.out[1], 1.0f); + } + } + else { + p.out[1] = 0.0f; + } + + if (p.color1[2] != 0.0f) { + tmp = 1.0f - value * p.color2[2]; + if (tmp <= 0.0f) { + p.out[2] = 1.0f; + } + else { + p.out[2] = p.color1[2] / tmp; + CLAMP_MAX(p.out[2], 1.0f); + } + } + else { + p.out[2] = 0.0f; + } + + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Glare Operation ******** */ void MixGlareOperation::executePixelSampled(float output[4], @@ -487,6 +763,33 @@ void MixGlareOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixGlareOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + const float value = p.value[0]; + /* Linear interpolation between 3 cases: + * value=-1:output=input value=0:output=input+glare value=1:output=glare + */ + float input_weight; + float glare_weight; + if (value < 0.0f) { + input_weight = 1.0f; + glare_weight = 1.0f + value; + } + else { + input_weight = 1.0f - value; + glare_weight = 1.0f; + } + p.out[0] = input_weight * MAX2(p.color1[0], 0.0f) + glare_weight * p.color2[0]; + p.out[1] = input_weight * MAX2(p.color1[1], 0.0f) + glare_weight * p.color2[1]; + p.out[2] = input_weight * MAX2(p.color1[2], 0.0f) + glare_weight * p.color2[2]; + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Hue Operation ******** */ void MixHueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) @@ -524,6 +827,36 @@ void MixHueOperation::executePixelSampled(float output[4], float x, float y, Pix clampIfNeeded(output); } +void MixHueOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + const float value_m = 1.0f - value; + + float colH, colS, colV; + rgb_to_hsv(p.color2[0], p.color2[1], p.color2[2], &colH, &colS, &colV); + if (colS != 0.0f) { + float rH, rS, rV; + float tmpr, tmpg, tmpb; + rgb_to_hsv(p.color1[0], p.color1[1], p.color1[2], &rH, &rS, &rV); + hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb); + p.out[0] = value_m * p.color1[0] + value * tmpr; + p.out[1] = value_m * p.color1[1] + value * tmpg; + p.out[2] = value_m * p.color1[2] + value * tmpb; + } + else { + copy_v3_v3(p.out, p.color1); + } + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Lighten Operation ******** */ void MixLightenOperation::executePixelSampled(float output[4], @@ -570,6 +903,30 @@ void MixLightenOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixLightenOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + + float tmp = value * p.color2[0]; + p.out[0] = MAX2(tmp, p.color1[0]); + + tmp = value * p.color2[1]; + p.out[1] = MAX2(tmp, p.color1[1]); + + tmp = value * p.color2[2]; + p.out[2] = MAX2(tmp, p.color1[2]); + + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Linear Light Operation ******** */ void MixLinearLightOperation::executePixelSampled(float output[4], @@ -613,6 +970,39 @@ void MixLinearLightOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixLinearLightOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + if (p.color2[0] > 0.5f) { + p.out[0] = p.color1[0] + value * (2.0f * (p.color2[0] - 0.5f)); + } + else { + p.out[0] = p.color1[0] + value * (2.0f * (p.color2[0]) - 1.0f); + } + if (p.color2[1] > 0.5f) { + p.out[1] = p.color1[1] + value * (2.0f * (p.color2[1] - 0.5f)); + } + else { + p.out[1] = p.color1[1] + value * (2.0f * (p.color2[1]) - 1.0f); + } + if (p.color2[2] > 0.5f) { + p.out[2] = p.color1[2] + value * (2.0f * (p.color2[2] - 0.5f)); + } + else { + p.out[2] = p.color1[2] + value * (2.0f * (p.color2[2]) - 1.0f); + } + + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Multiply Operation ******** */ void MixMultiplyOperation::executePixelSampled(float output[4], @@ -641,6 +1031,25 @@ void MixMultiplyOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixMultiplyOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + const float value_m = 1.0f - value; + p.out[0] = p.color1[0] * (value_m + value * p.color2[0]); + p.out[1] = p.color1[1] * (value_m + value * p.color2[1]); + p.out[2] = p.color1[2] * (value_m + value * p.color2[2]); + + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Overlay Operation ******** */ void MixOverlayOperation::executePixelSampled(float output[4], @@ -686,6 +1095,40 @@ void MixOverlayOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixOverlayOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + const float value_m = 1.0f - value; + if (p.color1[0] < 0.5f) { + p.out[0] = p.color1[0] * (value_m + 2.0f * value * p.color2[0]); + } + else { + p.out[0] = 1.0f - (value_m + 2.0f * value * (1.0f - p.color2[0])) * (1.0f - p.color1[0]); + } + if (p.color1[1] < 0.5f) { + p.out[1] = p.color1[1] * (value_m + 2.0f * value * p.color2[1]); + } + else { + p.out[1] = 1.0f - (value_m + 2.0f * value * (1.0f - p.color2[1])) * (1.0f - p.color1[1]); + } + if (p.color1[2] < 0.5f) { + p.out[2] = p.color1[2] * (value_m + 2.0f * value * p.color2[2]); + } + else { + p.out[2] = 1.0f - (value_m + 2.0f * value * (1.0f - p.color2[2])) * (1.0f - p.color1[2]); + } + + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Saturation Operation ******** */ void MixSaturationOperation::executePixelSampled(float output[4], @@ -723,6 +1166,33 @@ void MixSaturationOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixSaturationOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + const float value_m = 1.0f - value; + + float rH, rS, rV; + rgb_to_hsv(p.color1[0], p.color1[1], p.color1[2], &rH, &rS, &rV); + if (rS != 0.0f) { + float colH, colS, colV; + rgb_to_hsv(p.color2[0], p.color2[1], p.color2[2], &colH, &colS, &colV); + hsv_to_rgb(rH, (value_m * rS + value * colS), rV, &p.out[0], &p.out[1], &p.out[2]); + } + else { + copy_v3_v3(p.out, p.color1); + } + + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Screen Operation ******** */ void MixScreenOperation::executePixelSampled(float output[4], @@ -752,6 +1222,25 @@ void MixScreenOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixScreenOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + const float value_m = 1.0f - value; + + p.out[0] = 1.0f - (value_m + value * (1.0f - p.color2[0])) * (1.0f - p.color1[0]); + p.out[1] = 1.0f - (value_m + value * (1.0f - p.color2[1])) * (1.0f - p.color1[1]); + p.out[2] = 1.0f - (value_m + value * (1.0f - p.color2[2])) * (1.0f - p.color1[2]); + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Soft Light Operation ******** */ void MixSoftLightOperation::executePixelSampled(float output[4], @@ -793,6 +1282,34 @@ void MixSoftLightOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixSoftLightOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + const float value_m = 1.0f - value; + float scr, scg, scb; + + /* First calculate non-fac based Screen mix. */ + scr = 1.0f - (1.0f - p.color2[0]) * (1.0f - p.color1[0]); + scg = 1.0f - (1.0f - p.color2[1]) * (1.0f - p.color1[1]); + scb = 1.0f - (1.0f - p.color2[2]) * (1.0f - p.color1[2]); + + p.out[0] = value_m * p.color1[0] + + value * ((1.0f - p.color1[0]) * p.color2[0] * p.color1[0] + p.color1[0] * scr); + p.out[1] = value_m * p.color1[1] + + value * ((1.0f - p.color1[1]) * p.color2[1] * p.color1[1] + p.color1[1] * scg); + p.out[2] = value_m * p.color1[2] + + value * ((1.0f - p.color1[2]) * p.color2[2] * p.color1[2] + p.color1[2] * scb); + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Subtract Operation ******** */ void MixSubtractOperation::executePixelSampled(float output[4], @@ -820,6 +1337,23 @@ void MixSubtractOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixSubtractOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + p.out[0] = p.color1[0] - value * p.color2[0]; + p.out[1] = p.color1[1] - value * p.color2[1]; + p.out[2] = p.color1[2] - value * p.color2[2]; + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + /* ******** Mix Value Operation ******** */ void MixValueOperation::executePixelSampled(float output[4], @@ -851,4 +1385,25 @@ void MixValueOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MixValueOperation::update_memory_buffer_row(PixelCursor &p) +{ + while (p.out < p.row_end) { + float value = p.value[0]; + if (this->useValueAlphaMultiply()) { + value *= p.color2[3]; + } + float value_m = 1.0f - value; + + float rH, rS, rV; + float colH, colS, colV; + rgb_to_hsv(p.color1[0], p.color1[1], p.color1[2], &rH, &rS, &rV); + rgb_to_hsv(p.color2[0], p.color2[1], p.color2[2], &colH, &colS, &colV); + hsv_to_rgb(rH, rS, (value_m * rV + value * colV), &p.out[0], &p.out[1], &p.out[2]); + p.out[3] = p.color1[3]; + + clampIfNeeded(p.out); + p.next(); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MixOperation.h b/source/blender/compositor/operations/COM_MixOperation.h index 6c241bc5762..7ef9d78d58f 100644 --- a/source/blender/compositor/operations/COM_MixOperation.h +++ b/source/blender/compositor/operations/COM_MixOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { @@ -27,8 +27,29 @@ namespace blender::compositor { * it assumes we are in sRGB color space. */ -class MixBaseOperation : public NodeOperation { +class MixBaseOperation : public MultiThreadedOperation { protected: + struct PixelCursor { + float *out; + const float *row_end; + const float *value; + const float *color1; + const float *color2; + int out_stride; + int value_stride; + int color1_stride; + int color2_stride; + + void next() + { + BLI_assert(out < row_end); + out += out_stride; + value += value_stride; + color1 += color1_stride; + color2 += color2_stride; + } + }; + /** * Prefetched reference to the inputProgram */ @@ -81,101 +102,165 @@ class MixBaseOperation : public NodeOperation { { this->m_useClamp = value; } + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) final; + + protected: + virtual void update_memory_buffer_row(PixelCursor &p); }; class MixAddOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixBlendOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixColorBurnOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixColorOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixDarkenOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixDifferenceOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixDivideOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixDodgeOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixGlareOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixHueOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixLightenOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixLinearLightOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixMultiplyOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixOverlayOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixSaturationOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixScreenOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixSoftLightOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixSubtractOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; class MixValueOperation : public MixBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_row(PixelCursor &p) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cc b/source/blender/compositor/operations/COM_MovieClipOperation.cc index d93a75407c4..e520b928edf 100644 --- a/source/blender/compositor/operations/COM_MovieClipOperation.cc +++ b/source/blender/compositor/operations/COM_MovieClipOperation.cc @@ -116,6 +116,18 @@ void MovieClipBaseOperation::executePixelSampled(float output[4], } } +void MovieClipBaseOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> UNUSED(inputs)) +{ + if (m_movieClipBuffer) { + output->copy_from(m_movieClipBuffer, area); + } + else { + output->fill(area, COM_COLOR_TRANSPARENT); + } +} + MovieClipOperation::MovieClipOperation() : MovieClipBaseOperation() { this->addOutputSocket(DataType::Color); @@ -136,4 +148,16 @@ void MovieClipAlphaOperation::executePixelSampled(float output[4], output[0] = result[3]; } +void MovieClipAlphaOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> UNUSED(inputs)) +{ + if (m_movieClipBuffer) { + output->copy_from(m_movieClipBuffer, area, 3, COM_DATA_TYPE_VALUE_CHANNELS, 0); + } + else { + output->fill(area, COM_VALUE_ZERO); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.h b/source/blender/compositor/operations/COM_MovieClipOperation.h index c853ea43762..0a0c4c00f81 100644 --- a/source/blender/compositor/operations/COM_MovieClipOperation.h +++ b/source/blender/compositor/operations/COM_MovieClipOperation.h @@ -19,7 +19,7 @@ #pragma once #include "BLI_listbase.h" -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "DNA_movieclip_types.h" #include "IMB_imbuf_types.h" @@ -28,7 +28,7 @@ namespace blender::compositor { /** * Base class for movie clip */ -class MovieClipBaseOperation : public NodeOperation { +class MovieClipBaseOperation : public MultiThreadedOperation { protected: MovieClip *m_movieClip; MovieClipUser *m_movieClipUser; @@ -67,6 +67,10 @@ class MovieClipBaseOperation : public NodeOperation { this->m_framenumber = framenumber; } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; class MovieClipOperation : public MovieClipBaseOperation { @@ -78,6 +82,10 @@ class MovieClipAlphaOperation : public MovieClipBaseOperation { public: MovieClipAlphaOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc index 3c753591ced..b078d85372d 100644 --- a/source/blender/compositor/operations/COM_SMAAOperation.cc +++ b/source/blender/compositor/operations/COM_SMAAOperation.cc @@ -19,9 +19,9 @@ */ #include "COM_SMAAOperation.h" +#include "BKE_node.h" #include "BLI_math.h" #include "COM_SMAAAreaTexture.h" -#include "BKE_node.h" extern "C" { #include "IMB_colormanagement.h" diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cc b/source/blender/compositor/operations/COM_SunBeamsOperation.cc index ff117841e8e..bd82b6397ad 100644 --- a/source/blender/compositor/operations/COM_SunBeamsOperation.cc +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cc @@ -46,14 +46,14 @@ void SunBeamsOperation::initExecution() * (u,v) is used to designate sector space coordinates * * For a target point (x,y) the sector should be chosen such that - * ``u >= v >= 0`` + * `u >= v >= 0` * This removes the need to handle all sorts of special cases. * * Template parameters: - * fxu : buffer increment in x for sector u+1 - * fxv : buffer increment in x for sector v+1 - * fyu : buffer increment in y for sector u+1 - * fyv : buffer increment in y for sector v+1 + * \param fxu: buffer increment in x for sector `u + 1`. + * \param fxv: buffer increment in x for sector `v + 1`. + * \param fyu: buffer increment in y for sector `u + 1`. + * \param fyv: buffer increment in y for sector `v + 1`. */ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator { diff --git a/source/blender/compositor/operations/COM_TextureOperation.cc b/source/blender/compositor/operations/COM_TextureOperation.cc index 059a289ae4d..c8e0844d35f 100644 --- a/source/blender/compositor/operations/COM_TextureOperation.cc +++ b/source/blender/compositor/operations/COM_TextureOperation.cc @@ -157,14 +157,8 @@ void TextureBaseOperation::executePixelSampled(float output[4], m_sceneColorManage, false); - if (texres.talpha) { - output[3] = texres.ta; - } - else { - output[3] = texres.tin; - } - - if ((retval & TEX_RGB)) { + output[3] = texres.talpha ? texres.ta : texres.tin; + if (retval & TEX_RGB) { output[0] = texres.tr; output[1] = texres.tg; output[2] = texres.tb; @@ -174,4 +168,67 @@ void TextureBaseOperation::executePixelSampled(float output[4], } } +void TextureBaseOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const int op_width = this->getWidth(); + const int op_height = this->getHeight(); + const float center_x = op_width / 2; + const float center_y = op_height / 2; + TexResult tex_result = {0}; + float vec[3]; + const int thread_id = WorkScheduler::current_thread_id(); + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *tex_offset = it.in(0); + const float *tex_size = it.in(1); + float u = (it.x - center_x) / op_width * 2; + float v = (it.y - center_y) / op_height * 2; + + /* When no interpolation/filtering happens in multitex() force nearest interpolation. + * We do it here because (a) we can't easily say multitex() that we want nearest + * interpolation and (b) in such configuration multitex() simply floor's the value + * which often produces artifacts. + */ + if (m_texture != nullptr && (m_texture->imaflag & TEX_INTERPOL) == 0) { + u += 0.5f / center_x; + v += 0.5f / center_y; + } + + vec[0] = tex_size[0] * (u + tex_offset[0]); + vec[1] = tex_size[1] * (v + tex_offset[1]); + vec[2] = tex_size[2] * tex_offset[2]; + + const int retval = multitex_ext(this->m_texture, + vec, + nullptr, + nullptr, + 0, + &tex_result, + thread_id, + m_pool, + m_sceneColorManage, + false); + + it.out[3] = tex_result.talpha ? tex_result.ta : tex_result.tin; + if (retval & TEX_RGB) { + it.out[0] = tex_result.tr; + it.out[1] = tex_result.tg; + it.out[2] = tex_result.tb; + } + else { + it.out[0] = it.out[1] = it.out[2] = it.out[3]; + } + } +} + +void TextureAlphaOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + MemoryBuffer texture(DataType::Color, area); + TextureBaseOperation::update_memory_buffer_partial(&texture, area, inputs); + output->copy_from(&texture, area, 3, COM_DATA_TYPE_VALUE_CHANNELS, 0); +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TextureOperation.h b/source/blender/compositor/operations/COM_TextureOperation.h index 6fec9ab8f33..1e95cb270d0 100644 --- a/source/blender/compositor/operations/COM_TextureOperation.h +++ b/source/blender/compositor/operations/COM_TextureOperation.h @@ -19,7 +19,7 @@ #pragma once #include "BLI_listbase.h" -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "DNA_texture_types.h" #include "MEM_guardedalloc.h" @@ -33,7 +33,7 @@ namespace blender::compositor { * * \todo Rename to operation. */ -class TextureBaseOperation : public NodeOperation { +class TextureBaseOperation : public MultiThreadedOperation { private: Tex *m_texture; const RenderData *m_rd; @@ -71,6 +71,10 @@ class TextureBaseOperation : public NodeOperation { { this->m_sceneColorManage = sceneColorManage; } + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; class TextureOperation : public TextureBaseOperation { @@ -81,6 +85,10 @@ class TextureAlphaOperation : public TextureBaseOperation { public: TextureAlphaOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cc b/source/blender/compositor/operations/COM_ViewerOperation.cc index 860f56e23fa..37a45ac32cb 100644 --- a/source/blender/compositor/operations/COM_ViewerOperation.cc +++ b/source/blender/compositor/operations/COM_ViewerOperation.cc @@ -191,10 +191,11 @@ void ViewerOperation::initImage() BLI_thread_unlock(LOCK_DRAW_IMAGE); } -void ViewerOperation::updateImage(rcti *rect) +void ViewerOperation::updateImage(const rcti *rect) { + float *buffer = m_outputBuffer; IMB_partial_display_buffer_update(this->m_ibuf, - this->m_outputBuffer, + buffer, nullptr, getWidth(), 0, @@ -218,4 +219,44 @@ eCompositorPriority ViewerOperation::getRenderPriority() const return eCompositorPriority::Low; } +void ViewerOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output), + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + if (!m_outputBuffer) { + return; + } + + MemoryBuffer output_buffer( + m_outputBuffer, COM_DATA_TYPE_COLOR_CHANNELS, getWidth(), getHeight()); + const MemoryBuffer *input_image = inputs[0]; + output_buffer.copy_from(input_image, area); + if (this->m_useAlphaInput) { + const MemoryBuffer *input_alpha = inputs[1]; + output_buffer.copy_from(input_alpha, area, 0, COM_DATA_TYPE_VALUE_CHANNELS, 3); + } + + if (m_depthBuffer) { + MemoryBuffer depth_buffer( + m_depthBuffer, COM_DATA_TYPE_VALUE_CHANNELS, getWidth(), getHeight()); + const MemoryBuffer *input_depth = inputs[2]; + depth_buffer.copy_from(input_depth, area); + } + + updateImage(&area); +} + +void ViewerOperation::clear_display_buffer() +{ + BLI_assert(isActiveViewerOutput()); + initImage(); + size_t buf_bytes = (size_t)m_ibuf->y * m_ibuf->x * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float); + if (buf_bytes > 0) { + memset(m_outputBuffer, 0, buf_bytes); + rcti display_area; + BLI_rcti_init(&display_area, 0, m_ibuf->x, 0, m_ibuf->y); + updateImage(&display_area); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ViewerOperation.h b/source/blender/compositor/operations/COM_ViewerOperation.h index c0f13ff79fc..06ac501a535 100644 --- a/source/blender/compositor/operations/COM_ViewerOperation.h +++ b/source/blender/compositor/operations/COM_ViewerOperation.h @@ -20,15 +20,17 @@ #include "BKE_global.h" #include "BLI_rect.h" -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "DNA_image_types.h" namespace blender::compositor { -class ViewerOperation : public NodeOperation { +class ViewerOperation : public MultiThreadedOperation { private: + /* TODO(manzanilla): To be removed together with tiled implementation. */ float *m_outputBuffer; float *m_depthBuffer; + Image *m_image; ImageUser *m_imageUser; bool m_active; @@ -125,8 +127,14 @@ class ViewerOperation : public NodeOperation { this->m_displaySettings = displaySettings; } + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + + void clear_display_buffer(); + private: - void updateImage(rcti *rect); + void updateImage(const rcti *rect); void initImage(); }; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index e561d0b653c..8d1074d912f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -1496,7 +1496,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob add_operation_node( &object->id, NodeType::BATCH_CACHE, - OperationCode::BATCH_UPDATE_SELECT, + OperationCode::GEOMETRY_SELECT_UPDATE, [object_cow](::Depsgraph *depsgraph) { BKE_object_select_update(depsgraph, object_cow); }); } @@ -1517,37 +1517,33 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool if (key) { build_shapekeys(key); } - - /* Geometry evaluation. */ - /* Entry operation, takes care of initialization, and some other - * relations which needs to be run prior to actual geometry evaluation. */ - op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); - op_node->set_as_entry(); - - add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DEFORM); - + /* Nodes for result of obdata's evaluation, and geometry + * evaluation on object. */ const ID_Type id_type = GS(obdata->name); switch (id_type) { case ID_ME: { - add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - [obdata_cow](::Depsgraph *depsgraph) { - BKE_mesh_eval_geometry(depsgraph, (Mesh *)obdata_cow); - }); + op_node = add_operation_node(obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + [obdata_cow](::Depsgraph *depsgraph) { + BKE_mesh_eval_geometry(depsgraph, (Mesh *)obdata_cow); + }); + op_node->set_as_entry(); break; } case ID_MB: { - add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + op_node->set_as_entry(); break; } case ID_CU: { - add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - [obdata_cow](::Depsgraph *depsgraph) { - BKE_curve_eval_geometry(depsgraph, (Curve *)obdata_cow); - }); + op_node = add_operation_node(obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + [obdata_cow](::Depsgraph *depsgraph) { + BKE_curve_eval_geometry(depsgraph, (Curve *)obdata_cow); + }); + op_node->set_as_entry(); /* Make sure objects used for bevel.taper are in the graph. * NOTE: This objects might be not linked to the scene. */ Curve *cu = (Curve *)obdata; @@ -1563,41 +1559,47 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool break; } case ID_LT: { - add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - [obdata_cow](::Depsgraph *depsgraph) { - BKE_lattice_eval_geometry(depsgraph, (Lattice *)obdata_cow); - }); + op_node = add_operation_node(obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + [obdata_cow](::Depsgraph *depsgraph) { + BKE_lattice_eval_geometry(depsgraph, (Lattice *)obdata_cow); + }); + op_node->set_as_entry(); break; } case ID_GD: { /* GPencil evaluation operations. */ - add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - [obdata_cow](::Depsgraph *depsgraph) { - BKE_gpencil_frame_active_set(depsgraph, (bGPdata *)obdata_cow); - }); + op_node = add_operation_node(obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + [obdata_cow](::Depsgraph *depsgraph) { + BKE_gpencil_frame_active_set(depsgraph, + (bGPdata *)obdata_cow); + }); + op_node->set_as_entry(); break; } case ID_HA: { - add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + op_node->set_as_entry(); break; } case ID_PT: { - add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + op_node->set_as_entry(); break; } case ID_VO: { /* Volume frame update. */ - add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - [obdata_cow](::Depsgraph *depsgraph) { - BKE_volume_eval_geometry(depsgraph, (Volume *)obdata_cow); - }); + op_node = add_operation_node(obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + [obdata_cow](::Depsgraph *depsgraph) { + BKE_volume_eval_geometry(depsgraph, (Volume *)obdata_cow); + }); + op_node->set_as_entry(); break; } default: @@ -1611,22 +1613,10 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool /* Batch cache. */ add_operation_node(obdata, NodeType::BATCH_CACHE, - OperationCode::BATCH_UPDATE_SELECT, + OperationCode::GEOMETRY_SELECT_UPDATE, [obdata_cow](::Depsgraph *depsgraph) { BKE_object_data_select_update(depsgraph, obdata_cow); }); - add_operation_node(obdata, - NodeType::BATCH_CACHE, - OperationCode::BATCH_UPDATE_DEFORM, - [obdata_cow](::Depsgraph *depsgraph) { - BKE_object_data_eval_batch_cache_deform_tag(depsgraph, obdata_cow); - }); - add_operation_node(obdata, - NodeType::BATCH_CACHE, - OperationCode::BATCH_UPDATE_ALL, - [obdata_cow](::Depsgraph *depsgraph) { - BKE_object_data_eval_batch_cache_dirty_tag(depsgraph, obdata_cow); - }); } void DepsgraphNodeBuilder::build_armature(bArmature *armature) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 415145c8fa1..c7c6fafa512 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -647,7 +647,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll /* Only create geometry relations to child objects, if they have a geometry component. */ OperationKey object_geometry_key{ - &cob->ob->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT}; + &cob->ob->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL}; if (find_node(object_geometry_key) != nullptr) { add_relation(object_geometry_key, collection_geometry_key, "Collection Geometry"); } @@ -1098,8 +1098,7 @@ void DepsgraphRelationBuilder::build_object_pointcache(Object *object) } else { flag = FLAG_GEOMETRY; - OperationKey geometry_key( - &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); + OperationKey geometry_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); add_relation(point_cache_key, geometry_key, "Point Cache -> Geometry"); } BLI_assert(flag != -1); @@ -1869,8 +1868,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) void DepsgraphRelationBuilder::build_particle_systems(Object *object) { TimeSourceKey time_src_key; - OperationKey obdata_ubereval_key( - &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); + OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); OperationKey eval_init_key( &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_INIT); OperationKey eval_done_key( @@ -2018,8 +2016,7 @@ void DepsgraphRelationBuilder::build_particle_system_visualization_object(Object { OperationKey psys_key( &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_EVAL, psys->name); - OperationKey obdata_ubereval_key( - &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); + OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); ComponentKey dup_ob_key(&draw_object->id, NodeType::TRANSFORM); add_relation(dup_ob_key, psys_key, "Particle Object Visualization"); if (draw_object->type == OB_MBALL) { @@ -2076,15 +2073,15 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) /* Get nodes for result of obdata's evaluation, and geometry evaluation * on object. */ ComponentKey obdata_geom_key(obdata, NodeType::GEOMETRY); - OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + ComponentKey geom_key(&object->id, NodeType::GEOMETRY); /* Link components to each other. */ - add_relation(obdata_geom_key, obdata_ubereval_key, "Object Geometry Base Data"); - + add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data"); + OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); /* Special case: modifiers evaluation queries scene for various things like * data mask to be used. We add relation here to ensure object is never * evaluated prior to Scene's CoW is ready. */ OperationKey scene_key(&scene_->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL); - Relation *rel = add_relation(scene_key, geom_init_key, "CoW Relation"); + Relation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation"); rel->flag |= RELATION_FLAG_NO_FLUSH; /* Modifiers */ if (object->modifiers.first != nullptr) { @@ -2094,13 +2091,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type); if (mti->updateDepsgraph) { - DepsNodeHandle handle = create_node_handle(geom_init_key); + DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); mti->updateDepsgraph(md, &ctx); } if (BKE_object_modifier_use_time(object, md)) { TimeSourceKey time_src_key; - add_relation(time_src_key, geom_init_key, "Time Source"); + add_relation(time_src_key, obdata_ubereval_key, "Time Source"); } } } @@ -2113,13 +2110,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info( (GpencilModifierType)md->type); if (mti->updateDepsgraph) { - DepsNodeHandle handle = create_node_handle(geom_init_key); + DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); mti->updateDepsgraph(md, &ctx, graph_->mode); } if (BKE_object_modifier_gpencil_use_time(object, md)) { TimeSourceKey time_src_key; - add_relation(time_src_key, geom_init_key, "Time Source"); + add_relation(time_src_key, obdata_ubereval_key, "Time Source"); } } } @@ -2131,13 +2128,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) LISTBASE_FOREACH (ShaderFxData *, fx, &object->shader_fx) { const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info((ShaderFxType)fx->type); if (fxi->updateDepsgraph) { - DepsNodeHandle handle = create_node_handle(geom_init_key); + DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); fxi->updateDepsgraph(fx, &ctx); } if (BKE_object_shaderfx_use_time(object, fx)) { TimeSourceKey time_src_key; - add_relation(time_src_key, geom_init_key, "Time Source"); + add_relation(time_src_key, obdata_ubereval_key, "Time Source"); } } } @@ -2163,7 +2160,6 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) add_relation(mom_transform_key, mom_geom_key, "Metaball Motherball Transform -> Geometry"); } else { - ComponentKey geom_key(&object->id, NodeType::GEOMETRY); ComponentKey transform_key(&object->id, NodeType::TRANSFORM); add_relation(geom_key, mom_geom_key, "Metaball Motherball"); add_relation(transform_key, mom_geom_key, "Metaball Motherball"); @@ -2178,7 +2174,9 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) * Ideally we need to get rid of this relation. */ if (object_particles_depends_on_time(object)) { TimeSourceKey time_key; - add_relation(time_key, geom_init_key, "Legacy particle time"); + OperationKey obdata_ubereval_key( + &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + add_relation(time_key, obdata_ubereval_key, "Legacy particle time"); } /* Object data data-block. */ build_object_data_geometry_datablock((ID *)object->data); @@ -2200,33 +2198,12 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) add_relation(final_geometry_key, synchronize_key, "Synchronize to Original"); /* Batch cache. */ OperationKey object_data_select_key( - obdata, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_SELECT); + obdata, NodeType::BATCH_CACHE, OperationCode::GEOMETRY_SELECT_UPDATE); OperationKey object_select_key( - &object->id, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_SELECT); - + &object->id, NodeType::BATCH_CACHE, OperationCode::GEOMETRY_SELECT_UPDATE); add_relation(object_data_select_key, object_select_key, "Data Selection -> Object Selection"); - add_relation(final_geometry_key, - object_select_key, - "Object Geometry -> Select Update", - RELATION_FLAG_NO_FLUSH); - - OperationKey object_data_geom_deform_key( - obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DEFORM); - OperationKey object_data_geom_init_key( - obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); - - OperationKey object_data_batch_deform_key( - obdata, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_DEFORM); - OperationKey object_data_batch_all_key( - obdata, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_ALL); - - add_relation(geom_init_key, object_data_batch_all_key, "Object Geometry -> Batch Update All"); - add_relation( - object_data_geom_init_key, object_data_batch_all_key, "Data Init -> Batch Update All"); - add_relation(object_data_geom_deform_key, - object_data_batch_deform_key, - "Data Deform -> Batch Update Deform"); + geom_key, object_select_key, "Object Geometry -> Select Update", RELATION_FLAG_NO_FLUSH); } void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) @@ -2244,13 +2221,8 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) build_shapekeys(key); } /* Link object data evaluation node to exit operation. */ - OperationKey obdata_geom_deform_key( - obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DEFORM); - OperationKey obdata_geom_init_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); OperationKey obdata_geom_eval_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); OperationKey obdata_geom_done_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DONE); - add_relation(obdata_geom_init_key, obdata_geom_eval_key, "ObData Init -> Geom Eval"); - add_relation(obdata_geom_deform_key, obdata_geom_eval_key, "ObData Deform -> Geom Eval"); add_relation(obdata_geom_eval_key, obdata_geom_done_key, "ObData Geom Eval Done"); /* Type-specific links. */ const ID_Type id_type = GS(obdata->name); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index 8e3960e1a15..bdabd67cc07 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -153,8 +153,8 @@ bool RNANodeQuery::contains(const char *prop_identifier, const char *rna_path_co return false; } - // If substr != prop_identifier, it means that the substring is found further in prop_identifier, - // and that thus index -1 is a valid memory location. + /* If substr != prop_identifier, it means that the substring is found further in prop_identifier, + * and that thus index -1 is a valid memory location. */ const bool start_ok = substr == prop_identifier || substr[-1] == '.'; if (!start_ok) { return false; diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 34b33e9a6c0..ab93464d09a 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -117,7 +117,7 @@ void depsgraph_select_tag_to_component_opcode(const ID *id, } else if (is_selectable_data_id_type(id_type)) { *component_type = NodeType::BATCH_CACHE; - *operation_code = OperationCode::BATCH_UPDATE_SELECT; + *operation_code = OperationCode::GEOMETRY_SELECT_UPDATE; } else { *component_type = NodeType::COPY_ON_WRITE; @@ -168,11 +168,6 @@ void depsgraph_tag_to_component_opcode(const ID *id, break; case ID_RECALC_GEOMETRY: depsgraph_geometry_tag_to_component(id, component_type); - *operation_code = OperationCode::GEOMETRY_EVAL_INIT; - break; - case ID_RECALC_GEOMETRY_DEFORM: - depsgraph_geometry_tag_to_component(id, component_type); - *operation_code = OperationCode::GEOMETRY_EVAL_DEFORM; break; case ID_RECALC_ANIMATION: *component_type = NodeType::ANIMATION; @@ -713,8 +708,6 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag) return "GEOMETRY"; case ID_RECALC_GEOMETRY_ALL_MODES: return "GEOMETRY_ALL_MODES"; - case ID_RECALC_GEOMETRY_DEFORM: - return "GEOMETRY_DEFORM"; case ID_RECALC_ANIMATION: return "ANIMATION"; case ID_RECALC_PSYS_REDO: diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 915b9fedcec..ad88cf656ad 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -103,7 +103,7 @@ void evaluate_node(const DepsgraphEvalState *state, OperationNode *operation_nod ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(state->graph); /* Sanity checks. */ - BLI_assert(!operation_node->is_noop() && "NOOP nodes should not actually be scheduled"); + BLI_assert_msg(!operation_node->is_noop(), "NOOP nodes should not actually be scheduled"); /* Perform operation. */ if (state->do_stats) { const double start_time = PIL_check_seconds_timer(); 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 346eba5bbc2..a844d23b558 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 @@ -348,7 +348,7 @@ bool scene_copy_inplace_no_main(const Scene *scene, Scene *new_scene) /* For the given scene get view layer which corresponds to an original for the * scene's evaluated one. This depends on how the scene is pulled into the - * dependency graph. */ + * dependency graph. */ ViewLayer *get_original_view_layer(const Depsgraph *depsgraph, const IDNode *id_node) { if (id_node->linked_state == DEG_ID_LINKED_DIRECTLY) { diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 2cbb0b52e34..a015491e2d7 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -58,15 +58,15 @@ #include "intern/eval/deg_eval_copy_on_write.h" -// Invalidate data-block data when update is flushed on it. -// -// The idea of this is to help catching cases when area is accessing data which -// is not yet evaluated, which could happen due to missing relations. The issue -// is that usually that data will be kept from previous frame, and it looks to -// be plausible. -// -// This ensures that data does not look plausible, making it much easier to -// catch usage of invalid state. +/* Invalidate data-block data when update is flushed on it. + * + * The idea of this is to help catching cases when area is accessing data which + * is not yet evaluated, which could happen due to missing relations. The issue + * is that usually that data will be kept from previous frame, and it looks to + * be plausible. + * + * This ensures that data does not look plausible, making it much easier to + * catch usage of invalid state. */ #undef INVALIDATE_ON_FLUSH namespace blender::deg { @@ -144,10 +144,7 @@ inline void flush_handle_component_node(IDNode *id_node, * special component where we don't want all operations to be tagged. * * TODO(sergey): Make this a more generic solution. */ - if (!ELEM(comp_node->type, - NodeType::PARTICLE_SETTINGS, - NodeType::PARTICLE_SYSTEM, - NodeType::BATCH_CACHE)) { + if (!ELEM(comp_node->type, NodeType::PARTICLE_SETTINGS, NodeType::PARTICLE_SYSTEM)) { for (OperationNode *op : comp_node->operations) { op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; } diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc index d98486b83a8..c25dc6fc8d5 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc @@ -98,8 +98,6 @@ const char *operationCodeAsString(OperationCode opcode) /* Geometry. */ case OperationCode::GEOMETRY_EVAL_INIT: return "GEOMETRY_EVAL_INIT"; - case OperationCode::GEOMETRY_EVAL_DEFORM: - return "GEOMETRY_EVAL_DEFORM"; case OperationCode::GEOMETRY_EVAL: return "GEOMETRY_EVAL"; case OperationCode::GEOMETRY_EVAL_DONE: @@ -162,12 +160,8 @@ const char *operationCodeAsString(OperationCode opcode) case OperationCode::FILE_CACHE_UPDATE: return "FILE_CACHE_UPDATE"; /* Batch cache. */ - case OperationCode::BATCH_UPDATE_SELECT: - return "BATCH_UPDATE_SELECT"; - case OperationCode::BATCH_UPDATE_DEFORM: - return "BATCH_UPDATE_DEFORM"; - case OperationCode::BATCH_UPDATE_ALL: - return "BATCH_UPDATE_ALL"; + case OperationCode::GEOMETRY_SELECT_UPDATE: + return "GEOMETRY_SELECT_UPDATE"; /* Masks. */ case OperationCode::MASK_ANIMATION: return "MASK_ANIMATION"; diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h index b0130d03c69..a17186da941 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.h +++ b/source/blender/depsgraph/intern/node/deg_node_operation.h @@ -100,11 +100,7 @@ enum class OperationCode { /* Initialize evaluation of the geometry. Is an entry operation of geometry * component. */ GEOMETRY_EVAL_INIT, - /* Evaluate the geometry, including modifiers, and update only batches that - * are affected by deform operations. */ - GEOMETRY_EVAL_DEFORM, - /* Evaluate the geometry, including modifiers, but don't update the batch - * cache. */ + /* Evaluate the whole geometry, including modifiers. */ GEOMETRY_EVAL, /* Evaluation of geometry is completely done. */ GEOMETRY_EVAL_DONE, @@ -182,9 +178,7 @@ enum class OperationCode { WORLD_UPDATE, /* Batch caches. -------------------------------------------------------- */ - BATCH_UPDATE_SELECT, - BATCH_UPDATE_DEFORM, - BATCH_UPDATE_ALL, + GEOMETRY_SELECT_UPDATE, /* Masks. --------------------------------------------------------------- */ MASK_ANIMATION, diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index b7bcd127859..48c24d138e6 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -192,7 +192,7 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, gpumat, stl->effects->sss_sample_count, &sss_tex_profile); if (!sss_profile) { - BLI_assert(0 && "SSS pass requested but no SSS data was found"); + BLI_assert_msg(0, "SSS pass requested but no SSS data was found"); return; } diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl index b1368f90846..36a52e05a4a 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl @@ -327,7 +327,7 @@ vec2 safe_normalize_len(vec2 v, out float len) float stroke_thickness_modulate(float thickness) { - /* Modify stroke thickness by object and layer factors.-*/ + /* Modify stroke thickness by object and layer factors. */ thickness *= thicknessScale; thickness += thicknessOffset; thickness = max(1.0, thickness); diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c index e3f01d968ae..b50dc08bb97 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.c +++ b/source/blender/draw/engines/overlay/overlay_outline.c @@ -340,7 +340,7 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, if (shgroup && geom) { if (ob->type == OB_POINTCLOUD) { - /* Draw range to avoid drawcall batching messing up the instance attrib. */ + /* Draw range to avoid drawcall batching messing up the instance attribute. */ DRW_shgroup_call_instance_range(shgroup, ob, geom, 0, 0); } else { diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index e9d6763fbe9..f09c019ef8d 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -128,7 +128,7 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd, BLI_INLINE void workbench_object_drawcall(DRWShadingGroup *grp, struct GPUBatch *geom, Object *ob) { if (ob->type == OB_POINTCLOUD) { - /* Draw range to avoid drawcall batching messing up the instance attrib. */ + /* Draw range to avoid drawcall batching messing up the instance attribute. */ DRW_shgroup_call_instance_range(grp, ob, geom, 0, 0); } else { diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index f5b95ac97ff..cd8b6531037 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -327,7 +327,7 @@ typedef enum { /** Culling test */ DRW_STATE_CULL_BACK = (1 << 7), DRW_STATE_CULL_FRONT = (1 << 8), - /** Stencil test . These options are mutually exclusive and packed into 2 bits. */ + /** Stencil test. These options are mutually exclusive and packed into 2 bits. */ DRW_STATE_STENCIL_ALWAYS = (1 << 9), DRW_STATE_STENCIL_EQUAL = (2 << 9), DRW_STATE_STENCIL_NEQUAL = (3 << 9), diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index a2e8dc20907..000ab540813 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -770,9 +770,9 @@ GPUBatch *DRW_cache_normal_arrow_get(void) } /* -------------------------------------------------------------------- */ -/** \name Dummy vbos +/** \name Dummy VBO's * - * We need a dummy vbo containing the vertex count to draw instances ranges. + * We need a dummy VBO containing the vertex count to draw instances ranges. * * \{ */ diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index a0694a08f0b..7dc468d1a73 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -81,11 +81,12 @@ typedef enum eMRDataType { MR_DATA_POLY_NOR = 1 << 1, MR_DATA_LOOP_NOR = 1 << 2, MR_DATA_LOOPTRI = 1 << 3, + MR_DATA_LOOSE_GEOM = 1 << 4, /** Force loop normals calculation. */ - MR_DATA_TAN_LOOP_NOR = 1 << 4, - MR_DATA_MAT_OFFSETS = 1 << 5, + MR_DATA_TAN_LOOP_NOR = 1 << 5, + MR_DATA_POLYS_SORTED = 1 << 6, } eMRDataType; -ENUM_OPERATORS(eMRDataType, MR_DATA_MAT_OFFSETS) +ENUM_OPERATORS(eMRDataType, MR_DATA_POLYS_SORTED) #ifdef __cplusplus extern "C" { @@ -169,10 +170,10 @@ typedef struct MeshBufferExtractionCache { } loose_geom; struct { - int *tri; + int *tri_first_index; + int *mat_tri_len; int visible_tri_len; - } mat_offsets; - + } poly_sorted; } MeshBufferExtractionCache; #define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \ diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc index 344150014ed..8d8bb14d953 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc @@ -76,27 +76,23 @@ struct ExtractorRunData { class ExtractorRunDatas : public Vector<ExtractorRunData> { public: - void filter_into(ExtractorRunDatas &result, eMRIterType iter_type) const + void filter_into(ExtractorRunDatas &result, eMRIterType iter_type, const bool is_mesh) const { for (const ExtractorRunData &data : *this) { const MeshExtract *extractor = data.extractor; - if ((iter_type & MR_ITER_LOOPTRI) && extractor->iter_looptri_bm) { - BLI_assert(extractor->iter_looptri_mesh); + if ((iter_type & MR_ITER_LOOPTRI) && *(&extractor->iter_looptri_bm + is_mesh)) { result.append(data); continue; } - if ((iter_type & MR_ITER_POLY) && extractor->iter_poly_bm) { - BLI_assert(extractor->iter_poly_mesh); + if ((iter_type & MR_ITER_POLY) && *(&extractor->iter_poly_bm + is_mesh)) { result.append(data); continue; } - if ((iter_type & MR_ITER_LEDGE) && extractor->iter_ledge_bm) { - BLI_assert(extractor->iter_ledge_mesh); + if ((iter_type & MR_ITER_LEDGE) && *(&extractor->iter_ledge_bm + is_mesh)) { result.append(data); continue; } - if ((iter_type & MR_ITER_LVERT) && extractor->iter_lvert_bm) { - BLI_assert(extractor->iter_lvert_mesh); + if ((iter_type & MR_ITER_LVERT) && *(&extractor->iter_lvert_bm + is_mesh)) { result.append(data); continue; } @@ -427,7 +423,7 @@ BLI_INLINE void extract_task_range_run_iter(const MeshRenderData *mr, return; } - extractors->filter_into(range_data.extractors, iter_type); + extractors->filter_into(range_data.extractors, iter_type, is_mesh); BLI_task_parallel_range(0, stop, &range_data, func, settings); } @@ -535,7 +531,8 @@ static void mesh_extract_render_data_node_exec(void *__restrict task_data) mesh_render_data_update_normals(mr, data_flag); mesh_render_data_update_looptris(mr, iter_type, data_flag); - mesh_render_data_update_mat_offsets(mr, update_task_data->cache, data_flag); + mesh_render_data_update_loose_geom(mr, update_task_data->cache, iter_type, data_flag); + mesh_render_data_update_polys_sorted(mr, update_task_data->cache, data_flag); } static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph, @@ -689,19 +686,8 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, double rdata_start = PIL_check_seconds_timer(); #endif - eMRIterType iter_type = extractors.iter_types(); - eMRDataType data_flag = extractors.data_types(); - - MeshRenderData *mr = mesh_render_data_create(me, - extraction_cache, - is_editmode, - is_paint_mode, - is_mode_active, - obmat, - do_final, - do_uvedit, - ts, - iter_type); + MeshRenderData *mr = mesh_render_data_create( + me, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts); mr->use_hide = use_hide; mr->use_subsurf_fdots = use_subsurf_fdots; mr->use_final_mesh = do_final; @@ -710,6 +696,9 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, double rdata_end = PIL_check_seconds_timer(); #endif + eMRIterType iter_type = extractors.iter_types(); + eMRDataType data_flag = extractors.data_types(); + struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create( task_graph, mr, extraction_cache, iter_type, data_flag); diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_private.h b/source/blender/draw/intern/draw_cache_extract_mesh_private.h index 5f670bdc5ec..f24ccf1a028 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_private.h +++ b/source/blender/draw/intern/draw_cache_extract_mesh_private.h @@ -101,10 +101,12 @@ typedef struct MeshRenderData { float (*loop_normals)[3]; float (*poly_normals)[3]; int *lverts, *ledges; + struct { - int *tri; + int *tri_first_index; + int *mat_tri_len; int visible_tri_len; - } mat_offsets; + } poly_sorted; } MeshRenderData; BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx) @@ -240,20 +242,22 @@ typedef struct MeshExtract { /* draw_cache_extract_mesh_render_data.c */ MeshRenderData *mesh_render_data_create(Mesh *me, - MeshBufferExtractionCache *cache, const bool is_editmode, const bool is_paint_mode, const bool is_mode_active, const float obmat[4][4], const bool do_final, const bool do_uvedit, - const ToolSettings *ts, - const eMRIterType iter_type); + const ToolSettings *ts); void mesh_render_data_free(MeshRenderData *mr); void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag); -void mesh_render_data_update_mat_offsets(MeshRenderData *mr, - MeshBufferExtractionCache *cache, - const eMRDataType data_flag); +void mesh_render_data_update_loose_geom(MeshRenderData *mr, + MeshBufferExtractionCache *cache, + const eMRIterType iter_type, + const eMRDataType data_flag); +void mesh_render_data_update_polys_sorted(MeshRenderData *mr, + MeshBufferExtractionCache *cache, + const eMRDataType data_flag); void mesh_render_data_update_looptris(MeshRenderData *mr, const eMRIterType iter_type, const eMRDataType data_flag); diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c index bccf894cc53..987996ed696 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c @@ -25,6 +25,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_alloca.h" #include "BLI_bitmap.h" #include "BLI_math.h" #include "BLI_task.h" @@ -165,119 +166,118 @@ static void mesh_render_data_ledges_bm(const MeshRenderData *mr, } } +void mesh_render_data_update_loose_geom(MeshRenderData *mr, + MeshBufferExtractionCache *cache, + const eMRIterType iter_type, + const eMRDataType data_flag) +{ + if ((iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) || (data_flag & MR_DATA_LOOSE_GEOM)) { + mesh_render_data_loose_geom_ensure(mr, cache); + mesh_render_data_loose_geom_load(mr, cache); + } +} + /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Material Offsets +/** \name Polygons sorted per material * - * Material offsets contains the offset of a material after sorting tris based on their material. + * Contains polygon indices sorted based on their material. * * \{ */ -static void mesh_render_data_mat_offset_load(MeshRenderData *mr, - const MeshBufferExtractionCache *cache); -static void mesh_render_data_mat_offset_ensure(MeshRenderData *mr, - MeshBufferExtractionCache *cache); -static void mesh_render_data_mat_offset_build(MeshRenderData *mr, - MeshBufferExtractionCache *cache); -static void mesh_render_data_mat_offset_build_bm(MeshRenderData *mr, +static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, + const MeshBufferExtractionCache *cache); +static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferExtractionCache *cache); -static void mesh_render_data_mat_offset_build_mesh(MeshRenderData *mr, - MeshBufferExtractionCache *cache); -static void mesh_render_data_mat_offset_apply_offset(MeshRenderData *mr, - MeshBufferExtractionCache *cache); - -void mesh_render_data_update_mat_offsets(MeshRenderData *mr, - MeshBufferExtractionCache *cache, - const eMRDataType data_flag) +static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, + MeshBufferExtractionCache *cache); +static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr); + +void mesh_render_data_update_polys_sorted(MeshRenderData *mr, + MeshBufferExtractionCache *cache, + const eMRDataType data_flag) { - if (data_flag & MR_DATA_MAT_OFFSETS) { - mesh_render_data_mat_offset_ensure(mr, cache); - mesh_render_data_mat_offset_load(mr, cache); + if (data_flag & MR_DATA_POLYS_SORTED) { + mesh_render_data_polys_sorted_ensure(mr, cache); + mesh_render_data_polys_sorted_load(mr, cache); } } -static void mesh_render_data_mat_offset_load(MeshRenderData *mr, - const MeshBufferExtractionCache *cache) +static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, + const MeshBufferExtractionCache *cache) { - mr->mat_offsets.tri = cache->mat_offsets.tri; - mr->mat_offsets.visible_tri_len = cache->mat_offsets.visible_tri_len; + mr->poly_sorted.tri_first_index = cache->poly_sorted.tri_first_index; + mr->poly_sorted.mat_tri_len = cache->poly_sorted.mat_tri_len; + mr->poly_sorted.visible_tri_len = cache->poly_sorted.visible_tri_len; } -static void mesh_render_data_mat_offset_ensure(MeshRenderData *mr, - MeshBufferExtractionCache *cache) +static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, + MeshBufferExtractionCache *cache) { - if (cache->mat_offsets.tri) { + if (cache->poly_sorted.tri_first_index) { return; } - mesh_render_data_mat_offset_build(mr, cache); + mesh_render_data_polys_sorted_build(mr, cache); } -static void mesh_render_data_mat_offset_build(MeshRenderData *mr, MeshBufferExtractionCache *cache) +static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, + MeshBufferExtractionCache *cache) { - size_t mat_tri_idx_size = sizeof(int) * mr->mat_len; - cache->mat_offsets.tri = MEM_callocN(mat_tri_idx_size, __func__); + int *tri_first_index = MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__); + int *mat_tri_len = mesh_render_data_mat_tri_len_build(mr); + + /* Apply offset. */ + int visible_tri_len = 0; + int *mat_tri_offs = BLI_array_alloca(mat_tri_offs, mr->mat_len); + { + for (int i = 0; i < mr->mat_len; i++) { + mat_tri_offs[i] = visible_tri_len; + visible_tri_len += mat_tri_len[i]; + } + } - /* Count how many triangles for each material. */ + /* Sort per material. */ + int mat_last = mr->mat_len - 1; if (mr->extract_type == MR_EXTRACT_BMESH) { - mesh_render_data_mat_offset_build_bm(mr, cache); + BMIter iter; + BMFace *f; + int i; + BM_ITER_MESH_INDEX (f, &iter, mr->bm, BM_FACES_OF_MESH, i) { + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + const int mat = min_ii(f->mat_nr, mat_last); + tri_first_index[i] = mat_tri_offs[mat]; + mat_tri_offs[mat] += f->len - 2; + } + else { + tri_first_index[i] = -1; + } + } } else { - mesh_render_data_mat_offset_build_mesh(mr, cache); - } - - mesh_render_data_mat_offset_apply_offset(mr, cache); -} - -typedef struct MatOffsetUserData { - MeshRenderData *mr; - /** This struct is extended during allocation to hold mat_tri_len for each material. */ - int mat_tri_len[0]; -} MatOffsetUserData; - -static void mesh_render_data_mat_offset_reduce(const void *__restrict UNUSED(userdata), - void *__restrict chunk_join, - void *__restrict chunk) -{ - MatOffsetUserData *dst = chunk_join; - MatOffsetUserData *src = chunk; - int *dst_mat_len = dst->mat_tri_len; - int *src_mat_len = src->mat_tri_len; - for (int i = 0; i < dst->mr->mat_len; i++) { - dst_mat_len[i] += src_mat_len[i]; + const MPoly *mp = &mr->mpoly[0]; + for (int i = 0; i < mr->poly_len; i++, mp++) { + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + const int mat = min_ii(mp->mat_nr, mat_last); + tri_first_index[i] = mat_tri_offs[mat]; + mat_tri_offs[mat] += mp->totloop - 2; + } + else { + tri_first_index[i] = -1; + } + } } -} - -static void mesh_render_data_mat_offset_build_threaded(MeshRenderData *mr, - MeshBufferExtractionCache *cache, - int face_len, - TaskParallelRangeFunc range_func) -{ - /* Extending the #MatOffsetUserData with an int per material slot. */ - size_t userdata_size = sizeof(MatOffsetUserData) + - (mr->mat_len) * sizeof(*cache->mat_offsets.tri); - MatOffsetUserData *userdata = MEM_callocN(userdata_size, __func__); - userdata->mr = mr; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.userdata_chunk = userdata; - settings.userdata_chunk_size = userdata_size; - settings.min_iter_per_thread = MIN_RANGE_LEN; - settings.func_reduce = mesh_render_data_mat_offset_reduce; - BLI_task_parallel_range(0, face_len, NULL, range_func, &settings); - memcpy(cache->mat_offsets.tri, - &userdata->mat_tri_len, - (mr->mat_len) * sizeof(*cache->mat_offsets.tri)); - MEM_freeN(userdata); + cache->poly_sorted.tri_first_index = tri_first_index; + cache->poly_sorted.mat_tri_len = mat_tri_len; + cache->poly_sorted.visible_tri_len = visible_tri_len; } -static void mesh_render_data_mat_offset_bm_range(void *__restrict UNUSED(userdata), - const int iter, - const TaskParallelTLS *__restrict tls) +static void mesh_render_data_mat_tri_len_bm_range_fn(void *__restrict userdata, + const int iter, + const TaskParallelTLS *__restrict tls) { - MatOffsetUserData *mat_offset_userdata = tls->userdata_chunk; - MeshRenderData *mr = mat_offset_userdata->mr; - int *mat_tri_len = mat_offset_userdata->mat_tri_len; + MeshRenderData *mr = userdata; + int *mat_tri_len = tls->userdata_chunk; BMesh *bm = mr->bm; BMFace *efa = BM_face_at_index(bm, iter); @@ -287,21 +287,12 @@ static void mesh_render_data_mat_offset_bm_range(void *__restrict UNUSED(userdat } } -static void mesh_render_data_mat_offset_build_bm(MeshRenderData *mr, - MeshBufferExtractionCache *cache) +static void mesh_render_data_mat_tri_len_mesh_range_fn(void *__restrict userdata, + const int iter, + const TaskParallelTLS *__restrict tls) { - BMesh *bm = mr->bm; - mesh_render_data_mat_offset_build_threaded( - mr, cache, bm->totface, mesh_render_data_mat_offset_bm_range); -} - -static void mesh_render_data_mat_offset_mesh_range(void *__restrict UNUSED(userdata), - const int iter, - const TaskParallelTLS *__restrict tls) -{ - MatOffsetUserData *mat_offset_userdata = tls->userdata_chunk; - const MeshRenderData *mr = mat_offset_userdata->mr; - int *mat_tri_len = mat_offset_userdata->mat_tri_len; + MeshRenderData *mr = userdata; + int *mat_tri_len = tls->userdata_chunk; const MPoly *mp = &mr->mpoly[iter]; if (!(mr->use_hide && (mp->flag & ME_HIDE))) { @@ -310,25 +301,49 @@ static void mesh_render_data_mat_offset_mesh_range(void *__restrict UNUSED(userd } } -static void mesh_render_data_mat_offset_build_mesh(MeshRenderData *mr, - MeshBufferExtractionCache *cache) +static void mesh_render_data_mat_tri_len_reduce_fn(const void *__restrict userdata, + void *__restrict chunk_join, + void *__restrict chunk) +{ + const MeshRenderData *mr = userdata; + int *dst_mat_len = chunk_join; + int *src_mat_len = chunk; + for (int i = 0; i < mr->mat_len; i++) { + dst_mat_len[i] += src_mat_len[i]; + } +} + +static int *mesh_render_data_mat_tri_len_build_threaded(MeshRenderData *mr, + int face_len, + TaskParallelRangeFunc range_func) { - mesh_render_data_mat_offset_build_threaded( - mr, cache, mr->poly_len, mesh_render_data_mat_offset_mesh_range); + /* Extending the #MatOffsetUserData with an int per material slot. */ + size_t mat_tri_len_size = sizeof(int) * mr->mat_len; + int *mat_tri_len = MEM_callocN(mat_tri_len_size, __func__); + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.userdata_chunk = mat_tri_len; + settings.userdata_chunk_size = mat_tri_len_size; + settings.min_iter_per_thread = MIN_RANGE_LEN; + settings.func_reduce = mesh_render_data_mat_tri_len_reduce_fn; + BLI_task_parallel_range(0, face_len, mr, range_func, &settings); + + return mat_tri_len; } -static void mesh_render_data_mat_offset_apply_offset(MeshRenderData *mr, - MeshBufferExtractionCache *cache) +/* Count how many triangles for each material. */ +static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr) { - int *mat_tri_len = cache->mat_offsets.tri; - int ofs = mat_tri_len[0]; - mat_tri_len[0] = 0; - for (int i = 1; i < mr->mat_len; i++) { - int tmp = mat_tri_len[i]; - mat_tri_len[i] = ofs; - ofs += tmp; + if (mr->extract_type == MR_EXTRACT_BMESH) { + BMesh *bm = mr->bm; + return mesh_render_data_mat_tri_len_build_threaded( + mr, bm->totface, mesh_render_data_mat_tri_len_bm_range_fn); + } + else { + return mesh_render_data_mat_tri_len_build_threaded( + mr, mr->poly_len, mesh_render_data_mat_tri_len_mesh_range_fn); } - cache->mat_offsets.visible_tri_len = ofs; } /** \} */ @@ -447,15 +462,13 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_ * otherwise don't use modifiers as they are not from this object. */ MeshRenderData *mesh_render_data_create(Mesh *me, - MeshBufferExtractionCache *cache, const bool is_editmode, const bool is_paint_mode, const bool is_mode_active, const float obmat[4][4], const bool do_final, const bool do_uvedit, - const ToolSettings *ts, - const eMRIterType iter_type) + const ToolSettings *ts) { MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__); mr->toolsettings = ts; @@ -565,11 +578,6 @@ MeshRenderData *mesh_render_data_create(Mesh *me, mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); } - if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) { - mesh_render_data_loose_geom_ensure(mr, cache); - mesh_render_data_loose_geom_load(mr, cache); - } - return mr; } diff --git a/source/blender/draw/intern/draw_cache_impl_curve.cc b/source/blender/draw/intern/draw_cache_impl_curve.cc index 51bd4c535cd..1efe0c080be 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.cc +++ b/source/blender/draw/intern/draw_cache_impl_curve.cc @@ -663,7 +663,7 @@ static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_c for (const int i_spline : splines.index_range()) { const int eval_size = splines[i_spline]->evaluated_points_size(); - if (splines[i_spline]->is_cyclic()) { + if (splines[i_spline]->is_cyclic() && splines[i_spline]->evaluated_edges_size() > 1) { GPU_indexbuf_add_generic_vert(&elb, offsets[i_spline] + eval_size - 1); } for (const int i_point : IndexRange(eval_size)) { diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 0c002ff09f2..38ecdf7756b 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -821,17 +821,6 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode) mesh_batch_cache_discard_shaded_tri(cache); mesh_batch_cache_discard_uvedit(cache); break; - case BKE_MESH_BATCH_DIRTY_DEFORM: - FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) { - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.lnor); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_pos); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_nor); - GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.tris); - } - batch_map = MDEPS_CREATE_MAP(vbo.pos_nor, vbo.lnor, vbo.fdots_pos, vbo.fdots_nor, ibo.tris); - mesh_batch_cache_discard_batch(cache, batch_map); - break; case BKE_MESH_BATCH_DIRTY_UVEDIT_ALL: mesh_batch_cache_discard_uvedit(cache); break; @@ -867,7 +856,9 @@ static void mesh_buffer_extraction_cache_clear(MeshBufferExtractionCache *extrac extraction_cache->loose_geom.edge_len = 0; extraction_cache->loose_geom.vert_len = 0; - MEM_SAFE_FREE(extraction_cache->mat_offsets.tri); + MEM_SAFE_FREE(extraction_cache->poly_sorted.tri_first_index); + MEM_SAFE_FREE(extraction_cache->poly_sorted.mat_tri_len); + extraction_cache->poly_sorted.visible_tri_len = 0; } static void mesh_batch_cache_clear(Mesh *me) diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index 449f2cd9606..e055192eb21 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -80,7 +80,7 @@ typedef struct DRWTempInstancingHandle { GPUBatch *batch; /** Batch containing instancing attributes. */ GPUBatch *instancer; - /** Callbuffer to be used instead of instancer . */ + /** Callbuffer to be used instead of instancer. */ GPUVertBuf *buf; /** Original non-instanced batch pointer. */ GPUBatch *geom; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 6f5e041fa79..35072518b66 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -147,7 +147,7 @@ static bool drw_draw_show_annotation(void) * the draw manager is only used to draw the background. */ return false; default: - BLI_assert(""); + BLI_assert(0); return false; } } @@ -2253,7 +2253,7 @@ static void draw_select_framebuffer_depth_only_setup(const int size[2]) /* Must run after all instance datas have been added. */ void DRW_render_instance_buffer_finish(void) { - BLI_assert(!DST.buffer_finish_called && "DRW_render_instance_buffer_finish called twice!"); + BLI_assert_msg(!DST.buffer_finish_called, "DRW_render_instance_buffer_finish called twice!"); DST.buffer_finish_called = true; DRW_instance_buffer_finish(DST.idatalist); drw_resource_buffer_finish(DST.vmempool); diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 0a0e1ba9ac3..b001c5bbf8f 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -74,7 +74,7 @@ static void draw_call_sort(DRWCommand *array, DRWCommand *array_tmp, int array_l return; } } - /* Cumulate batch indices */ + /* Accumulate batch indices */ for (int i = 1; i < ARRAY_SIZE(idx); i++) { idx[i] += idx[i - 1]; } @@ -453,7 +453,7 @@ void DRW_shgroup_vertex_buffer(DRWShadingGroup *shgroup, { int location = GPU_shader_get_ssbo(shgroup->shader, name); if (location == -1) { - BLI_assert(false && "Unable to locate binding of shader storage buffer objects."); + BLI_assert_msg(0, "Unable to locate binding of shader storage buffer objects."); return; } drw_shgroup_uniform_create_ex( diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c index 6c63838201e..265fdba66fd 100644 --- a/source/blender/draw/intern/draw_manager_text.c +++ b/source/blender/draw/intern/draw_manager_text.c @@ -266,7 +266,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, } const short edge_tex_sep = (short)((edge_tex_count - 1) * 5.0f * U.dpi_fac); - /* make the precision of the display value proportionate to the gridsize */ + /* Make the precision of the display value proportionate to the grid-size. */ if (grid <= 0.01f) { conv_float = "%.6g"; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc index 2c2603af1b2..6c677debf88 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc @@ -237,7 +237,7 @@ constexpr MeshExtract create_extractor_lines_loose_only() { MeshExtract extractor = {nullptr}; extractor.init = extract_lines_loose_only_init; - extractor.data_type = MR_DATA_NONE; + extractor.data_type = MR_DATA_LOOSE_GEOM; extractor.data_size = 0; extractor.use_threading = false; extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_loose); diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc index 93f71f920eb..3b2da9879c5 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc @@ -27,59 +27,70 @@ namespace blender::draw { +static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_from) +{ + GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to); + GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from); + GPU_indexbuf_join(elb_to, elb_from); +} + /* ---------------------------------------------------------------------- */ /** \name Extract Triangles Indices (multi material) * \{ */ -struct MeshExtract_Tri_Data { - GPUIndexBufBuilder elb; - const int *tri_mat_start; - int *tri_mat_end; -}; - static void extract_tris_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(ibo), void *tls_data) { - MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(tls_data); - data->tri_mat_start = mr->mat_offsets.tri; - data->tri_mat_end = static_cast<int *>(MEM_dupallocN(data->tri_mat_start)); - GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, mr->mat_offsets.visible_tri_len, mr->loop_len); + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data); + GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr->poly_sorted.visible_tri_len, mr->loop_len); } -static void extract_tris_iter_looptri_bm(const MeshRenderData *mr, - BMLoop **elt, - const int UNUSED(elt_index), - void *_data) +static void extract_tris_iter_poly_bm(const MeshRenderData *mr, + const BMFace *f, + const int f_index, + void *_data) { - MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(_data); - const int mat_last = mr->mat_len - 1; + int tri_first_index = mr->poly_sorted.tri_first_index[f_index]; + if (tri_first_index == -1) { + return; + } - if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { - int *mat_tri_ofs = data->tri_mat_end; - const int mat = min_ii(elt[0]->f->mat_nr, mat_last); - GPU_indexbuf_set_tri_verts(&data->elb, - mat_tri_ofs[mat]++, + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data); + int tri_first_index_real = poly_to_tri_count(f_index, BM_elem_index_get(f->l_first)); + + struct BMLoop *(*looptris)[3] = mr->edit_bmesh->looptris; + int tri_len = f->len - 2; + for (int offs = 0; offs < tri_len; offs++) { + BMLoop **elt = looptris[tri_first_index_real + offs]; + int tri_index = tri_first_index + offs; + GPU_indexbuf_set_tri_verts(elb, + tri_index, BM_elem_index_get(elt[0]), BM_elem_index_get(elt[1]), BM_elem_index_get(elt[2])); } } -static void extract_tris_iter_looptri_mesh(const MeshRenderData *mr, - const MLoopTri *mlt, - const int UNUSED(elt_index), - void *_data) +static void extract_tris_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int mp_index, + void *_data) { - MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(_data); - const int mat_last = mr->mat_len - 1; - const MPoly *mp = &mr->mpoly[mlt->poly]; - if (!(mr->use_hide && (mp->flag & ME_HIDE))) { - int *mat_tri_ofs = data->tri_mat_end; - const int mat = min_ii(mp->mat_nr, mat_last); - GPU_indexbuf_set_tri_verts( - &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]); + int tri_first_index = mr->poly_sorted.tri_first_index[mp_index]; + if (tri_first_index == -1) { + return; + } + + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data); + int tri_first_index_real = poly_to_tri_count(mp_index, mp->loopstart); + + int tri_len = mp->totloop - 2; + for (int offs = 0; offs < tri_len; offs++) { + const MLoopTri *mlt = &mr->mlooptri[tri_first_index_real + offs]; + int tri_index = tri_first_index + offs; + GPU_indexbuf_set_tri_verts(elb, tri_index, mlt->tri[0], mlt->tri[1], mlt->tri[2]); } } @@ -89,40 +100,41 @@ static void extract_tris_finish(const MeshRenderData *mr, void *_data) { GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); - MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(_data); - GPU_indexbuf_build_in_place(&data->elb, ibo); + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data); + GPU_indexbuf_build_in_place(elb, ibo); /* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch * is created before the surfaces-per-material. */ if (mr->use_final_mesh && cache->final.tris_per_mat) { MeshBufferCache *mbc_final = &cache->final; + int mat_start = 0; for (int i = 0; i < mr->mat_len; i++) { /* These IBOs have not been queried yet but we create them just in case they are needed * later since they are not tracked by mesh_buffer_cache_create_requested(). */ if (mbc_final->tris_per_mat[i] == nullptr) { mbc_final->tris_per_mat[i] = GPU_indexbuf_calloc(); } + const int mat_tri_len = mr->poly_sorted.mat_tri_len[i]; /* Multiply by 3 because these are triangle indices. */ - const int mat_start = data->tri_mat_start[i]; - const int mat_end = data->tri_mat_end[i]; const int start = mat_start * 3; - const int len = (mat_end - mat_start) * 3; + const int len = mat_tri_len * 3; GPU_indexbuf_create_subrange_in_place(mbc_final->tris_per_mat[i], ibo, start, len); + mat_start += mat_tri_len; } } - MEM_freeN(data->tri_mat_end); } constexpr MeshExtract create_extractor_tris() { MeshExtract extractor = {nullptr}; extractor.init = extract_tris_init; - extractor.iter_looptri_bm = extract_tris_iter_looptri_bm; - extractor.iter_looptri_mesh = extract_tris_iter_looptri_mesh; + extractor.iter_poly_bm = extract_tris_iter_poly_bm; + extractor.iter_poly_mesh = extract_tris_iter_poly_mesh; + extractor.task_reduce = extract_tris_mat_task_reduce; extractor.finish = extract_tris_finish; - extractor.data_type = MR_DATA_MAT_OFFSETS; - extractor.data_size = sizeof(MeshExtract_Tri_Data); - extractor.use_threading = false; + extractor.data_type = MR_DATA_LOOPTRI | MR_DATA_POLYS_SORTED; + extractor.data_size = sizeof(GPUIndexBufBuilder); + extractor.use_threading = true; extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris); return extractor; } @@ -174,13 +186,6 @@ static void extract_tris_single_mat_iter_looptri_mesh(const MeshRenderData *mr, } } -static void extract_tris_single_mat_task_reduce(void *_userdata_to, void *_userdata_from) -{ - GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to); - GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from); - GPU_indexbuf_join(elb_to, elb_from); -} - static void extract_tris_single_mat_finish(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, @@ -213,7 +218,7 @@ constexpr MeshExtract create_extractor_tris_single_mat() extractor.init = extract_tris_single_mat_init; extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm; extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh; - extractor.task_reduce = extract_tris_single_mat_task_reduce; + extractor.task_reduce = extract_tris_mat_task_reduce; extractor.finish = extract_tris_single_mat_finish; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(GPUIndexBufBuilder); diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt index f50a5ffbb5e..7a53b54b5a4 100644 --- a/source/blender/editors/animation/CMakeLists.txt +++ b/source/blender/editors/animation/CMakeLists.txt @@ -47,6 +47,7 @@ set(SRC keyframes_draw.c keyframes_edit.c keyframes_general.c + keyframes_keylist.c keyframing.c keyingsets.c time_scrub_ui.c diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 2fcd59a1bbe..baf8adf28d0 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -48,6 +48,7 @@ #include "ED_anim_api.h" #include "ED_keyframes_draw.h" #include "ED_keyframes_edit.h" +#include "ED_keyframes_keylist.h" #include "RNA_access.h" diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 9d998326b4d..227af598f53 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -123,7 +123,7 @@ ListBase *ED_animcontext_get_markers(const bAnimContext *ac) * so don't assume anything. * \param scene: Current scene (for getting current frame) * \param mode: (TfmMode) transform mode that this transform is for - * \param value: From the transform code, this is ``t->vec[0]`` + * \param value: From the transform code, this is `t->vec[0]` * (which is delta transform for grab/extend, and scale factor for scale) * \param side: (B/L/R) for 'extend' functionality, which side of current frame to use */ diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c index 51a897600e1..bddd5dbff55 100644 --- a/source/blender/editors/animation/anim_motion_paths.c +++ b/source/blender/editors/animation/anim_motion_paths.c @@ -43,7 +43,7 @@ #include "GPU_vertex_buffer.h" #include "ED_anim_api.h" -#include "ED_keyframes_draw.h" +#include "ED_keyframes_keylist.h" #include "CLG_log.h" diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index 06107b6fee6..4f512c9d7ca 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -24,28 +24,17 @@ /* System includes ----------------------------------------------------- */ #include <float.h> -#include <math.h> -#include <stdlib.h> -#include <string.h> - -#include "MEM_guardedalloc.h" #include "BLI_dlrbTree.h" #include "BLI_listbase.h" -#include "BLI_math.h" #include "BLI_rect.h" -#include "BLI_utildefines.h" #include "DNA_anim_types.h" -#include "DNA_brush_types.h" -#include "DNA_cachefile_types.h" #include "DNA_gpencil_types.h" #include "DNA_mask_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "BKE_fcurve.h" - #include "GPU_immediate.h" #include "GPU_state.h" @@ -55,498 +44,7 @@ #include "ED_anim_api.h" #include "ED_keyframes_draw.h" - -/* *************************** Keyframe Processing *************************** */ - -/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */ - -BLI_INLINE bool is_cfra_eq(float a, float b) -{ - return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH); -} - -BLI_INLINE bool is_cfra_lt(float a, float b) -{ - return (b - a) > BEZT_BINARYSEARCH_THRESH; -} - -/* Comparator callback used for ActKeyColumns and cframe float-value pointer */ -/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */ -short compare_ak_cfraPtr(void *node, void *data) -{ - ActKeyColumn *ak = (ActKeyColumn *)node; - const float *cframe = data; - float val = *cframe; - - if (is_cfra_eq(val, ak->cfra)) { - return 0; - } - - if (val < ak->cfra) { - return -1; - } - return 1; -} - -/* --------------- */ - -/* Set of references to three logically adjacent keys. */ -typedef struct BezTripleChain { - /* Current keyframe. */ - BezTriple *cur; - - /* Logical neighbors. May be NULL. */ - BezTriple *prev, *next; -} BezTripleChain; - -/* Categorize the interpolation & handle type of the keyframe. */ -static eKeyframeHandleDrawOpts bezt_handle_type(BezTriple *bezt) -{ - if (bezt->h1 == HD_AUTO_ANIM && bezt->h2 == HD_AUTO_ANIM) { - return KEYFRAME_HANDLE_AUTO_CLAMP; - } - if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO)) { - return KEYFRAME_HANDLE_AUTO; - } - if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) { - return KEYFRAME_HANDLE_VECTOR; - } - if (ELEM(HD_FREE, bezt->h1, bezt->h2)) { - return KEYFRAME_HANDLE_FREE; - } - return KEYFRAME_HANDLE_ALIGNED; -} - -/* Determine if the keyframe is an extreme by comparing with neighbors. - * Ends of fixed-value sections and of the whole curve are also marked. - */ -static eKeyframeExtremeDrawOpts bezt_extreme_type(BezTripleChain *chain) -{ - if (chain->prev == NULL && chain->next == NULL) { - return KEYFRAME_EXTREME_NONE; - } - - /* Keyframe values for the current one and neighbors. */ - float cur_y = chain->cur->vec[1][1]; - float prev_y = cur_y, next_y = cur_y; - - if (chain->prev && !IS_EQF(cur_y, chain->prev->vec[1][1])) { - prev_y = chain->prev->vec[1][1]; - } - if (chain->next && !IS_EQF(cur_y, chain->next->vec[1][1])) { - next_y = chain->next->vec[1][1]; - } - - /* Static hold. */ - if (prev_y == cur_y && next_y == cur_y) { - return KEYFRAME_EXTREME_FLAT; - } - - /* Middle of an incline. */ - if ((prev_y < cur_y && next_y > cur_y) || (prev_y > cur_y && next_y < cur_y)) { - return KEYFRAME_EXTREME_NONE; - } - - /* Bezier handle values for the overshoot check. */ - bool l_bezier = chain->prev && chain->prev->ipo == BEZT_IPO_BEZ; - bool r_bezier = chain->next && chain->cur->ipo == BEZT_IPO_BEZ; - float handle_l = l_bezier ? chain->cur->vec[0][1] : cur_y; - float handle_r = r_bezier ? chain->cur->vec[2][1] : cur_y; - - /* Detect extremes. One of the neighbors is allowed to be equal to current. */ - if (prev_y < cur_y || next_y < cur_y) { - bool is_overshoot = (handle_l > cur_y || handle_r > cur_y); - - return KEYFRAME_EXTREME_MAX | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0); - } - - if (prev_y > cur_y || next_y > cur_y) { - bool is_overshoot = (handle_l < cur_y || handle_r < cur_y); - - return KEYFRAME_EXTREME_MIN | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0); - } - - return KEYFRAME_EXTREME_NONE; -} - -/* Comparator callback used for ActKeyColumns and BezTripleChain */ -static short compare_ak_bezt(void *node, void *data) -{ - BezTripleChain *chain = data; - - return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]); -} - -/* New node callback used for building ActKeyColumns from BezTripleChain */ -static DLRBT_Node *nalloc_ak_bezt(void *data) -{ - ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn"); - BezTripleChain *chain = data; - BezTriple *bezt = chain->cur; - - /* store settings based on state of BezTriple */ - ak->cfra = bezt->vec[1][0]; - ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0; - ak->key_type = BEZKEYTYPE(bezt); - ak->handle_type = bezt_handle_type(bezt); - ak->extreme_type = bezt_extreme_type(chain); - - /* count keyframes in this column */ - ak->totkey = 1; - - return (DLRBT_Node *)ak; -} - -/* Node updater callback used for building ActKeyColumns from BezTripleChain */ -static void nupdate_ak_bezt(void *node, void *data) -{ - ActKeyColumn *ak = node; - BezTripleChain *chain = data; - BezTriple *bezt = chain->cur; - - /* set selection status and 'touched' status */ - if (BEZT_ISSEL_ANY(bezt)) { - ak->sel = SELECT; - } - - /* count keyframes in this column */ - ak->totkey++; - - /* For keyframe type, 'proper' keyframes have priority over breakdowns - * (and other types for now). */ - if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME) { - ak->key_type = BEZT_KEYTYPE_KEYFRAME; - } - - /* For interpolation type, select the highest value (enum is sorted). */ - ak->handle_type = MAX2(ak->handle_type, bezt_handle_type(bezt)); - - /* For extremes, detect when combining different states. */ - char new_extreme = bezt_extreme_type(chain); - - if (new_extreme != ak->extreme_type) { - /* Replace the flat status without adding mixed. */ - if (ak->extreme_type == KEYFRAME_EXTREME_FLAT) { - ak->extreme_type = new_extreme; - } - else if (new_extreme != KEYFRAME_EXTREME_FLAT) { - ak->extreme_type |= (new_extreme | KEYFRAME_EXTREME_MIXED); - } - } -} - -/* ......... */ - -/* Comparator callback used for ActKeyColumns and GPencil frame */ -static short compare_ak_gpframe(void *node, void *data) -{ - bGPDframe *gpf = (bGPDframe *)data; - - float frame = gpf->framenum; - return compare_ak_cfraPtr(node, &frame); -} - -/* New node callback used for building ActKeyColumns from GPencil frames */ -static DLRBT_Node *nalloc_ak_gpframe(void *data) -{ - ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"); - bGPDframe *gpf = (bGPDframe *)data; - - /* store settings based on state of BezTriple */ - ak->cfra = gpf->framenum; - ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0; - ak->key_type = gpf->key_type; - - /* count keyframes in this column */ - ak->totkey = 1; - /* Set as visible block. */ - ak->totblock = 1; - ak->block.sel = ak->sel; - ak->block.flag |= ACTKEYBLOCK_FLAG_GPENCIL; - - return (DLRBT_Node *)ak; -} - -/* Node updater callback used for building ActKeyColumns from GPencil frames */ -static void nupdate_ak_gpframe(void *node, void *data) -{ - ActKeyColumn *ak = (ActKeyColumn *)node; - bGPDframe *gpf = (bGPDframe *)data; - - /* set selection status and 'touched' status */ - if (gpf->flag & GP_FRAME_SELECT) { - ak->sel = SELECT; - } - - /* count keyframes in this column */ - ak->totkey++; - - /* for keyframe type, 'proper' keyframes have priority over breakdowns - * (and other types for now). */ - if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME) { - ak->key_type = BEZT_KEYTYPE_KEYFRAME; - } -} - -/* ......... */ - -/* Comparator callback used for ActKeyColumns and GPencil frame */ -static short compare_ak_masklayshape(void *node, void *data) -{ - MaskLayerShape *masklay_shape = (MaskLayerShape *)data; - - float frame = masklay_shape->frame; - return compare_ak_cfraPtr(node, &frame); -} - -/* New node callback used for building ActKeyColumns from GPencil frames */ -static DLRBT_Node *nalloc_ak_masklayshape(void *data) -{ - ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"); - MaskLayerShape *masklay_shape = (MaskLayerShape *)data; - - /* store settings based on state of BezTriple */ - ak->cfra = masklay_shape->frame; - ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0; - - /* count keyframes in this column */ - ak->totkey = 1; - - return (DLRBT_Node *)ak; -} - -/* Node updater callback used for building ActKeyColumns from GPencil frames */ -static void nupdate_ak_masklayshape(void *node, void *data) -{ - ActKeyColumn *ak = (ActKeyColumn *)node; - MaskLayerShape *masklay_shape = (MaskLayerShape *)data; - - /* set selection status and 'touched' status */ - if (masklay_shape->flag & MASK_SHAPE_SELECT) { - ak->sel = SELECT; - } - - /* count keyframes in this column */ - ak->totkey++; -} - -/* --------------- */ - -/* Add the given BezTriple to the given 'list' of Keyframes */ -static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTripleChain *bezt) -{ - if (ELEM(NULL, keys, bezt)) { - return; - } - - BLI_dlrbTree_add(keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt); -} - -/* Add the given GPencil Frame to the given 'list' of Keyframes */ -static void add_gpframe_to_keycolumns_list(DLRBT_Tree *keys, bGPDframe *gpf) -{ - if (ELEM(NULL, keys, gpf)) { - return; - } - - BLI_dlrbTree_add(keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf); -} - -/* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */ -static void add_masklay_to_keycolumns_list(DLRBT_Tree *keys, MaskLayerShape *masklay_shape) -{ - if (ELEM(NULL, keys, masklay_shape)) { - return; - } - - BLI_dlrbTree_add(keys, - compare_ak_masklayshape, - nalloc_ak_masklayshape, - nupdate_ak_masklayshape, - masklay_shape); -} - -/* ActKeyBlocks (Long Keyframes) ------------------------------------------ */ - -static const ActKeyBlockInfo dummy_keyblock = {0}; - -static void compute_keyblock_data(ActKeyBlockInfo *info, BezTriple *prev, BezTriple *beztn) -{ - memset(info, 0, sizeof(ActKeyBlockInfo)); - - if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) { - /* Animator tagged a "moving hold" - * - Previous key must also be tagged as a moving hold, otherwise - * we're just dealing with the first of a pair, and we don't - * want to be creating any phantom holds... - */ - if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) { - info->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD; - } - } - - /* Check for same values... - * - Handles must have same central value as each other - * - Handles which control that section of the curve must be constant - */ - if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) { - bool hold; - - /* Only check handles in case of actual bezier interpolation. */ - if (prev->ipo == BEZT_IPO_BEZ) { - hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) && - IS_EQF(prev->vec[1][1], prev->vec[2][1]); - } - /* This interpolation type induces movement even between identical keys. */ - else { - hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC); - } - - if (hold) { - info->flag |= ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD; - } - } - - /* Remember non-bezier interpolation info. */ - if (prev->ipo != BEZT_IPO_BEZ) { - info->flag |= ACTKEYBLOCK_FLAG_NON_BEZIER; - } - - info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn); -} - -static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block) -{ - /* New curve and block. */ - if (col->totcurve <= 1 && col->totblock == 0) { - memcpy(&col->block, block, sizeof(ActKeyBlockInfo)); - } - /* Existing curve. */ - else { - col->block.conflict |= (col->block.flag ^ block->flag); - col->block.flag |= block->flag; - col->block.sel |= block->sel; - } - - if (block->flag) { - col->totblock++; - } -} - -static void add_bezt_to_keyblocks_list(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len) -{ - ActKeyColumn *col = keys->first; - - if (bezt && bezt_len >= 2) { - ActKeyBlockInfo block; - - /* Find the first key column while inserting dummy blocks. */ - for (; col != NULL && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) { - add_keyblock_info(col, &dummy_keyblock); - } - - BLI_assert(col != NULL); - - /* Insert real blocks. */ - for (int v = 1; col != NULL && v < bezt_len; v++, bezt++) { - /* Wrong order of bezier keys: resync position. */ - if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) { - /* Backtrack to find the right location. */ - if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) { - ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact( - keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]); - - if (newcol != NULL) { - col = newcol; - - /* The previous keyblock is garbage too. */ - if (col->prev != NULL) { - add_keyblock_info(col->prev, &dummy_keyblock); - } - } - else { - BLI_assert(false); - } - } - - continue; - } - - /* Normal sequence */ - BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0])); - - compute_keyblock_data(&block, bezt, bezt + 1); - - for (; col != NULL && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) { - add_keyblock_info(col, &block); - } - - BLI_assert(col != NULL); - } - } - - /* Insert dummy blocks at the end. */ - for (; col != NULL; col = col->next) { - add_keyblock_info(col, &dummy_keyblock); - } -} - -/* Walk through columns and propagate blocks and totcurve. - * - * This must be called even by animation sources that don't generate - * keyblocks to keep the data structure consistent after adding columns. - */ -static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len) -{ - /* Recompute the prev/next linked list. */ - BLI_dlrbTree_linkedlist_sync(keys); - - /* Find the curve count */ - int max_curve = 0; - - LISTBASE_FOREACH (ActKeyColumn *, col, keys) { - max_curve = MAX2(max_curve, col->totcurve); - } - - /* Propagate blocks to inserted keys */ - ActKeyColumn *prev_ready = NULL; - - LISTBASE_FOREACH (ActKeyColumn *, col, keys) { - /* Pre-existing column. */ - if (col->totcurve > 0) { - prev_ready = col; - } - /* Newly inserted column, so copy block data from previous. */ - else if (prev_ready != NULL) { - col->totblock = prev_ready->totblock; - memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo)); - } - - col->totcurve = max_curve + 1; - } - - /* Add blocks on top */ - add_bezt_to_keyblocks_list(keys, bezt, bezt_len); -} - -/* --------- */ - -bool actkeyblock_is_valid(ActKeyColumn *ac) -{ - return ac != NULL && ac->next != NULL && ac->totblock > 0; -} - -/* Checks if ActKeyBlock should exist... */ -int actkeyblock_get_valid_hold(ActKeyColumn *ac) -{ - /* check that block is valid */ - if (!actkeyblock_is_valid(ac)) { - return 0; - } - - const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD); - return (ac->block.flag & ~ac->block.conflict) & hold_mask; -} +#include "ED_keyframes_keylist.h" /* *************************** Keyframe Drawing *************************** */ @@ -1029,257 +527,3 @@ void draw_masklay_channel(View2D *v2d, BLI_dlrbTree_free(&keys); } - -/* *************************** Keyframe List Conversions *************************** */ - -void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, int saction_flag) -{ - if (ac) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* get F-Curves to take keyframes from */ - filter = ANIMFILTER_DATA_VISIBLE; - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* loop through each F-Curve, grabbing the keyframes */ - for (ale = anim_data.first; ale; ale = ale->next) { - /* Why not use all #eAnim_KeyType here? - * All of the other key types are actually "summaries" themselves, - * and will just end up duplicating stuff that comes up through - * standard filtering of just F-Curves. Given the way that these work, - * there isn't really any benefit at all from including them. - Aligorith */ - - switch (ale->datatype) { - case ALE_FCURVE: - fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag); - break; - case ALE_MASKLAY: - mask_to_keylist(ac->ads, ale->data, keys); - break; - case ALE_GPFRAME: - gpl_to_keylist(ac->ads, ale->data, keys); - break; - default: - // printf("%s: datatype %d unhandled\n", __func__, ale->datatype); - break; - } - } - - ANIM_animdata_freelist(&anim_data); - } -} - -void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, int saction_flag) -{ - bAnimContext ac = {NULL}; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - bAnimListElem dummychan = {NULL}; - - if (sce == NULL) { - return; - } - - /* create a dummy wrapper data to work with */ - dummychan.type = ANIMTYPE_SCENE; - dummychan.data = sce; - dummychan.id = &sce->id; - dummychan.adt = sce->adt; - - ac.ads = ads; - ac.data = &dummychan; - ac.datatype = ANIMCONT_CHANNEL; - - /* get F-Curves to take keyframes from */ - filter = ANIMFILTER_DATA_VISIBLE; /* curves only */ - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - - /* loop through each F-Curve, grabbing the keyframes */ - for (ale = anim_data.first; ale; ale = ale->next) { - fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag); - } - - ANIM_animdata_freelist(&anim_data); -} - -void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, int saction_flag) -{ - bAnimContext ac = {NULL}; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - bAnimListElem dummychan = {NULL}; - Base dummybase = {NULL}; - - if (ob == NULL) { - return; - } - - /* create a dummy wrapper data to work with */ - dummybase.object = ob; - - dummychan.type = ANIMTYPE_OBJECT; - dummychan.data = &dummybase; - dummychan.id = &ob->id; - dummychan.adt = ob->adt; - - ac.ads = ads; - ac.data = &dummychan; - ac.datatype = ANIMCONT_CHANNEL; - - /* get F-Curves to take keyframes from */ - filter = ANIMFILTER_DATA_VISIBLE; /* curves only */ - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - - /* loop through each F-Curve, grabbing the keyframes */ - for (ale = anim_data.first; ale; ale = ale->next) { - fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag); - } - - ANIM_animdata_freelist(&anim_data); -} - -void cachefile_to_keylist(bDopeSheet *ads, - CacheFile *cache_file, - DLRBT_Tree *keys, - int saction_flag) -{ - if (cache_file == NULL) { - return; - } - - /* create a dummy wrapper data to work with */ - bAnimListElem dummychan = {NULL}; - dummychan.type = ANIMTYPE_DSCACHEFILE; - dummychan.data = cache_file; - dummychan.id = &cache_file->id; - dummychan.adt = cache_file->adt; - - bAnimContext ac = {NULL}; - ac.ads = ads; - ac.data = &dummychan; - ac.datatype = ANIMCONT_CHANNEL; - - /* get F-Curves to take keyframes from */ - ListBase anim_data = {NULL, NULL}; - int filter = ANIMFILTER_DATA_VISIBLE; /* curves only */ - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - - /* loop through each F-Curve, grabbing the keyframes */ - LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { - fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag); - } - - ANIM_animdata_freelist(&anim_data); -} - -void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, int saction_flag) -{ - if (fcu && fcu->totvert && fcu->bezt) { - /* apply NLA-mapping (if applicable) */ - if (adt) { - ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0); - } - - /* Check if the curve is cyclic. */ - bool is_cyclic = BKE_fcurve_is_cyclic(fcu) && (fcu->totvert >= 2); - bool do_extremes = (saction_flag & SACTION_SHOW_EXTREMES) != 0; - - /* loop through beztriples, making ActKeysColumns */ - BezTripleChain chain = {0}; - - for (int v = 0; v < fcu->totvert; v++) { - chain.cur = &fcu->bezt[v]; - - /* Neighbor keys, accounting for being cyclic. */ - if (do_extremes) { - chain.prev = (v > 0) ? &fcu->bezt[v - 1] : is_cyclic ? &fcu->bezt[fcu->totvert - 2] : NULL; - chain.next = (v + 1 < fcu->totvert) ? &fcu->bezt[v + 1] : is_cyclic ? &fcu->bezt[1] : NULL; - } - - add_bezt_to_keycolumns_list(keys, &chain); - } - - /* Update keyblocks. */ - update_keyblocks(keys, fcu->bezt, fcu->totvert); - - /* unapply NLA-mapping if applicable */ - if (adt) { - ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0); - } - } -} - -void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys, int saction_flag) -{ - FCurve *fcu; - - if (agrp) { - /* loop through F-Curves */ - for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) { - fcurve_to_keylist(adt, fcu, keys, saction_flag); - } - } -} - -void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, int saction_flag) -{ - FCurve *fcu; - - if (act) { - /* loop through F-Curves */ - for (fcu = act->curves.first; fcu; fcu = fcu->next) { - fcurve_to_keylist(adt, fcu, keys, saction_flag); - } - } -} - -void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active) -{ - bGPDlayer *gpl; - - if (gpd && keys) { - /* for now, just aggregate out all the frames, but only for visible layers */ - for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) { - if ((gpl->flag & GP_LAYER_HIDE) == 0) { - if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) { - gpl_to_keylist(ads, gpl, keys); - } - } - } - } -} - -void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys) -{ - bGPDframe *gpf; - - if (gpl && keys) { - /* Although the frames should already be in an ordered list, - * they are not suitable for displaying yet. */ - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { - add_gpframe_to_keycolumns_list(keys, gpf); - } - - update_keyblocks(keys, NULL, 0); - } -} - -void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, DLRBT_Tree *keys) -{ - MaskLayerShape *masklay_shape; - - if (masklay && keys) { - for (masklay_shape = masklay->splines_shapes.first; masklay_shape; - masklay_shape = masklay_shape->next) { - add_masklay_to_keycolumns_list(keys, masklay_shape); - } - - update_keyblocks(keys, NULL, 0); - } -} diff --git a/source/blender/editors/animation/keyframes_keylist.c b/source/blender/editors/animation/keyframes_keylist.c new file mode 100644 index 00000000000..47ed2b56300 --- /dev/null +++ b/source/blender/editors/animation/keyframes_keylist.c @@ -0,0 +1,793 @@ +/* + * 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) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + */ + +/** \file + * \ingroup edanimation + */ + +/* System includes ----------------------------------------------------- */ + +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_dlrbTree.h" +#include "BLI_listbase.h" +#include "BLI_utildefines.h" + +#include "DNA_anim_types.h" +#include "DNA_cachefile_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_mask_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_fcurve.h" + +#include "ED_anim_api.h" +#include "ED_keyframes_keylist.h" + +/* *************************** Keyframe Processing *************************** */ + +/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */ + +BLI_INLINE bool is_cfra_eq(float a, float b) +{ + return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH); +} + +BLI_INLINE bool is_cfra_lt(float a, float b) +{ + return (b - a) > BEZT_BINARYSEARCH_THRESH; +} + +/* Comparator callback used for ActKeyColumns and cframe float-value pointer */ +/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */ +short compare_ak_cfraPtr(void *node, void *data) +{ + ActKeyColumn *ak = (ActKeyColumn *)node; + const float *cframe = data; + float val = *cframe; + + if (is_cfra_eq(val, ak->cfra)) { + return 0; + } + + if (val < ak->cfra) { + return -1; + } + return 1; +} + +/* --------------- */ + +/* Set of references to three logically adjacent keys. */ +typedef struct BezTripleChain { + /* Current keyframe. */ + BezTriple *cur; + + /* Logical neighbors. May be NULL. */ + BezTriple *prev, *next; +} BezTripleChain; + +/* Categorize the interpolation & handle type of the keyframe. */ +static eKeyframeHandleDrawOpts bezt_handle_type(BezTriple *bezt) +{ + if (bezt->h1 == HD_AUTO_ANIM && bezt->h2 == HD_AUTO_ANIM) { + return KEYFRAME_HANDLE_AUTO_CLAMP; + } + if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO)) { + return KEYFRAME_HANDLE_AUTO; + } + if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) { + return KEYFRAME_HANDLE_VECTOR; + } + if (ELEM(HD_FREE, bezt->h1, bezt->h2)) { + return KEYFRAME_HANDLE_FREE; + } + return KEYFRAME_HANDLE_ALIGNED; +} + +/* Determine if the keyframe is an extreme by comparing with neighbors. + * Ends of fixed-value sections and of the whole curve are also marked. + */ +static eKeyframeExtremeDrawOpts bezt_extreme_type(BezTripleChain *chain) +{ + if (chain->prev == NULL && chain->next == NULL) { + return KEYFRAME_EXTREME_NONE; + } + + /* Keyframe values for the current one and neighbors. */ + float cur_y = chain->cur->vec[1][1]; + float prev_y = cur_y, next_y = cur_y; + + if (chain->prev && !IS_EQF(cur_y, chain->prev->vec[1][1])) { + prev_y = chain->prev->vec[1][1]; + } + if (chain->next && !IS_EQF(cur_y, chain->next->vec[1][1])) { + next_y = chain->next->vec[1][1]; + } + + /* Static hold. */ + if (prev_y == cur_y && next_y == cur_y) { + return KEYFRAME_EXTREME_FLAT; + } + + /* Middle of an incline. */ + if ((prev_y < cur_y && next_y > cur_y) || (prev_y > cur_y && next_y < cur_y)) { + return KEYFRAME_EXTREME_NONE; + } + + /* Bezier handle values for the overshoot check. */ + bool l_bezier = chain->prev && chain->prev->ipo == BEZT_IPO_BEZ; + bool r_bezier = chain->next && chain->cur->ipo == BEZT_IPO_BEZ; + float handle_l = l_bezier ? chain->cur->vec[0][1] : cur_y; + float handle_r = r_bezier ? chain->cur->vec[2][1] : cur_y; + + /* Detect extremes. One of the neighbors is allowed to be equal to current. */ + if (prev_y < cur_y || next_y < cur_y) { + bool is_overshoot = (handle_l > cur_y || handle_r > cur_y); + + return KEYFRAME_EXTREME_MAX | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0); + } + + if (prev_y > cur_y || next_y > cur_y) { + bool is_overshoot = (handle_l < cur_y || handle_r < cur_y); + + return KEYFRAME_EXTREME_MIN | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0); + } + + return KEYFRAME_EXTREME_NONE; +} + +/* Comparator callback used for ActKeyColumns and BezTripleChain */ +static short compare_ak_bezt(void *node, void *data) +{ + BezTripleChain *chain = data; + + return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]); +} + +/* New node callback used for building ActKeyColumns from BezTripleChain */ +static DLRBT_Node *nalloc_ak_bezt(void *data) +{ + ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn"); + BezTripleChain *chain = data; + BezTriple *bezt = chain->cur; + + /* store settings based on state of BezTriple */ + ak->cfra = bezt->vec[1][0]; + ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0; + ak->key_type = BEZKEYTYPE(bezt); + ak->handle_type = bezt_handle_type(bezt); + ak->extreme_type = bezt_extreme_type(chain); + + /* count keyframes in this column */ + ak->totkey = 1; + + return (DLRBT_Node *)ak; +} + +/* Node updater callback used for building ActKeyColumns from BezTripleChain */ +static void nupdate_ak_bezt(void *node, void *data) +{ + ActKeyColumn *ak = node; + BezTripleChain *chain = data; + BezTriple *bezt = chain->cur; + + /* set selection status and 'touched' status */ + if (BEZT_ISSEL_ANY(bezt)) { + ak->sel = SELECT; + } + + /* count keyframes in this column */ + ak->totkey++; + + /* For keyframe type, 'proper' keyframes have priority over breakdowns + * (and other types for now). */ + if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME) { + ak->key_type = BEZT_KEYTYPE_KEYFRAME; + } + + /* For interpolation type, select the highest value (enum is sorted). */ + ak->handle_type = MAX2(ak->handle_type, bezt_handle_type(bezt)); + + /* For extremes, detect when combining different states. */ + char new_extreme = bezt_extreme_type(chain); + + if (new_extreme != ak->extreme_type) { + /* Replace the flat status without adding mixed. */ + if (ak->extreme_type == KEYFRAME_EXTREME_FLAT) { + ak->extreme_type = new_extreme; + } + else if (new_extreme != KEYFRAME_EXTREME_FLAT) { + ak->extreme_type |= (new_extreme | KEYFRAME_EXTREME_MIXED); + } + } +} + +/* ......... */ + +/* Comparator callback used for ActKeyColumns and GPencil frame */ +static short compare_ak_gpframe(void *node, void *data) +{ + bGPDframe *gpf = (bGPDframe *)data; + + float frame = gpf->framenum; + return compare_ak_cfraPtr(node, &frame); +} + +/* New node callback used for building ActKeyColumns from GPencil frames */ +static DLRBT_Node *nalloc_ak_gpframe(void *data) +{ + ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"); + bGPDframe *gpf = (bGPDframe *)data; + + /* store settings based on state of BezTriple */ + ak->cfra = gpf->framenum; + ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0; + ak->key_type = gpf->key_type; + + /* count keyframes in this column */ + ak->totkey = 1; + /* Set as visible block. */ + ak->totblock = 1; + ak->block.sel = ak->sel; + ak->block.flag |= ACTKEYBLOCK_FLAG_GPENCIL; + + return (DLRBT_Node *)ak; +} + +/* Node updater callback used for building ActKeyColumns from GPencil frames */ +static void nupdate_ak_gpframe(void *node, void *data) +{ + ActKeyColumn *ak = (ActKeyColumn *)node; + bGPDframe *gpf = (bGPDframe *)data; + + /* set selection status and 'touched' status */ + if (gpf->flag & GP_FRAME_SELECT) { + ak->sel = SELECT; + } + + /* count keyframes in this column */ + ak->totkey++; + + /* for keyframe type, 'proper' keyframes have priority over breakdowns + * (and other types for now). */ + if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME) { + ak->key_type = BEZT_KEYTYPE_KEYFRAME; + } +} + +/* ......... */ + +/* Comparator callback used for ActKeyColumns and GPencil frame */ +static short compare_ak_masklayshape(void *node, void *data) +{ + MaskLayerShape *masklay_shape = (MaskLayerShape *)data; + + float frame = masklay_shape->frame; + return compare_ak_cfraPtr(node, &frame); +} + +/* New node callback used for building ActKeyColumns from GPencil frames */ +static DLRBT_Node *nalloc_ak_masklayshape(void *data) +{ + ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"); + MaskLayerShape *masklay_shape = (MaskLayerShape *)data; + + /* store settings based on state of BezTriple */ + ak->cfra = masklay_shape->frame; + ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0; + + /* count keyframes in this column */ + ak->totkey = 1; + + return (DLRBT_Node *)ak; +} + +/* Node updater callback used for building ActKeyColumns from GPencil frames */ +static void nupdate_ak_masklayshape(void *node, void *data) +{ + ActKeyColumn *ak = (ActKeyColumn *)node; + MaskLayerShape *masklay_shape = (MaskLayerShape *)data; + + /* set selection status and 'touched' status */ + if (masklay_shape->flag & MASK_SHAPE_SELECT) { + ak->sel = SELECT; + } + + /* count keyframes in this column */ + ak->totkey++; +} + +/* --------------- */ + +/* Add the given BezTriple to the given 'list' of Keyframes */ +static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTripleChain *bezt) +{ + if (ELEM(NULL, keys, bezt)) { + return; + } + + BLI_dlrbTree_add(keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt); +} + +/* Add the given GPencil Frame to the given 'list' of Keyframes */ +static void add_gpframe_to_keycolumns_list(DLRBT_Tree *keys, bGPDframe *gpf) +{ + if (ELEM(NULL, keys, gpf)) { + return; + } + + BLI_dlrbTree_add(keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf); +} + +/* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */ +static void add_masklay_to_keycolumns_list(DLRBT_Tree *keys, MaskLayerShape *masklay_shape) +{ + if (ELEM(NULL, keys, masklay_shape)) { + return; + } + + BLI_dlrbTree_add(keys, + compare_ak_masklayshape, + nalloc_ak_masklayshape, + nupdate_ak_masklayshape, + masklay_shape); +} + +/* ActKeyBlocks (Long Keyframes) ------------------------------------------ */ + +static const ActKeyBlockInfo dummy_keyblock = {0}; + +static void compute_keyblock_data(ActKeyBlockInfo *info, BezTriple *prev, BezTriple *beztn) +{ + memset(info, 0, sizeof(ActKeyBlockInfo)); + + if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) { + /* Animator tagged a "moving hold" + * - Previous key must also be tagged as a moving hold, otherwise + * we're just dealing with the first of a pair, and we don't + * want to be creating any phantom holds... + */ + if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) { + info->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD; + } + } + + /* Check for same values... + * - Handles must have same central value as each other + * - Handles which control that section of the curve must be constant + */ + if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) { + bool hold; + + /* Only check handles in case of actual bezier interpolation. */ + if (prev->ipo == BEZT_IPO_BEZ) { + hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) && + IS_EQF(prev->vec[1][1], prev->vec[2][1]); + } + /* This interpolation type induces movement even between identical keys. */ + else { + hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC); + } + + if (hold) { + info->flag |= ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD; + } + } + + /* Remember non-bezier interpolation info. */ + if (prev->ipo != BEZT_IPO_BEZ) { + info->flag |= ACTKEYBLOCK_FLAG_NON_BEZIER; + } + + info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn); +} + +static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block) +{ + /* New curve and block. */ + if (col->totcurve <= 1 && col->totblock == 0) { + memcpy(&col->block, block, sizeof(ActKeyBlockInfo)); + } + /* Existing curve. */ + else { + col->block.conflict |= (col->block.flag ^ block->flag); + col->block.flag |= block->flag; + col->block.sel |= block->sel; + } + + if (block->flag) { + col->totblock++; + } +} + +static void add_bezt_to_keyblocks_list(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len) +{ + ActKeyColumn *col = keys->first; + + if (bezt && bezt_len >= 2) { + ActKeyBlockInfo block; + + /* Find the first key column while inserting dummy blocks. */ + for (; col != NULL && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) { + add_keyblock_info(col, &dummy_keyblock); + } + + BLI_assert(col != NULL); + + /* Insert real blocks. */ + for (int v = 1; col != NULL && v < bezt_len; v++, bezt++) { + /* Wrong order of bezier keys: resync position. */ + if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) { + /* Backtrack to find the right location. */ + if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) { + ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact( + keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]); + + if (newcol != NULL) { + col = newcol; + + /* The previous keyblock is garbage too. */ + if (col->prev != NULL) { + add_keyblock_info(col->prev, &dummy_keyblock); + } + } + else { + BLI_assert(false); + } + } + + continue; + } + + /* Normal sequence */ + BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0])); + + compute_keyblock_data(&block, bezt, bezt + 1); + + for (; col != NULL && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) { + add_keyblock_info(col, &block); + } + + BLI_assert(col != NULL); + } + } + + /* Insert dummy blocks at the end. */ + for (; col != NULL; col = col->next) { + add_keyblock_info(col, &dummy_keyblock); + } +} + +/* Walk through columns and propagate blocks and totcurve. + * + * This must be called even by animation sources that don't generate + * keyblocks to keep the data structure consistent after adding columns. + */ +static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len) +{ + /* Recompute the prev/next linked list. */ + BLI_dlrbTree_linkedlist_sync(keys); + + /* Find the curve count */ + int max_curve = 0; + + LISTBASE_FOREACH (ActKeyColumn *, col, keys) { + max_curve = MAX2(max_curve, col->totcurve); + } + + /* Propagate blocks to inserted keys */ + ActKeyColumn *prev_ready = NULL; + + LISTBASE_FOREACH (ActKeyColumn *, col, keys) { + /* Pre-existing column. */ + if (col->totcurve > 0) { + prev_ready = col; + } + /* Newly inserted column, so copy block data from previous. */ + else if (prev_ready != NULL) { + col->totblock = prev_ready->totblock; + memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo)); + } + + col->totcurve = max_curve + 1; + } + + /* Add blocks on top */ + add_bezt_to_keyblocks_list(keys, bezt, bezt_len); +} + +/* --------- */ + +bool actkeyblock_is_valid(ActKeyColumn *ac) +{ + return ac != NULL && ac->next != NULL && ac->totblock > 0; +} + +/* Checks if ActKeyBlock should exist... */ +int actkeyblock_get_valid_hold(ActKeyColumn *ac) +{ + /* check that block is valid */ + if (!actkeyblock_is_valid(ac)) { + return 0; + } + + const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD); + return (ac->block.flag & ~ac->block.conflict) & hold_mask; +} + +/* *************************** Keyframe List Conversions *************************** */ + +void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, int saction_flag) +{ + if (ac) { + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* get F-Curves to take keyframes from */ + filter = ANIMFILTER_DATA_VISIBLE; + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through each F-Curve, grabbing the keyframes */ + for (ale = anim_data.first; ale; ale = ale->next) { + /* Why not use all #eAnim_KeyType here? + * All of the other key types are actually "summaries" themselves, + * and will just end up duplicating stuff that comes up through + * standard filtering of just F-Curves. Given the way that these work, + * there isn't really any benefit at all from including them. - Aligorith */ + + switch (ale->datatype) { + case ALE_FCURVE: + fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag); + break; + case ALE_MASKLAY: + mask_to_keylist(ac->ads, ale->data, keys); + break; + case ALE_GPFRAME: + gpl_to_keylist(ac->ads, ale->data, keys); + break; + default: + // printf("%s: datatype %d unhandled\n", __func__, ale->datatype); + break; + } + } + + ANIM_animdata_freelist(&anim_data); + } +} + +void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, int saction_flag) +{ + bAnimContext ac = {NULL}; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + bAnimListElem dummychan = {NULL}; + + if (sce == NULL) { + return; + } + + /* create a dummy wrapper data to work with */ + dummychan.type = ANIMTYPE_SCENE; + dummychan.data = sce; + dummychan.id = &sce->id; + dummychan.adt = sce->adt; + + ac.ads = ads; + ac.data = &dummychan; + ac.datatype = ANIMCONT_CHANNEL; + + /* get F-Curves to take keyframes from */ + filter = ANIMFILTER_DATA_VISIBLE; /* curves only */ + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* loop through each F-Curve, grabbing the keyframes */ + for (ale = anim_data.first; ale; ale = ale->next) { + fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag); + } + + ANIM_animdata_freelist(&anim_data); +} + +void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, int saction_flag) +{ + bAnimContext ac = {NULL}; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + bAnimListElem dummychan = {NULL}; + Base dummybase = {NULL}; + + if (ob == NULL) { + return; + } + + /* create a dummy wrapper data to work with */ + dummybase.object = ob; + + dummychan.type = ANIMTYPE_OBJECT; + dummychan.data = &dummybase; + dummychan.id = &ob->id; + dummychan.adt = ob->adt; + + ac.ads = ads; + ac.data = &dummychan; + ac.datatype = ANIMCONT_CHANNEL; + + /* get F-Curves to take keyframes from */ + filter = ANIMFILTER_DATA_VISIBLE; /* curves only */ + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* loop through each F-Curve, grabbing the keyframes */ + for (ale = anim_data.first; ale; ale = ale->next) { + fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag); + } + + ANIM_animdata_freelist(&anim_data); +} + +void cachefile_to_keylist(bDopeSheet *ads, + CacheFile *cache_file, + DLRBT_Tree *keys, + int saction_flag) +{ + if (cache_file == NULL) { + return; + } + + /* create a dummy wrapper data to work with */ + bAnimListElem dummychan = {NULL}; + dummychan.type = ANIMTYPE_DSCACHEFILE; + dummychan.data = cache_file; + dummychan.id = &cache_file->id; + dummychan.adt = cache_file->adt; + + bAnimContext ac = {NULL}; + ac.ads = ads; + ac.data = &dummychan; + ac.datatype = ANIMCONT_CHANNEL; + + /* get F-Curves to take keyframes from */ + ListBase anim_data = {NULL, NULL}; + int filter = ANIMFILTER_DATA_VISIBLE; /* curves only */ + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* loop through each F-Curve, grabbing the keyframes */ + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag); + } + + ANIM_animdata_freelist(&anim_data); +} + +void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, int saction_flag) +{ + if (fcu && fcu->totvert && fcu->bezt) { + /* apply NLA-mapping (if applicable) */ + if (adt) { + ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0); + } + + /* Check if the curve is cyclic. */ + bool is_cyclic = BKE_fcurve_is_cyclic(fcu) && (fcu->totvert >= 2); + bool do_extremes = (saction_flag & SACTION_SHOW_EXTREMES) != 0; + + /* loop through beztriples, making ActKeysColumns */ + BezTripleChain chain = {0}; + + for (int v = 0; v < fcu->totvert; v++) { + chain.cur = &fcu->bezt[v]; + + /* Neighbor keys, accounting for being cyclic. */ + if (do_extremes) { + chain.prev = (v > 0) ? &fcu->bezt[v - 1] : is_cyclic ? &fcu->bezt[fcu->totvert - 2] : NULL; + chain.next = (v + 1 < fcu->totvert) ? &fcu->bezt[v + 1] : is_cyclic ? &fcu->bezt[1] : NULL; + } + + add_bezt_to_keycolumns_list(keys, &chain); + } + + /* Update keyblocks. */ + update_keyblocks(keys, fcu->bezt, fcu->totvert); + + /* unapply NLA-mapping if applicable */ + if (adt) { + ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0); + } + } +} + +void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys, int saction_flag) +{ + FCurve *fcu; + + if (agrp) { + /* loop through F-Curves */ + for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) { + fcurve_to_keylist(adt, fcu, keys, saction_flag); + } + } +} + +void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, int saction_flag) +{ + FCurve *fcu; + + if (act) { + /* loop through F-Curves */ + for (fcu = act->curves.first; fcu; fcu = fcu->next) { + fcurve_to_keylist(adt, fcu, keys, saction_flag); + } + } +} + +void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active) +{ + bGPDlayer *gpl; + + if (gpd && keys) { + /* for now, just aggregate out all the frames, but only for visible layers */ + for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) { + if ((gpl->flag & GP_LAYER_HIDE) == 0) { + if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) { + gpl_to_keylist(ads, gpl, keys); + } + } + } + } +} + +void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys) +{ + bGPDframe *gpf; + + if (gpl && keys) { + /* Although the frames should already be in an ordered list, + * they are not suitable for displaying yet. */ + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + add_gpframe_to_keycolumns_list(keys, gpf); + } + + update_keyblocks(keys, NULL, 0); + } +} + +void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, DLRBT_Tree *keys) +{ + MaskLayerShape *masklay_shape; + + if (masklay && keys) { + for (masklay_shape = masklay->splines_shapes.first; masklay_shape; + masklay_shape = masklay_shape->next) { + add_masklay_to_keycolumns_list(keys, masklay_shape); + } + + update_keyblocks(keys, NULL, 0); + } +} diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index e942bcf2902..aff5803f037 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -44,7 +44,7 @@ set(SRC armature_utils.c editarmature_undo.c meshlaplacian.c - pose_backup.c + pose_backup.cc pose_edit.c pose_group.c pose_lib.c diff --git a/source/blender/editors/armature/pose_backup.c b/source/blender/editors/armature/pose_backup.cc index dffcd9bdc5a..9b2d3e37d98 100644 --- a/source/blender/editors/armature/pose_backup.c +++ b/source/blender/editors/armature/pose_backup.cc @@ -20,7 +20,7 @@ #include "ED_armature.h" -#include <string.h> +#include <cstring> #include "BLI_listbase.h" @@ -31,9 +31,12 @@ #include "DNA_object_types.h" #include "BKE_action.h" -#include "BKE_armature.h" +#include "BKE_action.hh" +#include "BKE_armature.hh" #include "BKE_idprop.h" +using namespace blender::bke; + /* simple struct for storing backup info for one pose channel */ typedef struct PoseChannelBackup { struct PoseChannelBackup *next, *prev; @@ -44,31 +47,38 @@ typedef struct PoseChannelBackup { struct IDProperty *oldprops; /* Backup copy (needs freeing) of pose channel's ID properties. */ } PoseChannelBackup; -typedef struct PoseBackup { +struct PoseBackup { bool is_bone_selection_relevant; ListBase /* PoseChannelBackup* */ backups; -} PoseBackup; +}; static PoseBackup *pose_backup_create(const Object *ob, const bAction *action, - const bool is_bone_selection_relevant) + const BoneNameSet &selected_bone_names) { - ListBase backups = {NULL, NULL}; - const bArmature *armature = ob->data; - - /* TODO(Sybren): reuse same approach as in `armature_pose.cc` in this function, as that doesn't - * have the assumption that action group names are bone names. */ - LISTBASE_FOREACH (bActionGroup *, agrp, &action->groups) { - bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name); - if (pchan == NULL) { - continue; + ListBase backups = {nullptr, nullptr}; + const bool is_bone_selection_relevant = !selected_bone_names.is_empty(); + + BoneNameSet backed_up_bone_names; + /* Make a backup of the given pose channel. */ + auto store_animated_pchans = [&](FCurve *, const char *bone_name) { + if (backed_up_bone_names.contains(bone_name)) { + /* Only backup each bone once. */ + return; + } + + bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + if (pchan == nullptr) { + /* FCurve targets non-existent bone. */ + return; } - if (is_bone_selection_relevant && !PBONE_SELECTED(armature, pchan->bone)) { - continue; + if (is_bone_selection_relevant && !selected_bone_names.contains(bone_name)) { + return; } - PoseChannelBackup *chan_bak = MEM_callocN(sizeof(*chan_bak), "PoseChannelBackup"); + PoseChannelBackup *chan_bak = static_cast<PoseChannelBackup *>( + MEM_callocN(sizeof(*chan_bak), "PoseChannelBackup")); chan_bak->pchan = pchan; memcpy(&chan_bak->olddata, chan_bak->pchan, sizeof(chan_bak->olddata)); @@ -77,10 +87,14 @@ static PoseBackup *pose_backup_create(const Object *ob, } BLI_addtail(&backups, chan_bak); - } + backed_up_bone_names.add_new(bone_name); + }; + + /* Call `store_animated_pchans()` for each FCurve that targets a bone. */ + BKE_action_find_fcurves_with_bones(action, store_animated_pchans); /* PoseBackup is constructed late, so that the above loop can use stack variables. */ - PoseBackup *pose_backup = MEM_callocN(sizeof(*pose_backup), __func__); + PoseBackup *pose_backup = static_cast<PoseBackup *>(MEM_callocN(sizeof(*pose_backup), __func__)); pose_backup->is_bone_selection_relevant = is_bone_selection_relevant; pose_backup->backups = backups; return pose_backup; @@ -88,24 +102,14 @@ static PoseBackup *pose_backup_create(const Object *ob, PoseBackup *ED_pose_backup_create_all_bones(const Object *ob, const bAction *action) { - return pose_backup_create(ob, action, false); + return pose_backup_create(ob, action, BoneNameSet()); } PoseBackup *ED_pose_backup_create_selected_bones(const Object *ob, const bAction *action) { - /* See if bone selection is relevant. */ - bool all_bones_selected = true; - bool no_bones_selected = true; - const bArmature *armature = ob->data; - LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { - const bool is_selected = PBONE_SELECTED(armature, pchan->bone); - all_bones_selected &= is_selected; - no_bones_selected &= !is_selected; - } - - /* If no bones are selected, act as if all are. */ - const bool is_bone_selection_relevant = !all_bones_selected && !no_bones_selected; - return pose_backup_create(ob, action, is_bone_selection_relevant); + const bArmature *armature = static_cast<const bArmature *>(ob->data); + const BoneNameSet selected_bone_names = BKE_armature_find_selected_bone_names(armature); + return pose_backup_create(ob, action, selected_bone_names); } bool ED_pose_backup_is_selection_relevant(const struct PoseBackup *pose_backup) diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index df3550d5db6..cb70b2810d1 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -62,8 +62,8 @@ #include "ED_anim_api.h" #include "ED_armature.h" -#include "ED_keyframes_draw.h" #include "ED_keyframes_edit.h" +#include "ED_keyframes_keylist.h" #include "ED_keyframing.h" #include "ED_object.h" #include "ED_screen.h" diff --git a/source/blender/editors/armature/pose_lib_2.c b/source/blender/editors/armature/pose_lib_2.c index eb091296282..32440f941ba 100644 --- a/source/blender/editors/armature/pose_lib_2.c +++ b/source/blender/editors/armature/pose_lib_2.c @@ -130,7 +130,7 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, PoseBlendData *pbd) /* start tagging/keying */ const bArmature *armature = pbd->ob->data; LISTBASE_FOREACH (bActionGroup *, agrp, &act->groups) { - /* only for selected bones unless there aren't any selected, in which case all are included */ + /* Only for selected bones unless there aren't any selected, in which case all are included. */ bPoseChannel *pchan = BKE_pose_channel_find_name(pose, agrp->name); if (pchan == NULL) { continue; @@ -422,7 +422,7 @@ static void poselib_blend_cleanup(bContext *C, wmOperator *op) case POSE_BLEND_BLENDING: case POSE_BLEND_ORIGINAL: /* Cleanup should not be called directly from these states. */ - BLI_assert(!"poselib_blend_cleanup: unexpected pose blend state"); + BLI_assert_msg(0, "poselib_blend_cleanup: unexpected pose blend state"); BKE_report(op->reports, RPT_ERROR, "Internal pose library error, cancelling operator"); ATTR_FALLTHROUGH; case POSE_BLEND_CANCEL: @@ -544,7 +544,7 @@ static bool poselib_asset_in_context(bContext *C) AssetHandle asset_handle = CTX_wm_asset_handle(C, &asset_handle_valid); return (asset_library != NULL) && asset_handle_valid && - (asset_handle.file_data->blentype == ID_AC); + (ED_asset_handle_get_id_type(&asset_handle) == ID_AC); } /* Poll callback for operators that require existing PoseLib data (with poses) to work. */ diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 1a1685e4a01..e87d221058c 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -77,11 +77,12 @@ #include "UI_resources.h" #include "ED_armature.h" -#include "ED_keyframes_draw.h" +#include "ED_keyframes_keylist.h" #include "ED_markers.h" #include "ED_numinput.h" #include "ED_screen.h" #include "ED_space_api.h" +#include "ED_util.h" #include "GPU_immediate.h" #include "GPU_immediate_util.h" @@ -137,8 +138,8 @@ typedef struct tPoseSlideOp { Scene *scene; /** area that we're operating in (needed for modal()) */ ScrArea *area; - /** Header of the region used for drawing the slider. */ - ARegion *region_header; + /** Region we're operating in (needed for modal()). */ + ARegion *region; /** len of the PoseSlideObject array. */ uint objects_len; @@ -168,26 +169,7 @@ typedef struct tPoseSlideOp { /** Axis-limits for transforms. */ ePoseSlide_AxisLock axislock; - /** Allow overshoot or clamp between 0% and 100%. */ - bool overshoot; - - /** Reduces factor delta from mouse movement. */ - bool precision; - - /** Move factor in 10% steps. */ - bool increments; - - /** Draw callback handler. */ - void *draw_handle; - - /** Accumulative, unclamped and unrounded factor. */ - float raw_factor; - - /** 0-1 value for determining the influence of whatever is relevant. */ - float factor; - - /** Last cursor position in screen space used for mouse movement delta calculation. */ - int last_cursor_x; + struct tSlider *slider; /** Numeric input. */ NumInput num; @@ -232,256 +214,6 @@ static const EnumPropertyItem prop_axis_lock_types[] = { /* ------------------------------------ */ -static void draw_overshoot_triangle(const uint8_t color[4], - const bool facing_right, - const float x, - const float y) -{ - const uint shdr_pos_2d = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - GPU_blend(GPU_BLEND_ALPHA); - GPU_polygon_smooth(true); - immUniformColor3ubvAlpha(color, 225); - const float triangle_side_length = facing_right ? 6 * U.pixelsize : -6 * U.pixelsize; - const float triangle_offset = facing_right ? 2 * U.pixelsize : -2 * U.pixelsize; - - immBegin(GPU_PRIM_TRIS, 3); - immVertex2f(shdr_pos_2d, x + triangle_offset + triangle_side_length, y); - immVertex2f(shdr_pos_2d, x + triangle_offset, y + triangle_side_length / 2); - immVertex2f(shdr_pos_2d, x + triangle_offset, y - triangle_side_length / 2); - immEnd(); - - GPU_polygon_smooth(false); - GPU_blend(GPU_BLEND_NONE); - immUnbindProgram(); -} - -static void draw_ticks(const float start_factor, - const float end_factor, - const float line_start[2], - const float base_tick_height, - const float line_width, - const uint8_t color_overshoot[4], - const uint8_t color_line[4]) -{ - /* Use factor represented as 0-100 int to avoid floating point precision problems. */ - const int tick_increment = 10; - - /* Round initial_tick_factor up to the next tick_increment. */ - int tick_percentage = ceil((start_factor * 100) / tick_increment) * tick_increment; - - while (tick_percentage <= (int)(end_factor * 100)) { - float tick_height; - /* Different ticks have different heights. Multiples of 100% are the tallest, 50% is a bit - * smaller and the rest is the minimum size. */ - if (tick_percentage % 100 == 0) { - tick_height = base_tick_height; - } - else if (tick_percentage % 50 == 0) { - tick_height = base_tick_height * 0.8; - } - else { - tick_height = base_tick_height * 0.5; - } - - const float x = line_start[0] + - (((float)tick_percentage / 100) - start_factor) * SLIDE_PIXEL_DISTANCE; - const rctf tick_rect = { - .xmin = x - (line_width / 2), - .xmax = x + (line_width / 2), - .ymin = line_start[1] - (tick_height / 2), - .ymax = line_start[1] + (tick_height / 2), - }; - - if (tick_percentage < 0 || tick_percentage > 100) { - UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_overshoot, 255); - } - else { - UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_line, 255); - } - tick_percentage += tick_increment; - } -} - -static void draw_main_line(const rctf *main_line_rect, - const float factor, - const bool overshoot, - const uint8_t color_overshoot[4], - const uint8_t color_line[4]) -{ - if (overshoot) { - /* In overshoot mode, draw the 0-100% range differently to provide a visual reference. */ - const float line_zero_percent = main_line_rect->xmin - - ((factor - 0.5f - OVERSHOOT_RANGE_DELTA) * - SLIDE_PIXEL_DISTANCE); - - const float clamped_line_zero_percent = clamp_f( - line_zero_percent, main_line_rect->xmin, main_line_rect->xmax); - const float clamped_line_hundred_percent = clamp_f( - line_zero_percent + SLIDE_PIXEL_DISTANCE, main_line_rect->xmin, main_line_rect->xmax); - - const rctf left_overshoot_line_rect = { - .xmin = main_line_rect->xmin, - .xmax = clamped_line_zero_percent, - .ymin = main_line_rect->ymin, - .ymax = main_line_rect->ymax, - }; - const rctf right_overshoot_line_rect = { - .xmin = clamped_line_hundred_percent, - .xmax = main_line_rect->xmax, - .ymin = main_line_rect->ymin, - .ymax = main_line_rect->ymax, - }; - UI_draw_roundbox_3ub_alpha(&left_overshoot_line_rect, true, 0, color_overshoot, 255); - UI_draw_roundbox_3ub_alpha(&right_overshoot_line_rect, true, 0, color_overshoot, 255); - - const rctf non_overshoot_line_rect = { - .xmin = clamped_line_zero_percent, - .xmax = clamped_line_hundred_percent, - .ymin = main_line_rect->ymin, - .ymax = main_line_rect->ymax, - }; - UI_draw_roundbox_3ub_alpha(&non_overshoot_line_rect, true, 0, color_line, 255); - } - else { - UI_draw_roundbox_3ub_alpha(main_line_rect, true, 0, color_line, 255); - } -} - -static void draw_backdrop(const int fontid, - const rctf *main_line_rect, - const float color_bg[4], - const short region_y_size, - const float base_tick_height) -{ - float string_pixel_size[2]; - const char *percentage_string_placeholder = "000%%"; - BLF_width_and_height(fontid, - percentage_string_placeholder, - sizeof(percentage_string_placeholder), - &string_pixel_size[0], - &string_pixel_size[1]); - const float pad[2] = {(region_y_size - base_tick_height) / 2, 2.0f * U.pixelsize}; - const rctf backdrop_rect = { - .xmin = main_line_rect->xmin - string_pixel_size[0] - pad[0], - .xmax = main_line_rect->xmax + pad[0], - .ymin = pad[1], - .ymax = region_y_size - pad[1], - }; - UI_draw_roundbox_aa(&backdrop_rect, true, 4.0f, color_bg); -} - -/** - * Draw an on screen Slider for a Pose Slide Operator. - */ -static void pose_slide_draw_2d_slider(const struct bContext *UNUSED(C), ARegion *region, void *arg) -{ - tPoseSlideOp *pso = arg; - - /* Only draw in region from which the Operator was started. */ - if (region != pso->region_header) { - return; - } - - uint8_t color_text[4]; - uint8_t color_line[4]; - uint8_t color_handle[4]; - uint8_t color_overshoot[4]; - float color_bg[4]; - - /* Get theme colors. */ - UI_GetThemeColor4ubv(TH_TEXT, color_text); - UI_GetThemeColor4ubv(TH_TEXT, color_line); - UI_GetThemeColor4ubv(TH_TEXT, color_overshoot); - UI_GetThemeColor4ubv(TH_ACTIVE, color_handle); - UI_GetThemeColor3fv(TH_BACK, color_bg); - - color_bg[3] = 0.5f; - color_overshoot[0] = color_overshoot[0] * 0.7; - color_overshoot[1] = color_overshoot[1] * 0.7; - color_overshoot[2] = color_overshoot[2] * 0.7; - - /* Get the default font. */ - const uiStyle *style = UI_style_get(); - const uiFontStyle *fstyle = &style->widget; - const int fontid = fstyle->uifont_id; - BLF_color3ubv(fontid, color_text); - BLF_rotation(fontid, 0.0f); - - const float line_width = 1.5 * U.pixelsize; - const float base_tick_height = 12.0 * U.pixelsize; - const float line_y = region->winy / 2; - - rctf main_line_rect = { - .xmin = (region->winx / 2) - (SLIDE_PIXEL_DISTANCE / 2), - .xmax = (region->winx / 2) + (SLIDE_PIXEL_DISTANCE / 2), - .ymin = line_y - line_width / 2, - .ymax = line_y + line_width / 2, - }; - float line_start_factor = 0; - int handle_pos_x = main_line_rect.xmin + SLIDE_PIXEL_DISTANCE * pso->factor; - - if (pso->overshoot) { - main_line_rect.xmin = main_line_rect.xmin - SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA; - main_line_rect.xmax = main_line_rect.xmax + SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA; - line_start_factor = pso->factor - 0.5f - OVERSHOOT_RANGE_DELTA; - handle_pos_x = region->winx / 2; - } - - draw_backdrop(fontid, &main_line_rect, color_bg, pso->region_header->winy, base_tick_height); - - draw_main_line(&main_line_rect, pso->factor, pso->overshoot, color_overshoot, color_line); - - const float factor_range = pso->overshoot ? 1 + OVERSHOOT_RANGE_DELTA * 2 : 1; - const float line_start_position[2] = {main_line_rect.xmin, line_y}; - draw_ticks(line_start_factor, - line_start_factor + factor_range, - line_start_position, - base_tick_height, - line_width, - color_overshoot, - color_line); - - /* Draw triangles at the ends of the line in overshoot mode to indicate direction of 0-100% - * range. */ - if (pso->overshoot) { - if (pso->factor > 1 + OVERSHOOT_RANGE_DELTA + 0.5) { - draw_overshoot_triangle(color_line, false, main_line_rect.xmin, line_y); - } - if (pso->factor < 0 - OVERSHOOT_RANGE_DELTA - 0.5) { - draw_overshoot_triangle(color_line, true, main_line_rect.xmax, line_y); - } - } - - char percentage_string[256]; - - /* Draw handle indicating current factor. */ - const rctf handle_rect = { - .xmin = handle_pos_x - (line_width), - .xmax = handle_pos_x + (line_width), - .ymin = line_y - (base_tick_height / 2), - .ymax = line_y + (base_tick_height / 2), - }; - - UI_draw_roundbox_3ub_alpha(&handle_rect, true, 1, color_handle, 255); - BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", pso->factor * 100); - - /* Draw percentage string. */ - float percentage_string_pixel_size[2]; - BLF_width_and_height(fontid, - percentage_string, - sizeof(percentage_string), - &percentage_string_pixel_size[0], - &percentage_string_pixel_size[1]); - - BLF_position(fontid, - main_line_rect.xmin - 24.0 * U.pixelsize - percentage_string_pixel_size[0] / 2, - (region->winy / 2) - percentage_string_pixel_size[1] / 2, - 0.0f); - BLF_draw(fontid, percentage_string, sizeof(percentage_string)); -} - /** Operator custom-data initialization. */ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) { @@ -492,15 +224,13 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) /* Get info from context. */ pso->scene = CTX_data_scene(C); - pso->area = CTX_wm_area(C); /* Only really needed when doing modal(). */ - pso->region_header = CTX_wm_region(C); /* Only really needed when doing modal(). */ + pso->area = CTX_wm_area(C); /* Only really needed when doing modal(). */ + pso->region = CTX_wm_region(C); /* Only really needed when doing modal(). */ pso->cframe = pso->scene->r.cfra; pso->mode = mode; /* Set range info from property values - these may get overridden for the invoke(). */ - pso->factor = RNA_float_get(op->ptr, "factor"); - pso->raw_factor = pso->factor; pso->prevFrame = RNA_int_get(op->ptr, "prev_frame"); pso->nextFrame = RNA_int_get(op->ptr, "next_frame"); @@ -508,6 +238,9 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) pso->channels = RNA_enum_get(op->ptr, "channels"); pso->axislock = RNA_enum_get(op->ptr, "axis_lock"); + pso->slider = ED_slider_create(C); + ED_slider_factor_set(pso->slider, RNA_float_get(op->ptr, "factor")); + /* For each Pose-Channel which gets affected, get the F-Curves for that channel * and set the relevant transform flags. */ poseAnim_mapping_get(C, &pso->pfLinks); @@ -552,14 +285,6 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) pso->num.val_flag[0] |= NUM_NO_NEGATIVE; pso->num.unit_type[0] = B_UNIT_NONE; /* Percentages don't have any units. */ - /* Register UI drawing callback. */ - ARegion *region_header = BKE_area_find_region_type(pso->area, RGN_TYPE_HEADER); - if (region_header != NULL) { - pso->region_header = region_header; - pso->draw_handle = ED_region_draw_cb_activate( - region_header->type, pose_slide_draw_2d_slider, pso, REGION_DRAW_POST_PIXEL); - } - /* Return status is whether we've got all the data we were requested to get. */ return 1; } @@ -567,17 +292,16 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) /** * Exiting the operator (free data). */ -static void pose_slide_exit(wmOperator *op) +static void pose_slide_exit(bContext *C, wmOperator *op) { tPoseSlideOp *pso = op->customdata; + ED_slider_destroy(C, pso->slider); + /* Hide Bone Overlay. */ View3D *v3d = pso->area->spacedata.first; v3d->overlay.flag = pso->overlay_flag; - /* Remove UI drawing callback. */ - ED_region_draw_cb_exit(pso->region_header->type, pso->draw_handle); - /* Free the temp pchan links and their data. */ poseAnim_mapping_free(&pso->pfLinks); @@ -655,8 +379,8 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, flo /* Calculate the relative weights of the endpoints. */ if (pso->mode == POSESLIDE_BREAKDOWN) { /* Get weights from the factor control. */ - w1 = pso->factor; /* This must come second. */ - w2 = 1.0f - w1; /* This must come first. */ + w1 = ED_slider_factor_get(pso->slider); /* This must come second. */ + w2 = 1.0f - w1; /* This must come first. */ } else { /* - these weights are derived from the relative distance of these @@ -682,13 +406,13 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, flo case POSESLIDE_PUSH: /* Make the current pose more pronounced. */ { /* Slide the pose away from the breakdown pose in the timeline */ - (*val) -= ((sVal * w2) + (eVal * w1) - (*val)) * pso->factor; + (*val) -= ((sVal * w2) + (eVal * w1) - (*val)) * ED_slider_factor_get(pso->slider); break; } case POSESLIDE_RELAX: /* Make the current pose more like its surrounding ones. */ { /* Slide the pose towards the breakdown pose in the timeline */ - (*val) += ((sVal * w2) + (eVal * w1) - (*val)) * pso->factor; + (*val) += ((sVal * w2) + (eVal * w1) - (*val)) * ED_slider_factor_get(pso->slider); break; } case POSESLIDE_BREAKDOWN: /* Make the current pose slide around between the endpoints. */ @@ -888,7 +612,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) normalize_qt(quat_prev); normalize_qt(quat_next); - interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->factor); + interp_qt_qtqt(quat_final, quat_prev, quat_next, ED_slider_factor_get(pso->slider)); } else { /* POSESLIDE_PUSH and POSESLIDE_RELAX. */ @@ -906,11 +630,12 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) normalize_qt(quat_curr); if (pso->mode == POSESLIDE_PUSH) { - interp_qt_qtqt(quat_final, quat_breakdown, quat_curr, 1.0f + pso->factor); + interp_qt_qtqt( + quat_final, quat_breakdown, quat_curr, 1.0f + ED_slider_factor_get(pso->slider)); } else { BLI_assert(pso->mode == POSESLIDE_RELAX); - interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, pso->factor); + interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, ED_slider_factor_get(pso->slider)); } } @@ -931,11 +656,11 @@ static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], flo ((lock & PS_LOCK_Z) && (idx == 2))) { float diff_val = default_value - vec[idx]; if (pso->mode == POSESLIDE_RELAX_REST) { - vec[idx] += pso->factor * diff_val; + vec[idx] += ED_slider_factor_get(pso->slider) * diff_val; } else { /* Push */ - vec[idx] -= pso->factor * diff_val; + vec[idx] -= ED_slider_factor_get(pso->slider) * diff_val; } } } @@ -953,11 +678,11 @@ static void pose_slide_rest_pose_apply_other_rot(tPoseSlideOp *pso, float vec[4] for (int idx = 0; idx < 4; idx++) { float diff_val = default_values[idx] - vec[idx]; if (pso->mode == POSESLIDE_RELAX_REST) { - vec[idx] += pso->factor * diff_val; + vec[idx] += ED_slider_factor_get(pso->slider) * diff_val; } else { /* Push */ - vec[idx] -= pso->factor * diff_val; + vec[idx] -= ED_slider_factor_get(pso->slider) * diff_val; } } } @@ -1130,9 +855,7 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso) char limits_str[UI_MAX_DRAW_STR]; char axis_str[50]; char mode_str[32]; - char overshoot_str[50]; - char precision_str[50]; - char increments_str[50]; + char slider_str[UI_MAX_DRAW_STR]; char bone_vis_str[50]; switch (pso->mode) { @@ -1203,29 +926,10 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso) break; } - if (pso->overshoot) { - STRNCPY(overshoot_str, TIP_("[E] - Disable overshoot")); - } - else { - STRNCPY(overshoot_str, TIP_("[E] - Enable overshoot")); - } - - if (pso->precision) { - STRNCPY(precision_str, TIP_("[Shift] - Precision active")); - } - else { - STRNCPY(precision_str, TIP_("Shift - Hold for precision")); - } - - if (pso->increments) { - STRNCPY(increments_str, TIP_("[Ctrl] - Increments active")); - } - else { - STRNCPY(increments_str, TIP_("Ctrl - Hold for 10% increments")); - } - STRNCPY(bone_vis_str, TIP_("[H] - Toggle bone visibility")); + ED_slider_status_string_get(pso->slider, slider_str, sizeof(slider_str)); + if (hasNumInput(&pso->num)) { Scene *scene = pso->scene; char str_offs[NUM_STR_REP_LEN]; @@ -1237,12 +941,10 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso) else { BLI_snprintf(status_str, sizeof(status_str), - "%s: %s | %s | %s | %s | %s", + "%s: %s | %s | %s", mode_str, limits_str, - overshoot_str, - precision_str, - increments_str, + slider_str, bone_vis_str); } @@ -1253,11 +955,15 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso) /** * Common code for invoke() methods. */ -static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *pso) +static int pose_slide_invoke_common(bContext *C, wmOperator *op, const wmEvent *event) { tPChanFCurveLink *pfl; wmWindow *win = CTX_wm_window(C); + tPoseSlideOp *pso = op->customdata; + + ED_slider_init(pso->slider, event); + /* For each link, add all its keyframes to the search tree. */ for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) { LinkData *ld; @@ -1315,7 +1021,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p } else { BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between"); - pose_slide_exit(op); + pose_slide_exit(C, op); return OPERATOR_CANCELLED; } @@ -1349,29 +1055,6 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p } /** - * Calculate factor based on mouse movement, clamp or round to increments if - * enabled by the user. Store the new factor value. - */ -static void pose_slide_mouse_update_factor(tPoseSlideOp *pso, wmOperator *op, const wmEvent *event) -{ - const float factor_delta = (event->x - pso->last_cursor_x) / ((float)(SLIDE_PIXEL_DISTANCE)); - /* Reduced factor delta in precision mode (shift held). */ - pso->raw_factor += pso->precision ? (factor_delta / 8) : factor_delta; - pso->factor = pso->raw_factor; - pso->last_cursor_x = event->x; - - if (!pso->overshoot) { - pso->factor = clamp_f(pso->factor, 0, 1); - } - - if (pso->increments) { - pso->factor = round(pso->factor * 10) / 10; - } - - RNA_float_set(op->ptr, "factor", pso->factor); -} - -/** * Handle an event to toggle channels mode. */ static void pose_slide_toggle_channels_mode(wmOperator *op, @@ -1434,6 +1117,8 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) const bool has_numinput = hasNumInput(&pso->num); + do_pose_update = ED_slider_modal(pso->slider, event); + switch (event->type) { case LEFTMOUSE: /* Confirm. */ case EVT_RETKEY: @@ -1449,7 +1134,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Insert keyframes as required. */ pose_slide_autoKeyframe(C, pso); - pose_slide_exit(op); + pose_slide_exit(C, op); /* Done! */ return OPERATOR_FINISHED; @@ -1472,7 +1157,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) pose_slide_refresh(C, pso); /* Clean up temp data. */ - pose_slide_exit(op); + pose_slide_exit(C, op); /* Canceled! */ return OPERATOR_CANCELLED; @@ -1485,9 +1170,6 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) { /* Only handle mouse-move if not doing numinput. */ if (has_numinput == false) { - /* Update factor based on position of mouse. */ - pose_slide_mouse_update_factor(pso, op, event); - /* Update pose to reflect the new values (see below). */ do_pose_update = true; } @@ -1500,12 +1182,13 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Grab percentage from numeric input, and store this new value for redo * NOTE: users see ints, while internally we use a 0-1 float */ - value = pso->factor * 100.0f; + value = ED_slider_factor_get(pso->slider) * 100.0f; applyNumInput(&pso->num, &value); - pso->factor = value / 100.0f; - CLAMP(pso->factor, 0.0f, 1.0f); - RNA_float_set(op->ptr, "factor", pso->factor); + float factor = value / 100; + CLAMP(factor, 0.0f, 1.0f); + ED_slider_factor_set(pso->slider, factor); + RNA_float_set(op->ptr, "factor", ED_slider_factor_get(pso->slider)); /* Update pose to reflect the new values (see below) */ do_pose_update = true; @@ -1567,29 +1250,6 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } - /* Overshoot. */ - case EVT_EKEY: { - pso->overshoot = !pso->overshoot; - do_pose_update = true; - break; - } - - /* Precision mode. */ - case EVT_LEFTSHIFTKEY: - case EVT_RIGHTSHIFTKEY: { - pso->precision = true; - do_pose_update = true; - break; - } - - /* Increments mode. */ - case EVT_LEFTCTRLKEY: - case EVT_RIGHTCTRLKEY: { - pso->increments = true; - do_pose_update = true; - break; - } - /* Toggle Bone visibility. */ case EVT_HKEY: { View3D *v3d = pso->area->spacedata.first; @@ -1600,25 +1260,6 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - /* Precision and stepping only active while button is held. */ - else if (event->val == KM_RELEASE) { - switch (event->type) { - case EVT_LEFTSHIFTKEY: - case EVT_RIGHTSHIFTKEY: { - pso->precision = false; - do_pose_update = true; - break; - } - case EVT_LEFTCTRLKEY: - case EVT_RIGHTCTRLKEY: { - pso->increments = false; - do_pose_update = true; - break; - } - default: - break; - } - } else { /* Unhandled event - maybe it was some view manipulation? */ /* Allow to pass through. */ @@ -1652,10 +1293,10 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) /** * Common code for cancel() */ -static void pose_slide_cancel(bContext *UNUSED(C), wmOperator *op) +static void pose_slide_cancel(bContext *C, wmOperator *op) { /* Cleanup and done. */ - pose_slide_exit(op); + pose_slide_exit(C, op); } /** @@ -1675,7 +1316,7 @@ static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso pose_slide_autoKeyframe(C, pso); /* Cleanup and done. */ - pose_slide_exit(op); + pose_slide_exit(C, op); return OPERATOR_FINISHED; } @@ -1743,23 +1384,14 @@ static void pose_slide_opdef_properties(wmOperatorType *ot) */ static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - tPoseSlideOp *pso; - /* Initialize data. */ if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) { - pose_slide_exit(op); + pose_slide_exit(C, op); return OPERATOR_CANCELLED; } - pso = op->customdata; - - pso->last_cursor_x = event->x; - - /* Initialize factor so that it won't pop on first mouse move. */ - pose_slide_mouse_update_factor(pso, op, event); - /* Do common setup work. */ - return pose_slide_invoke_common(C, op, pso); + return pose_slide_invoke_common(C, op, event); } /** @@ -1771,7 +1403,7 @@ static int pose_slide_push_exec(bContext *C, wmOperator *op) /* Initialize data (from RNA-props). */ if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) { - pose_slide_exit(op); + pose_slide_exit(C, op); return OPERATOR_CANCELLED; } @@ -1809,23 +1441,14 @@ void POSE_OT_push(wmOperatorType *ot) */ static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - tPoseSlideOp *pso; - /* Initialize data. */ if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) { - pose_slide_exit(op); + pose_slide_exit(C, op); return OPERATOR_CANCELLED; } - pso = op->customdata; - - pso->last_cursor_x = event->x; - - /* Initialize factor so that it won't pop on first mouse move. */ - pose_slide_mouse_update_factor(pso, op, event); - /* Do common setup work. */ - return pose_slide_invoke_common(C, op, pso); + return pose_slide_invoke_common(C, op, event); } /** @@ -1837,7 +1460,7 @@ static int pose_slide_relax_exec(bContext *C, wmOperator *op) /* Initialize data (from RNA-props). */ if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) { - pose_slide_exit(op); + pose_slide_exit(C, op); return OPERATOR_CANCELLED; } @@ -1874,23 +1497,14 @@ void POSE_OT_relax(wmOperatorType *ot) */ static int pose_slide_push_rest_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - tPoseSlideOp *pso; - /* Initialize data. */ if (pose_slide_init(C, op, POSESLIDE_PUSH_REST) == 0) { - pose_slide_exit(op); + pose_slide_exit(C, op); return OPERATOR_CANCELLED; } - pso = op->customdata; - - pso->last_cursor_x = event->x; - - /* Initialize factor so that it won't pop on first mouse move. */ - pose_slide_mouse_update_factor(pso, op, event); - /* do common setup work */ - return pose_slide_invoke_common(C, op, pso); + return pose_slide_invoke_common(C, op, event); } /** @@ -1902,7 +1516,7 @@ static int pose_slide_push_rest_exec(bContext *C, wmOperator *op) /* Initialize data (from RNA-props). */ if (pose_slide_init(C, op, POSESLIDE_PUSH_REST) == 0) { - pose_slide_exit(op); + pose_slide_exit(C, op); return OPERATOR_CANCELLED; } @@ -1940,23 +1554,14 @@ void POSE_OT_push_rest(wmOperatorType *ot) */ static int pose_slide_relax_rest_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - tPoseSlideOp *pso; - /* Initialize data. */ if (pose_slide_init(C, op, POSESLIDE_RELAX_REST) == 0) { - pose_slide_exit(op); + pose_slide_exit(C, op); return OPERATOR_CANCELLED; } - pso = op->customdata; - - pso->last_cursor_x = event->x; - - /* Initialize factor so that it won't pop on first mouse move. */ - pose_slide_mouse_update_factor(pso, op, event); - /* Do common setup work. */ - return pose_slide_invoke_common(C, op, pso); + return pose_slide_invoke_common(C, op, event); } /** @@ -1968,7 +1573,7 @@ static int pose_slide_relax_rest_exec(bContext *C, wmOperator *op) /* Initialize data (from RNA-props). */ if (pose_slide_init(C, op, POSESLIDE_RELAX_REST) == 0) { - pose_slide_exit(op); + pose_slide_exit(C, op); return OPERATOR_CANCELLED; } @@ -2006,23 +1611,14 @@ void POSE_OT_relax_rest(wmOperatorType *ot) */ static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - tPoseSlideOp *pso; - /* Initialize data. */ if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) { - pose_slide_exit(op); + pose_slide_exit(C, op); return OPERATOR_CANCELLED; } - pso = op->customdata; - - pso->last_cursor_x = event->x; - - /* Initialize factor so that it won't pop on first mouse move. */ - pose_slide_mouse_update_factor(pso, op, event); - /* Do common setup work. */ - return pose_slide_invoke_common(C, op, pso); + return pose_slide_invoke_common(C, op, event); } /** @@ -2034,7 +1630,7 @@ static int pose_slide_breakdown_exec(bContext *C, wmOperator *op) /* Initialize data (from RNA-props). */ if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) { - pose_slide_exit(op); + pose_slide_exit(C, op); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt index a27975bc37b..d56edd43d7d 100644 --- a/source/blender/editors/asset/CMakeLists.txt +++ b/source/blender/editors/asset/CMakeLists.txt @@ -16,6 +16,7 @@ # ***** END GPL LICENSE BLOCK ***** set(INC + . ../include ../../blenkernel ../../blenlib @@ -30,10 +31,21 @@ set(INC_SYS ) set(SRC - asset_edit.cc - asset_list.cc - asset_ops.cc - asset_temp_id_consumer.cc + intern/asset_handle.cc + intern/asset_library_reference.cc + intern/asset_library_reference_enum.cc + intern/asset_list.cc + intern/asset_mark_clear.cc + intern/asset_ops.cc + intern/asset_temp_id_consumer.cc + + ED_asset_handle.h + ED_asset_library.h + ED_asset_list.h + ED_asset_list.hh + ED_asset_mark_clear.h + ED_asset_temp_id_consumer.h + intern/asset_library_reference.hh ) set(LIB diff --git a/source/blender/editors/asset/ED_asset_handle.h b/source/blender/editors/asset/ED_asset_handle.h new file mode 100644 index 00000000000..c51ce422c25 --- /dev/null +++ b/source/blender/editors/asset/ED_asset_handle.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/** \file + * \ingroup edasset + */ + +#pragma once + +#include "DNA_ID_enums.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct AssetHandle; +struct AssetLibraryReference; +struct bContext; + +const char *ED_asset_handle_get_name(const struct AssetHandle *asset); +struct AssetMetaData *ED_asset_handle_get_metadata(const struct AssetHandle *asset); +struct ID *ED_asset_handle_get_local_id(const struct AssetHandle *asset); +ID_Type ED_asset_handle_get_id_type(const struct AssetHandle *asset); +int ED_asset_handle_get_preview_icon_id(const struct AssetHandle *asset); +void ED_asset_handle_get_full_library_path(const struct bContext *C, + const struct AssetLibraryReference *asset_library, + const struct AssetHandle *asset, + char r_full_lib_path[]); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/asset/ED_asset_library.h b/source/blender/editors/asset/ED_asset_library.h new file mode 100644 index 00000000000..905d097d223 --- /dev/null +++ b/source/blender/editors/asset/ED_asset_library.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +/** \file + * \ingroup edasset + */ + +#pragma once + +#include "DNA_asset_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library); +AssetLibraryReference ED_asset_library_reference_from_enum_value(int value); +const struct EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(void); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h new file mode 100644 index 00000000000..1e7f0f0de55 --- /dev/null +++ b/source/blender/editors/asset/ED_asset_list.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +/** \file + * \ingroup edasset + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +struct AssetFilterSettings; +struct AssetHandle; +struct AssetLibraryReference; +struct bContext; +struct ID; +struct wmNotifier; + +void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference, + const struct AssetFilterSettings *filter_settings, + const struct bContext *C); +void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference, + struct bContext *C); +void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C); +bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference); +void ED_assetlist_storage_tag_main_data_dirty(void); +void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new); +void ED_assetlist_storage_exit(void); + +struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle); +const char *ED_assetlist_library_path(const struct AssetLibraryReference *library_reference); + +bool ED_assetlist_listen(const struct AssetLibraryReference *library_reference, + const struct wmNotifier *notifier); +int ED_assetlist_size(const struct AssetLibraryReference *library_reference); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/asset/ED_asset_list.hh b/source/blender/editors/asset/ED_asset_list.hh new file mode 100644 index 00000000000..7f41fba3457 --- /dev/null +++ b/source/blender/editors/asset/ED_asset_list.hh @@ -0,0 +1,38 @@ +/* + * 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. + */ + +/** \file + * \ingroup edasset + */ + +#pragma once + +#include <string> + +#include "BLI_function_ref.hh" + +struct AssetLibraryReference; +struct AssetHandle; +struct bContext; +struct FileDirEntry; + +std::string ED_assetlist_asset_filepath_get(const bContext *C, + const AssetLibraryReference &library_reference, + const AssetHandle &asset_handle); + +/* Can return false to stop iterating. */ +using AssetListIterFn = blender::FunctionRef<bool(FileDirEntry &)>; +void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn); diff --git a/source/blender/editors/asset/ED_asset_mark_clear.h b/source/blender/editors/asset/ED_asset_mark_clear.h new file mode 100644 index 00000000000..cdd1f0d080b --- /dev/null +++ b/source/blender/editors/asset/ED_asset_mark_clear.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +/** \file + * \ingroup edasset + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +struct bContext; +struct ID; + +bool ED_asset_mark_id(const struct bContext *C, struct ID *id); +bool ED_asset_clear_id(struct ID *id); + +bool ED_asset_can_mark_single_from_context(const struct bContext *C); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/asset/ED_asset_temp_id_consumer.h b/source/blender/editors/asset/ED_asset_temp_id_consumer.h new file mode 100644 index 00000000000..8aa53f9ea3b --- /dev/null +++ b/source/blender/editors/asset/ED_asset_temp_id_consumer.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +/** \file + * \ingroup edasset + */ + +#pragma once + +#include "DNA_ID_enums.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct AssetTempIDConsumer AssetTempIDConsumer; + +struct AssetHandle; +struct AssetLibraryReference; +struct bContext; +struct Main; +struct ReportList; + +AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const struct AssetHandle *handle); +void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer); +struct ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer, + const struct bContext *C, + const struct AssetLibraryReference *asset_library, + ID_Type id_type, + struct Main *bmain, + struct ReportList *reports); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/asset/asset_edit.cc b/source/blender/editors/asset/asset_edit.cc deleted file mode 100644 index f4860737193..00000000000 --- a/source/blender/editors/asset/asset_edit.cc +++ /dev/null @@ -1,155 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup edasset - */ - -#include <memory> -#include <string> - -#include "BKE_asset.h" -#include "BKE_context.h" -#include "BKE_lib_id.h" - -#include "BLO_readfile.h" - -#include "DNA_ID.h" -#include "DNA_asset_types.h" -#include "DNA_space_types.h" - -#include "UI_interface_icons.h" - -#include "RNA_access.h" - -#include "ED_asset.h" - -using namespace blender; - -bool ED_asset_mark_id(const bContext *C, ID *id) -{ - if (id->asset_data) { - return false; - } - if (!BKE_id_can_be_asset(id)) { - return false; - } - - id_fake_user_set(id); - - id->asset_data = BKE_asset_metadata_create(); - - UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true); - - /* Important for asset storage to update properly! */ - ED_assetlist_storage_tag_main_data_dirty(); - - return true; -} - -bool ED_asset_clear_id(ID *id) -{ - if (!id->asset_data) { - return false; - } - BKE_asset_metadata_free(&id->asset_data); - /* Don't clear fake user here, there's no guarantee that it was actually set by - * #ED_asset_mark_id(), it might have been something/someone else. */ - - /* Important for asset storage to update properly! */ - ED_assetlist_storage_tag_main_data_dirty(); - - return true; -} - -bool ED_asset_can_make_single_from_context(const bContext *C) -{ - /* Context needs a "id" pointer to be set for #ASSET_OT_mark()/#ASSET_OT_clear() to use. */ - return CTX_data_pointer_get_type_silent(C, "id", &RNA_ID).data != nullptr; -} - -/* TODO better place? */ -/* TODO What about the setter and the `itemf` callback? */ -#include "BKE_preferences.h" -#include "DNA_asset_types.h" -#include "DNA_userdef_types.h" -int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library) -{ - /* Simple case: Predefined repository, just set the value. */ - if (library->type < ASSET_LIBRARY_CUSTOM) { - return library->type; - } - - /* Note that the path isn't checked for validity here. If an invalid library path is used, the - * Asset Browser can give a nice hint on what's wrong. */ - const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index( - &U, library->custom_library_index); - if (user_library) { - return ASSET_LIBRARY_CUSTOM + library->custom_library_index; - } - - BLI_assert(0); - return ASSET_LIBRARY_LOCAL; -} - -AssetLibraryReference ED_asset_library_reference_from_enum_value(int value) -{ - AssetLibraryReference library; - - /* Simple case: Predefined repository, just set the value. */ - if (value < ASSET_LIBRARY_CUSTOM) { - library.type = value; - library.custom_library_index = -1; - BLI_assert(ELEM(value, ASSET_LIBRARY_LOCAL)); - return library; - } - - const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index( - &U, value - ASSET_LIBRARY_CUSTOM); - - /* Note that the path isn't checked for validity here. If an invalid library path is used, the - * Asset Browser can give a nice hint on what's wrong. */ - const bool is_valid = (user_library->name[0] && user_library->path[0]); - if (!user_library) { - library.type = ASSET_LIBRARY_LOCAL; - library.custom_library_index = -1; - } - else if (user_library && is_valid) { - library.custom_library_index = value - ASSET_LIBRARY_CUSTOM; - library.type = ASSET_LIBRARY_CUSTOM; - } - return library; -} - -const char *ED_asset_handle_get_name(const AssetHandle *asset) -{ - return asset->file_data->name; -} - -void ED_asset_handle_get_full_library_path(const bContext *C, - const AssetLibraryReference *asset_library, - const AssetHandle *asset, - char r_full_lib_path[FILE_MAX_LIBEXTRA]) -{ - *r_full_lib_path = '\0'; - - std::string asset_path = ED_assetlist_asset_filepath_get(C, *asset_library, *asset); - if (asset_path.empty()) { - return; - } - - BLO_library_path_explode(asset_path.c_str(), r_full_lib_path, nullptr, nullptr); -} diff --git a/source/blender/editors/asset/intern/asset_handle.cc b/source/blender/editors/asset/intern/asset_handle.cc new file mode 100644 index 00000000000..aae85e61372 --- /dev/null +++ b/source/blender/editors/asset/intern/asset_handle.cc @@ -0,0 +1,75 @@ +/* + * 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. + */ + +/** \file + * \ingroup edasset + * + * Asset-handle is a temporary design, not part of the core asset system design. + * + * Currently asset-list items are just file directory items (#FileDirEntry). So an asset-handle is + * just wraps a pointer to this. We try to abstract away the fact that it's just a file entry, + * although that doesn't always work (see #rna_def_asset_handle()). + */ + +#include <string> + +#include "DNA_asset_types.h" +#include "DNA_space_types.h" + +#include "BLO_readfile.h" + +#include "ED_asset_handle.h" +#include "ED_asset_list.hh" + +const char *ED_asset_handle_get_name(const AssetHandle *asset) +{ + return asset->file_data->name; +} + +AssetMetaData *ED_asset_handle_get_metadata(const AssetHandle *asset) +{ + return asset->file_data->asset_data; +} + +ID *ED_asset_handle_get_local_id(const AssetHandle *asset) +{ + return asset->file_data->id; +} + +ID_Type ED_asset_handle_get_id_type(const AssetHandle *asset) +{ + return static_cast<ID_Type>(asset->file_data->blentype); +} + +int ED_asset_handle_get_preview_icon_id(const AssetHandle *asset) +{ + return asset->file_data->preview_icon_id; +} + +void ED_asset_handle_get_full_library_path(const bContext *C, + const AssetLibraryReference *asset_library, + const AssetHandle *asset, + char r_full_lib_path[FILE_MAX_LIBEXTRA]) +{ + *r_full_lib_path = '\0'; + + std::string asset_path = ED_assetlist_asset_filepath_get(C, *asset_library, *asset); + if (asset_path.empty()) { + return; + } + + BLO_library_path_explode(asset_path.c_str(), r_full_lib_path, nullptr, nullptr); +} diff --git a/source/blender/editors/asset/intern/asset_library_reference.cc b/source/blender/editors/asset/intern/asset_library_reference.cc new file mode 100644 index 00000000000..df1d58df5f9 --- /dev/null +++ b/source/blender/editors/asset/intern/asset_library_reference.cc @@ -0,0 +1,50 @@ +/* + * 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. + */ + +/** \file + * \ingroup edasset + */ + +#include "BLI_hash.hh" + +#include "asset_library_reference.hh" + +namespace blender::ed::asset { + +AssetLibraryReferenceWrapper::AssetLibraryReferenceWrapper(const AssetLibraryReference &reference) + : AssetLibraryReference(reference) +{ +} + +bool operator==(const AssetLibraryReferenceWrapper &a, const AssetLibraryReferenceWrapper &b) +{ + return (a.type == b.type) && (a.type == ASSET_LIBRARY_CUSTOM) ? + (a.custom_library_index == b.custom_library_index) : + true; +} + +uint64_t AssetLibraryReferenceWrapper::hash() const +{ + uint64_t hash1 = DefaultHash<decltype(type)>{}(type); + if (type != ASSET_LIBRARY_CUSTOM) { + return hash1; + } + + uint64_t hash2 = DefaultHash<decltype(custom_library_index)>{}(custom_library_index); + return hash1 ^ (hash2 * 33); /* Copied from DefaultHash for std::pair. */ +} + +} // namespace blender::ed::asset diff --git a/source/blender/editors/asset/intern/asset_library_reference.hh b/source/blender/editors/asset/intern/asset_library_reference.hh new file mode 100644 index 00000000000..7e8cb4a3472 --- /dev/null +++ b/source/blender/editors/asset/intern/asset_library_reference.hh @@ -0,0 +1,46 @@ +/* + * 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. + */ + +/** \file + * \ingroup edasset + * + * Utility to extend #AssetLibraryReference with C++ functionality (operators, hash function, etc). + */ + +#pragma once + +#include <cstdint> + +#include "DNA_asset_types.h" + +namespace blender::ed::asset { + +/** + * Wrapper to add logic to the AssetLibraryReference DNA struct. + */ +class AssetLibraryReferenceWrapper : public AssetLibraryReference { + public: + /* Intentionally not `explicit`, allow implicit conversion for convenience. Might have to be + * NOLINT */ + AssetLibraryReferenceWrapper(const AssetLibraryReference &reference); + ~AssetLibraryReferenceWrapper() = default; + + friend bool operator==(const AssetLibraryReferenceWrapper &a, + const AssetLibraryReferenceWrapper &b); + uint64_t hash() const; +}; + +} // namespace blender::ed::asset diff --git a/source/blender/editors/asset/intern/asset_library_reference_enum.cc b/source/blender/editors/asset/intern/asset_library_reference_enum.cc new file mode 100644 index 00000000000..13595ffa6ba --- /dev/null +++ b/source/blender/editors/asset/intern/asset_library_reference_enum.cc @@ -0,0 +1,156 @@ +/* + * 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. + */ + +/** \file + * \ingroup edasset + * + * Helpers to convert asset library references from and to enum values and RNA enums. + * In some cases it's simply not possible to reference an asset library with + * #AssetLibraryReferences. This API guarantees a safe translation to indices/enum values for as + * long as there is no change in the order of registered custom asset libraries. + */ + +#include "BLI_listbase.h" + +#include "BKE_preferences.h" + +#include "DNA_asset_types.h" +#include "DNA_userdef_types.h" + +#include "UI_resources.h" + +#include "RNA_define.h" + +#include "ED_asset_library.h" + +/** + * Return an index that can be used to uniquely identify \a library, assuming + * that all relevant indices were created with this function. + */ +int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library) +{ + /* Simple case: Predefined repository, just set the value. */ + if (library->type < ASSET_LIBRARY_CUSTOM) { + return library->type; + } + + /* Note that the path isn't checked for validity here. If an invalid library path is used, the + * Asset Browser can give a nice hint on what's wrong. */ + const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index( + &U, library->custom_library_index); + if (user_library) { + return ASSET_LIBRARY_CUSTOM + library->custom_library_index; + } + + BLI_assert_unreachable(); + return ASSET_LIBRARY_LOCAL; +} + +/** + * Return an asset library reference matching the index returned by + * #ED_asset_library_reference_to_enum_value(). + */ +AssetLibraryReference ED_asset_library_reference_from_enum_value(int value) +{ + AssetLibraryReference library; + + /* Simple case: Predefined repository, just set the value. */ + if (value < ASSET_LIBRARY_CUSTOM) { + library.type = value; + library.custom_library_index = -1; + BLI_assert(ELEM(value, ASSET_LIBRARY_LOCAL)); + return library; + } + + const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index( + &U, value - ASSET_LIBRARY_CUSTOM); + + /* Note that there is no check if the path exists here. If an invalid library path is used, the + * Asset Browser can give a nice hint on what's wrong. */ + const bool is_valid = (user_library->name[0] && user_library->path[0]); + if (!user_library) { + library.type = ASSET_LIBRARY_LOCAL; + library.custom_library_index = -1; + } + else if (user_library && is_valid) { + library.custom_library_index = value - ASSET_LIBRARY_CUSTOM; + library.type = ASSET_LIBRARY_CUSTOM; + } + return library; +} + +/** + * Translate all available asset libraries to an RNA enum, whereby the enum values match the result + * of #ED_asset_library_reference_to_enum_value() for any given library. + * + * Since this is meant for UI display, skips non-displayable libraries, that is, libraries with an + * empty name or path. + */ +const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf() +{ + const EnumPropertyItem predefined_items[] = { + /* For the future. */ + // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"}, + {ASSET_LIBRARY_LOCAL, + "LOCAL", + ICON_BLENDER, + "Current File", + "Show the assets currently available in this Blender session"}, + {0, NULL, 0, NULL, NULL}, + }; + + EnumPropertyItem *item = NULL; + int totitem = 0; + + /* Add separator if needed. */ + if (!BLI_listbase_is_empty(&U.asset_libraries)) { + const EnumPropertyItem sepr = {0, "", 0, "Custom", NULL}; + RNA_enum_item_add(&item, &totitem, &sepr); + } + + int i = 0; + for (bUserAssetLibrary *user_library = (bUserAssetLibrary *)U.asset_libraries.first; + user_library; + user_library = user_library->next, i++) { + /* Note that the path itself isn't checked for validity here. If an invalid library path is + * used, the Asset Browser can give a nice hint on what's wrong. */ + const bool is_valid = (user_library->name[0] && user_library->path[0]); + if (!is_valid) { + continue; + } + + AssetLibraryReference library_reference; + library_reference.type = ASSET_LIBRARY_CUSTOM; + library_reference.custom_library_index = i; + + const int enum_value = ED_asset_library_reference_to_enum_value(&library_reference); + /* Use library path as description, it's a nice hint for users. */ + EnumPropertyItem tmp = { + enum_value, user_library->name, ICON_NONE, user_library->name, user_library->path}; + RNA_enum_item_add(&item, &totitem, &tmp); + } + + if (totitem) { + const EnumPropertyItem sepr = {0, "", 0, "Built-in", NULL}; + RNA_enum_item_add(&item, &totitem, &sepr); + } + + /* Add predefined items. */ + RNA_enum_items_add(&item, &totitem, predefined_items); + + RNA_enum_item_end(&item, &totitem); + return item; +} diff --git a/source/blender/editors/asset/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index dd1c5f360a0..445269d563e 100644 --- a/source/blender/editors/asset/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -26,12 +26,8 @@ #include <optional> #include <string> -#include "BKE_asset.h" #include "BKE_context.h" -#include "BKE_screen.h" -#include "BLI_function_ref.hh" -#include "BLI_hash.hh" #include "BLI_map.hh" #include "BLI_path_util.h" #include "BLI_utility_mixins.hh" @@ -41,9 +37,7 @@ #include "BKE_preferences.h" -#include "ED_asset.h" #include "ED_fileselect.h" -#include "ED_screen.h" #include "WM_api.h" #include "WM_types.h" @@ -51,48 +45,12 @@ /* XXX uses private header of file-space. */ #include "../space_file/filelist.h" -using namespace blender; +#include "ED_asset_handle.h" +#include "ED_asset_list.h" +#include "ED_asset_list.hh" +#include "asset_library_reference.hh" -/** - * Wrapper to add logic to the AssetLibraryReference DNA struct. - */ -class AssetLibraryReferenceWrapper { - const AssetLibraryReference reference_; - - public: - /* Intentionally not `explicit`, allow implicit conversion for convenience. Might have to be - * NOLINT */ - AssetLibraryReferenceWrapper(const AssetLibraryReference &reference); - ~AssetLibraryReferenceWrapper() = default; - - friend bool operator==(const AssetLibraryReferenceWrapper &a, - const AssetLibraryReferenceWrapper &b); - uint64_t hash() const; -}; - -AssetLibraryReferenceWrapper::AssetLibraryReferenceWrapper(const AssetLibraryReference &reference) - : reference_(reference) -{ -} - -bool operator==(const AssetLibraryReferenceWrapper &a, const AssetLibraryReferenceWrapper &b) -{ - return (a.reference_.type == b.reference_.type) && (a.reference_.type == ASSET_LIBRARY_CUSTOM) ? - (a.reference_.custom_library_index == b.reference_.custom_library_index) : - true; -} - -uint64_t AssetLibraryReferenceWrapper::hash() const -{ - uint64_t hash1 = DefaultHash<decltype(reference_.type)>{}(reference_.type); - if (reference_.type != ASSET_LIBRARY_CUSTOM) { - return hash1; - } - - uint64_t hash2 = DefaultHash<decltype(reference_.custom_library_index)>{}( - reference_.custom_library_index); - return hash1 ^ (hash2 * 33); /* Copied from DefaultHash for std::pair. */ -} +namespace blender::ed::asset { /* -------------------------------------------------------------------- */ /** \name Asset list API @@ -187,11 +145,6 @@ void AssetList::setup(const AssetFilterSettings *filter_settings) { FileList *files = filelist_; - /* TODO there should only be one (FileSelectAssetLibraryUID vs. AssetLibraryReference). */ - FileSelectAssetLibraryUID file_asset_lib_ref; - file_asset_lib_ref.type = library_ref_.type; - file_asset_lib_ref.custom_library_index = library_ref_.custom_library_index; - bUserAssetLibrary *user_library = nullptr; /* Ensure valid repository, or fall-back to local one. */ @@ -206,7 +159,7 @@ void AssetList::setup(const AssetFilterSettings *filter_settings) /* TODO pass options properly. */ filelist_setrecursion(files, 1); filelist_setsorting(files, FILE_SORT_ALPHA, false); - filelist_setlibrary(files, &file_asset_lib_ref); + filelist_setlibrary(files, &library_ref_); /* TODO different filtering settings require the list to be reread. That's a no-go for when we * want to allow showing the same asset library with different filter settings (as in, * different ID types). The filelist needs to be made smarter somehow, maybe goes together with @@ -469,10 +422,14 @@ AssetListStorage::AssetListMap &AssetListStorage::global_storage() /** \} */ +} // namespace blender::ed::asset + /* -------------------------------------------------------------------- */ /** \name C-API * \{ */ +using namespace blender::ed::asset; + /** * Invoke asset list reading, potentially in a parallel job. Won't wait until the job is done, * and may return earlier. @@ -506,7 +463,6 @@ bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *libr return AssetListStorage::lookup_list(*library_reference) != nullptr; } -/* TODO expose AssetList with an iterator? */ void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn) { AssetList *list = AssetListStorage::lookup_list(*library_reference); @@ -536,11 +492,12 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C, const AssetLibraryReference &library_reference, const AssetHandle &asset_handle) { - if (asset_handle.file_data->id || !asset_handle.file_data->asset_data) { + if (ED_asset_handle_get_local_id(&asset_handle) || + !ED_asset_handle_get_metadata(&asset_handle)) { return {}; } const char *library_path = ED_assetlist_library_path(&library_reference); - if (!library_path) { + if (!library_path && C) { library_path = assetlist_library_path_from_sfile_get_hack(C); } if (!library_path) { @@ -554,11 +511,6 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C, return path; } -ID *ED_assetlist_asset_local_id_get(const AssetHandle *asset_handle) -{ - return asset_handle->file_data->asset_data ? asset_handle->file_data->id : nullptr; -} - ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle) { ImBuf *imbuf = filelist_file_getimage(asset_handle->file_data); diff --git a/source/blender/editors/asset/intern/asset_mark_clear.cc b/source/blender/editors/asset/intern/asset_mark_clear.cc new file mode 100644 index 00000000000..ba348e38823 --- /dev/null +++ b/source/blender/editors/asset/intern/asset_mark_clear.cc @@ -0,0 +1,83 @@ +/* + * 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. + */ + +/** \file + * \ingroup edasset + * + * Functions for marking and clearing assets. + */ + +#include <memory> +#include <string> + +#include "BKE_asset.h" +#include "BKE_context.h" +#include "BKE_lib_id.h" + +#include "BLO_readfile.h" + +#include "DNA_ID.h" +#include "DNA_asset_types.h" +#include "DNA_space_types.h" + +#include "UI_interface_icons.h" + +#include "RNA_access.h" + +#include "ED_asset_list.h" +#include "ED_asset_mark_clear.h" + +bool ED_asset_mark_id(const bContext *C, ID *id) +{ + if (id->asset_data) { + return false; + } + if (!BKE_id_can_be_asset(id)) { + return false; + } + + id_fake_user_set(id); + + id->asset_data = BKE_asset_metadata_create(); + + UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true); + + /* Important for asset storage to update properly! */ + ED_assetlist_storage_tag_main_data_dirty(); + + return true; +} + +bool ED_asset_clear_id(ID *id) +{ + if (!id->asset_data) { + return false; + } + BKE_asset_metadata_free(&id->asset_data); + /* Don't clear fake user here, there's no guarantee that it was actually set by + * #ED_asset_mark_id(), it might have been something/someone else. */ + + /* Important for asset storage to update properly! */ + ED_assetlist_storage_tag_main_data_dirty(); + + return true; +} + +bool ED_asset_can_mark_single_from_context(const bContext *C) +{ + /* Context needs a "id" pointer to be set for #ASSET_OT_mark()/#ASSET_OT_clear() to use. */ + return CTX_data_pointer_get_type_silent(C, "id", &RNA_ID).data != nullptr; +} diff --git a/source/blender/editors/asset/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc index 79edd1f8a6a..79edd1f8a6a 100644 --- a/source/blender/editors/asset/asset_ops.cc +++ b/source/blender/editors/asset/intern/asset_ops.cc diff --git a/source/blender/editors/asset/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc index 24e1fc86fef..bed35fdeeb5 100644 --- a/source/blender/editors/asset/asset_temp_id_consumer.cc +++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc @@ -21,6 +21,8 @@ * Uses the `BLO_library_temp_xxx()` API internally. */ +#include <new> + #include "DNA_asset_types.h" #include "DNA_space_types.h" @@ -32,7 +34,8 @@ #include "MEM_guardedalloc.h" -#include "ED_asset.h" +#include "ED_asset_handle.h" +#include "ED_asset_temp_id_consumer.h" using namespace blender; @@ -53,7 +56,7 @@ class AssetTemporaryIDConsumer : NonCopyable, NonMovable { ID *get_local_id() { - return ED_assetlist_asset_local_id_get(&handle_); + return ED_asset_handle_get_local_id(&handle_); } ID *import_id(const bContext *C, diff --git a/source/blender/editors/geometry/geometry_attributes.c b/source/blender/editors/geometry/geometry_attributes.c index 9b034d82a51..5cb491f116a 100644 --- a/source/blender/editors/geometry/geometry_attributes.c +++ b/source/blender/editors/geometry/geometry_attributes.c @@ -47,6 +47,21 @@ static bool geometry_attributes_poll(bContext *C) BKE_id_attributes_supported(data); } +static bool geometry_attributes_remove_poll(bContext *C) +{ + if (!geometry_attributes_poll(C)) { + return false; + } + + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + if (BKE_id_attributes_active_get(data) != NULL) { + return true; + } + + return false; +} + static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), @@ -160,7 +175,7 @@ void GEOMETRY_OT_attribute_remove(wmOperatorType *ot) /* api callbacks */ ot->exec = geometry_attribute_remove_exec; - ot->poll = geometry_attributes_poll; + ot->poll = geometry_attributes_remove_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 78eaab01b1a..cf49aefe2ea 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -1316,8 +1316,7 @@ static void gpencil_primitive_interaction_end(bContext *C, BrushGpencilSettings *brush_settings = brush->gpencil_settings; const int def_nr = tgpi->gpd->vertex_group_active_index - 1; - const ListBase *defbase = BKE_object_defgroup_list(tgpi->ob); - const bool have_weight = (bool)BLI_findlink(defbase, def_nr); + const bool have_weight = BLI_findlink(&tgpi->gpd->vertex_group_names, def_nr) != NULL; /* return to normal cursor and header status */ ED_workspace_status_text(C, NULL); diff --git a/source/blender/editors/include/ED_asset.h b/source/blender/editors/include/ED_asset.h index 0058c0615c3..42faf716560 100644 --- a/source/blender/editors/include/ED_asset.h +++ b/source/blender/editors/include/ED_asset.h @@ -16,66 +16,19 @@ /** \file * \ingroup editors + * + * The public API for assets is defined in dedicated headers. This is a utility file that just + * includes all of these. */ #pragma once -#include "DNA_ID_enums.h" - #ifdef __cplusplus extern "C" { #endif -struct AssetFilterSettings; -struct AssetLibraryReference; -struct Main; -struct ReportList; -struct bContext; -struct wmNotifier; - -typedef struct AssetTempIDConsumer AssetTempIDConsumer; - -bool ED_asset_mark_id(const struct bContext *C, struct ID *id); -bool ED_asset_clear_id(struct ID *id); - -bool ED_asset_can_make_single_from_context(const struct bContext *C); - -int ED_asset_library_reference_to_enum_value(const struct AssetLibraryReference *library); -struct AssetLibraryReference ED_asset_library_reference_from_enum_value(int value); - -const char *ED_asset_handle_get_name(const AssetHandle *asset); -void ED_asset_handle_get_full_library_path(const struct bContext *C, - const AssetLibraryReference *asset_library, - const AssetHandle *asset, - char r_full_lib_path[]); - -AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle); -void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer); -struct ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer, - const struct bContext *C, - const AssetLibraryReference *asset_library, - ID_Type id_type, - struct Main *bmain, - struct ReportList *reports); - -void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference, - const struct AssetFilterSettings *filter_settings, - const struct bContext *C); -void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference, - struct bContext *C); -void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C); -bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference); -void ED_assetlist_storage_tag_main_data_dirty(void); -void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new); -void ED_assetlist_storage_exit(void); - -ID *ED_assetlist_asset_local_id_get(const AssetHandle *asset_handle); -struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle); -const char *ED_assetlist_library_path(const struct AssetLibraryReference *library_reference); - -bool ED_assetlist_listen(const struct AssetLibraryReference *library_reference, - const struct wmNotifier *notifier); -int ED_assetlist_size(const struct AssetLibraryReference *library_reference); +/* Barely anything here. Just general editor level functions. Actual asset level code is in + * dedicated headers. */ void ED_operatortypes_asset(void); @@ -83,17 +36,13 @@ void ED_operatortypes_asset(void); } #endif -/* TODO move to C++ asset-list header? */ -#ifdef __cplusplus +#include "../asset/ED_asset_handle.h" +#include "../asset/ED_asset_library.h" +#include "../asset/ED_asset_list.h" +#include "../asset/ED_asset_mark_clear.h" +#include "../asset/ED_asset_temp_id_consumer.h" -# include <string> - -std::string ED_assetlist_asset_filepath_get(const bContext *C, - const AssetLibraryReference &library_reference, - const AssetHandle &asset_handle); - -# include "BLI_function_ref.hh" -/* Can return false to stop iterating. */ -using AssetListIterFn = blender::FunctionRef<bool(FileDirEntry &)>; -void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn); +/* C++ only headers. */ +#ifdef __cplusplus +# include "../asset/ED_asset_list.hh" #endif diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h index 2f8faf1b2bd..d2d22dd38dc 100644 --- a/source/blender/editors/include/ED_keyframes_draw.h +++ b/source/blender/editors/include/ED_keyframes_draw.h @@ -28,10 +28,7 @@ extern "C" { #endif struct AnimData; -struct CacheFile; -struct DLRBT_Tree; struct FCurve; -struct ListBase; struct MaskLayer; struct Object; struct Scene; @@ -42,99 +39,6 @@ struct bAnimContext; struct bDopeSheet; struct bGPDlayer; -/* ****************************** Base Structs ****************************** */ - -/* Information about the stretch of time from current to the next column */ -typedef struct ActKeyBlockInfo { - /* Combination of flags from all curves. */ - short flag; - /* Mask of flags that differ between curves. */ - short conflict; - - /* Selection flag. */ - char sel; -} ActKeyBlockInfo; - -/* Keyframe Column Struct */ -typedef struct ActKeyColumn { - /* ListBase linkage */ - struct ActKeyColumn *next, *prev; - - /* sorting-tree linkage */ - /** 'children' of this node, less than and greater than it (respectively) */ - struct ActKeyColumn *left, *right; - /** parent of this node in the tree */ - struct ActKeyColumn *parent; - /** DLRB_BLACK or DLRB_RED */ - char tree_col; - - /* keyframe info */ - /** eBezTripe_KeyframeType */ - char key_type; - /** eKeyframeHandleDrawOpts */ - char handle_type; - /** eKeyframeExtremeDrawOpts */ - char extreme_type; - short sel; - float cfra; - - /* key-block info */ - ActKeyBlockInfo block; - - /* number of curves and keys in this column */ - short totcurve, totkey, totblock; -} ActKeyColumn; - -/* ActKeyBlockInfo - Flag */ -typedef enum eActKeyBlock_Hold { - /* Key block represents a moving hold */ - ACTKEYBLOCK_FLAG_MOVING_HOLD = (1 << 0), - /* Key block represents a static hold */ - ACTKEYBLOCK_FLAG_STATIC_HOLD = (1 << 1), - /* Key block represents any kind of hold */ - ACTKEYBLOCK_FLAG_ANY_HOLD = (1 << 2), - /* The curve segment uses non-bezier interpolation */ - ACTKEYBLOCK_FLAG_NON_BEZIER = (1 << 3), - /* The block is grease pencil */ - ACTKEYBLOCK_FLAG_GPENCIL = (1 << 4), -} eActKeyBlock_Flag; - -/* *********************** Keyframe Drawing ****************************** */ - -/* options for keyframe shape drawing */ -typedef enum eKeyframeShapeDrawOpts { - /* only the border */ - KEYFRAME_SHAPE_FRAME = 0, - /* only the inside filling */ - KEYFRAME_SHAPE_INSIDE, - /* the whole thing */ - KEYFRAME_SHAPE_BOTH, -} eKeyframeShapeDrawOpts; - -/* Handle type. */ -typedef enum eKeyframeHandleDrawOpts { - /* Don't draw */ - KEYFRAME_HANDLE_NONE = 0, - /* Various marks in order of increasing display priority. */ - KEYFRAME_HANDLE_AUTO_CLAMP, - KEYFRAME_HANDLE_AUTO, - KEYFRAME_HANDLE_VECTOR, - KEYFRAME_HANDLE_ALIGNED, - KEYFRAME_HANDLE_FREE, -} eKeyframeHandleDrawOpts; - -/* Extreme type. */ -typedef enum eKeyframeExtremeDrawOpts { - KEYFRAME_EXTREME_NONE = 0, - /* Minimum/maximum present. */ - KEYFRAME_EXTREME_MIN = (1 << 0), - KEYFRAME_EXTREME_MAX = (1 << 1), - /* Grouped keys have different states. */ - KEYFRAME_EXTREME_MIXED = (1 << 2), - /* Both neighbors are equal to this key. */ - KEYFRAME_EXTREME_FLAT = (1 << 3), -} eKeyframeExtremeDrawOpts; - /* draw simple diamond-shape keyframe */ /* caller should set up vertex format, bind GPU_SHADER_KEYFRAME_DIAMOND, * immBegin(GPU_PRIM_POINTS, n), then call this n times */ @@ -216,59 +120,6 @@ void draw_masklay_channel(struct View2D *v2d, float yscale_fac, int saction_flag); -/* Keydata Generation --------------- */ -/* F-Curve */ -void fcurve_to_keylist(struct AnimData *adt, - struct FCurve *fcu, - struct DLRBT_Tree *keys, - int saction_flag); -/* Action Group */ -void agroup_to_keylist(struct AnimData *adt, - struct bActionGroup *agrp, - struct DLRBT_Tree *keys, - int saction_flag); -/* Action */ -void action_to_keylist(struct AnimData *adt, - struct bAction *act, - struct DLRBT_Tree *keys, - int saction_flag); -/* Object */ -void ob_to_keylist(struct bDopeSheet *ads, - struct Object *ob, - struct DLRBT_Tree *keys, - int saction_flag); -/* Cache File */ -void cachefile_to_keylist(struct bDopeSheet *ads, - struct CacheFile *cache_file, - struct DLRBT_Tree *keys, - int saction_flag); -/* Scene */ -void scene_to_keylist(struct bDopeSheet *ads, - struct Scene *sce, - struct DLRBT_Tree *keys, - int saction_flag); -/* DopeSheet Summary */ -void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, int saction_flag); -/* Grease Pencil datablock summary */ -void gpencil_to_keylist(struct bDopeSheet *ads, - struct bGPdata *gpd, - struct DLRBT_Tree *keys, - const bool active); -/* Grease Pencil Layer */ -void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys); -/* Mask */ -void mask_to_keylist(struct bDopeSheet *ads, struct MaskLayer *masklay, struct DLRBT_Tree *keys); - -/* ActKeyColumn API ---------------- */ -/* Comparator callback used for ActKeyColumns and cframe float-value pointer */ -short compare_ak_cfraPtr(void *node, void *data); - -/* Checks if ActKeyColumn has any block data */ -bool actkeyblock_is_valid(ActKeyColumn *ac); - -/* Checks if ActKeyColumn can be used as a block (i.e. drawn/used to detect "holds") */ -int actkeyblock_get_valid_hold(ActKeyColumn *ac); - #ifdef __cplusplus } #endif diff --git a/source/blender/editors/include/ED_keyframes_keylist.h b/source/blender/editors/include/ED_keyframes_keylist.h new file mode 100644 index 00000000000..be3eac66771 --- /dev/null +++ b/source/blender/editors/include/ED_keyframes_keylist.h @@ -0,0 +1,192 @@ +/* + * 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) (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + */ + +/** \file + * \ingroup editors + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +struct AnimData; +struct CacheFile; +struct DLRBT_Tree; +struct FCurve; +struct MaskLayer; +struct Object; +struct Scene; +struct bAnimContext; +struct bDopeSheet; +struct bGPDlayer; + +/* ****************************** Base Structs ****************************** */ + +/* Information about the stretch of time from current to the next column */ +typedef struct ActKeyBlockInfo { + /* Combination of flags from all curves. */ + short flag; + /* Mask of flags that differ between curves. */ + short conflict; + + /* Selection flag. */ + char sel; +} ActKeyBlockInfo; + +/* Keyframe Column Struct */ +typedef struct ActKeyColumn { + /* ListBase linkage */ + struct ActKeyColumn *next, *prev; + + /* sorting-tree linkage */ + /** 'children' of this node, less than and greater than it (respectively) */ + struct ActKeyColumn *left, *right; + /** parent of this node in the tree */ + struct ActKeyColumn *parent; + /** DLRB_BLACK or DLRB_RED */ + char tree_col; + + /* keyframe info */ + /** eBezTripe_KeyframeType */ + char key_type; + /** eKeyframeHandleDrawOpts */ + char handle_type; + /** eKeyframeExtremeDrawOpts */ + char extreme_type; + short sel; + float cfra; + + /* key-block info */ + ActKeyBlockInfo block; + + /* number of curves and keys in this column */ + short totcurve, totkey, totblock; +} ActKeyColumn; + +/* ActKeyBlockInfo - Flag */ +typedef enum eActKeyBlock_Hold { + /* Key block represents a moving hold */ + ACTKEYBLOCK_FLAG_MOVING_HOLD = (1 << 0), + /* Key block represents a static hold */ + ACTKEYBLOCK_FLAG_STATIC_HOLD = (1 << 1), + /* Key block represents any kind of hold */ + ACTKEYBLOCK_FLAG_ANY_HOLD = (1 << 2), + /* The curve segment uses non-bezier interpolation */ + ACTKEYBLOCK_FLAG_NON_BEZIER = (1 << 3), + /* The block is grease pencil */ + ACTKEYBLOCK_FLAG_GPENCIL = (1 << 4), +} eActKeyBlock_Flag; + +/* *********************** Keyframe Drawing ****************************** */ + +/* options for keyframe shape drawing */ +typedef enum eKeyframeShapeDrawOpts { + /* only the border */ + KEYFRAME_SHAPE_FRAME = 0, + /* only the inside filling */ + KEYFRAME_SHAPE_INSIDE, + /* the whole thing */ + KEYFRAME_SHAPE_BOTH, +} eKeyframeShapeDrawOpts; + +/* Handle type. */ +typedef enum eKeyframeHandleDrawOpts { + /* Don't draw */ + KEYFRAME_HANDLE_NONE = 0, + /* Various marks in order of increasing display priority. */ + KEYFRAME_HANDLE_AUTO_CLAMP, + KEYFRAME_HANDLE_AUTO, + KEYFRAME_HANDLE_VECTOR, + KEYFRAME_HANDLE_ALIGNED, + KEYFRAME_HANDLE_FREE, +} eKeyframeHandleDrawOpts; + +/* Extreme type. */ +typedef enum eKeyframeExtremeDrawOpts { + KEYFRAME_EXTREME_NONE = 0, + /* Minimum/maximum present. */ + KEYFRAME_EXTREME_MIN = (1 << 0), + KEYFRAME_EXTREME_MAX = (1 << 1), + /* Grouped keys have different states. */ + KEYFRAME_EXTREME_MIXED = (1 << 2), + /* Both neighbors are equal to this key. */ + KEYFRAME_EXTREME_FLAT = (1 << 3), +} eKeyframeExtremeDrawOpts; + +/* ******************************* Methods ****************************** */ + +/* Key-data Generation --------------- */ + +/* F-Curve */ +void fcurve_to_keylist(struct AnimData *adt, + struct FCurve *fcu, + struct DLRBT_Tree *keys, + int saction_flag); +/* Action Group */ +void agroup_to_keylist(struct AnimData *adt, + struct bActionGroup *agrp, + struct DLRBT_Tree *keys, + int saction_flag); +/* Action */ +void action_to_keylist(struct AnimData *adt, + struct bAction *act, + struct DLRBT_Tree *keys, + int saction_flag); +/* Object */ +void ob_to_keylist(struct bDopeSheet *ads, + struct Object *ob, + struct DLRBT_Tree *keys, + int saction_flag); +/* Cache File */ +void cachefile_to_keylist(struct bDopeSheet *ads, + struct CacheFile *cache_file, + struct DLRBT_Tree *keys, + int saction_flag); +/* Scene */ +void scene_to_keylist(struct bDopeSheet *ads, + struct Scene *sce, + struct DLRBT_Tree *keys, + int saction_flag); +/* DopeSheet Summary */ +void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, int saction_flag); +/* Grease Pencil datablock summary */ +void gpencil_to_keylist(struct bDopeSheet *ads, + struct bGPdata *gpd, + struct DLRBT_Tree *keys, + const bool active); +/* Grease Pencil Layer */ +void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys); +/* Mask */ +void mask_to_keylist(struct bDopeSheet *ads, struct MaskLayer *masklay, struct DLRBT_Tree *keys); + +/* ActKeyColumn API ---------------- */ +/* Comparator callback used for ActKeyColumns and cframe float-value pointer */ +short compare_ak_cfraPtr(void *node, void *data); + +/* Checks if ActKeyColumn has any block data */ +bool actkeyblock_is_valid(ActKeyColumn *ac); + +/* Checks if ActKeyColumn can be used as a block (i.e. drawn/used to detect "holds") */ +int actkeyblock_get_valid_hold(ActKeyColumn *ac); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index 0fb06639dbf..5cdcbbab42a 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -72,13 +72,12 @@ struct Scene *ED_render_job_get_current_scene(const struct bContext *C); * - PR_NODE_RENDER: preview is rendered for node editor * - PR_ICON_DEFERRED: No render, we just ensure deferred icon data gets generated. */ - -enum { +typedef enum ePreviewRenderMethod { PR_BUTS_RENDER = 0, PR_ICON_RENDER = 1, PR_NODE_RENDER = 2, PR_ICON_DEFERRED = 3, -}; +} ePreviewRenderMethod; void ED_preview_ensure_dbase(void); void ED_preview_free_dbase(void); diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index 953f26aa45f..0105af843bb 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -24,6 +24,7 @@ #pragma once #include "BLI_compiler_attrs.h" +#include "WM_types.h" #ifdef __cplusplus extern "C" { @@ -61,6 +62,24 @@ void ED_region_draw_mouse_line_cb(const struct bContext *C, void ED_region_image_metadata_draw( int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy); +/* Slider */ +struct tSlider; + +struct tSlider *ED_slider_create(struct bContext *C); +void ED_slider_init(struct tSlider *slider, const struct wmEvent *event); +bool ED_slider_modal(struct tSlider *slider, const struct wmEvent *event); +void ED_slider_destroy(struct bContext *C, struct tSlider *slider); + +void ED_slider_status_string_get(const struct tSlider *slider, + char *status_string, + const size_t size_of_status_string); + +float ED_slider_factor_get(struct tSlider *slider); +void ED_slider_factor_set(struct tSlider *slider, float factor); + +bool ED_slider_allow_overshoot_get(struct tSlider *slider); +void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value); + /* ************** XXX OLD CRUFT WARNING ************* */ void apply_keyb_grid( diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index a25aac5803c..a6e465d04e8 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -35,9 +35,11 @@ extern "C" { /* Struct Declarations */ struct ARegion; +struct AssetHandle; struct AssetFilterSettings; struct AutoComplete; struct EnumPropertyItem; +struct FileDirEntry; struct FileSelectParams; struct ID; struct IDProperty; @@ -769,9 +771,8 @@ int UI_but_return_value_get(uiBut *but); void UI_but_drag_set_id(uiBut *but, struct ID *id); void UI_but_drag_set_asset(uiBut *but, - const char *name, + const struct AssetHandle *asset, const char *path, - int id_type, int import_type, /* eFileAssetImportType */ int icon, struct ImBuf *imb, diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index ddde4f5a9dc..72e379e9b0a 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -6176,10 +6176,12 @@ void UI_but_drag_set_id(uiBut *but, ID *id) but->dragpoin = (void *)id; } +/** + * \param asset: May be passed from a temporary variable, drag data only stores a copy of this. + */ void UI_but_drag_set_asset(uiBut *but, - const char *name, + const AssetHandle *asset, const char *path, - int id_type, int import_type, int icon, struct ImBuf *imb, @@ -6187,9 +6189,10 @@ void UI_but_drag_set_asset(uiBut *but, { wmDragAsset *asset_drag = MEM_mallocN(sizeof(*asset_drag), "wmDragAsset"); - BLI_strncpy(asset_drag->name, name, sizeof(asset_drag->name)); + asset_drag->asset_handle = MEM_mallocN(sizeof(asset_drag->asset_handle), + "wmDragAsset asset handle"); + *asset_drag->asset_handle = *asset; asset_drag->path = path; - asset_drag->id_type = id_type; asset_drag->import_type = import_type; but->dragtype = WM_DRAG_ASSET; diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 3049e2bd7b8..d917534895d 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -952,7 +952,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev } /* If the button represents an id, it can set the "id" context pointer. */ - if (U.experimental.use_asset_browser && ED_asset_can_make_single_from_context(C)) { + if (U.experimental.use_asset_browser && ED_asset_can_mark_single_from_context(C)) { ID *id = CTX_data_pointer_get_type(C, "id", &RNA_ID).data; /* Gray out items depending on if data-block is an asset. Preferably this could be done via diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 4f8bb6342f7..bfc03a95949 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3066,7 +3066,7 @@ static bool ui_textedit_set_cursor_pos_foreach_glyph(const char *UNUSED(str), /** * \param x: Screen space cursor location - #wmEvent.x * - * \note ``but->block->aspect`` is used here, so drawing button style is getting scaled too. + * \note `but->block->aspect` is used here, so drawing button style is getting scaled too. */ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, const float x) { @@ -3929,7 +3929,7 @@ static void ui_do_but_textedit( /* exception that's useful for number buttons, some keyboard * numpads have a comma instead of a period */ - if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { /* could use data->min*/ + if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { /* Could use `data->min`. */ if (event->type == EVT_PADPERIOD && ascii == ',') { ascii = '.'; utf8_buf = NULL; /* force ascii fallback */ @@ -9486,7 +9486,7 @@ static void ui_list_activate_row_from_index( /* A bit ugly, set the active index in RNA directly. That's because a button that's * scrolled away in the list box isn't created at all. * The custom activate operator (#uiList.custom_activate_opname) is not called in this case - * (which may need the row button context).*/ + * (which may need the row button context). */ RNA_property_int_set(&listbox->rnapoin, listbox->rnaprop, index); RNA_property_update(C, &listbox->rnapoin, listbox->rnaprop); ui_apply_but_undo(listbox); @@ -9505,7 +9505,7 @@ static int ui_list_get_increment(const uiList *ui_list, const int type, const in increment = (type == EVT_UPARROWKEY) ? -columns : columns; } else { - /* Left or right in grid layouts or any direction in single column layouts increments by 1. */ + /* Left or right in grid layouts or any direction in single column layouts increments by 1. */ increment = ELEM(type, EVT_UPARROWKEY, EVT_LEFTARROWKEY, WHEELUPMOUSE) ? -1 : 1; } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 43ac646f053..975c86f3e71 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -66,6 +66,7 @@ #include "ED_datafiles.h" #include "ED_keyframes_draw.h" +#include "ED_keyframes_keylist.h" #include "ED_render.h" #include "UI_interface.h" diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 376a41ff9bb..3ab49b8773b 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -675,7 +675,7 @@ static int override_remove_button_exec(bContext *C, wmOperator *op) PropertyRNA *src_prop; RNA_id_pointer_create(id->override_library->reference, &id_refptr); if (!RNA_path_resolve_property(&id_refptr, oprop->rna_path, &src, &src_prop)) { - BLI_assert(0 && "Failed to create matching source (linked data) RNA pointer"); + BLI_assert_msg(0, "Failed to create matching source (linked data) RNA pointer"); } } diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc index 5a05813f947..de3b49eec07 100644 --- a/source/blender/editors/interface/interface_template_asset_view.cc +++ b/source/blender/editors/interface/interface_template_asset_view.cc @@ -52,25 +52,24 @@ static void asset_view_item_but_drag_set(uiBut *but, AssetViewListData *list_data, AssetHandle *asset_handle) { - ID *id = asset_handle->file_data->id; + ID *id = ED_asset_handle_get_local_id(asset_handle); if (id != nullptr) { UI_but_drag_set_id(but, id); return; } - const blender::StringRef asset_list_path = ED_assetlist_library_path(&list_data->asset_library); char blend_path[FILE_MAX_LIBEXTRA]; + /* Context can be NULL here, it's only needed for a File Browser specific hack that should go + * away before too long. */ + ED_asset_handle_get_full_library_path(NULL, &list_data->asset_library, asset_handle, blend_path); - char path[FILE_MAX_LIBEXTRA]; - BLI_join_dirfile(path, sizeof(path), asset_list_path.data(), asset_handle->file_data->relpath); - if (BLO_library_path_explode(path, blend_path, nullptr, nullptr)) { + if (blend_path[0]) { ImBuf *imbuf = ED_assetlist_asset_image_get(asset_handle); UI_but_drag_set_asset(but, - asset_handle->file_data->name, + asset_handle, BLI_strdup(blend_path), - asset_handle->file_data->blentype, FILE_ASSET_IMPORT_APPEND, - asset_handle->file_data->preview_icon_id, + ED_asset_handle_get_preview_icon_id(asset_handle), imbuf, 1.0f); } @@ -101,8 +100,8 @@ static void asset_view_draw_item(uiList *ui_list, uiBut *but = uiDefIconTextBut(block, UI_BTYPE_PREVIEW_TILE, 0, - asset_handle->file_data->preview_icon_id, - asset_handle->file_data->name, + ED_asset_handle_get_preview_icon_id(asset_handle), + ED_asset_handle_get_name(asset_handle), 0, 0, size_x, @@ -114,7 +113,7 @@ static void asset_view_draw_item(uiList *ui_list, 0, ""); ui_def_but_icon(but, - asset_handle->file_data->preview_icon_id, + ED_asset_handle_get_preview_icon_id(asset_handle), /* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */ UI_HAS_ICON | UI_BUT_ICON_PREVIEW); if (!ui_list->dyn_data->custom_drag_optype) { diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc index eaab33e32c9..0ab45ea0f81 100644 --- a/source/blender/editors/interface/interface_template_list.cc +++ b/source/blender/editors/interface/interface_template_list.cc @@ -1170,7 +1170,7 @@ uiList *uiTemplateList_ex(uiLayout *layout, enum uiTemplateListFlags flags, void *customdata) { - TemplateListInputData input_data = {nullptr}; + TemplateListInputData input_data = {{nullptr}}; uiListType *ui_list_type; if (!ui_template_list_data_retrieve(listtype_name, list_id, @@ -1271,7 +1271,9 @@ PointerRNA *UI_list_custom_activate_operator_set(uiList *ui_list, } if (create_properties) { - WM_operator_properties_alloc(&dyn_data->custom_activate_opptr, nullptr, opname); + PointerRNA *opptr = dyn_data->custom_activate_opptr; + WM_operator_properties_alloc( + &dyn_data->custom_activate_opptr, opptr ? (IDProperty **)&opptr->data : nullptr, opname); } return dyn_data->custom_activate_opptr; @@ -1291,7 +1293,9 @@ PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list, } if (create_properties) { - WM_operator_properties_alloc(&dyn_data->custom_drag_opptr, nullptr, opname); + PointerRNA *opptr = dyn_data->custom_drag_opptr; + WM_operator_properties_alloc( + &dyn_data->custom_drag_opptr, opptr ? (IDProperty **)&opptr->data : nullptr, opname); } return dyn_data->custom_drag_opptr; diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index e9804840801..db2766f1b19 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -1914,7 +1914,7 @@ float UI_view2d_scale_get_y(const View2D *v2d) return BLI_rcti_size_y(&v2d->mask) / BLI_rctf_size_y(&v2d->cur); } /** - * Same as ``UI_view2d_scale_get() - 1.0f / x, y`` + * Same as `UI_view2d_scale_get() - 1.0f / x, y`. */ void UI_view2d_scale_get_inverse(const View2D *v2d, float *r_x, float *r_y) { diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index 880d27e1615..ad71f4d9da7 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -361,8 +361,10 @@ static bool add_vertex_extrude(const bContext *C, } } - // print_v2("", tangent_point); - // printf("%d\n", point_index); +#if 0 + print_v2("", tangent_point); + printf("%d\n", point_index); +#endif mask_spline_add_point_at_index(spline, point_index); diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 73b3fb9724e..b2379610f65 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -482,8 +482,34 @@ bool ED_mesh_color_remove_named(Mesh *me, const char *name) return false; } +/*********************** General poll ************************/ + +static bool layers_poll(bContext *C) +{ + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + return (ob && !ID_IS_LINKED(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED(data)); +} + /*********************** Sculpt Vertex colors operators ************************/ +static bool sculpt_vertex_color_remove_poll(bContext *C) +{ + if (!layers_poll(C)) { + return false; + } + + Object *ob = ED_object_context(C); + Mesh *me = ob->data; + CustomData *vdata = GET_CD_DATA(me, vdata); + const int active = CustomData_get_active_layer(vdata, CD_PROP_COLOR); + if (active != -1) { + return true; + } + + return false; +} + /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */ int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool active_set, const bool do_init) { @@ -591,11 +617,21 @@ bool ED_mesh_sculpt_color_remove_named(Mesh *me, const char *name) /*********************** UV texture operators ************************/ -static bool layers_poll(bContext *C) +static bool uv_texture_remove_poll(bContext *C) { + if (!layers_poll(C)) { + return false; + } + Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED(data)); + Mesh *me = ob->data; + CustomData *ldata = GET_CD_DATA(me, ldata); + const int active = CustomData_get_active_layer(ldata, CD_MLOOPUV); + if (active != -1) { + return true; + } + + return false; } static int mesh_uv_texture_add_exec(bContext *C, wmOperator *UNUSED(op)) @@ -657,7 +693,7 @@ void MESH_OT_uv_texture_remove(wmOperatorType *ot) ot->idname = "MESH_OT_uv_texture_remove"; /* api callbacks */ - ot->poll = layers_poll; + ot->poll = uv_texture_remove_poll; ot->exec = mesh_uv_texture_remove_exec; /* flags */ @@ -666,6 +702,23 @@ void MESH_OT_uv_texture_remove(wmOperatorType *ot) /*********************** vertex color operators ************************/ +static bool vertex_color_remove_poll(bContext *C) +{ + if (!layers_poll(C)) { + return false; + } + + Object *ob = ED_object_context(C); + Mesh *me = ob->data; + CustomData *ldata = GET_CD_DATA(me, ldata); + const int active = CustomData_get_active_layer(ldata, CD_MLOOPCOL); + if (active != -1) { + return true; + } + + return false; +} + static int mesh_vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = ED_object_context(C); @@ -714,7 +767,7 @@ void MESH_OT_vertex_color_remove(wmOperatorType *ot) /* api callbacks */ ot->exec = mesh_vertex_color_remove_exec; - ot->poll = layers_poll; + ot->poll = vertex_color_remove_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -770,7 +823,7 @@ void MESH_OT_sculpt_vertex_color_remove(wmOperatorType *ot) /* api callbacks */ ot->exec = mesh_sculpt_vertex_color_remove_exec; - ot->poll = layers_poll; + ot->poll = sculpt_vertex_color_remove_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 34e9a3f45a5..94823b92c44 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -336,7 +336,7 @@ void ED_operatormacros_mesh(void) ot = WM_operatortype_append_macro("MESH_OT_polybuild_face_at_cursor_move", "Face at Cursor Move", - "", + NULL, OPTYPE_UNDO | OPTYPE_REGISTER); WM_operatortype_macro_define(ot, "MESH_OT_polybuild_face_at_cursor"); otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); @@ -345,7 +345,7 @@ void ED_operatormacros_mesh(void) ot = WM_operatortype_append_macro("MESH_OT_polybuild_split_at_cursor_move", "Split at Cursor Move", - "", + NULL, OPTYPE_UNDO | OPTYPE_REGISTER); WM_operatortype_macro_define(ot, "MESH_OT_polybuild_split_at_cursor"); otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); @@ -354,7 +354,7 @@ void ED_operatormacros_mesh(void) ot = WM_operatortype_append_macro("MESH_OT_polybuild_transform_at_cursor_move", "Transform at Cursor Move", - "", + NULL, OPTYPE_UNDO | OPTYPE_REGISTER); WM_operatortype_macro_define(ot, "MESH_OT_polybuild_transform_at_cursor"); otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); @@ -363,7 +363,7 @@ void ED_operatormacros_mesh(void) ot = WM_operatortype_append_macro("MESH_OT_polybuild_extrude_at_cursor_move", "Extrude at Cursor Move", - "", + NULL, OPTYPE_UNDO | OPTYPE_REGISTER); WM_operatortype_macro_define(ot, "MESH_OT_polybuild_transform_at_cursor"); otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_edges_indiv"); diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 2109fe2a822..6251fb799c5 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -123,9 +123,14 @@ static const EnumPropertyItem *dt_layers_select_src_itemf(bContext *C, RNA_enum_items_add_value( &item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC); - if (data_type == DT_TYPE_MDEFORMVERT) { - Object *ob_src = CTX_data_active_object(C); + Object *ob_src = CTX_data_active_object(C); + if (ob_src == NULL) { + RNA_enum_item_end(&item, &totitem); + *r_free = true; + return item; + } + if (data_type == DT_TYPE_MDEFORMVERT && BKE_object_supports_vertex_groups(ob_src)) { if (BKE_object_pose_armature_get(ob_src)) { RNA_enum_items_add_value( &item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT); @@ -133,67 +138,57 @@ static const EnumPropertyItem *dt_layers_select_src_itemf(bContext *C, &item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM); } - if (ob_src) { - const bDeformGroup *dg; - int i; + const bDeformGroup *dg; + int i; - RNA_enum_item_add_separator(&item, &totitem); + RNA_enum_item_add_separator(&item, &totitem); - const ListBase *defbase = BKE_object_defgroup_list(ob_src); - for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) { - tmp_item.value = i; - tmp_item.identifier = tmp_item.name = dg->name; - RNA_enum_item_add(&item, &totitem, &tmp_item); - } + const ListBase *defbase = BKE_object_defgroup_list(ob_src); + for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = dg->name; + RNA_enum_item_add(&item, &totitem, &tmp_item); } } else if (data_type == DT_TYPE_SHAPEKEY) { /* TODO */ } else if (data_type == DT_TYPE_UV) { - Object *ob_src = CTX_data_active_object(C); - - if (ob_src) { - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); - CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH; - cddata_masks.lmask |= CD_MASK_MLOOPUV; - Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks); - int num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPUV); + CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH; + cddata_masks.lmask |= CD_MASK_MLOOPUV; + Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks); + int num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPUV); - RNA_enum_item_add_separator(&item, &totitem); + RNA_enum_item_add_separator(&item, &totitem); - for (int i = 0; i < num_data; i++) { - tmp_item.value = i; - tmp_item.identifier = tmp_item.name = CustomData_get_layer_name( - &me_eval->ldata, CD_MLOOPUV, i); - RNA_enum_item_add(&item, &totitem, &tmp_item); - } + for (int i = 0; i < num_data; i++) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = CustomData_get_layer_name( + &me_eval->ldata, CD_MLOOPUV, i); + RNA_enum_item_add(&item, &totitem, &tmp_item); } } else if (data_type == DT_TYPE_VCOL) { - Object *ob_src = CTX_data_active_object(C); - - if (ob_src) { - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); - CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH; - cddata_masks.lmask |= CD_MASK_MLOOPCOL; - Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks); - int num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPCOL); + CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH; + cddata_masks.lmask |= CD_MASK_MLOOPCOL; + Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks); + int num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPCOL); - RNA_enum_item_add_separator(&item, &totitem); + RNA_enum_item_add_separator(&item, &totitem); - for (int i = 0; i < num_data; i++) { - tmp_item.value = i; - tmp_item.identifier = tmp_item.name = CustomData_get_layer_name( - &me_eval->ldata, CD_MLOOPCOL, i); - RNA_enum_item_add(&item, &totitem, &tmp_item); - } + for (int i = 0; i < num_data; i++) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = CustomData_get_layer_name( + &me_eval->ldata, CD_MLOOPCOL, i); + RNA_enum_item_add(&item, &totitem, &tmp_item); } } diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c index 3d4d3c8f622..92f3d28878c 100644 --- a/source/blender/editors/object/object_facemap_ops.c +++ b/source/blender/editors/object/object_facemap_ops.c @@ -176,6 +176,21 @@ static bool face_map_supported_edit_mode_poll(bContext *C) return false; } +static bool face_map_supported_remove_poll(bContext *C) +{ + if (!face_map_supported_poll(C)) { + return false; + } + + Object *ob = ED_object_context(C); + bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); + if (fmap) { + return true; + } + + return false; +} + static int face_map_add_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = ED_object_context(C); @@ -225,7 +240,7 @@ void OBJECT_OT_face_map_remove(struct wmOperatorType *ot) ot->description = "Remove a face map from the active object"; /* api callbacks */ - ot->poll = face_map_supported_poll; + ot->poll = face_map_supported_remove_poll; ot->exec = face_map_remove_exec; /* flags */ diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 4ea599fd30e..f64f95c5322 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -3892,7 +3892,7 @@ static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op) int fail = 0; CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - if (obact != ob) { + if (obact != ob && BKE_object_supports_vertex_groups(ob)) { if (ED_vgroup_array_copy(ob, obact)) { DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); DEG_relations_tag_update(CTX_data_main(C)); @@ -3909,8 +3909,8 @@ static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op) if ((changed_tot == 0 && fail == 0) || fail) { BKE_reportf(op->reports, RPT_ERROR, - "Copy vertex groups to selected: %d done, %d failed (object data must have " - "matching indices)", + "Copy vertex groups to selected: %d done, %d failed (object data must support " + "vertex groups and have matching indices)", changed_tot, fail); } diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index f2bbd6d5084..5a629058c81 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -368,7 +368,7 @@ static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *o else if (pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) { if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) { pset->flag |= PE_FADE_TIME; - // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB; + /* Nice to have but doesn't work: `pset->brushtype = PE_BRUSH_COMB;`. */ PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL); } edit = pid->cache->edit; @@ -377,7 +377,7 @@ static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *o else if (pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) { if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) { pset->flag |= PE_FADE_TIME; - // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB; + /* Nice to have but doesn't work: `pset->brushtype = PE_BRUSH_COMB;`. */ PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL); } edit = pid->cache->edit; diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 9abf15d2198..702c8d052c5 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -234,7 +234,7 @@ static Scene *preview_get_scene(Main *pr_main) return pr_main->scenes.first; } -static const char *preview_collection_name(const char pr_type) +static const char *preview_collection_name(const ePreviewType pr_type) { switch (pr_type) { case MA_FLAT: @@ -265,10 +265,7 @@ static const char *preview_collection_name(const char pr_type) } } -static void set_preview_visibility(Scene *scene, - ViewLayer *view_layer, - char pr_type, - int pr_method) +static void switch_preview_collection_visibilty(ViewLayer *view_layer, const ePreviewType pr_type) { /* Set appropriate layer as visible. */ LayerCollection *lc = view_layer->layer_collections.first; @@ -282,7 +279,11 @@ static void set_preview_visibility(Scene *scene, lc->collection->flag |= COLLECTION_RESTRICT_RENDER; } } +} +static void switch_preview_floor_visibility(ViewLayer *view_layer, + const ePreviewRenderMethod pr_method) +{ /* Hide floor for icon renders. */ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { if (STREQ(base->object->id.name + 2, "Floor")) { @@ -294,7 +295,15 @@ static void set_preview_visibility(Scene *scene, } } } +} +static void set_preview_visibility(Scene *scene, + ViewLayer *view_layer, + const ePreviewType pr_type, + const ePreviewRenderMethod pr_method) +{ + switch_preview_collection_visibilty(view_layer, pr_type); + switch_preview_floor_visibility(view_layer, pr_method); BKE_layer_collection_sync(scene, view_layer); } @@ -348,6 +357,38 @@ static ID *duplicate_ids(ID *id, const bool allow_failure) } } +static World *preview_get_world(Main *pr_main) +{ + World *result = NULL; + const char *world_name = "World"; + result = BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2); + + /* No world found return first world. */ + if (result == NULL) { + result = pr_main->worlds.first; + } + + BLI_assert_msg(result, "Preview file has no world."); + return result; +} + +static void preview_sync_exposure(World *dst, const World *src) +{ + BLI_assert(dst); + BLI_assert(src); + dst->exp = src->exp; + dst->range = src->range; +} + +static World *preview_prepare_world(Main *pr_main, const World *world) +{ + World *result = preview_get_world(pr_main); + if (world) { + preview_sync_exposure(result, world); + } + return result; +} + /* call this with a pointer to initialize preview scene */ /* call this with NULL to restore assigned ID pointers in preview scene */ static Scene *preview_prepare_scene( @@ -368,13 +409,7 @@ static Scene *preview_prepare_scene( /* this flag tells render to not execute depsgraph or ipos etc */ sce->r.scemode |= R_BUTS_PREVIEW; - /* set world always back, is used now */ - sce->world = pr_main->worlds.first; - /* now: exposure copy */ - if (scene->world) { - sce->world->exp = scene->world->exp; - sce->world->range = scene->world->range; - } + BLI_strncpy(sce->r.engine, scene->r.engine, sizeof(sce->r.engine)); sce->r.color_mgt_flag = scene->r.color_mgt_flag; BKE_color_managed_display_settings_copy(&sce->display_settings, &scene->display_settings); @@ -400,13 +435,13 @@ static Scene *preview_prepare_scene( sce->r.cfra = scene->r.cfra; + /* Setup the world. */ + sce->world = preview_prepare_world(pr_main, scene->world); + if (id_type == ID_TE) { /* Texture is not actually rendered with engine, just set dummy value. */ BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine)); } - else { - BLI_strncpy(sce->r.engine, scene->r.engine, sizeof(sce->r.engine)); - } if (id_type == ID_MA) { Material *mat = NULL, *origmat = (Material *)id; @@ -432,14 +467,12 @@ static Scene *preview_prepare_scene( sce->world->horb = 0.05f; } - if (sp->pr_method == PR_ICON_RENDER && sp->pr_main == G_pr_main_grease_pencil) { - /* For grease pencil, always use sphere for icon renders. */ - set_preview_visibility(sce, view_layer, MA_SPHERE_A, sp->pr_method); - } - else { - /* Use specified preview shape for both preview panel and icon previews. */ - set_preview_visibility(sce, view_layer, mat->pr_type, sp->pr_method); - } + /* For grease pencil, always use sphere for icon renders. */ + const ePreviewType preview_type = (sp->pr_method == PR_ICON_RENDER && + sp->pr_main == G_pr_main_grease_pencil) ? + MA_SPHERE_A : + mat->pr_type; + set_preview_visibility(sce, view_layer, preview_type, sp->pr_method); if (sp->pr_method != PR_ICON_RENDER) { if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) { @@ -691,8 +724,8 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r struct ObjectPreviewData { /* The main for the preview, not of the current file. */ Main *pr_main; - /* Copy of the object to create the preview for. The copy is for thread safety (and to insert it - * into an own main). */ + /* Copy of the object to create the preview for. The copy is for thread safety (and to insert + * it into an own main). */ Object *object; int sizex; int sizey; @@ -861,9 +894,9 @@ static void action_preview_render_cleanup(IconPreview *preview, struct PoseBacku DEG_id_tag_update(&preview->active_object->id, ID_RECALC_GEOMETRY); } -/* Render a pose. It is assumed that the pose has already been applied and that the scene camera is - * capturing the pose. In other words, this function just renders from the scene camera without - * evaluating the Action stored in preview->id. */ +/* Render a pose from the scene camera. It is assumed that the scene camera is + * capturing the pose. The pose is applied temporarily to the current object + * before rendering. */ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview_sized) { char err_out[256] = ""; @@ -1308,8 +1341,9 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect) scaledy = (float)h; } - ex = (short)scaledx; - ey = (short)scaledy; + /* Scaling down must never assign zero width/height, see: T89868. */ + ex = MAX2(1, (short)scaledx); + ey = MAX2(1, (short)scaledy); dx = (w - ex) / 2; dy = (h - ey) / 2; @@ -1550,8 +1584,8 @@ static void icon_preview_startjob_all_sizes(void *customdata, /* check_engine_supports_preview() checks whether the engine supports "preview mode" (think: * Material Preview). This check is only relevant when the render function called below is - * going to use such a mode. Object and Action render functions use Solid mode, though, so they - * can skip this test. */ + * going to use such a mode. Object and Action render functions use Solid mode, though, so + * they can skip this test. */ /* TODO: Decouple the ID-type-specific render functions from this function, so that it's not * necessary to know here what happens inside lower-level functions. */ const bool use_solid_render_mode = (ip->id != NULL) && ELEM(GS(ip->id->name), ID_OB, ID_AC); diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index d2b1ebdad78..8a3d8f9636b 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -56,6 +56,7 @@ #include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_material.h" +#include "BKE_node.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -1043,6 +1044,10 @@ static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op)) engine = NULL; } + if (scene->nodetree) { + ntreeCompositUpdateRLayers(scene->nodetree); + } + DEG_id_tag_update(&scene->id, 0); DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); @@ -1091,6 +1096,10 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op)) engine = NULL; } + if (scene->nodetree) { + ntreeCompositUpdateRLayers(scene->nodetree); + } + DEG_id_tag_update(&scene->id, 0); DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 80b5623b9c3..fb9d11feb63 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -65,7 +65,7 @@ /***************************** Render Engines ********************************/ -/* Update 3D viewport render or draw engine on changes to the scene or view settings . */ +/* Update 3D viewport render or draw engine on changes to the scene or view settings. */ void ED_render_view3d_update(Depsgraph *depsgraph, wmWindow *window, ScrArea *area, diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 3ce2f326dca..8123d8bb104 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -1031,7 +1031,7 @@ static eContextResult screen_ctx_asset_library(const bContext *C, bContextDataRe { WorkSpace *workspace = CTX_wm_workspace(C); CTX_data_pointer_set( - result, &workspace->id, &RNA_AssetLibraryReference, &workspace->active_asset_library); + result, &workspace->id, &RNA_AssetLibraryReference, &workspace->asset_library); return CTX_RESULT_OK; } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index ffeaf514642..3d0d856b1c5 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -71,7 +71,7 @@ #include "ED_armature.h" #include "ED_clip.h" #include "ED_image.h" -#include "ED_keyframes_draw.h" +#include "ED_keyframes_keylist.h" #include "ED_mesh.h" #include "ED_object.h" #include "ED_screen.h" diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index bd05d309421..19f72a66b9b 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -375,7 +375,7 @@ typedef struct ProjPaintState { /* -------------------------------------------------------------------- */ /* Vars shared between multiple views (keep last) */ /** - * This data is owned by ``ProjStrokeHandle.ps_views[0]``, + * This data is owned by `ProjStrokeHandle.ps_views[0]`, * all other views re-use the data. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c index de9511bab6f..4b49bf2cefb 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c @@ -10,7 +10,7 @@ * 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, + * 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) 2020 Blender Foundation. diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c index c3977b28178..936ebb7e8f7 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c @@ -10,7 +10,7 @@ * 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, + * 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) 2020 Blender Foundation. diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 0d5b197ae93..59d2063ea84 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -51,8 +51,8 @@ #include "ED_anim_api.h" #include "ED_gpencil.h" -#include "ED_keyframes_draw.h" #include "ED_keyframes_edit.h" +#include "ED_keyframes_keylist.h" #include "ED_markers.h" #include "ED_mask.h" #include "ED_screen.h" diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index a314a85491d..37a56816677 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -185,9 +185,8 @@ static void file_draw_icon(const SpaceFile *sfile, BLI_assert(asset_params != NULL); UI_but_drag_set_asset(but, - file->name, + &(AssetHandle){.file_data = file}, BLI_strdup(blend_path), - file->blentype, asset_params->import_type, icon, preview_image, @@ -500,9 +499,8 @@ static void file_draw_preview(const SpaceFile *sfile, BLI_assert(asset_params != NULL); UI_but_drag_set_asset(but, - file->name, + &(AssetHandle){.file_data = file}, BLI_strdup(blend_path), - file->blentype, asset_params->import_type, icon, imb, diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 995383d9d0e..4d25524cd19 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -2340,7 +2340,9 @@ static int file_directory_new_exec(bContext *C, wmOperator *op) /* If we don't enter the directory directly, remember file to jump into editing. */ if (do_diropen == false) { - BLI_assert(params->rename_id == NULL || !"File rename handling should immediately clear rename_id when done, because otherwise it will keep taking precedence over renamefile."); + BLI_assert_msg(params->rename_id == NULL, + "File rename handling should immediately clear rename_id when done, " + "because otherwise it will keep taking precedence over renamefile."); BLI_strncpy(params->renamefile, name, FILE_MAXFILE); rename_flag = FILE_PARAMS_RENAME_PENDING; } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 492a189fc81..6ac67a126cd 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -382,7 +382,7 @@ typedef struct FileList { eFileSelectType type; /* The library this list was created for. Stored here so we know when to re-read. */ - FileSelectAssetLibraryUID *asset_library; + AssetLibraryReference *asset_library; short flags; @@ -1045,8 +1045,8 @@ void filelist_setfilter_options(FileList *filelist, * Checks two libraries for equality. * \return True if the libraries match. */ -static bool filelist_compare_asset_libraries(const FileSelectAssetLibraryUID *library_a, - const FileSelectAssetLibraryUID *library_b) +static bool filelist_compare_asset_libraries(const AssetLibraryReference *library_a, + const AssetLibraryReference *library_b) { if (library_a->type != library_b->type) { return false; @@ -1065,7 +1065,7 @@ static bool filelist_compare_asset_libraries(const FileSelectAssetLibraryUID *li /** * \param asset_library: May be NULL to unset the library. */ -void filelist_setlibrary(FileList *filelist, const FileSelectAssetLibraryUID *asset_library) +void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library) { /* Unset if needed. */ if (!asset_library) { diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index cb98cf6e74a..6915e853681 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -29,7 +29,7 @@ extern "C" { struct BlendHandle; struct FileList; -struct FileSelectAssetLibraryUID; +struct AssetLibraryReference; struct FileSelection; struct wmWindowManager; @@ -73,7 +73,7 @@ void filelist_setfilter_options(struct FileList *filelist, const char *filter_search); void filelist_filter(struct FileList *filelist); void filelist_setlibrary(struct FileList *filelist, - const struct FileSelectAssetLibraryUID *asset_library); + const struct AssetLibraryReference *asset_library); void filelist_init_icons(void); void filelist_free_icons(void); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 7bc83e8fc79..68dd1e28f99 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -415,7 +415,7 @@ FileAssetSelectParams *ED_fileselect_get_asset_params(const SpaceFile *sfile) static void fileselect_refresh_asset_params(FileAssetSelectParams *asset_params) { - FileSelectAssetLibraryUID *library = &asset_params->asset_library; + AssetLibraryReference *library = &asset_params->asset_library; FileSelectParams *base_params = &asset_params->base_params; bUserAssetLibrary *user_library = NULL; diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 31c7dee294b..274b21f7043 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -910,13 +910,6 @@ static int /*eContextResult*/ file_context(const bContext *C, return CTX_RESULT_NO_DATA; } - BLI_STATIC_ASSERT(offsetof(FileSelectAssetLibraryUID, type) == - offsetof(AssetLibraryReference, type), - "Expected FileSelectAssetLibraryUID to match AssetLibraryReference"); - BLI_STATIC_ASSERT(offsetof(FileSelectAssetLibraryUID, custom_library_index) == - offsetof(AssetLibraryReference, custom_library_index), - "Expected FileSelectAssetLibraryUID to match AssetLibraryReference"); - CTX_data_pointer_set( result, &screen->id, &RNA_AssetLibraryReference, &asset_params->asset_library); return CTX_RESULT_OK; diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 6f1b0bb0d7d..9f9869a854c 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -261,7 +261,7 @@ static int graphkeys_insertkey_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - /* Which channels to affect?. */ + /* Which channels to affect? */ mode = RNA_enum_get(op->ptr, "type"); /* Insert keyframes. */ @@ -2814,7 +2814,7 @@ static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op) } ANIM_animdata_freelist(&anim_data); - /* Successful or not?. */ + /* Successful or not? */ if (ok) { /* Set notifier that keyframes have changed. */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); @@ -2873,7 +2873,7 @@ static int graph_driver_vars_copy_exec(bContext *C, wmOperator *op) ok = ANIM_driver_vars_copy(op->reports, fcu); } - /* Successful or not?. */ + /* Successful or not? */ if (ok) { return OPERATOR_FINISHED; } @@ -2915,7 +2915,7 @@ static int graph_driver_vars_paste_exec(bContext *C, wmOperator *op) ok = ANIM_driver_vars_paste(op->reports, fcu, replace); } - /* Successful or not?. */ + /* Successful or not? */ if (ok) { /* Rebuild depsgraph, now that there are extra deps here. */ DEG_relations_tag_update(CTX_data_main(C)); diff --git a/source/blender/editors/space_graph/graph_view.c b/source/blender/editors/space_graph/graph_view.c index 31c53cde62c..036fd354c18 100644 --- a/source/blender/editors/space_graph/graph_view.c +++ b/source/blender/editors/space_graph/graph_view.c @@ -398,7 +398,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end) ANIMFILTER_NODUPLIS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - /* Loop through filtered data and add keys between selected keyframes on every frame . */ + /* Loop through filtered data and add keys between selected keyframes on every frame. */ for (ale = anim_data.first; ale; ale = ale->next) { FCurve *fcu = (FCurve *)ale->key_data; FCurve *gcu = BKE_fcurve_create(); diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 4779a82948d..86349a64681 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -1189,7 +1189,7 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser const int menus_width = 160 * dpi_fac; const bool is_render_result = (ima->type == IMA_TYPE_R_RESULT); - /* use BKE_image_acquire_renderresult so we get the correct slot in the menu */ + /* Use BKE_image_acquire_renderresult so we get the correct slot in the menu. */ rr = BKE_image_acquire_renderresult(scene, ima); uiblock_layer_pass_buttons( layout, ima, rr, iuser, menus_width, is_render_result ? &ima->render_slot : NULL); diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index f9fb386095d..c96047da0c8 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -44,6 +44,7 @@ #include "ED_anim_api.h" #include "ED_keyframes_draw.h" +#include "ED_keyframes_keylist.h" #include "GPU_immediate.h" #include "GPU_immediate_util.h" diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index af9c888cbf7..cbf03f553f6 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -613,9 +613,8 @@ void snode_set_context(const bContext *C) /* check the tree type */ if (!treetype || (treetype->poll && !treetype->poll(C, treetype))) { /* invalid tree type, skip - * NB: not resetting the node path here, invalid bNodeTreeType - * may still be registered at a later point. - */ + * NOTE: not resetting the node path here, invalid #bNodeTreeType + * may still be registered at a later point. */ return; } @@ -1303,9 +1302,8 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) } } - /* copy links between selected nodes - * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy! - */ + /* Copy links between selected nodes. + * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */ bNodeLink *lastlink = (bNodeLink *)ntree->links.last; LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { /* This creates new links between copied nodes. @@ -2163,9 +2161,9 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) } } - /* copy links between selected nodes - * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy! - */ + /* Copy links between selected nodes. + * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */ + LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { /* This creates new links between copied nodes. */ if (link->tonode && (link->tonode->flag & NODE_SELECT) && link->fromnode && diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 725c872e98f..61a874b2b2d 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -299,7 +299,7 @@ static void pick_input_link_by_link_intersect(const bContext *C, /* If no linked was picked in this call, try using the one picked in the previous call. * Not essential for the basic behavior, but can make interaction feel a bit better if - * the mouse moves to the right and loses the "selection." */ + * the mouse moves to the right and loses the "selection." */ if (!link_to_pick) { bNodeLink *last_picked_link = nldrag->last_picked_multi_input_socket_link; if (last_picked_link) { diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index a081cc83481..6c07c41f451 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -1196,7 +1196,7 @@ static void node_find_create_label(const bNode *node, char *str, int maxlen) } } -/* generic search invoke */ +/* Generic search invoke. */ static void node_find_update_fn(const struct bContext *C, void *UNUSED(arg), const char *str, diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc index cbe33fab64e..648ede7abd5 100644 --- a/source/blender/editors/space_node/node_templates.cc +++ b/source/blender/editors/space_node/node_templates.cc @@ -848,7 +848,10 @@ static void ui_node_draw_input( break; case SOCK_STRING: { const bNodeTree *node_tree = (const bNodeTree *)nodeptr.owner_id; - if (node_tree->type == NTREE_GEOMETRY) { + SpaceNode *snode = CTX_wm_space_node(C); + if (node_tree->type == NTREE_GEOMETRY && snode != nullptr) { + /* Only add the attribute search in the node editor, in other places there is not + * enough context. */ node_geometry_add_attribute_search_button(C, node_tree, node, &inputptr, row); } else { diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 35015356f0b..aaa52f6b649 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -697,7 +697,9 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED { Editing *ed = SEQ_editing_get(scene, false); - /* XXX select_single_seq(seq, 1); */ +#if 0 + select_single_seq(seq, 1); +#endif Sequence *p = ed->seqbasep->first; while (p) { if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) { @@ -705,8 +707,11 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED continue; } - /* XXX: if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) select_single_seq(p, - * 0); */ +#if 0 + if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { + select_single_seq(p, 0); + } +#endif p = p->next; } } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc index 1ac2075e281..c38e765caee 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc @@ -489,7 +489,7 @@ bool ED_spreadsheet_context_path_is_active(const bContext *C, SpaceSpreadsheet * break; } SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)node_context_path[i]; - if (!STREQ(node_context->node_name, tree_path[i]->node_name)) { + if (!STREQ(node_context->node_name, tree_path[i + 1]->node_name)) { break; } valid_count++; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 54f10e259f9..5baa12f7367 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -53,6 +53,7 @@ #include "BKE_screen.h" #include "BKE_workspace.h" +#include "ED_asset.h" #include "ED_render.h" #include "ED_screen.h" #include "ED_space_api.h" @@ -495,7 +496,7 @@ static ID_Type view3d_drop_id_in_main_region_poll_get_id_type(bContext *C, wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, 0); if (asset_drag) { - return asset_drag->id_type; + return ED_asset_handle_get_id_type(asset_drag->asset_handle); } return 0; diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index 638c8a49ffd..8380c87b999 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -24,7 +24,7 @@ * Typical view-control usage: * * - Acquire a view-control (#ED_view3d_cameracontrol_acquire). - * - Modify ``rv3d->ofs``, ``rv3d->viewquat``. + * - Modify `rv3d->ofs`, `rv3d->viewquat`. * - Update the view data (#ED_view3d_cameracontrol_acquire) - * within a loop which draws the viewport. * - Finish and release the view-control (#ED_view3d_cameracontrol_release), @@ -32,8 +32,8 @@ * * Notes: * - * - when acquiring ``rv3d->dist`` is set to zero - * (so ``rv3d->ofs`` is always the view-point) + * - when acquiring `rv3d->dist` is set to zero + * (so `rv3d->ofs` is always the view-point) * - updating can optionally keyframe the camera object. */ @@ -244,7 +244,7 @@ static bool object_apply_mat4_with_protect(Object *ob, } /** - * Updates cameras from the ``rv3d`` values, optionally auto-keyframing. + * Updates cameras from the `rv3d` values, optionally auto-keyframing. */ void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl, /* args for keyframing */ diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index c7a4030c402..20e00356152 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -439,7 +439,7 @@ void mesh_foreachScreenEdge(ViewContext *vc, } BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE); - BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge__mapFunc, &data); + BKE_mesh_foreach_mapped_edge(me, vc->em->bm->totedge, mesh_foreachScreenEdge__mapFunc, &data); } /** \} */ @@ -529,10 +529,11 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc, if ((clip_flag & V3D_PROJ_TEST_CLIP_BB) && (vc->rv3d->clipbb != NULL)) { ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups. */ - BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge_clip_bb_segment__mapFunc, &data); + BKE_mesh_foreach_mapped_edge( + me, vc->em->bm->totedge, mesh_foreachScreenEdge_clip_bb_segment__mapFunc, &data); } else { - BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge__mapFunc, &data); + BKE_mesh_foreach_mapped_edge(me, vc->em->bm->totedge, mesh_foreachScreenEdge__mapFunc, &data); } } diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 8bcc05c1e55..e09453b9957 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -506,8 +506,8 @@ void ED_view3d_lock_clear(View3D *v3d) /** * For viewport operators that exit camera perspective. * - * \note This differs from simply setting ``rv3d->persp = persp`` because it - * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera, + * \note This differs from simply setting `rv3d->persp = persp` because it + * sets the `ofs` and `dist` values of the viewport so it matches the camera, * otherwise switching out of camera view may jump to a different part of the scene. */ void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph, diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 383f9870714..7377e47da3d 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1981,7 +1981,7 @@ static void tc_mesh_partial_update(TransInfo *t, /* Promote the partial update types based on the previous state * so the values that no longer modified are reset before being left as-is. - * Needed for translation which can toggle snap-to-normal during transform. */ + * Needed for translation which can toggle snap-to-normal during transform. */ const enum ePartialType partial_for_looptri = MAX2(partial_state->for_looptri, partial_state_prev->for_looptri); const enum ePartialType partial_for_normals = MAX2(partial_state->for_normals, @@ -2067,27 +2067,6 @@ static void tc_mesh_transdata_mirror_apply(TransDataContainer *tc) } } -static bool tc_mesh_is_deform_only_update(TransInfo *t, TransDataContainer *tc) -{ - if (tc->custom.type.data && - ((struct TransCustomDataMesh *)tc->custom.type.data)->cd_layer_correct) { - return false; - } - - Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(t->depsgraph, (ID *)tc->obedit->data); - Mesh *mesh_eval_cage = me_eval->edit_mesh->mesh_eval_cage; - Mesh *mesh_eval_final = me_eval->edit_mesh->mesh_eval_final; - if (mesh_eval_cage && !mesh_eval_cage->runtime.is_original) { - return false; - } - if (mesh_eval_final && mesh_eval_final != mesh_eval_cage && - !mesh_eval_final->runtime.is_original) { - return false; - } - - return me_eval->runtime.deformed_only; -} - void recalcData_mesh(TransInfo *t) { bool is_canceling = t->state == TRANS_CANCEL; @@ -2115,10 +2094,7 @@ void recalcData_mesh(TransInfo *t) tc_mesh_partial_types_calc(t, &partial_state); FOREACH_TRANS_DATA_CONTAINER (t, tc) { - const bool is_deform_only = tc_mesh_is_deform_only_update(t, tc); - - DEG_id_tag_update(tc->obedit->data, - is_deform_only ? ID_RECALC_GEOMETRY_DEFORM : ID_RECALC_GEOMETRY); + DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); tc_mesh_partial_update(t, tc, &partial_state); } diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index a6f5aba5a1d..17512c79d03 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -262,8 +262,16 @@ static void free_transform_custom_data(TransCustomData *custom_data) /* Canceled, need to update the strips display. */ static void seq_transform_cancel(TransInfo *t, SeqCollection *transformed_strips) { + ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene, false)); + Sequence *seq; SEQ_ITERATOR_FOREACH (seq, transformed_strips) { + /* Handle pre-existing overlapping strips even when operator is canceled. + * This is necessary for SEQUENCER_OT_duplicate_move macro for example. */ + if (SEQ_transform_test_overlap(seqbase, seq)) { + SEQ_transform_seqbase_shuffle(seqbase, seq, t->scene); + } + SEQ_time_update_sequence_bounds(t->scene, seq); } } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index aaac8e21cb9..e89ab6729d2 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -343,9 +343,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } else { if (region) { - /* XXX for now, get View2D from the active region */ + /* XXX: For now, get View2D from the active region. */ t->view = ®ion->v2d; - /* XXX for now, the center point is the midpoint of the data */ + /* XXX: For now, the center point is the midpoint of the data. */ } else { t->view = NULL; diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 2cbf52b6100..75744f26c15 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -266,7 +266,8 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ if (t->flag & T_AUTOIK) { short chainlen = t->settings->autoik_chainlen; if (chainlen) { - ofs += BLI_snprintf_rlen(str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("AutoIK-Len: %d"), chainlen); + ofs += BLI_snprintf_rlen( + str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Auto IK Length: %d"), chainlen); ofs += BLI_strncpy_rlen(str + ofs, " ", UI_MAX_DRAW_STR - ofs); } } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 155250261de..33f4b06eb0e 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -537,10 +537,10 @@ short ED_transform_calc_orientation_from_type_ex(const bContext *C, case V3D_ORIENT_LOCAL: { if (ob) { if (ob->mode & OB_MODE_POSE) { - /* each bone moves on its own local axis, but to avoid confusion, + /* Each bone moves on its own local axis, but to avoid confusion, * use the active pones axis for display T33575, this works as expected on a single * bone and users who select many bones will understand what's going on and what local - * means when they start transforming */ + * means when they start transforming. */ ED_getTransformOrientationMatrix(C, ob, obedit, pivot_point, r_mat); } else { diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 2d98d756dba..bb04f557074 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -1142,7 +1142,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx, * \param r_loc: Hit location. * \param r_no: Hit normal (optional). * \param r_index: Hit index or -1 when no valid index is found. - * (currently only set to the polygon index when using ``snap_to == SCE_SNAP_MODE_FACE``). + * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE`). * \param r_ob: Hit object. * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). @@ -1213,49 +1213,56 @@ static bool snap_bound_box_check_dist(const float min[3], return true; } -static void cb_mvert_co_get(const int index, const float **co, const BVHTreeFromMesh *data) +static void cb_mvert_co_get(const int index, const void *user_data, const float **r_co) { - *co = data->vert[index].co; + const BVHTreeFromMesh *data = user_data; + *r_co = data->vert[index].co; } -static void cb_bvert_co_get(const int index, const float **co, const BMEditMesh *data) +static void cb_bvert_co_get(const int index, const void *user_data, const float **r_co) { + const BMEditMesh *data = user_data; BMVert *eve = BM_vert_at_index(data->bm, index); - *co = eve->co; + *r_co = eve->co; } -static void cb_mvert_no_copy(const int index, float r_no[3], const BVHTreeFromMesh *data) +static void cb_mvert_no_copy(const int index, const void *user_data, float r_no[3]) { + const BVHTreeFromMesh *data = user_data; const MVert *vert = data->vert + index; normal_short_to_float_v3(r_no, vert->no); } -static void cb_bvert_no_copy(const int index, float r_no[3], const BMEditMesh *data) +static void cb_bvert_no_copy(const int index, const void *user_data, float r_no[3]) { + const BMEditMesh *data = user_data; BMVert *eve = BM_vert_at_index(data->bm, index); copy_v3_v3(r_no, eve->no); } -static void cb_medge_verts_get(const int index, int v_index[2], const BVHTreeFromMesh *data) +static void cb_medge_verts_get(const int index, const void *user_data, int r_v_index[2]) { + const BVHTreeFromMesh *data = user_data; const MEdge *edge = &data->edge[index]; - v_index[0] = edge->v1; - v_index[1] = edge->v2; + r_v_index[0] = edge->v1; + r_v_index[1] = edge->v2; } -static void cb_bedge_verts_get(const int index, int v_index[2], const BMEditMesh *data) +static void cb_bedge_verts_get(const int index, const void *user_data, int r_v_index[2]) { + const BMEditMesh *data = user_data; BMEdge *eed = BM_edge_at_index(data->bm, index); - v_index[0] = BM_elem_index_get(eed->v1); - v_index[1] = BM_elem_index_get(eed->v2); + r_v_index[0] = BM_elem_index_get(eed->v1); + r_v_index[1] = BM_elem_index_get(eed->v2); } -static void cb_mlooptri_edges_get(const int index, int v_index[3], const BVHTreeFromMesh *data) +static void cb_mlooptri_edges_get(const int index, const void *user_data, int r_v_index[3]) { + const BVHTreeFromMesh *data = user_data; const MEdge *medge = data->edge; const MLoop *mloop = data->loop; const MLoopTri *lt = &data->looptri[index]; @@ -1264,22 +1271,23 @@ static void cb_mlooptri_edges_get(const int index, int v_index[3], const BVHTree const uint tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v}; if (ELEM(ed->v1, tri_edge[0], tri_edge[1]) && ELEM(ed->v2, tri_edge[0], tri_edge[1])) { // printf("real edge found\n"); - v_index[j] = mloop[lt->tri[j]].e; + r_v_index[j] = mloop[lt->tri[j]].e; } else { - v_index[j] = -1; + r_v_index[j] = -1; } } } -static void cb_mlooptri_verts_get(const int index, int v_index[3], const BVHTreeFromMesh *data) +static void cb_mlooptri_verts_get(const int index, const void *user_data, int r_v_index[3]) { + const BVHTreeFromMesh *data = user_data; const MLoop *loop = data->loop; const MLoopTri *looptri = &data->looptri[index]; - v_index[0] = loop[looptri->tri[0]].v; - v_index[1] = loop[looptri->tri[1]].v; - v_index[2] = loop[looptri->tri[2]].v; + r_v_index[0] = loop[looptri->tri[0]].v; + r_v_index[1] = loop[looptri->tri[1]].v; + r_v_index[2] = loop[looptri->tri[2]].v; } static bool test_projected_vert_dist(const struct DistProjectedAABBPrecalc *precalc, @@ -1348,12 +1356,20 @@ static bool test_projected_edge_dist(const struct DistProjectedAABBPrecalc *prec /** \name Walk DFS * \{ */ -typedef void (*Nearest2DGetVertCoCallback)(const int index, const float **co, void *data); -typedef void (*Nearest2DGetEdgeVertsCallback)(const int index, const int v_index[2], void *data); -typedef void (*Nearest2DGetTriVertsCallback)(const int index, const int v_index[3], void *data); +typedef void (*Nearest2DGetVertCoCallback)(const int index, + const void *user_data, + const float **r_co); +typedef void (*Nearest2DGetEdgeVertsCallback)(const int index, + const void *user_data, + int r_v_index[2]); +typedef void (*Nearest2DGetTriVertsCallback)(const int index, + const void *user_data, + int r_v_index[3]); /* Equal the previous one */ -typedef void (*Nearest2DGetTriEdgesCallback)(const int index, const int e_index[3], void *data); -typedef void (*Nearest2DCopyVertNoCallback)(const int index, const float r_no[3], void *data); +typedef void (*Nearest2DGetTriEdgesCallback)(const int index, + const void *user_data, + int r_e_index[3]); +typedef void (*Nearest2DCopyVertNoCallback)(const int index, const void *user_data, float r_no[3]); typedef struct Nearest2dUserData { void *userdata; @@ -1374,18 +1390,18 @@ static void nearest2d_data_init(SnapObjectData *sod, { if (sod->type == SNAP_MESH) { r_nearest2d->userdata = &sod->treedata_mesh; - r_nearest2d->get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get; - r_nearest2d->get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get; - r_nearest2d->copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy; - r_nearest2d->get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get; - r_nearest2d->get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get; + r_nearest2d->get_vert_co = cb_mvert_co_get; + r_nearest2d->get_edge_verts_index = cb_medge_verts_get; + r_nearest2d->copy_vert_no = cb_mvert_no_copy; + r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get; + r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get; } else { BLI_assert(sod->type == SNAP_EDIT_MESH); r_nearest2d->userdata = sod->treedata_editmesh.em; - r_nearest2d->get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get; - r_nearest2d->get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get; - r_nearest2d->copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy; + r_nearest2d->get_vert_co = cb_bvert_co_get; + r_nearest2d->get_edge_verts_index = cb_bedge_verts_get; + r_nearest2d->copy_vert_no = cb_bvert_no_copy; r_nearest2d->get_tri_verts_index = NULL; r_nearest2d->get_tri_edges_index = NULL; } @@ -1404,7 +1420,7 @@ static void cb_snap_vert(void *userdata, struct Nearest2dUserData *data = userdata; const float *co; - data->get_vert_co(index, &co, data->userdata); + data->get_vert_co(index, data->userdata, &co); if (test_projected_vert_dist(precalc, clip_plane, @@ -1413,7 +1429,7 @@ static void cb_snap_vert(void *userdata, co, &nearest->dist_sq, nearest->co)) { - data->copy_vert_no(index, nearest->no, data->userdata); + data->copy_vert_no(index, data->userdata, nearest->no); nearest->index = index; } } @@ -1428,11 +1444,11 @@ static void cb_snap_edge(void *userdata, struct Nearest2dUserData *data = userdata; int vindex[2]; - data->get_edge_verts_index(index, vindex, data->userdata); + data->get_edge_verts_index(index, data->userdata, vindex); const float *v_pair[2]; - data->get_vert_co(vindex[0], &v_pair[0], data->userdata); - data->get_vert_co(vindex[1], &v_pair[1], data->userdata); + data->get_vert_co(vindex[0], data->userdata, &v_pair[0]); + data->get_vert_co(vindex[1], data->userdata, &v_pair[1]); if (test_projected_edge_dist(precalc, clip_plane, @@ -1457,7 +1473,7 @@ static void cb_snap_edge_verts(void *userdata, struct Nearest2dUserData *data = userdata; int vindex[2]; - data->get_edge_verts_index(index, vindex, data->userdata); + data->get_edge_verts_index(index, data->userdata, vindex); for (int i = 2; i--;) { if (vindex[i] == nearest->index) { @@ -1478,12 +1494,12 @@ static void cb_snap_tri_edges(void *userdata, if (data->use_backface_culling) { int vindex[3]; - data->get_tri_verts_index(index, vindex, data->userdata); + data->get_tri_verts_index(index, data->userdata, vindex); const float *t0, *t1, *t2; - data->get_vert_co(vindex[0], &t0, data->userdata); - data->get_vert_co(vindex[1], &t1, data->userdata); - data->get_vert_co(vindex[2], &t2, data->userdata); + data->get_vert_co(vindex[0], data->userdata, &t0); + data->get_vert_co(vindex[1], data->userdata, &t1); + data->get_vert_co(vindex[2], data->userdata, &t2); float dummy[3]; if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) { return; @@ -1491,7 +1507,7 @@ static void cb_snap_tri_edges(void *userdata, } int eindex[3]; - data->get_tri_edges_index(index, eindex, data->userdata); + data->get_tri_edges_index(index, data->userdata, eindex); for (int i = 3; i--;) { if (eindex[i] != -1) { if (eindex[i] == nearest->index) { @@ -1512,13 +1528,13 @@ static void cb_snap_tri_verts(void *userdata, struct Nearest2dUserData *data = userdata; int vindex[3]; - data->get_tri_verts_index(index, vindex, data->userdata); + data->get_tri_verts_index(index, data->userdata, vindex); if (data->use_backface_culling) { const float *t0, *t1, *t2; - data->get_vert_co(vindex[0], &t0, data->userdata); - data->get_vert_co(vindex[1], &t1, data->userdata); - data->get_vert_co(vindex[2], &t2, data->userdata); + data->get_vert_co(vindex[0], data->userdata, &t0); + data->get_vert_co(vindex[1], data->userdata, &t1); + data->get_vert_co(vindex[2], data->userdata, &t2); float dummy[3]; if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) { return; @@ -1693,11 +1709,11 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); int vindex[2]; - nearest2d.get_edge_verts_index(*r_index, vindex, nearest2d.userdata); + nearest2d.get_edge_verts_index(*r_index, nearest2d.userdata, vindex); const float *v_pair[2]; - nearest2d.get_vert_co(vindex[0], &v_pair[0], nearest2d.userdata); - nearest2d.get_vert_co(vindex[1], &v_pair[1], nearest2d.userdata); + nearest2d.get_vert_co(vindex[0], nearest2d.userdata, &v_pair[0]); + nearest2d.get_vert_co(vindex[1], nearest2d.userdata, &v_pair[1]); struct DistProjectedAABBPrecalc neasrest_precalc; { @@ -1744,7 +1760,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, if (r_no) { float imat[4][4]; invert_m4_m4(imat, obmat); - nearest2d.copy_vert_no(vindex[v_id], r_no, nearest2d.userdata); + nearest2d.copy_vert_no(vindex[v_id], nearest2d.userdata, r_no); mul_transposed_mat3_m4_v3(imat, r_no); normalize_v3(r_no); } @@ -2777,7 +2793,7 @@ static void snap_obj_fn(SnapObjectContext *sctx, * \param r_loc: Hit location. * \param r_no: Hit normal (optional). * \param r_index: Hit index or -1 when no valid index is found. - * (currently only set to the polygon index when using ``snap_to == SCE_SNAP_MODE_FACE``). + * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE`). * \param r_ob: Hit object. * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). */ diff --git a/source/blender/editors/util/ed_draw.c b/source/blender/editors/util/ed_draw.c index 3b543cdf6ce..159d750da4e 100644 --- a/source/blender/editors/util/ed_draw.c +++ b/source/blender/editors/util/ed_draw.c @@ -33,6 +33,8 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "BKE_context.h" #include "BKE_image.h" @@ -56,6 +58,464 @@ #include "WM_api.h" #include "WM_types.h" +/* -------------------------------------------------------------------- */ +/** \name Generic Slider + * + * The generic slider is supposed to be called during modal operations. It calculates a factor + * value based on mouse position and draws a visual representation. In order to use it, you need to + * store a reference to a tSlider in your operator which you get by calling "ED_slider_create". + * Then you need to update it during modal operations by calling "ED_slider_modal", which will + * update tSlider->factor for you to use. To remove drawing and free the memory, call + * "ED_slider_destroy". + * \{ */ + +#define SLIDE_PIXEL_DISTANCE (300.0f * U.dpi_fac) +#define OVERSHOOT_RANGE_DELTA 0.2f + +typedef struct tSlider { + struct Scene *scene; + struct ScrArea *area; + /* Header of the region used for drawing the slider. */ + struct ARegion *region_header; + + /* Draw callback handler. */ + void *draw_handle; + + /* Accumulative, unclamped and unrounded factor. */ + float raw_factor; + + /** 0-1 value for determining the influence of whatever is relevant. */ + float factor; + + /* Last mouse cursor position used for mouse movement delta calculation. */ + float last_cursor[2]; + + /* Enable range beyond 0-100%. */ + bool allow_overshoot; + + /* Allow overshoot or clamp between 0% and 100%. */ + bool overshoot; + + /* Move factor in 10% steps. */ + bool increments; + + /* Reduces factor delta from mouse movement. */ + bool precision; +} tSlider; + +static void draw_overshoot_triangle(const uint8_t color[4], + const bool facing_right, + const float x, + const float y) +{ + const uint shdr_pos_2d = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + GPU_blend(GPU_BLEND_ALPHA); + GPU_polygon_smooth(true); + immUniformColor3ubvAlpha(color, 225); + const float triangle_side_length = facing_right ? 6 * U.pixelsize : -6 * U.pixelsize; + const float triangle_offset = facing_right ? 2 * U.pixelsize : -2 * U.pixelsize; + + immBegin(GPU_PRIM_TRIS, 3); + immVertex2f(shdr_pos_2d, x + triangle_offset + triangle_side_length, y); + immVertex2f(shdr_pos_2d, x + triangle_offset, y + triangle_side_length / 2); + immVertex2f(shdr_pos_2d, x + triangle_offset, y - triangle_side_length / 2); + immEnd(); + + GPU_polygon_smooth(false); + GPU_blend(GPU_BLEND_NONE); + immUnbindProgram(); +} + +static void draw_ticks(const float start_factor, + const float end_factor, + const float line_start[2], + const float base_tick_height, + const float line_width, + const uint8_t color_overshoot[4], + const uint8_t color_line[4]) +{ + /* Use factor represented as 0-100 int to avoid floating point precision problems. */ + const int tick_increment = 10; + + /* Round initial_tick_factor up to the next tick_increment. */ + int tick_percentage = ceil((start_factor * 100) / tick_increment) * tick_increment; + + while (tick_percentage <= (int)(end_factor * 100)) { + float tick_height; + /* Different ticks have different heights. Multiples of 100% are the tallest, 50% is a bit + * smaller and the rest is the minimum size. */ + if (tick_percentage % 100 == 0) { + tick_height = base_tick_height; + } + else if (tick_percentage % 50 == 0) { + tick_height = base_tick_height * 0.8; + } + else { + tick_height = base_tick_height * 0.5; + } + + const float x = line_start[0] + + (((float)tick_percentage / 100) - start_factor) * SLIDE_PIXEL_DISTANCE; + const rctf tick_rect = { + .xmin = x - (line_width / 2), + .xmax = x + (line_width / 2), + .ymin = line_start[1] - (tick_height / 2), + .ymax = line_start[1] + (tick_height / 2), + }; + + if (tick_percentage < 0 || tick_percentage > 100) { + UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_overshoot, 255); + } + else { + UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_line, 255); + } + tick_percentage += tick_increment; + } +} + +static void draw_main_line(const rctf *main_line_rect, + const float factor, + const bool overshoot, + const uint8_t color_overshoot[4], + const uint8_t color_line[4]) +{ + if (overshoot) { + /* In overshoot mode, draw the 0-100% range differently to provide a visual reference. */ + const float line_zero_percent = main_line_rect->xmin - + ((factor - 0.5f - OVERSHOOT_RANGE_DELTA) * + SLIDE_PIXEL_DISTANCE); + + const float clamped_line_zero_percent = clamp_f( + line_zero_percent, main_line_rect->xmin, main_line_rect->xmax); + const float clamped_line_hundred_percent = clamp_f( + line_zero_percent + SLIDE_PIXEL_DISTANCE, main_line_rect->xmin, main_line_rect->xmax); + + const rctf left_overshoot_line_rect = { + .xmin = main_line_rect->xmin, + .xmax = clamped_line_zero_percent, + .ymin = main_line_rect->ymin, + .ymax = main_line_rect->ymax, + }; + const rctf right_overshoot_line_rect = { + .xmin = clamped_line_hundred_percent, + .xmax = main_line_rect->xmax, + .ymin = main_line_rect->ymin, + .ymax = main_line_rect->ymax, + }; + UI_draw_roundbox_3ub_alpha(&left_overshoot_line_rect, true, 0, color_overshoot, 255); + UI_draw_roundbox_3ub_alpha(&right_overshoot_line_rect, true, 0, color_overshoot, 255); + + const rctf non_overshoot_line_rect = { + .xmin = clamped_line_zero_percent, + .xmax = clamped_line_hundred_percent, + .ymin = main_line_rect->ymin, + .ymax = main_line_rect->ymax, + }; + UI_draw_roundbox_3ub_alpha(&non_overshoot_line_rect, true, 0, color_line, 255); + } + else { + UI_draw_roundbox_3ub_alpha(main_line_rect, true, 0, color_line, 255); + } +} + +static void draw_backdrop(const int fontid, + const rctf *main_line_rect, + const float color_bg[4], + const short region_y_size, + const float base_tick_height) +{ + float string_pixel_size[2]; + const char *percentage_string_placeholder = "000%%"; + BLF_width_and_height(fontid, + percentage_string_placeholder, + sizeof(percentage_string_placeholder), + &string_pixel_size[0], + &string_pixel_size[1]); + const float pad[2] = {(region_y_size - base_tick_height) / 2, 2.0f * U.pixelsize}; + const rctf backdrop_rect = { + .xmin = main_line_rect->xmin - string_pixel_size[0] - pad[0], + .xmax = main_line_rect->xmax + pad[0], + .ymin = pad[1], + .ymax = region_y_size - pad[1], + }; + UI_draw_roundbox_aa(&backdrop_rect, true, 4.0f, color_bg); +} + +/* Draw an on screen Slider for a Pose Slide Operator. */ +static void slider_draw(const struct bContext *UNUSED(C), ARegion *region, void *arg) +{ + tSlider *slider = arg; + + /* Only draw in region from which the Operator was started. */ + if (region != slider->region_header) { + return; + } + + uint8_t color_text[4]; + uint8_t color_line[4]; + uint8_t color_handle[4]; + uint8_t color_overshoot[4]; + float color_bg[4]; + + /* Get theme colors. */ + UI_GetThemeColor4ubv(TH_TEXT, color_text); + UI_GetThemeColor4ubv(TH_TEXT, color_line); + UI_GetThemeColor4ubv(TH_TEXT, color_overshoot); + UI_GetThemeColor4ubv(TH_ACTIVE, color_handle); + UI_GetThemeColor3fv(TH_BACK, color_bg); + + color_bg[3] = 0.5f; + color_overshoot[0] = color_overshoot[0] * 0.7; + color_overshoot[1] = color_overshoot[1] * 0.7; + color_overshoot[2] = color_overshoot[2] * 0.7; + + /* Get the default font. */ + const uiStyle *style = UI_style_get(); + const uiFontStyle *fstyle = &style->widget; + const int fontid = fstyle->uifont_id; + BLF_color3ubv(fontid, color_text); + BLF_rotation(fontid, 0.0f); + + const float line_width = 1.5 * U.pixelsize; + const float base_tick_height = 12.0 * U.pixelsize; + const float line_y = region->winy / 2; + + rctf main_line_rect = { + .xmin = (region->winx / 2) - (SLIDE_PIXEL_DISTANCE / 2), + .xmax = (region->winx / 2) + (SLIDE_PIXEL_DISTANCE / 2), + .ymin = line_y - line_width / 2, + .ymax = line_y + line_width / 2, + }; + float line_start_factor = 0; + int handle_pos_x = main_line_rect.xmin + SLIDE_PIXEL_DISTANCE * slider->factor; + + if (slider->overshoot) { + main_line_rect.xmin = main_line_rect.xmin - SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA; + main_line_rect.xmax = main_line_rect.xmax + SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA; + line_start_factor = slider->factor - 0.5f - OVERSHOOT_RANGE_DELTA; + handle_pos_x = region->winx / 2; + } + + draw_backdrop(fontid, &main_line_rect, color_bg, slider->region_header->winy, base_tick_height); + + draw_main_line(&main_line_rect, slider->factor, slider->overshoot, color_overshoot, color_line); + + const float factor_range = slider->overshoot ? 1 + OVERSHOOT_RANGE_DELTA * 2 : 1; + const float line_start_position[2] = {main_line_rect.xmin, line_y}; + draw_ticks(line_start_factor, + line_start_factor + factor_range, + line_start_position, + base_tick_height, + line_width, + color_overshoot, + color_line); + + /* Draw triangles at the ends of the line in overshoot mode to indicate direction of 0-100% + * range. */ + if (slider->overshoot) { + if (slider->factor > 1 + OVERSHOOT_RANGE_DELTA + 0.5) { + draw_overshoot_triangle(color_line, false, main_line_rect.xmin, line_y); + } + if (slider->factor < 0 - OVERSHOOT_RANGE_DELTA - 0.5) { + draw_overshoot_triangle(color_line, true, main_line_rect.xmax, line_y); + } + } + + char percentage_string[256]; + + /* Draw handle indicating current factor. */ + const rctf handle_rect = { + .xmin = handle_pos_x - (line_width), + .xmax = handle_pos_x + (line_width), + .ymin = line_y - (base_tick_height / 2), + .ymax = line_y + (base_tick_height / 2), + }; + + UI_draw_roundbox_3ub_alpha(&handle_rect, true, 1, color_handle, 255); + BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", slider->factor * 100); + + /* Draw percentage string. */ + float percentage_string_pixel_size[2]; + BLF_width_and_height(fontid, + percentage_string, + sizeof(percentage_string), + &percentage_string_pixel_size[0], + &percentage_string_pixel_size[1]); + + BLF_position(fontid, + main_line_rect.xmin - 24.0 * U.pixelsize - percentage_string_pixel_size[0] / 2, + (region->winy / 2) - percentage_string_pixel_size[1] / 2, + 0.0f); + BLF_draw(fontid, percentage_string, sizeof(percentage_string)); +} + +static void slider_update_factor(tSlider *slider, const wmEvent *event) +{ + const float factor_delta = (event->x - slider->last_cursor[0]) / SLIDE_PIXEL_DISTANCE; + /* Reduced factor delta in precision mode (shift held). */ + slider->raw_factor += slider->precision ? (factor_delta / 8) : factor_delta; + slider->factor = slider->raw_factor; + slider->last_cursor[0] = event->x; + slider->last_cursor[1] = event->y; + + if (!slider->overshoot) { + slider->factor = clamp_f(slider->factor, 0, 1); + } + + if (slider->increments) { + slider->factor = round(slider->factor * 10) / 10; + } +} + +tSlider *ED_slider_create(struct bContext *C) +{ + tSlider *slider = MEM_callocN(sizeof(tSlider), "tSlider"); + slider->scene = CTX_data_scene(C); + slider->area = CTX_wm_area(C); + slider->region_header = CTX_wm_region(C); + + /* Default is true, caller needs to manually set to false. */ + slider->allow_overshoot = true; + + /* Set initial factor. */ + slider->raw_factor = 0.5f; + slider->factor = 0.5; + + /* Add draw callback. Always in header. */ + LISTBASE_FOREACH (ARegion *, region, &slider->area->regionbase) { + if (region->regiontype == RGN_TYPE_HEADER) { + slider->region_header = region; + slider->draw_handle = ED_region_draw_cb_activate( + region->type, slider_draw, slider, REGION_DRAW_POST_PIXEL); + } + } + + return slider; +} + +/* For modal operations so the percentage doesn't pop on the first mouse movement. */ +void ED_slider_init(struct tSlider *slider, const wmEvent *event) +{ + slider->last_cursor[0] = event->x; + slider->last_cursor[1] = event->y; +} + +/* Calculate slider factor based on mouse position. */ +bool ED_slider_modal(tSlider *slider, const wmEvent *event) +{ + bool event_handled = true; + /* Handle key presses. */ + switch (event->type) { + case EVT_EKEY: + if (slider->allow_overshoot) { + slider->overshoot = event->val == KM_PRESS ? !slider->overshoot : slider->overshoot; + slider_update_factor(slider, event); + } + break; + case EVT_LEFTSHIFTKEY: + case EVT_RIGHTSHIFTKEY: + slider->precision = event->val == KM_PRESS; + break; + case EVT_LEFTCTRLKEY: + case EVT_RIGHTCTRLKEY: + slider->increments = event->val == KM_PRESS; + break; + case MOUSEMOVE:; + /* Update factor. */ + slider_update_factor(slider, event); + break; + default: + event_handled = false; + break; + } + + ED_region_tag_redraw(slider->region_header); + + return event_handled; +} + +/* Return string based on the current state of the slider. */ +void ED_slider_status_string_get(const struct tSlider *slider, + char *status_string, + const size_t size_of_status_string) +{ + /* 50 characters is enough to fit the individual setting strings. Extend if message is longer. */ + char overshoot_str[50]; + char precision_str[50]; + char increments_str[50]; + + if (slider->allow_overshoot) { + if (slider->overshoot) { + STRNCPY(overshoot_str, TIP_("[E] - Disable overshoot")); + } + else { + STRNCPY(overshoot_str, TIP_("[E] - Enable overshoot")); + } + } + else { + STRNCPY(overshoot_str, TIP_("Overshoot disabled")); + } + + if (slider->precision) { + STRNCPY(precision_str, TIP_("[Shift] - Precision active")); + } + else { + STRNCPY(precision_str, TIP_("Shift - Hold for precision")); + } + + if (slider->increments) { + STRNCPY(increments_str, TIP_("[Ctrl] - Increments active")); + } + else { + STRNCPY(increments_str, TIP_("Ctrl - Hold for 10% increments")); + } + + BLI_snprintf(status_string, + size_of_status_string, + "%s | %s | %s", + overshoot_str, + precision_str, + increments_str); +} + +void ED_slider_destroy(struct bContext *C, tSlider *slider) +{ + /* Remove draw callback. */ + ED_region_draw_cb_exit(slider->region_header->type, slider->draw_handle); + ED_area_status_text(slider->area, NULL); + ED_workspace_status_text(C, NULL); + MEM_freeN(slider); +} + +/* Setters & Getters */ + +float ED_slider_factor_get(struct tSlider *slider) +{ + return slider->factor; +} + +void ED_slider_factor_set(struct tSlider *slider, const float factor) +{ + slider->factor = factor; + if (!slider->overshoot) { + slider->factor = clamp_f(slider->factor, 0, 1); + } +} + +bool ED_slider_allow_overshoot_get(struct tSlider *slider) +{ + return slider->allow_overshoot; +} + +void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value) +{ + slider->allow_overshoot = value; +} + +/** \} */ + /** * Callback that draws a line between the mouse and a position given as the initial argument. */ diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index 7709b76290f..20aadb84b7b 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -1126,7 +1126,7 @@ static void uv_select_edgeloop_single_side_tag(const Scene *scene, while (l_step != NULL) { if (!uvedit_face_visible_test(scene, l_step->f) || - /* Check the boundary is still a boundary. */ + /* Check the boundary is still a boundary. */ (uvedit_loop_find_other_radial_loop_with_visible_face( scene, l_step, cd_loop_uv_offset) != NULL)) { break; diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index b40e50851c3..535a0e00347 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -1928,6 +1928,11 @@ static StitchState *stitch_init(bContext *C, state->obedit = obedit; state->em = em; + /* Workaround for sync-select & face-select mode which implies all selected faces are detached, + * for stitch this isn't useful behavior, see T86924. */ + const int selectmode_orig = scene->toolsettings->selectmode; + scene->toolsettings->selectmode = SCE_SELECT_VERTEX; + /* in uv synch selection, all uv's are visible */ if (ts->uv_flag & UV_SYNC_SELECTION) { state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, false, true, true); @@ -1935,6 +1940,9 @@ static StitchState *stitch_init(bContext *C, else { state->element_map = BM_uv_element_map_create(state->em->bm, scene, true, false, true, true); } + + scene->toolsettings->selectmode = selectmode_orig; + if (!state->element_map) { state_delete(state); return NULL; diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp index 9c675c93a2e..0d243a812fa 100644 --- a/source/blender/freestyle/intern/application/Controller.cpp +++ b/source/blender/freestyle/intern/application/Controller.cpp @@ -707,7 +707,7 @@ void Controller::ComputeSteerableViewMap() for (unsigned int x = 0; x < img[i]->width(); ++x) { //img[i]->setPixel(x, y, (float)qGray(qimg.pixel(x, y)) / 255.0f); img[i]->setPixel(x, y, (float)qGray(qimg.pixel(x, y))); - //float c = qGray(qimg.pixel(x, y)); + // float c = qGray(qimg.pixel(x, y)); //img[i]->setPixel(x, y, qGray(qimg.pixel(x, y))); } } diff --git a/source/blender/freestyle/intern/geometry/FastGrid.cpp b/source/blender/freestyle/intern/geometry/FastGrid.cpp index 1e0ae06da19..0f1edd647c7 100644 --- a/source/blender/freestyle/intern/geometry/FastGrid.cpp +++ b/source/blender/freestyle/intern/geometry/FastGrid.cpp @@ -62,7 +62,7 @@ Cell *FastGrid::getCell(const Vec3u &p) << " " << _cells_size << endl; } #endif - BLI_assert(_cells || ("_cells is a null pointer")); + BLI_assert_msg(_cells, "_cells is a null pointer"); BLI_assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]) < _cells_size); BLI_assert(p[0] < _cells_nb[0]); BLI_assert(p[1] < _cells_nb[1]); @@ -72,7 +72,7 @@ Cell *FastGrid::getCell(const Vec3u &p) void FastGrid::fillCell(const Vec3u &p, Cell &cell) { - BLI_assert(_cells || ("_cells is a null pointer")); + BLI_assert_msg(_cells, "_cells is a null pointer"); BLI_assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]) < _cells_size); BLI_assert(p[0] < _cells_nb[0]); BLI_assert(p[1] < _cells_nb[1]); diff --git a/source/blender/freestyle/intern/view_map/Interface0D.h b/source/blender/freestyle/intern/view_map/Interface0D.h index 065319578e5..d7b213706b5 100644 --- a/source/blender/freestyle/intern/view_map/Interface0D.h +++ b/source/blender/freestyle/intern/view_map/Interface0D.h @@ -311,13 +311,13 @@ class Interface0DIterator : public Iterator { return result; } - /** operator == . */ + /** operator `==`. */ bool operator==(const Interface0DIterator &it) const { return _iterator->operator==(*(it._iterator)); } - /** operator != . */ + /** operator `!=`. */ bool operator!=(const Interface0DIterator &it) const { return !(*this == it); diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h index 3709b0ae11a..479dbaeedc1 100644 --- a/source/blender/freestyle/intern/view_map/Silhouette.h +++ b/source/blender/freestyle/intern/view_map/Silhouette.h @@ -745,7 +745,7 @@ class FEdge : public Interface1D { _VertexB = vB; } - /** Sets the FEdge Id . */ + /** Sets the FEdge Id. */ inline void setId(const Id &id) { _Id = id; @@ -1153,7 +1153,7 @@ class FEdgeSharp : public FEdge { bool _bFaceMark; public: - /** Returns the string "FEdgeSharp" . */ + /** Returns the string "FEdgeSharp". */ virtual string getExactTypeName() const { return "FEdgeSharp"; @@ -1305,7 +1305,7 @@ class FEdgeSmooth : public FEdge { bool _FaceMark; public: - /** Returns the string "FEdgeSmooth" . */ + /** Returns the string "FEdgeSmooth". */ virtual string getExactTypeName() const { return "FEdgeSmooth"; diff --git a/source/blender/freestyle/intern/view_map/ViewMap.h b/source/blender/freestyle/intern/view_map/ViewMap.h index bd7edad7642..e7d57c9dfb4 100644 --- a/source/blender/freestyle/intern/view_map/ViewMap.h +++ b/source/blender/freestyle/intern/view_map/ViewMap.h @@ -477,10 +477,14 @@ class TVertex : public ViewVertex { directedViewEdge _FrontEdgeB; directedViewEdge _BackEdgeA; directedViewEdge _BackEdgeB; - Id _Id; // id to identify t vertices . these id will be negative in order not to be mixed with - // NonTVertex ids. - edge_pointers_container - _sortedEdges; // the list of the four ViewEdges, ordered in CCW order (in the image plan) + + /** + * ID to identify t vertices. + * these id will be negative in order not to be mixed with NonTVertex ids. + */ + Id _Id; + /** The list of the four ViewEdges, ordered in CCW order (in the image plan). */ + edge_pointers_container _sortedEdges; public: /** Default constructor. */ diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp index 478e48de66c..f052f1af104 100644 --- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp +++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp @@ -371,29 +371,29 @@ void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, V } e = *itE; - /* since this vertex passed the tests in gts_vertex_mean_curvature_normal(), this should be - * true. */ + /* Since this vertex passed the tests in gts_vertex_mean_curvature_normal(), + this should be true. */ // g_assert(gts_edge_face_number (e, s) == 2); - /* identify the two triangles bordering e in s */ + /* Identify the two triangles bordering e in s. */ f1 = e->GetaFace(); f2 = e->GetbFace(); /* We are solving for the values of the curvature tensor - * B = [ a b ; b c ]. - * The computations here are from section 5 of [Meyer et al 2002]. + * `B = [ a b ; b c ]`. + * The computations here are from section 5 of [Meyer et al 2002]. * - * The first step is to calculate the linear equations governing the values of (a,b,c). These + * The first step is to calculate the linear equations governing the values of (a,b,c). These * can be computed by setting the derivatives of the error E to zero (section 5.3). * - * Since a + c = norm(Kh), we only compute the linear equations for dE/da and dE/db. (NB: - * [Meyer et al 2002] has the equation a + b = norm(Kh), but I'm almost positive this is - * incorrect). + * Since a + c = norm(Kh), we only compute the linear equations for `dE/da` and `dE/db`. + * (NOTE: [Meyer et al 2002] has the equation `a + b = norm(Kh)`, + * but I'm almost positive this is incorrect). * - * Note that the w_ij (defined in section 5.2) are all scaled by (1/8*A_mixed). We drop this + * Note that the w_ij (defined in section 5.2) are all scaled by `(1/8*A_mixed)`. We drop this * uniform scale factor because the solution of the linear equations doesn't rely on it. * - * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are + * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are * also const_dy terms that are the constant factors in the equations. */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c index a156fca5b7b..a79e212b9db 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c @@ -9,7 +9,7 @@ * 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, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c index fcc44aab583..bc6a9e53f11 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c @@ -432,6 +432,19 @@ static void occlusion_panel_draw(const bContext *UNUSED(C), Panel *panel) } } +static bool anything_showing_through(PointerRNA *ptr) +{ + const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels"); + const int level_start = RNA_int_get(ptr, "level_start"); + const int level_end = RNA_int_get(ptr, "level_end"); + if (use_multiple_levels) { + return (MAX2(level_start, level_end) > 0); + } + else { + return (level_start > 0); + } +} + static void material_mask_panel_draw_header(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; @@ -439,6 +452,7 @@ static void material_mask_panel_draw_header(const bContext *UNUSED(C), Panel *pa const bool is_baked = RNA_boolean_get(ptr, "is_baked"); uiLayoutSetEnabled(layout, !is_baked); + uiLayoutSetActive(layout, anything_showing_through(ptr)); uiItemR(layout, ptr, "use_material_mask", 0, IFACE_("Material Mask"), ICON_NONE); } @@ -450,24 +464,24 @@ static void material_mask_panel_draw(const bContext *UNUSED(C), Panel *panel) const bool is_baked = RNA_boolean_get(ptr, "is_baked"); uiLayoutSetEnabled(layout, !is_baked); + uiLayoutSetActive(layout, anything_showing_through(ptr)); uiLayoutSetPropSep(layout, true); uiLayoutSetEnabled(layout, RNA_boolean_get(ptr, "use_material_mask")); - uiLayout *row = uiLayoutRow(layout, true); - uiLayoutSetPropDecorate(row, false); - uiLayout *sub = uiLayoutRowWithHeading(row, true, IFACE_("Masks")); - char text[2] = "0"; + uiLayout *col = uiLayoutColumn(layout, true); + uiLayout *sub = uiLayoutRowWithHeading(col, true, IFACE_("Masks")); PropertyRNA *prop = RNA_struct_find_property(ptr, "use_material_mask_bits"); - for (int i = 0; i < 8; i++, text[0]++) { - uiItemFullR(sub, ptr, prop, i, 0, UI_ITEM_R_TOGGLE, text, ICON_NONE); + for (int i = 0; i < 8; i++) { + uiItemFullR(sub, ptr, prop, i, 0, UI_ITEM_R_TOGGLE, " ", ICON_NONE); + if (i == 3) { + sub = uiLayoutRow(col, true); + } } - uiItemL(row, "", ICON_BLANK1); /* Space for decorator. */ - uiLayout *col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_material_mask_match", 0, IFACE_("Match All Masks"), ICON_NONE); + uiItemR(layout, ptr, "use_material_mask_match", 0, IFACE_("Exact Match"), ICON_NONE); } static void intersection_panel_draw(const bContext *UNUSED(C), Panel *panel) @@ -482,19 +496,18 @@ static void intersection_panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_intersection")); - uiLayout *row = uiLayoutRow(layout, true); - uiLayoutSetPropDecorate(row, false); - uiLayout *sub = uiLayoutRowWithHeading(row, true, IFACE_("Masks")); - char text[2] = "0"; + uiLayout *col = uiLayoutColumn(layout, true); + uiLayout *sub = uiLayoutRowWithHeading(col, true, IFACE_("Collection Masks")); PropertyRNA *prop = RNA_struct_find_property(ptr, "use_intersection_mask"); - for (int i = 0; i < 8; i++, text[0]++) { - uiItemFullR(sub, ptr, prop, i, 0, UI_ITEM_R_TOGGLE, text, ICON_NONE); + for (int i = 0; i < 8; i++) { + uiItemFullR(sub, ptr, prop, i, 0, UI_ITEM_R_TOGGLE, " ", ICON_NONE); + if (i == 3) { + sub = uiLayoutRow(col, true); + } } - uiItemL(row, "", ICON_BLANK1); /* Space for decorator. */ - uiLayout *col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_intersection_match", 0, IFACE_("Match All Masks"), ICON_NONE); + uiItemR(layout, ptr, "use_intersection_match", 0, IFACE_("Exact Match"), ICON_NONE); } static void face_mark_panel_draw_header(const bContext *UNUSED(C), Panel *panel) { @@ -566,7 +579,7 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(col, ptr, "use_fuzzy_all", 0, NULL, ICON_NONE); uiItemR(col, ptr, "use_loose_edge_chain", 0, IFACE_("Loose Edges"), ICON_NONE); uiItemR(col, ptr, "use_loose_as_contour", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "use_geometry_space_chain", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_geometry_space_chain", 0, IFACE_("Geometry Space"), ICON_NONE); uiItemR(layout, ptr, diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 82fd85f5c65..83abac201d0 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -1803,10 +1803,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu tri->material_mask_bits |= ((mat && (mat->lineart.flags & LRT_MATERIAL_MASK_ENABLED)) ? mat->lineart.material_mask_bits : 0); - tri->mat_occlusion |= ((mat && - (mat->lineart.flags & LRT_MATERIAL_CUSTOM_OCCLUSION_EFFECTIVENESS)) ? - mat->lineart.mat_occlusion : - 1); + tri->mat_occlusion |= (mat ? mat->lineart.mat_occlusion : 1); tri->intersection_mask = obi->override_intersection_mask; @@ -2125,7 +2122,7 @@ static void lineart_main_load_geometries( Object *use_ob = DEG_get_evaluated_object(depsgraph, ob); /* Prepare the matrix used for transforming this specific object (instance). This has to be - * done before mesh boundbox check because the function needs that. */ + * done before mesh boundbox check because the function needs that. */ mul_m4db_m4db_m4fl_uniq(obi->model_view_proj, rb->view_projection, ob->obmat); mul_m4db_m4db_m4fl_uniq(obi->model_view, rb->view, ob->obmat); @@ -2156,7 +2153,7 @@ static void lineart_main_load_geometries( obi->free_use_mesh = true; } - /* Make normal matrix. */ + /* Make normal matrix. */ float imat[4][4]; invert_m4_m4(imat, ob->obmat); transpose_m4(imat); diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h index e3a566e5f21..0d5388c6b82 100644 --- a/source/blender/gpu/GPU_vertex_format.h +++ b/source/blender/gpu/GPU_vertex_format.h @@ -127,7 +127,7 @@ BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format, } /* WARNING: Can only rename using a string with same character count. - * WARNING: This removes all other aliases of this attrib */ + * WARNING: This removes all other aliases of this attribute. */ void GPU_vertformat_attr_rename(GPUVertFormat *format, int attr, const char *new_name); void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len); diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index 9dc24c59e22..677777132e6 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -184,7 +184,7 @@ int GPU_batch_instbuf_add_ex(GPUBatch *batch, GPUVertBuf *insts, bool own_vbo) } } /* we only make it this far if there is no room for another GPUVertBuf */ - BLI_assert(0 && "Not enough Instance VBO slot in batch"); + BLI_assert_msg(0, "Not enough Instance VBO slot in batch"); return -1; } @@ -207,7 +207,7 @@ int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo) } } /* we only make it this far if there is no room for another GPUVertBuf */ - BLI_assert(0 && "Not enough VBO slot in batch"); + BLI_assert_msg(0, "Not enough VBO slot in batch"); return -1; } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index d12cecd129e..bb1ebc0e85d 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -657,7 +657,7 @@ static const char *attr_prefix_get(CustomDataType type) case CD_AUTO_FROM_NAME: return "a"; default: - BLI_assert(false && "GPUVertAttr Prefix type not found : This should not happen!"); + BLI_assert_msg(0, "GPUVertAttr Prefix type not found : This should not happen!"); return ""; } } diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index 1293cc0953d..a6f7d43e563 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -495,7 +495,7 @@ void GPU_framebuffer_py_reference_set(GPUFrameBuffer *gpu_fb, void **py_ref) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Frame-Buffer Stack +/** \name Frame-Buffer Stack * * Keeps track of frame-buffer binding operation to restore previously bound frame-buffers. * \{ */ @@ -609,7 +609,13 @@ GPUOffScreen *GPU_offscreen_create( } if ((depth && !ofs->depth) || !ofs->color) { - BLI_snprintf(err_out, 256, "GPUTexture: Texture allocation failed."); + const char error[] = "GPUTexture: Texture allocation failed."; + if (err_out) { + BLI_snprintf(err_out, 256, error); + } + else { + fprintf(stderr, error); + } GPU_offscreen_free(ofs); return nullptr; } diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh index 2b8a5a5cc12..26be6f57312 100644 --- a/source/blender/gpu/intern/gpu_texture_private.hh +++ b/source/blender/gpu/intern/gpu_texture_private.hh @@ -316,7 +316,7 @@ inline size_t to_bytesize(eGPUTextureFormat format) case GPU_RGBA8_DXT5: return 1; /* Incorrect but actual size is fractional. */ default: - BLI_assert(!"Texture format incorrect or unsupported\n"); + BLI_assert_msg(0, "Texture format incorrect or unsupported"); return 0; } } @@ -333,7 +333,7 @@ inline size_t to_block_size(eGPUTextureFormat data_type) case GPU_RGBA8_DXT5: return 16; default: - BLI_assert(!"Texture format is not a compressed format\n"); + BLI_assert_msg(0, "Texture format is not a compressed format"); return 0; } } @@ -407,7 +407,7 @@ inline size_t to_bytesize(eGPUDataFormat data_format) case GPU_DATA_2_10_10_10_REV: return 4; default: - BLI_assert(!"Data format incorrect or unsupported\n"); + BLI_assert_msg(0, "Data format incorrect or unsupported"); return 0; } } @@ -503,7 +503,7 @@ inline eGPUFrameBufferBits to_framebuffer_bits(eGPUTextureFormat tex_format) static inline eGPUTextureFormat to_texture_format(const GPUVertFormat *format) { if (format->attr_len > 1 || format->attr_len == 0) { - BLI_assert(!"Incorrect vertex format for buffer texture"); + BLI_assert_msg(0, "Incorrect vertex format for buffer texture"); return GPU_DEPTH_COMPONENT24; } switch (format->attrs[0].comp_len) { @@ -584,7 +584,7 @@ static inline eGPUTextureFormat to_texture_format(const GPUVertFormat *format) default: break; } - BLI_assert(!"Unsupported vertex format for buffer texture"); + BLI_assert_msg(0, "Unsupported vertex format for buffer texture"); return GPU_DEPTH_COMPONENT24; } diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc index 9cf072b2e8a..9900a4e0766 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.cc +++ b/source/blender/gpu/opengl/gl_shader_interface.cc @@ -170,7 +170,7 @@ GLShaderInterface::GLShaderInterface(GLuint program) program, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &max_ssbo_name_len); } - BLI_assert(ubo_len <= 16 && "enabled_ubo_mask_ is uint16_t"); + BLI_assert_msg(ubo_len <= 16, "enabled_ubo_mask_ is uint16_t"); /* Work around driver bug with Intel HD 4600 on Windows 7/8, where * GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */ diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh index dc048ea05c0..2a480e71017 100644 --- a/source/blender/gpu/opengl/gl_texture.hh +++ b/source/blender/gpu/opengl/gl_texture.hh @@ -192,7 +192,7 @@ inline GLenum to_gl_internal_format(eGPUTextureFormat format) case GPU_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT16; default: - BLI_assert(!"Texture format incorrect or unsupported\n"); + BLI_assert_msg(0, "Texture format incorrect or unsupported"); return 0; } } @@ -287,7 +287,7 @@ inline GLenum to_gl(eGPUDataFormat format) case GPU_DATA_10_11_11_REV: return GL_UNSIGNED_INT_10F_11F_11F_REV; default: - BLI_assert(!"Unhandled data format"); + BLI_assert_msg(0, "Unhandled data format"); return GL_FLOAT; } } @@ -359,7 +359,7 @@ inline GLenum to_gl_data_format(eGPUTextureFormat format) case GPU_RGBA8_DXT5: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; default: - BLI_assert(!"Texture format incorrect or unsupported\n"); + BLI_assert_msg(0, "Texture format incorrect or unsupported\n"); return 0; } } @@ -377,7 +377,7 @@ inline GLenum channel_len_to_gl(int channel_len) case 4: return GL_RGBA; default: - BLI_assert(!"Wrong number of texture channels"); + BLI_assert_msg(0, "Wrong number of texture channels"); return GL_RED; } } diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc index ea2770f099d..e324916b934 100644 --- a/source/blender/gpu/opengl/gl_vertex_array.cc +++ b/source/blender/gpu/opengl/gl_vertex_array.cc @@ -108,7 +108,7 @@ static uint16_t vbo_bind(const ShaderInterface *interface, return enabled_attrib; } -/* Update the Attrib Binding of the currently bound VAO. */ +/* Update the Attribute Binding of the currently bound VAO. */ void GLVertArray::update_bindings(const GLuint vao, const GPUBatch *batch_, /* Should be GLBatch. */ const ShaderInterface *interface, diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c index e62473fb8c7..59a17fcc600 100644 --- a/source/blender/imbuf/intern/iris.c +++ b/source/blender/imbuf/intern/iris.c @@ -39,7 +39,7 @@ #define IMAGIC 0732 typedef struct { - ushort imagic; /* stuff saved on disk . . */ + ushort imagic; /* Stuff saved on disk. */ ushort type; ushort dim; ushort xsize; diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp index 0941338160d..3ad902a241d 100644 --- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp +++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp @@ -28,7 +28,7 @@ # define _USE_MATH_DEFINES #endif -// NOTE: Keep first, BLI_path_util conflicts with OIIO's format. +/* NOTE: Keep first, #BLI_path_util conflicts with OIIO's format. */ #include "openimageio_api.h" #include <OpenImageIO/imageio.h> #include <memory> diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index ab578e25b94..d1fa26e1a3e 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -1705,7 +1705,7 @@ static void exr_print_filecontents(MultiPartInputFile &file) } } -/* for non-multilayer, map R G B A channel names to something that's in this file */ +/* For non-multi-layer, map R G B A channel names to something that's in this file. */ static const char *exr_rgba_channelname(MultiPartInputFile &file, const char *chan) { const ChannelList &channels = file.header(0).channels(); diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index 4a964c64917..1c4b7af6ef1 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -867,7 +867,7 @@ static void q_scale_float( * * only handles common cases when we either * - * scale both, x and y or + * scale both, x and y or * shrink both, x and y * * but that is pretty fast: @@ -1195,22 +1195,9 @@ static ImBuf *scaleupx(struct ImBuf *ibuf, int newx) { uchar *rect, *_newrect = NULL, *newrect; float *rectf, *_newrectf = NULL, *newrectf; - float sample, add; - float val_a, nval_a, diff_a; - float val_b, nval_b, diff_b; - float val_g, nval_g, diff_g; - float val_r, nval_r, diff_r; - float val_af, nval_af, diff_af; - float val_bf, nval_bf, diff_bf; - float val_gf, nval_gf, diff_gf; - float val_rf, nval_rf, diff_rf; int x, y; bool do_rect = false, do_float = false; - val_a = nval_a = diff_a = val_b = nval_b = diff_b = 0; - val_g = nval_g = diff_g = val_r = nval_r = diff_r = 0; - val_af = nval_af = diff_af = val_bf = nval_bf = diff_bf = 0; - val_gf = nval_gf = diff_gf = val_rf = nval_rf = diff_rf = 0; if (ibuf == NULL) { return NULL; } @@ -1236,119 +1223,158 @@ static ImBuf *scaleupx(struct ImBuf *ibuf, int newx) } } - add = (ibuf->x - 1.001) / (newx - 1.0); - rect = (uchar *)ibuf->rect; rectf = (float *)ibuf->rect_float; newrect = _newrect; newrectf = _newrectf; - for (y = ibuf->y; y > 0; y--) { - - sample = 0; - + /* Special case, copy all columns, needed since the scaling logic assumes there is at least + * two rows to interpolate between causing out of bounds read for 1px images, see T70356. */ + if (UNLIKELY(ibuf->x == 1)) { if (do_rect) { - val_a = rect[0]; - nval_a = rect[4]; - diff_a = nval_a - val_a; - val_a += 0.5f; - - val_b = rect[1]; - nval_b = rect[5]; - diff_b = nval_b - val_b; - val_b += 0.5f; - - val_g = rect[2]; - nval_g = rect[6]; - diff_g = nval_g - val_g; - val_g += 0.5f; - - val_r = rect[3]; - nval_r = rect[7]; - diff_r = nval_r - val_r; - val_r += 0.5f; - - rect += 8; + for (y = ibuf->y; y > 0; y--) { + for (x = newx; x > 0; x--) { + memcpy(newrect, rect, sizeof(char[4])); + newrect += 4; + } + rect += 4; + } } if (do_float) { - val_af = rectf[0]; - nval_af = rectf[4]; - diff_af = nval_af - val_af; + for (y = ibuf->y; y > 0; y--) { + for (x = newx; x > 0; x--) { + memcpy(newrectf, rectf, sizeof(float[4])); + newrectf += 4; + } + rectf += 4; + } + } + } + else { + const float add = (ibuf->x - 1.001) / (newx - 1.0); + float sample; - val_bf = rectf[1]; - nval_bf = rectf[5]; - diff_bf = nval_bf - val_bf; + float val_a, nval_a, diff_a; + float val_b, nval_b, diff_b; + float val_g, nval_g, diff_g; + float val_r, nval_r, diff_r; + float val_af, nval_af, diff_af; + float val_bf, nval_bf, diff_bf; + float val_gf, nval_gf, diff_gf; + float val_rf, nval_rf, diff_rf; - val_gf = rectf[2]; - nval_gf = rectf[6]; - diff_gf = nval_gf - val_gf; + val_a = nval_a = diff_a = val_b = nval_b = diff_b = 0; + val_g = nval_g = diff_g = val_r = nval_r = diff_r = 0; + val_af = nval_af = diff_af = val_bf = nval_bf = diff_bf = 0; + val_gf = nval_gf = diff_gf = val_rf = nval_rf = diff_rf = 0; - val_rf = rectf[3]; - nval_rf = rectf[7]; - diff_rf = nval_rf - val_rf; + for (y = ibuf->y; y > 0; y--) { - rectf += 8; - } - for (x = newx; x > 0; x--) { - if (sample >= 1.0f) { - sample -= 1.0f; + sample = 0; - if (do_rect) { - val_a = nval_a; - nval_a = rect[0]; - diff_a = nval_a - val_a; - val_a += 0.5f; - - val_b = nval_b; - nval_b = rect[1]; - diff_b = nval_b - val_b; - val_b += 0.5f; - - val_g = nval_g; - nval_g = rect[2]; - diff_g = nval_g - val_g; - val_g += 0.5f; - - val_r = nval_r; - nval_r = rect[3]; - diff_r = nval_r - val_r; - val_r += 0.5f; - rect += 4; - } - if (do_float) { - val_af = nval_af; - nval_af = rectf[0]; - diff_af = nval_af - val_af; + if (do_rect) { + val_a = rect[0]; + nval_a = rect[4]; + diff_a = nval_a - val_a; + val_a += 0.5f; + + val_b = rect[1]; + nval_b = rect[5]; + diff_b = nval_b - val_b; + val_b += 0.5f; + + val_g = rect[2]; + nval_g = rect[6]; + diff_g = nval_g - val_g; + val_g += 0.5f; + + val_r = rect[3]; + nval_r = rect[7]; + diff_r = nval_r - val_r; + val_r += 0.5f; + + rect += 8; + } + if (do_float) { + val_af = rectf[0]; + nval_af = rectf[4]; + diff_af = nval_af - val_af; - val_bf = nval_bf; - nval_bf = rectf[1]; - diff_bf = nval_bf - val_bf; + val_bf = rectf[1]; + nval_bf = rectf[5]; + diff_bf = nval_bf - val_bf; - val_gf = nval_gf; - nval_gf = rectf[2]; - diff_gf = nval_gf - val_gf; + val_gf = rectf[2]; + nval_gf = rectf[6]; + diff_gf = nval_gf - val_gf; - val_rf = nval_rf; - nval_rf = rectf[3]; - diff_rf = nval_rf - val_rf; - rectf += 4; - } - } - if (do_rect) { - newrect[0] = val_a + sample * diff_a; - newrect[1] = val_b + sample * diff_b; - newrect[2] = val_g + sample * diff_g; - newrect[3] = val_r + sample * diff_r; - newrect += 4; + val_rf = rectf[3]; + nval_rf = rectf[7]; + diff_rf = nval_rf - val_rf; + + rectf += 8; } - if (do_float) { - newrectf[0] = val_af + sample * diff_af; - newrectf[1] = val_bf + sample * diff_bf; - newrectf[2] = val_gf + sample * diff_gf; - newrectf[3] = val_rf + sample * diff_rf; - newrectf += 4; + for (x = newx; x > 0; x--) { + if (sample >= 1.0f) { + sample -= 1.0f; + + if (do_rect) { + val_a = nval_a; + nval_a = rect[0]; + diff_a = nval_a - val_a; + val_a += 0.5f; + + val_b = nval_b; + nval_b = rect[1]; + diff_b = nval_b - val_b; + val_b += 0.5f; + + val_g = nval_g; + nval_g = rect[2]; + diff_g = nval_g - val_g; + val_g += 0.5f; + + val_r = nval_r; + nval_r = rect[3]; + diff_r = nval_r - val_r; + val_r += 0.5f; + rect += 4; + } + if (do_float) { + val_af = nval_af; + nval_af = rectf[0]; + diff_af = nval_af - val_af; + + val_bf = nval_bf; + nval_bf = rectf[1]; + diff_bf = nval_bf - val_bf; + + val_gf = nval_gf; + nval_gf = rectf[2]; + diff_gf = nval_gf - val_gf; + + val_rf = nval_rf; + nval_rf = rectf[3]; + diff_rf = nval_rf - val_rf; + rectf += 4; + } + } + if (do_rect) { + newrect[0] = val_a + sample * diff_a; + newrect[1] = val_b + sample * diff_b; + newrect[2] = val_g + sample * diff_g; + newrect[3] = val_r + sample * diff_r; + newrect += 4; + } + if (do_float) { + newrectf[0] = val_af + sample * diff_af; + newrectf[1] = val_bf + sample * diff_bf; + newrectf[2] = val_gf + sample * diff_gf; + newrectf[3] = val_rf + sample * diff_rf; + newrectf += 4; + } + sample += add; } - sample += add; } } @@ -1371,22 +1397,9 @@ static ImBuf *scaleupy(struct ImBuf *ibuf, int newy) { uchar *rect, *_newrect = NULL, *newrect; float *rectf, *_newrectf = NULL, *newrectf; - float sample, add; - float val_a, nval_a, diff_a; - float val_b, nval_b, diff_b; - float val_g, nval_g, diff_g; - float val_r, nval_r, diff_r; - float val_af, nval_af, diff_af; - float val_bf, nval_bf, diff_bf; - float val_gf, nval_gf, diff_gf; - float val_rf, nval_rf, diff_rf; int x, y, skipx; bool do_rect = false, do_float = false; - val_a = nval_a = diff_a = val_b = nval_b = diff_b = 0; - val_g = nval_g = diff_g = val_r = nval_r = diff_r = 0; - val_af = nval_af = diff_af = val_bf = nval_bf = diff_bf = 0; - val_gf = nval_gf = diff_gf = val_rf = nval_rf = diff_rf = 0; if (ibuf == NULL) { return NULL; } @@ -1412,126 +1425,159 @@ static ImBuf *scaleupy(struct ImBuf *ibuf, int newy) } } - add = (ibuf->y - 1.001) / (newy - 1.0); - skipx = 4 * ibuf->x; - rect = (uchar *)ibuf->rect; rectf = (float *)ibuf->rect_float; newrect = _newrect; newrectf = _newrectf; - for (x = ibuf->x; x > 0; x--) { + skipx = 4 * ibuf->x; - sample = 0; + /* Special case, copy all rows, needed since the scaling logic assumes there is at least + * two rows to interpolate between causing out of bounds read for 1px images, see T70356. */ + if (UNLIKELY(ibuf->y == 1)) { if (do_rect) { - rect = ((uchar *)ibuf->rect) + 4 * (x - 1); - newrect = _newrect + 4 * (x - 1); - - val_a = rect[0]; - nval_a = rect[skipx]; - diff_a = nval_a - val_a; - val_a += 0.5f; - - val_b = rect[1]; - nval_b = rect[skipx + 1]; - diff_b = nval_b - val_b; - val_b += 0.5f; - - val_g = rect[2]; - nval_g = rect[skipx + 2]; - diff_g = nval_g - val_g; - val_g += 0.5f; - - val_r = rect[3]; - nval_r = rect[skipx + 3]; - diff_r = nval_r - val_r; - val_r += 0.5f; - - rect += 2 * skipx; + for (y = newy; y > 0; y--) { + memcpy(newrect, rect, sizeof(char) * skipx); + newrect += skipx; + } } if (do_float) { - rectf = ibuf->rect_float + 4 * (x - 1); - newrectf = _newrectf + 4 * (x - 1); - - val_af = rectf[0]; - nval_af = rectf[skipx]; - diff_af = nval_af - val_af; + for (y = newy; y > 0; y--) { + memcpy(newrectf, rectf, sizeof(float) * skipx); + newrectf += skipx; + } + } + } + else { + const float add = (ibuf->y - 1.001) / (newy - 1.0); + float sample; + + float val_a, nval_a, diff_a; + float val_b, nval_b, diff_b; + float val_g, nval_g, diff_g; + float val_r, nval_r, diff_r; + float val_af, nval_af, diff_af; + float val_bf, nval_bf, diff_bf; + float val_gf, nval_gf, diff_gf; + float val_rf, nval_rf, diff_rf; + + val_a = nval_a = diff_a = val_b = nval_b = diff_b = 0; + val_g = nval_g = diff_g = val_r = nval_r = diff_r = 0; + val_af = nval_af = diff_af = val_bf = nval_bf = diff_bf = 0; + val_gf = nval_gf = diff_gf = val_rf = nval_rf = diff_rf = 0; + + for (x = ibuf->x; x > 0; x--) { + sample = 0; + if (do_rect) { + rect = ((uchar *)ibuf->rect) + 4 * (x - 1); + newrect = _newrect + 4 * (x - 1); + + val_a = rect[0]; + nval_a = rect[skipx]; + diff_a = nval_a - val_a; + val_a += 0.5f; + + val_b = rect[1]; + nval_b = rect[skipx + 1]; + diff_b = nval_b - val_b; + val_b += 0.5f; + + val_g = rect[2]; + nval_g = rect[skipx + 2]; + diff_g = nval_g - val_g; + val_g += 0.5f; + + val_r = rect[3]; + nval_r = rect[skipx + 3]; + diff_r = nval_r - val_r; + val_r += 0.5f; + + rect += 2 * skipx; + } + if (do_float) { + rectf = ibuf->rect_float + 4 * (x - 1); + newrectf = _newrectf + 4 * (x - 1); - val_bf = rectf[1]; - nval_bf = rectf[skipx + 1]; - diff_bf = nval_bf - val_bf; + val_af = rectf[0]; + nval_af = rectf[skipx]; + diff_af = nval_af - val_af; - val_gf = rectf[2]; - nval_gf = rectf[skipx + 2]; - diff_gf = nval_gf - val_gf; + val_bf = rectf[1]; + nval_bf = rectf[skipx + 1]; + diff_bf = nval_bf - val_bf; - val_rf = rectf[3]; - nval_rf = rectf[skipx + 3]; - diff_rf = nval_rf - val_rf; + val_gf = rectf[2]; + nval_gf = rectf[skipx + 2]; + diff_gf = nval_gf - val_gf; - rectf += 2 * skipx; - } + val_rf = rectf[3]; + nval_rf = rectf[skipx + 3]; + diff_rf = nval_rf - val_rf; - for (y = newy; y > 0; y--) { - if (sample >= 1.0f) { - sample -= 1.0f; + rectf += 2 * skipx; + } + for (y = newy; y > 0; y--) { + if (sample >= 1.0f) { + sample -= 1.0f; + + if (do_rect) { + val_a = nval_a; + nval_a = rect[0]; + diff_a = nval_a - val_a; + val_a += 0.5f; + + val_b = nval_b; + nval_b = rect[1]; + diff_b = nval_b - val_b; + val_b += 0.5f; + + val_g = nval_g; + nval_g = rect[2]; + diff_g = nval_g - val_g; + val_g += 0.5f; + + val_r = nval_r; + nval_r = rect[3]; + diff_r = nval_r - val_r; + val_r += 0.5f; + rect += skipx; + } + if (do_float) { + val_af = nval_af; + nval_af = rectf[0]; + diff_af = nval_af - val_af; + + val_bf = nval_bf; + nval_bf = rectf[1]; + diff_bf = nval_bf - val_bf; + + val_gf = nval_gf; + nval_gf = rectf[2]; + diff_gf = nval_gf - val_gf; + + val_rf = nval_rf; + nval_rf = rectf[3]; + diff_rf = nval_rf - val_rf; + rectf += skipx; + } + } if (do_rect) { - val_a = nval_a; - nval_a = rect[0]; - diff_a = nval_a - val_a; - val_a += 0.5f; - - val_b = nval_b; - nval_b = rect[1]; - diff_b = nval_b - val_b; - val_b += 0.5f; - - val_g = nval_g; - nval_g = rect[2]; - diff_g = nval_g - val_g; - val_g += 0.5f; - - val_r = nval_r; - nval_r = rect[3]; - diff_r = nval_r - val_r; - val_r += 0.5f; - rect += skipx; + newrect[0] = val_a + sample * diff_a; + newrect[1] = val_b + sample * diff_b; + newrect[2] = val_g + sample * diff_g; + newrect[3] = val_r + sample * diff_r; + newrect += skipx; } if (do_float) { - val_af = nval_af; - nval_af = rectf[0]; - diff_af = nval_af - val_af; - - val_bf = nval_bf; - nval_bf = rectf[1]; - diff_bf = nval_bf - val_bf; - - val_gf = nval_gf; - nval_gf = rectf[2]; - diff_gf = nval_gf - val_gf; - - val_rf = nval_rf; - nval_rf = rectf[3]; - diff_rf = nval_rf - val_rf; - rectf += skipx; + newrectf[0] = val_af + sample * diff_af; + newrectf[1] = val_bf + sample * diff_bf; + newrectf[2] = val_gf + sample * diff_gf; + newrectf[3] = val_rf + sample * diff_rf; + newrectf += skipx; } + sample += add; } - if (do_rect) { - newrect[0] = val_a + sample * diff_a; - newrect[1] = val_b + sample * diff_b; - newrect[2] = val_g + sample * diff_g; - newrect[3] = val_r + sample * diff_r; - newrect += skipx; - } - if (do_float) { - newrectf[0] = val_af + sample * diff_af; - newrectf[1] = val_bf + sample * diff_bf; - newrectf[2] = val_gf + sample * diff_gf; - newrectf[3] = val_rf + sample * diff_rf; - newrectf += skipx; - } - sample += add; } } @@ -1620,6 +1666,8 @@ static void scalefast_Z_ImBuf(ImBuf *ibuf, int newx, int newy) */ bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy) { + BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!"); + if (ibuf == NULL) { return false; } @@ -1666,6 +1714,8 @@ struct imbufRGBA { */ bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy) { + BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!"); + unsigned int *rect, *_newrect, *newrect; struct imbufRGBA *rectf, *_newrectf, *newrectf; int x, y; @@ -1838,6 +1888,8 @@ static void *do_scale_thread(void *data_v) void IMB_scaleImBuf_threaded(ImBuf *ibuf, unsigned int newx, unsigned int newy) { + BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!"); + ScaleTreadInitData init_data = {NULL}; /* prepare initialization data */ diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc index 7ffb61e1d1b..131b60b90fb 100644 --- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc @@ -538,7 +538,7 @@ static void get_loop_normals(struct Mesh *mesh, BKE_mesh_calc_normals_split(mesh); const float(*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL)); - BLI_assert(lnors != nullptr || !"BKE_mesh_calc_normals_split() should have computed CD_NORMAL"); + BLI_assert_msg(lnors != nullptr, "BKE_mesh_calc_normals_split() should have computed CD_NORMAL"); normals.resize(mesh->totloop); diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp index 626e4258239..e52bdca0d87 100644 --- a/source/blender/io/collada/AnimationImporter.cpp +++ b/source/blender/io/collada/AnimationImporter.cpp @@ -1090,7 +1090,7 @@ void AnimationImporter::translate_Animations( apply_matrix_curves(ob, animcurves, root, node, transform); } else { - /* calculate rnapaths and array index of fcurves according to transformation and + /* Calculate RNA-paths and array index of F-curves according to transformation and * animation class */ Assign_transform_animations(transform, &bindings[j], &animcurves, is_joint, joint_path); diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp index 02a4e1f3167..d2bde193c0a 100644 --- a/source/blender/io/collada/BCAnimationSampler.cpp +++ b/source/blender/io/collada/BCAnimationSampler.cpp @@ -161,10 +161,12 @@ void BCAnimationSampler::update_animation_curves(BCAnimation &animation, BCSample &BCAnimationSampler::sample_object(Object *ob, int frame_index, bool for_opensim) { BCSample &ob_sample = sample_data.add(ob, frame_index); - // if (export_settings.get_apply_global_orientation()) { - // const BCMatrix &global_transform = export_settings.get_global_transform(); - // ob_sample.get_matrix(global_transform); - //} +#if 0 + if (export_settings.get_apply_global_orientation()) { + const BCMatrix &global_transform = export_settings.get_global_transform(); + ob_sample.get_matrix(global_transform); + } +#endif if (ob->type == OB_ARMATURE) { bPoseChannel *pchan; diff --git a/source/blender/io/collada/ControllerExporter.cpp b/source/blender/io/collada/ControllerExporter.cpp index e61ed47adee..d768d2e44e8 100644 --- a/source/blender/io/collada/ControllerExporter.cpp +++ b/source/blender/io/collada/ControllerExporter.cpp @@ -231,7 +231,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm) uint idx = vert->dw[j].def_nr; if (idx >= joint_index_by_def_index.size()) { /* XXX: Maybe better find out where and - * why the Out Of Bound indexes get created ? */ + * why the Out Of Bound indexes get created? */ oob_counter += 1; } else { diff --git a/source/blender/io/collada/DocumentExporter.cpp b/source/blender/io/collada/DocumentExporter.cpp index 46dfdda4ede..3c64591366c 100644 --- a/source/blender/io/collada/DocumentExporter.cpp +++ b/source/blender/io/collada/DocumentExporter.cpp @@ -180,7 +180,7 @@ int DocumentExporter::exportCurrentScene() bContext *C = blender_context.get_context(); PointerRNA sceneptr, unit_settings; - PropertyRNA *system; /* unused , *scale; */ + PropertyRNA *system; /* unused, *scale; */ clear_global_id_map(); diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp index 5aa57159328..ef486375ce3 100644 --- a/source/blender/io/collada/MeshImporter.cpp +++ b/source/blender/io/collada/MeshImporter.cpp @@ -708,7 +708,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) prim.totpoly++; } - /* Moving cursor to the next triangle fan. */ + /* Moving cursor to the next triangle fan. */ if (mp_has_normals) { normal_indices += 2; } diff --git a/source/blender/io/collada/TransformReader.cpp b/source/blender/io/collada/TransformReader.cpp index 81b0ffc340a..d23f8da2570 100644 --- a/source/blender/io/collada/TransformReader.cpp +++ b/source/blender/io/collada/TransformReader.cpp @@ -103,9 +103,11 @@ void TransformReader::dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[ COLLADABU::Math::Vector3 &axis = ro->getRotationAxis(); const float angle = (float)DEG2RAD(ro->getRotationAngle()); const float ax[] = {(float)axis[0], (float)axis[1], (float)axis[2]}; - // float quat[4]; - // axis_angle_to_quat(quat, axis, angle); - // quat_to_mat4(m, quat); +#if 0 + float quat[4]; + axis_angle_to_quat(quat, axis, angle); + quat_to_mat4(m, quat); +#endif axis_angle_to_mat4(m, ax, angle); } diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp index 9967a526971..60c4a9bad13 100644 --- a/source/blender/io/collada/collada_utils.cpp +++ b/source/blender/io/collada/collada_utils.cpp @@ -1216,8 +1216,10 @@ static bNodeSocket *bc_group_add_input_socket(bNodeTree *ntree, { bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index); - //bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket); - //return socket; +# if 0 + bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket); + return socket; +# endif bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket); bNode *inputGroup = ntreeFindType(ntree, NODE_GROUP_INPUT); @@ -1235,8 +1237,10 @@ static bNodeSocket *bc_group_add_output_socket(bNodeTree *ntree, { bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index); - //bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket); - //return socket; +# if 0 + bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket); + return socket; +# endif bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(ntree, from_node, from_socket); bNode *outputGroup = ntreeFindType(ntree, NODE_GROUP_OUTPUT); diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc index 3b20ac9f110..82f8444d43e 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc @@ -91,19 +91,20 @@ bool GpencilExporterPDF::write() { /* Support unicode character paths on Windows. */ HPDF_STATUS res = 0; - /* TODO: It looks libharu does not support unicode. */ - //#ifdef WIN32 - // char filename_cstr[FILE_MAX]; - // BLI_strncpy(filename_cstr, filename_, FILE_MAX); - // - // UTF16_ENCODE(filename_cstr); - // std::wstring wstr(filename_cstr_16); - // res = HPDF_SaveToFile(pdf_, wstr.c_str()); - // - // UTF16_UN_ENCODE(filename_cstr); - //#else + + /* TODO: It looks `libharu` does not support unicode. */ +#if 0 /* `ifdef WIN32` */ + char filename_cstr[FILE_MAX]; + BLI_strncpy(filename_cstr, filename_, FILE_MAX); + + UTF16_ENCODE(filename_cstr); + std::wstring wstr(filename_cstr_16); + res = HPDF_SaveToFile(pdf_, wstr.c_str()); + + UTF16_UN_ENCODE(filename_cstr); +#else res = HPDF_SaveToFile(pdf_, filename_); - //#endif +#endif return (res == 0) ? true : false; } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 43969bf0768..c9d652ad03d 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -621,9 +621,9 @@ typedef enum IDRecalcFlag { * When a collection gets tagged with this flag, all objects depending on the geometry and * transforms on any of the objects in the collection are updated. */ ID_RECALC_GEOMETRY = (1 << 1), - /* Same as #ID_RECALC_GEOMETRY, but instead of tagging the batch cache as `dirty_all`, just tags - what matches the deform cache. */ - ID_RECALC_GEOMETRY_DEFORM = (1 << 2), + + /* ** Animation or time changed and animation is to be re-evaluated. ** */ + ID_RECALC_ANIMATION = (1 << 2), /* ** Particle system changed. ** */ /* Only do pathcache etc. */ @@ -683,9 +683,6 @@ typedef enum IDRecalcFlag { * have to be copied on every update. */ ID_RECALC_PARAMETERS = (1 << 21), - /* ** Animation or time changed and animation is to be re-evaluated. ** */ - ID_RECALC_ANIMATION = (1 << 22), - /* Input has changed and datablock is to be reload from disk. * Applies to movie clips to inform that copy-on-written version is to be refreshed for the new * input file or for color space changes. */ diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index aba6ccfd3ba..baed2aa2866 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -830,7 +830,7 @@ typedef struct SpaceAction { /** The currently active context (when not showing action). */ bDopeSheet ads; - /** For Time-Slide transform mode drawing - current frame?. */ + /** For Time-Slide transform mode drawing - current frame? */ float timeslide; short flag; @@ -838,7 +838,7 @@ typedef struct SpaceAction { char mode; /* Storage for sub-space types. */ char mode_prev; - /** Automatic keyframe snapping mode . */ + /** Automatic keyframe snapping mode. */ char autosnap; /** (eTimeline_Cache_Flag). */ char cache_display; diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index c02035be4ac..a49a76c3f26 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -51,7 +51,7 @@ typedef struct FModifier { /** Pointer to modifier data. */ void *data; - /** User-defined description for the modifier - MAX_ID_NAME-2. */ + /** User-defined description for the modifier - `MAX_ID_NAME - 2`. */ char name[64]; /** Type of f-curve modifier. */ short type; @@ -185,7 +185,7 @@ typedef enum eFMod_Generator_Functions { /* envelope modifier - envelope data */ typedef struct FCM_EnvelopeData { - /** Min/max values for envelope at this point (absolute values) . */ + /** Min/max values for envelope at this point (absolute values). */ float min, max; /** Time for that this sample-point occurs. */ float time; @@ -198,7 +198,7 @@ typedef struct FCM_EnvelopeData { /* envelope-like adjustment to values (for fade in/out) */ typedef struct FMod_Envelope { - /** Data-points defining envelope to apply (array) . */ + /** Data-points defining envelope to apply (array). */ FCM_EnvelopeData *data; /** Number of envelope points. */ int totvert; @@ -210,7 +210,7 @@ typedef struct FMod_Envelope { } FMod_Envelope; /* cycling/repetition modifier data */ -// TODO: we can only do complete cycles... +/* TODO: we can only do complete cycles. */ typedef struct FMod_Cycles { /** Extrapolation mode to use before first keyframe. */ short before_mode; @@ -321,7 +321,7 @@ typedef struct DriverTarget { /** * Name of the posebone to use - * (for vars where DTAR_FLAG_STRUCT_REF is used) - MAX_ID_NAME-2. + * (for vars where DTAR_FLAG_STRUCT_REF is used) - `MAX_ID_NAME - 2`. */ char pchan_name[64]; /** Transform channel index (for #DVAR_TYPE_TRANSFORM_CHAN). */ @@ -418,7 +418,7 @@ typedef struct DriverVar { /** * Name of the variable to use in py-expression - * (must be valid python identifier) - MAX_ID_NAME-2. + * (must be valid python identifier) - `MAX_ID_NAME - 2`. */ char name[64]; @@ -734,7 +734,7 @@ typedef struct NlaStrip { /** F-Curve modifiers to be applied to the entire strip's referenced F-Curves. */ ListBase modifiers; - /** User-Visible Identifier for Strip - MAX_ID_NAME-2. */ + /** User-Visible Identifier for Strip - `MAX_ID_NAME - 2`. */ char name[64]; /** Influence of strip. */ @@ -873,7 +873,7 @@ typedef struct NlaTrack { * \note not really useful, but we need a '_pad' var anyways! */ int index; - /** Short user-description of this track - MAX_ID_NAME-2. */ + /** Short user-description of this track - `MAX_ID_NAME - 2`. */ char name[64]; } NlaTrack; @@ -917,7 +917,7 @@ typedef struct KS_Path { /** ID block that keyframes are for. */ ID *id; - /** Name of the group to add to - MAX_ID_NAME-2. */ + /** Name of the group to add to - `MAX_ID_NAME - 2`. */ char group[64]; /** ID-type that path can be used on. */ @@ -977,13 +977,13 @@ typedef struct KeyingSet { /** (KS_Path) paths to keyframe to. */ ListBase paths; - /** Unique name (for search, etc.) - MAX_ID_NAME-2 . */ + /** Unique name (for search, etc.) - `MAX_ID_NAME - 2`. */ char idname[64]; - /** User-viewable name for KeyingSet (for menus, etc.) - MAX_ID_NAME-2. */ + /** User-viewable name for KeyingSet (for menus, etc.) - `MAX_ID_NAME - 2`. */ char name[64]; /** (RNA_DYN_DESCR_MAX) short help text. */ char description[240]; - /** Name of the typeinfo data used for the relative paths - MAX_ID_NAME-2. */ + /** Name of the typeinfo data used for the relative paths - `MAX_ID_NAME - 2`. */ char typeinfo[64]; /** Index of the active path. */ diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h index 3907c158573..316f8631ece 100644 --- a/source/blender/makesdna/DNA_asset_types.h +++ b/source/blender/makesdna/DNA_asset_types.h @@ -89,7 +89,6 @@ typedef enum eAssetLibraryType { ASSET_LIBRARY_CUSTOM = 100, } eAssetLibraryType; -/* TODO copy of FileSelectAssetLibraryUID */ /** * Information to identify a asset library. May be either one of the predefined types (current * 'Main', builtin library, project library), or a custom type as defined in the Preferences. @@ -116,7 +115,7 @@ typedef struct AssetLibraryReference { # # typedef struct AssetHandle { - struct FileDirEntry *file_data; + const struct FileDirEntry *file_data; } AssetHandle; #ifdef __cplusplus diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 34f50b23c77..a77fbc9e45e 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -425,7 +425,7 @@ typedef struct bRigidBodyJointConstraint { typedef struct bClampToConstraint { /** 'target' must be a curve. */ struct Object *tar; - /** Which axis/plane to compare owner's location on . */ + /** Which axis/plane to compare owner's location on. */ int flag; /** For legacy reasons, this is flag2. used for any extra settings. */ int flag2; @@ -474,7 +474,7 @@ typedef struct bTransformConstraint { float from_min[3]; /** To map on to to_min/max range. */ float from_max[3]; - /** Range of motion on owner caused by target . */ + /** Range of motion on owner caused by target. */ float to_min[3]; float to_max[3]; @@ -482,7 +482,7 @@ typedef struct bTransformConstraint { float from_min_rot[3]; /** To map on to to_min/max range. */ float from_max_rot[3]; - /** Range of motion on owner caused by target . */ + /** Range of motion on owner caused by target. */ float to_min_rot[3]; float to_max_rot[3]; @@ -490,7 +490,7 @@ typedef struct bTransformConstraint { float from_min_scale[3]; /** To map on to to_min/max range. */ float from_max_scale[3]; - /** Range of motion on owner caused by target . */ + /** Range of motion on owner caused by target. */ float to_min_scale[3]; float to_max_scale[3]; } bTransformConstraint; @@ -1102,7 +1102,7 @@ typedef enum eRotLimit_Flags { /* distance limit constraint */ /* bDistLimitConstraint->flag */ typedef enum eDistLimit_Flag { - /* "soft" cushion effect when reaching the limit sphere */ // NOT IMPLEMENTED! + /* "soft" cushion effect when reaching the limit sphere */ /* NOT IMPLEMENTED! */ LIMITDIST_USESOFT = (1 << 0), /* as for all Limit constraints - allow to be used during transform? */ LIMITDIST_TRANSFORM = (1 << 1), diff --git a/source/blender/makesdna/DNA_documentation.h b/source/blender/makesdna/DNA_documentation.h index 0251625292c..85190d8a56d 100644 --- a/source/blender/makesdna/DNA_documentation.h +++ b/source/blender/makesdna/DNA_documentation.h @@ -56,7 +56,7 @@ * * Ignored structs can only be referred to from non-ignored structs * when referred to as a pointer (where they're usually allocated - * and cleared in ``readfile.c``). + * and cleared in `readfile.c`). * * - %Path to the header files * diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h index 0552c449819..4f71a257877 100644 --- a/source/blender/makesdna/DNA_ipo_types.h +++ b/source/blender/makesdna/DNA_ipo_types.h @@ -63,9 +63,9 @@ typedef struct IpoDriver { typedef struct IpoCurve { struct IpoCurve *next, *prev; - /** Array of BPoints (sizeof(BPoint) * totvert) - i.e. baked/imported data. */ + /** Array of #BPoints `(sizeof(BPoint) * totvert)` - i.e. baked/imported data. */ struct BPoint *bp; - /** Array of BezTriples (sizeof(BezTriple) * totvert) - i.e. user-editable keyframes . */ + /** Array of #BezTriples `(sizeof(BezTriple) * totvert)` - i.e. user-editable keyframes. */ struct BezTriple *bezt; /** Bounding boxes. */ @@ -75,7 +75,7 @@ typedef struct IpoCurve { short blocktype, adrcode, vartype; /** Total number of BezTriples (i.e. keyframes) on curve. */ short totvert; - /** Interpolation and extrapolation modes . */ + /** Interpolation and extrapolation modes. */ short ipo, extrap; /** Flag= settings. */ short flag; @@ -102,7 +102,7 @@ typedef struct Ipo { /** A list of IpoCurve structs in a linked list. */ ListBase curve; - /** Rect defining extents of keyframes?. */ + /** Rect defining extents of keyframes? */ rctf cur; /** Blocktype: self-explanatory; showkey: either 0 or 1 diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h index 82ff3c95834..5ec82a68a2d 100644 --- a/source/blender/makesdna/DNA_light_types.h +++ b/source/blender/makesdna/DNA_light_types.h @@ -134,7 +134,7 @@ typedef struct Light { /* #define LA_NO_DIFF (1 << 11) */ /* not used anywhere */ /* #define LA_NO_SPEC (1 << 12) */ /* not used anywhere */ /* #define LA_SHAD_RAY (1 << 13) */ /* not used anywhere - cleaned */ -/* yafray: light shadowbuffer flag, softlight */ +/* yafray: light shadowbuffer flag, softlight */ /* Since it is used with LOCAL light, can't use LA_SHAD */ /* #define LA_YF_SOFT (1 << 14) */ /* not used anymore */ /* #define LA_LAYER_SHADOW (1 << 15) */ /* not used anymore */ diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h index 8868ac1ea12..e6a7c004078 100644 --- a/source/blender/makesdna/DNA_mask_types.h +++ b/source/blender/makesdna/DNA_mask_types.h @@ -93,7 +93,7 @@ typedef struct MaskSplinePointUW { } MaskSplinePointUW; typedef struct MaskSplinePoint { - /** Actual point coordinates and its handles . */ + /** Actual point coordinates and its handles. */ BezTriple bezt; char _pad[4]; /** Number of uv feather values. */ @@ -173,7 +173,7 @@ typedef struct MaskLayer { /** For animation. */ char flag; - /** Matching 'Object' flag of the same name - eventually use in the outliner . */ + /** Matching 'Object' flag of the same name - eventually use in the outliner. */ char restrictflag; } MaskLayer; diff --git a/source/blender/makesdna/DNA_material_defaults.h b/source/blender/makesdna/DNA_material_defaults.h index 3f4496ce735..3fa87800b2e 100644 --- a/source/blender/makesdna/DNA_material_defaults.h +++ b/source/blender/makesdna/DNA_material_defaults.h @@ -45,6 +45,8 @@ .alpha_threshold = 0.5f, \ \ .blend_shadow = MA_BS_SOLID, \ + \ + .lineart.mat_occlusion = 1, \ } /** \} */ diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index b7354aaa724..67cd68afb8a 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -160,6 +160,8 @@ typedef struct MaterialLineArt { typedef enum eMaterialLineArtFlags { LRT_MATERIAL_MASK_ENABLED = (1 << 0), + + /* Deprecated, kept for versioning code. */ LRT_MATERIAL_CUSTOM_OCCLUSION_EFFECTIVENESS = (1 << 1), } eMaterialLineArtFlags; @@ -295,37 +297,21 @@ typedef struct Material { #define MAP_COL (1 << 0) #define MAP_ALPHA (1 << 7) -/* pmapto */ -/* init */ -#define MAP_PA_INIT ((1 << 5) - 1) -#define MAP_PA_TIME (1 << 0) -#define MAP_PA_LIFE (1 << 1) -#define MAP_PA_DENS (1 << 2) -#define MAP_PA_SIZE (1 << 3) -#define MAP_PA_LENGTH (1 << 4) -/* reset */ -#define MAP_PA_IVEL (1 << 5) -/* physics */ -#define MAP_PA_PVEL (1 << 6) -/* path cache */ -#define MAP_PA_CLUMP (1 << 7) -#define MAP_PA_KINK (1 << 8) -#define MAP_PA_ROUGH (1 << 9) -#define MAP_PA_FREQ (1 << 10) - /* pr_type */ -#define MA_FLAT 0 -#define MA_SPHERE 1 -#define MA_CUBE 2 -#define MA_SHADERBALL 3 -#define MA_SPHERE_A 4 /* Used for icon renders only. */ -#define MA_TEXTURE 5 -#define MA_LAMP 6 -#define MA_SKY 7 -#define MA_HAIR 10 -#define MA_ATMOS 11 -#define MA_CLOTH 12 -#define MA_FLUID 13 +typedef enum ePreviewType { + MA_FLAT = 0, + MA_SPHERE = 1, + MA_CUBE = 2, + MA_SHADERBALL = 3, + MA_SPHERE_A = 4, /* Used for icon renders only. */ + MA_TEXTURE = 5, + MA_LAMP = 6, + MA_SKY = 7, + MA_HAIR = 10, + MA_ATMOS = 11, + MA_CLOTH = 12, + MA_FLUID = 13, +} ePreviewType; /* pr_flag */ #define MA_PREVIEW_WORLD (1 << 0) diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h index f6dac88051b..1b3dbd148df 100644 --- a/source/blender/makesdna/DNA_modifier_defaults.h +++ b/source/blender/makesdna/DNA_modifier_defaults.h @@ -647,7 +647,8 @@ .target = NULL, \ .verts = NULL, \ .falloff = 4.0f, \ - .numverts = 0, \ + .num_mesh_verts = 0, \ + .num_bind_verts = 0, \ .numpoly = 0, \ .flags = 0, \ .mat = _DNA_DEFAULT_UNIT_M4, \ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 1c765d19ce2..99c346bf589 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -2023,6 +2023,7 @@ typedef struct WeldModifierData { /* WeldModifierData->flag */ enum { MOD_WELD_INVERT_VGROUP = (1 << 0), + MOD_WELD_LOOSE_EDGES = (1 << 1), }; /* #WeldModifierData.mode */ @@ -2180,7 +2181,7 @@ typedef struct SDefBind { typedef struct SDefVert { SDefBind *binds; unsigned int numbinds; - char _pad[4]; + unsigned int vertex_idx; } SDefVert; typedef struct SurfaceDeformModifierData { @@ -2192,11 +2193,10 @@ typedef struct SurfaceDeformModifierData { /** Vertex bind data. */ SDefVert *verts; float falloff; - unsigned int numverts, numpoly; + unsigned int num_mesh_verts, num_bind_verts, numpoly; int flags; float mat[4][4]; float strength; - char _pad[4]; char defgrp_name[64]; } SurfaceDeformModifierData; @@ -2204,10 +2204,9 @@ typedef struct SurfaceDeformModifierData { enum { /* This indicates "do bind on next modifier evaluation" as well as "is bound". */ MOD_SDEF_BIND = (1 << 0), - MOD_SDEF_INVERT_VGROUP = (1 << 1) - - /* MOD_SDEF_USES_LOOPTRI = (1 << 1), */ /* UNUSED */ - /* MOD_SDEF_HAS_CONCAVE = (1 << 2), */ /* UNUSED */ + MOD_SDEF_INVERT_VGROUP = (1 << 1), + /* Only store bind data for nonzero vgroup weights at the time of bind. */ + MOD_SDEF_SPARSE_BIND = (1 << 2), }; /* Surface Deform vertex bind modes */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index ac900bbee4f..5c3cf3f340a 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1360,6 +1360,13 @@ typedef struct NodeSwitch { uint8_t input_type; } NodeSwitch; +typedef struct NodeGeometryCurveSetHandles { + /* GeometryNodeCurveHandleType. */ + uint8_t handle_type; + /* GeometryNodeCurveHandleMode. */ + uint8_t mode; +} NodeGeometryCurveSetHandles; + typedef struct NodeGeometryCurvePrimitiveLine { /* GeometryNodeCurvePrimitiveLineMode. */ uint8_t mode; @@ -1390,6 +1397,11 @@ typedef struct NodeGeometryCurveSubdivide { uint8_t cuts_type; } NodeGeometryCurveSubdivide; +typedef struct NodeGeometryCurveTrim { + /* GeometryNodeCurveInterpolateMode. */ + uint8_t mode; +} NodeGeometryCurveTrim; + typedef struct NodeGeometryCurveToPoints { /* GeometryNodeCurveSampleMode. */ uint8_t mode; @@ -1826,6 +1838,18 @@ typedef enum GeometryNodeCurvePrimitiveCircleMode { GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS = 1 } GeometryNodeCurvePrimitiveCircleMode; +typedef enum GeometryNodeCurveHandleType { + GEO_NODE_CURVE_HANDLE_FREE = 0, + GEO_NODE_CURVE_HANDLE_AUTO = 1, + GEO_NODE_CURVE_HANDLE_VECTOR = 2, + GEO_NODE_CURVE_HANDLE_ALIGN = 3 +} GeometryNodeCurveHandleType; + +typedef enum GeometryNodeCurveHandleMode { + GEO_NODE_CURVE_HANDLE_LEFT = (1 << 0), + GEO_NODE_CURVE_HANDLE_RIGHT = (1 << 1) +} GeometryNodeCurveHandleMode; + typedef enum GeometryNodeTriangulateNGons { GEO_NODE_TRIANGULATE_NGON_BEAUTY = 0, GEO_NODE_TRIANGULATE_NGON_EARCLIP = 1, @@ -1949,6 +1973,11 @@ typedef enum GeometryNodeCurveSampleMode { GEO_NODE_CURVE_SAMPLE_EVALUATED = 2, } GeometryNodeCurveSampleMode; +typedef enum GeometryNodeCurveInterpolateMode { + GEO_NODE_CURVE_INTERPOLATE_FACTOR = 0, + GEO_NODE_CURVE_INTERPOLATE_LENGTH = 1, +} GeometryNodeCurveInterpolateMode; + typedef enum GeometryNodeAttributeTransferMapMode { GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED = 0, GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST = 1, diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index dd31e85647d..60a34fef899 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -336,7 +336,7 @@ typedef struct Object { /** Deprecated, use 'matbits'. */ short colbits DNA_DEPRECATED; - /** Transformation settings and transform locks . */ + /** Transformation settings and transform locks. */ short transflag, protectflag; short trackflag, upflag; /** Used for DopeSheet filtering settings (expanded/collapsed). */ diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h index 1d5e5eeed31..aa11e74e89d 100644 --- a/source/blender/makesdna/DNA_rigidbody_types.h +++ b/source/blender/makesdna/DNA_rigidbody_types.h @@ -125,7 +125,7 @@ typedef struct RigidBodyOb_Shared { */ typedef struct RigidBodyOb { /* General Settings for this RigidBodyOb */ - /** (eRigidBodyOb_Type) role of RigidBody in sim . */ + /** (eRigidBodyOb_Type) role of RigidBody in sim. */ short type; /** (eRigidBody_Shape) collision shape to use. */ short shape; @@ -243,7 +243,7 @@ typedef struct RigidBodyCon { struct Object *ob2; /* General Settings for this RigidBodyCon */ - /** (eRigidBodyCon_Type) role of RigidBody in sim . */ + /** (eRigidBodyCon_Type) role of RigidBody in sim. */ short type; /** Number of constraint solver iterations made per simulation step. */ short num_solver_iterations; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index cd752b220a3..31352b2c8f4 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1750,7 +1750,7 @@ typedef struct Scene { /** (runtime) info/cache used for presenting playback framerate info to the user. */ void *fps_info; - /* none of the dependency graph vars is mean to be saved */ + /* None of the dependency graph vars is mean to be saved. */ struct GHash *depsgraph_hash; char _pad7[4]; diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 5bd9cc7a999..d5b7458ae7b 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -522,7 +522,7 @@ typedef struct ARegion { /** Use this string to draw info. */ char *headerstr; - /** XXX 2.50, need spacedata equivalent?. */ + /** XXX 2.50, need spacedata equivalent? */ void *regiondata; ARegion_Runtime runtime; diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 55dc51e0632..af524ff4866 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -201,6 +201,7 @@ typedef struct Sequence { ListBase anims; float effect_fader; + /* DEPRECATED, only used for versioning. */ float speed_fader; /* pointers for effects: */ @@ -335,12 +336,28 @@ typedef struct SolidColorVars { typedef struct SpeedControlVars { float *frameMap; + /* DEPRECATED, only used for versioning. */ float globalSpeed; + /* DEPRECATED, only used for versioning. */ int flags; + int length; int lastValidFrame; + int speed_control_type; + + float speed_fader; + float speed_fader_length; + float speed_fader_frame_number; } SpeedControlVars; +/* SpeedControlVars.speed_control_type */ +enum { + SEQ_SPEED_STRETCH = 0, + SEQ_SPEED_MULTIPLY = 1, + SEQ_SPEED_LENGTH = 2, + SEQ_SPEED_FRAME_NUMBER = 3, +}; + typedef struct GaussianBlurVars { float size_x; float size_y; @@ -485,9 +502,9 @@ typedef struct SequencerScopes { #define SEQ_EDIT_PROXY_DIR_STORAGE 1 /* SpeedControlVars->flags */ -#define SEQ_SPEED_INTEGRATE (1 << 0) +#define SEQ_SPEED_UNUSED_2 (1 << 0) /* cleared */ #define SEQ_SPEED_UNUSED_1 (1 << 1) /* cleared */ -#define SEQ_SPEED_COMPRESS_IPO_Y (1 << 2) +#define SEQ_SPEED_UNUSED_3 (1 << 2) /* cleared */ #define SEQ_SPEED_USE_INTERPOLATION (1 << 3) /* ***************** SEQUENCE ****************** */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index b990de29ff3..04c9eab33f1 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -24,6 +24,7 @@ #pragma once +#include "DNA_asset_types.h" #include "DNA_color_types.h" /* for Histogram */ #include "DNA_defs.h" #include "DNA_image_types.h" /* ImageUser */ @@ -696,24 +697,6 @@ typedef enum eSpaceSeq_OverlayType { /** \name File Selector * \{ */ -/** - * Information to identify a asset library. May be either one of the predefined types (current - * 'Main', builtin library, project library), or a custom type as defined in the Preferences. - * - * If the type is set to #ASSET_LIBRARY_CUSTOM, idname must have the name to identify the - * custom library. Otherwise idname is not used. - */ -typedef struct FileSelectAssetLibraryUID { - short type; /* eFileAssetLibrary_Type */ - char _pad[2]; - /** - * If showing a custom asset library (#ASSET_LIBRARY_CUSTOM), this is the index of the - * #bUserAssetLibrary within #UserDef.asset_libraries. - * Should be ignored otherwise (but better set to -1 then, for sanity and debugging). - */ - int custom_library_index; -} FileSelectAssetLibraryUID; - /* Config and Input for File Selector */ typedef struct FileSelectParams { /** Title, also used for the text of the execute button. */ @@ -785,7 +768,7 @@ typedef struct FileSelectParams { typedef struct FileAssetSelectParams { FileSelectParams base_params; - FileSelectAssetLibraryUID asset_library; + AssetLibraryReference asset_library; short import_type; /* eFileAssetImportType */ char _pad[6]; diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 2308f04c4c7..ee33e8666ec 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -54,11 +54,10 @@ typedef struct MTex { float ofs[3], size[3], rot, random_angle; char _pad0[2]; - short colormodel, pmapto, pmaptoneg; + short colormodel; short normapspace, which_output; float r, g, b, k; float def_var; - char _pad1[4]; /* common */ float colfac, varfac; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 629aa191890..5f8a8c6230a 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -513,7 +513,7 @@ typedef struct bTheme { typedef struct bAddon { struct bAddon *next, *prev; char module[64]; - /** User-Defined Properties on this Addon (for storing preferences). */ + /** User-Defined Properties on this add-on (for storing preferences). */ IDProperty *prop; } bAddon; @@ -800,7 +800,7 @@ typedef struct UserDef { short rvisize; /** Rotating view icon brightness. */ short rvibright; - /** Maximum number of recently used files to remember . */ + /** Maximum number of recently used files to remember. */ short recent_files; /** Milliseconds to spend spinning the view. */ short smooth_viewtx; @@ -1291,7 +1291,7 @@ typedef enum eTimecodeStyles { USER_TIMECODE_SECONDS_ONLY = 4, /** * Private (not exposed as generic choices) options. - * milliseconds for sub-frames , SubRip format- HH:MM:SS,sss. + * milliseconds for sub-frames, SubRip format- HH:MM:SS,sss. */ USER_TIMECODE_SUBRIP = 100, } eTimecodeStyles; diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h index 131772d49b4..c385ac04bd3 100644 --- a/source/blender/makesdna/DNA_view2d_types.h +++ b/source/blender/makesdna/DNA_view2d_types.h @@ -50,7 +50,7 @@ typedef struct View2D { /** Scroll_ui - temp settings used for UI drawing of scrollers. */ short scroll_ui; - /** Keeptot - 'cur' rect cannot move outside the 'tot' rect?. */ + /** Keeptot - 'cur' rect cannot move outside the 'tot' rect? */ short keeptot; /** Keepzoom - axes that zooming cannot occur on, and also clamp within zoom-limits. */ short keepzoom; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 94e89944f08..a9016dd4edd 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -94,7 +94,7 @@ typedef struct Report { /** ReportType. */ short type; short flag; - /** `strlen(message)`, saves some time calculating the word wrap . */ + /** `strlen(message)`, saves some time calculating the word wrap. */ int len; const char *typestr; const char *message; diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h index 9ed01a7dbcc..2bac040ea90 100644 --- a/source/blender/makesdna/DNA_workspace_types.h +++ b/source/blender/makesdna/DNA_workspace_types.h @@ -139,7 +139,7 @@ typedef struct WorkSpace { /** Workspace-wide active asset library, for asset UIs to use (e.g. asset view UI template). The * Asset Browser has its own and doesn't use this. */ - AssetLibraryReference active_asset_library; + AssetLibraryReference asset_library; } WorkSpace; /** diff --git a/source/blender/makesdna/DNA_xr_types.h b/source/blender/makesdna/DNA_xr_types.h index 8e63760fef7..fc00d5eb839 100644 --- a/source/blender/makesdna/DNA_xr_types.h +++ b/source/blender/makesdna/DNA_xr_types.h @@ -50,6 +50,7 @@ typedef struct XrSessionSettings { typedef enum eXrSessionFlag { XR_SESSION_USE_POSITION_TRACKING = (1 << 0), + XR_SESSION_USE_ABSOLUTE_TRACKING = (1 << 1), } eXrSessionFlag; typedef enum eXRSessionBasePoseType { diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index d23b9441822..24d0d39292e 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -84,8 +84,8 @@ * **Remember to read/write integer and short aligned!** * * While writing a file, the names of a struct is indicated with a type number, - * to be found with: ``type = DNA_struct_find_nr(SDNA *, const char *)`` - * The value of ``type`` corresponds with the index within the structs array + * to be found with: `type = DNA_struct_find_nr(SDNA *, const char *)` + * The value of `type` corresponds with the index within the structs array * * For the moment: the complete DNA file is included in a .blend file. For * the future we can think of smarter methods, like only included the used @@ -101,7 +101,7 @@ * - Change of a pointer type: when the name doesn't change the contents is copied. * * NOT YET: - * - array (``vec[3]``) to float struct (``vec3f``). + * - array (`vec[3]`) to float struct (`vec3f`). * * DONE: * - Endian compatibility. diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h index 735be0c10bf..d363e40e4f0 100644 --- a/source/blender/makesdna/intern/dna_rename_defs.h +++ b/source/blender/makesdna/intern/dna_rename_defs.h @@ -136,4 +136,5 @@ DNA_STRUCT_RENAME_ELEM(wmWindow, global_area_map, global_areas) DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, line_types, edge_types) DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_flags, mask_switches) DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_mask, material_mask_bits) +DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numverts, num_bind_verts) DNA_STRUCT_RENAME_ELEM(MaterialLineArt, transparency_mask, material_mask_bits) diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index c2335b82fca..d880c892aa9 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -226,7 +226,7 @@ typedef enum PropertyFlag { PROP_ICONS_CONSECUTIVE = (1 << 12), PROP_ICONS_REVERSE = (1 << 8), - /** Hidden in the user interface. */ + /** Hidden in the user interface. */ PROP_HIDDEN = (1 << 19), /** Do not write in presets. */ PROP_SKIP_SAVE = (1 << 28), diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 0285ef44e17..feacd47c98c 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -5031,7 +5031,7 @@ static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen, int } } else { - /* get data until . or [ */ + /* Get data until `.` or `[`. */ p = *path; while (*p && *p != '.' && *p != '[') { @@ -5998,7 +5998,7 @@ static void rna_path_array_multi_string_from_flat_index(PointerRNA *ptr, /** * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc. - * \param index: The *flattened* index to use when \a ``index_dim > 0``, + * \param index: The *flattened* index to use when \a `index_dim > 0`, * this is expanded when used with multi-dimensional arrays. */ char *RNA_path_from_ID_to_property_index(PointerRNA *ptr, diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c index 0020d90ba1a..484b7593812 100644 --- a/source/blender/makesrna/intern/rna_asset.c +++ b/source/blender/makesrna/intern/rna_asset.c @@ -129,7 +129,17 @@ static void rna_AssetMetaData_active_tag_range( static PointerRNA rna_AssetHandle_file_data_get(PointerRNA *ptr) { AssetHandle *asset_handle = ptr->data; - return rna_pointer_inherit_refine(ptr, &RNA_FileSelectEntry, asset_handle->file_data); + /* Have to cast away const, but the file entry API doesn't allow modifications anyway. */ + return rna_pointer_inherit_refine( + ptr, &RNA_FileSelectEntry, (FileDirEntry *)asset_handle->file_data); +} + +static void rna_AssetHandle_file_data_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) +{ + AssetHandle *asset_handle = ptr->data; + asset_handle->file_data = value.data; } static void rna_AssetHandle_get_full_library_path( @@ -146,83 +156,22 @@ static void rna_AssetHandle_get_full_library_path( static PointerRNA rna_AssetHandle_local_id_get(PointerRNA *ptr) { const AssetHandle *asset = ptr->data; - ID *id = ED_assetlist_asset_local_id_get(asset); + ID *id = ED_asset_handle_get_local_id(asset); return rna_pointer_inherit_refine(ptr, &RNA_ID, id); } -static void rna_AssetHandle_file_data_set(PointerRNA *ptr, - PointerRNA value, - struct ReportList *UNUSED(reports)) -{ - AssetHandle *asset_handle = ptr->data; - asset_handle->file_data = value.data; -} - -int rna_asset_library_reference_get(const AssetLibraryReference *library) -{ - return ED_asset_library_reference_to_enum_value(library); -} - -void rna_asset_library_reference_set(AssetLibraryReference *library, int value) -{ - *library = ED_asset_library_reference_from_enum_value(value); -} - const EnumPropertyItem *rna_asset_library_reference_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { - const EnumPropertyItem predefined_items[] = { - /* For the future. */ - // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"}, - {ASSET_LIBRARY_LOCAL, - "LOCAL", - ICON_BLENDER, - "Current File", - "Show the assets currently available in this Blender session"}, - {0, NULL, 0, NULL, NULL}, - }; - - EnumPropertyItem *item = NULL; - int totitem = 0; - - /* Add separator if needed. */ - if (!BLI_listbase_is_empty(&U.asset_libraries)) { - const EnumPropertyItem sepr = {0, "", 0, "Custom", NULL}; - RNA_enum_item_add(&item, &totitem, &sepr); + const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf(); + if (!items) { + *r_free = false; } - int i = 0; - for (bUserAssetLibrary *user_library = U.asset_libraries.first; user_library; - user_library = user_library->next, i++) { - /* Note that the path itself isn't checked for validity here. If an invalid library path is - * used, the Asset Browser can give a nice hint on what's wrong. */ - const bool is_valid = (user_library->name[0] && user_library->path[0]); - if (!is_valid) { - continue; - } - - /* Use library path as description, it's a nice hint for users. */ - EnumPropertyItem tmp = {ASSET_LIBRARY_CUSTOM + i, - user_library->name, - ICON_NONE, - user_library->name, - user_library->path}; - RNA_enum_item_add(&item, &totitem, &tmp); - } - - if (totitem) { - const EnumPropertyItem sepr = {0, "", 0, "Built-in", NULL}; - RNA_enum_item_add(&item, &totitem, &sepr); - } - - /* Add predefined items. */ - RNA_enum_items_add(&item, &totitem, predefined_items); - - RNA_enum_item_end(&item, &totitem); *r_free = true; - return item; + return items; } #else @@ -343,13 +292,16 @@ static void rna_def_asset_handle(BlenderRNA *brna) srna = RNA_def_struct(brna, "AssetHandle", "PropertyGroup"); RNA_def_struct_ui_text(srna, "Asset Handle", "Reference to some asset"); - /* TODO why is this editable? There probably shouldn't be a setter. */ + /* TODO It is super ugly to expose the file data here. We have to do it though so the asset view + * template can populate a RNA collection with asset-handles, which are just file entries + * currently. A proper design is being worked on. */ prop = RNA_def_property(srna, "file_data", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "FileSelectEntry"); RNA_def_property_pointer_funcs( prop, "rna_AssetHandle_file_data_get", "rna_AssetHandle_file_data_set", NULL, NULL); - RNA_def_property_ui_text(prop, "File Entry", "File data used to refer to the asset"); + RNA_def_property_ui_text( + prop, "File Entry", "TEMPORARY, DO NOT USE - File data used to refer to the asset"); prop = RNA_def_property(srna, "local_id", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "ID"); @@ -377,7 +329,7 @@ PropertyRNA *rna_def_asset_library_reference_common(struct StructRNA *srna, const char *get, const char *set) { - PropertyRNA *prop = RNA_def_property(srna, "active_asset_library", PROP_ENUM, PROP_NONE); + PropertyRNA *prop = RNA_def_property(srna, "asset_library", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, DummyRNA_NULL_items); RNA_def_property_enum_funcs(prop, get, set, "rna_asset_library_reference_itemf"); diff --git a/source/blender/makesrna/intern/rna_collection.c b/source/blender/makesrna/intern/rna_collection.c index 752c9495e50..608a8e51b09 100644 --- a/source/blender/makesrna/intern/rna_collection.c +++ b/source/blender/makesrna/intern/rna_collection.c @@ -170,7 +170,7 @@ static bool rna_Collection_objects_override_apply(Main *bmain, Collection *coll_dst = (Collection *)ptr_dst->owner_id; if (ptr_item_dst->type == NULL || ptr_item_src->type == NULL) { - // BLI_assert(0 && "invalid source or destination object."); + // BLI_assert_msg(0, "invalid source or destination object."); return false; } @@ -185,7 +185,7 @@ static bool rna_Collection_objects_override_apply(Main *bmain, &coll_dst->gobject, ob_dst, offsetof(CollectionObject, ob)); if (cob_dst == NULL) { - BLI_assert(0 && "Could not find destination object in destination collection!"); + BLI_assert_msg(0, "Could not find destination object in destination collection!"); return false; } @@ -288,7 +288,7 @@ static bool rna_Collection_children_override_apply(Main *bmain, &coll_dst->children, subcoll_dst, offsetof(CollectionChild, collection)); if (collchild_dst == NULL) { - BLI_assert(0 && "Could not find destination sub-collection in destination collection!"); + BLI_assert_msg(0, "Could not find destination sub-collection in destination collection!"); return false; } diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c index 9da08de2168..70fb10c54b0 100644 --- a/source/blender/makesrna/intern/rna_context.c +++ b/source/blender/makesrna/intern/rna_context.c @@ -146,7 +146,9 @@ static PointerRNA rna_Context_asset_file_handle_get(PointerRNA *ptr) } PointerRNA newptr; - RNA_pointer_create(NULL, &RNA_FileSelectEntry, asset_handle.file_data, &newptr); + /* Have to cast away const, but the file entry API doesn't allow modifications anyway. */ + RNA_pointer_create( + NULL, &RNA_FileSelectEntry, (struct FileDirEntry *)asset_handle.file_data, &newptr); return newptr; } diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index f1c05079d9c..b5dea7b019f 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -656,6 +656,24 @@ static void rna_TextureGpencilModifier_material_set(PointerRNA *ptr, rna_GpencilModifier_material_set(ptr, value, ma_target, reports); } +static void rna_Lineart_start_level_set(PointerRNA *ptr, int value) +{ + LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)ptr->data; + + CLAMP(value, 0, 128); + lmd->level_start = value; + lmd->level_end = MAX2(value, lmd->level_end); +} + +static void rna_Lineart_end_level_set(PointerRNA *ptr, int value) +{ + LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)ptr->data; + + CLAMP(value, 0, 128); + lmd->level_end = value; + lmd->level_start = MIN2(value, lmd->level_start); +} + #else static void rna_def_modifier_gpencilnoise(BlenderRNA *brna) @@ -3068,12 +3086,14 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Level Start", "Minimum number of occlusions for the generated strokes"); RNA_def_property_range(prop, 0, 128); + RNA_def_property_int_funcs(prop, NULL, "rna_Lineart_start_level_set", NULL); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "level_end", PROP_INT, PROP_NONE); RNA_def_property_ui_text( prop, "Level End", "Maximum number of occlusions for the generated strokes"); RNA_def_property_range(prop, 0, 128); + RNA_def_property_int_funcs(prop, NULL, "rna_Lineart_end_level_set", NULL); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "target_material", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 9dc08430307..0bb76fd933a 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -270,8 +270,6 @@ void rna_def_view_layer_common(struct BlenderRNA *brna, struct StructRNA *srna, PropertyRNA *rna_def_asset_library_reference_common(struct StructRNA *srna, const char *get, const char *set); -int rna_asset_library_reference_get(const struct AssetLibraryReference *library); -void rna_asset_library_reference_set(struct AssetLibraryReference *library, int value); const EnumPropertyItem *rna_asset_library_reference_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index b662f54ed4c..d91c0bfaf29 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -702,14 +702,6 @@ static void rna_def_material_lineart(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Mask", ""); RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update"); - prop = RNA_def_property(srna, "use_mat_occlusion", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_default(prop, 0); - RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_MATERIAL_CUSTOM_OCCLUSION_EFFECTIVENESS); - RNA_def_property_ui_text(prop, - "Custom Occlusion Effectiveness", - "Use custom occlusion effectiveness for this material"); - RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update"); - prop = RNA_def_property(srna, "mat_occlusion", PROP_INT, PROP_NONE); RNA_def_property_int_default(prop, 1); RNA_def_property_ui_range(prop, 0.0f, 5.0f, 1.0f, 1); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index e64eaf8c363..388f587dfb4 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -6279,6 +6279,12 @@ static void rna_def_modifier_weld(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "loose_edges", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WELD_LOOSE_EDGES); + RNA_def_property_ui_text( + prop, "Only Loose Edges", "Collapse edges without faces, cloth sewing edges"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + RNA_define_lib_overridable(false); } @@ -6884,6 +6890,15 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "use_sparse_bind", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SDEF_SPARSE_BIND); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text( + prop, + "Sparse Bind", + "Only record binding data for vertices matching the vertex group at the time of bind"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, -100, 100); RNA_def_property_ui_range(prop, -100, 100, 10, 2); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 86e94690395..9696b05cf71 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -6638,10 +6638,9 @@ static void def_cmp_image(StructRNA *srna) "Put node output buffer to straight alpha instead of premultiplied"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); - /* NB: image user properties used in the UI are redefined in def_node_image_user, + /* NOTE: Image user properties used in the UI are redefined in def_node_image_user, * to trigger correct updates of the node editor. RNA design problem that prevents - * updates from nested structs ... - */ + * updates from nested structs. */ RNA_def_struct_sdna_from(srna, "ImageUser", "storage"); def_node_image_user(srna); } @@ -6738,9 +6737,8 @@ static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna, parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "New socket"); RNA_def_function_return(func, parm); - /* NB: methods below can use the standard node socket API functions, - * included here for completeness. - */ + /* NOTE: methods below can use the standard node socket API functions, + * included here for completeness. */ func = RNA_def_function(srna, "remove", "rna_Node_socket_remove"); RNA_def_function_ui_description(func, "Remove a file slot from this node"); @@ -9459,6 +9457,52 @@ static void def_geo_attribute_vector_rotate(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_geo_curve_set_handles(StructRNA *srna) +{ + static const EnumPropertyItem type_items[] = { + {GEO_NODE_CURVE_HANDLE_FREE, + "FREE", + ICON_HANDLE_FREE, + "Free", + "The handle can be moved anywhere, and doesn't influence the point's other handle"}, + {GEO_NODE_CURVE_HANDLE_AUTO, + "AUTO", + ICON_HANDLE_AUTO, + "Auto", + "The location is automatically calculated to be smooth"}, + {GEO_NODE_CURVE_HANDLE_VECTOR, + "VECTOR", + ICON_HANDLE_VECTOR, + "Vector", + "The location is calculated to point to the next/previous control point"}, + {GEO_NODE_CURVE_HANDLE_ALIGN, + "ALIGN", + ICON_HANDLE_ALIGNED, + "Align", + "The location is constrained to point in the opposite direction as the other handle"}, + {0, NULL, 0, NULL, NULL}}; + + static const EnumPropertyItem mode_items[] = { + {GEO_NODE_CURVE_HANDLE_LEFT, "LEFT", ICON_NONE, "Left", "Update the left handles"}, + {GEO_NODE_CURVE_HANDLE_RIGHT, "RIGHT", ICON_NONE, "Right", "Update the right handles"}, + {0, NULL, 0, NULL, NULL}}; + + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSetHandles", "storage"); + + prop = RNA_def_property(srna, "handle_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "handle_type"); + RNA_def_property_enum_items(prop, type_items); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, mode_items); + RNA_def_property_ui_text(prop, "Mode", "Whether to update left and right handles"); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + static void def_geo_curve_primitive_circle(StructRNA *srna) { static const EnumPropertyItem mode_items[] = { @@ -10055,6 +10099,32 @@ static void def_geo_curve_to_points(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_geo_curve_trim(StructRNA *srna) +{ + PropertyRNA *prop; + + static EnumPropertyItem mode_items[] = { + {GEO_NODE_CURVE_INTERPOLATE_FACTOR, + "FACTOR", + 0, + "Factor", + "Find the endpoint positions using a factor of each spline's length"}, + {GEO_NODE_CURVE_INTERPOLATE_LENGTH, + "LENGTH", + 0, + "Length", + "Find the endpoint positions using a length from the start of each spline"}, + {0, NULL, 0, NULL, NULL}, + }; + + RNA_def_struct_sdna_from(srna, "NodeGeometryCurveTrim", "storage"); + + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, mode_items); + RNA_def_property_ui_text(prop, "Mode", "How to find endpoint positions for the trimmed spline"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + static void def_geo_attribute_transfer(StructRNA *srna) { static EnumPropertyItem mapping_items[] = { @@ -10291,11 +10361,11 @@ static void rna_def_node_socket(BlenderRNA *brna) RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_ui_text(prop, "Node", "Node owning this socket"); - /* NB: the type property is used by standard sockets. + /* NOTE: The type property is used by standard sockets. * Ideally should be defined only for the registered subclass, * but to use the existing DNA is added in the base type here. - * Future socket types can ignore or override this if needed. - */ + * Future socket types can ignore or override this if needed. */ + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, node_socket_type_items); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index e110459eeea..ed681291e29 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -1997,16 +1997,25 @@ static void rna_Object_boundbox_get(PointerRNA *ptr, float *values) } } +static bool check_object_vgroup_support_and_warn(const Object *ob, + const char *op_name, + ReportList *reports) +{ + if (!BKE_object_supports_vertex_groups(ob)) { + const char *ob_type_name = "Unknown"; + RNA_enum_name_from_value(rna_enum_object_type_items, ob->type, &ob_type_name); + BKE_reportf(reports, RPT_ERROR, "%s is not supported for '%s' objects", op_name, ob_type_name); + return false; + } + return true; +} + static bDeformGroup *rna_Object_vgroup_new(Object *ob, Main *bmain, ReportList *reports, const char *name) { - if (!OB_TYPE_SUPPORT_VGROUP(ob->type)) { - const char *ob_type_name = "Unknown"; - RNA_enum_name_from_value(rna_enum_object_type_items, ob->type, &ob_type_name); - BKE_reportf( - reports, RPT_ERROR, "VertexGroups.new(): is not supported for '%s' objects", ob_type_name); + if (!check_object_vgroup_support_and_warn(ob, "VertexGroups.new()", reports)) { return NULL; } @@ -2023,6 +2032,10 @@ static void rna_Object_vgroup_remove(Object *ob, ReportList *reports, PointerRNA *defgroup_ptr) { + if (!check_object_vgroup_support_and_warn(ob, "VertexGroups.remove()", reports)) { + return; + } + bDeformGroup *defgroup = defgroup_ptr->data; ListBase *defbase = BKE_object_defgroup_list_mutable(ob); @@ -2042,8 +2055,12 @@ static void rna_Object_vgroup_remove(Object *ob, WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob); } -static void rna_Object_vgroup_clear(Object *ob, Main *bmain) +static void rna_Object_vgroup_clear(Object *ob, Main *bmain, ReportList *reports) { + if (!check_object_vgroup_support_and_warn(ob, "VertexGroups.clear()", reports)) { + return; + } + BKE_object_defgroup_remove_all(ob); DEG_relations_tag_update(bmain); @@ -2777,7 +2794,7 @@ static void rna_def_object_vertex_groups(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "clear", "rna_Object_vgroup_clear"); - RNA_def_function_flag(func, FUNC_USE_MAIN); + RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Delete all vertex groups from object"); } diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 6008ef40b60..b080e572fa2 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -2089,7 +2089,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain), switch (RNA_property_type(prop_local)) { case PROP_BOOLEAN: /* TODO: support boolean ops? Really doubt this would ever be useful though. */ - BLI_assert(0 && "Boolean properties support no override diff operation"); + BLI_assert_msg(0, "Boolean properties support no override diff operation"); break; case PROP_INT: { int prop_min, prop_max; @@ -2123,7 +2123,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain), for (int j = len_local; j--;) { array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]); if (array_b[j] < prop_min || array_b[j] > prop_max) { - /* We failed to find a suitable diff op, + /* We failed to find a suitable diff op, * fall back to plain REPLACE one. */ opop->operation = IDOVERRIDE_LIBRARY_OP_REPLACE; do_set = false; @@ -2143,7 +2143,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain), break; } default: - BLI_assert(0 && "Unsupported RNA override diff operation on integer"); + BLI_assert_msg(0, "Unsupported RNA override diff operation on integer"); break; } @@ -2175,7 +2175,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain), break; } default: - BLI_assert(0 && "Unsupported RNA override diff operation on integer"); + BLI_assert_msg(0, "Unsupported RNA override diff operation on integer"); break; } } @@ -2213,7 +2213,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain), for (int j = len_local; j--;) { array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]); if (array_b[j] < prop_min || array_b[j] > prop_max) { - /* We failed to find a suitable diff op, + /* We failed to find a suitable diff op, * fall back to plain REPLACE one. */ opop->operation = IDOVERRIDE_LIBRARY_OP_REPLACE; do_set = false; @@ -2256,7 +2256,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain), break; } default: - BLI_assert(0 && "Unsupported RNA override diff operation on float"); + BLI_assert_msg(0, "Unsupported RNA override diff operation on float"); break; } @@ -2299,7 +2299,7 @@ bool rna_property_override_store_default(Main *UNUSED(bmain), break; } default: - BLI_assert(0 && "Unsupported RNA override diff operation on float"); + BLI_assert_msg(0, "Unsupported RNA override diff operation on float"); break; } } @@ -2307,17 +2307,17 @@ bool rna_property_override_store_default(Main *UNUSED(bmain), } case PROP_ENUM: /* TODO: support add/sub, for bitflags? */ - BLI_assert(0 && "Enum properties support no override diff operation"); + BLI_assert_msg(0, "Enum properties support no override diff operation"); break; case PROP_POINTER: - BLI_assert(0 && "Pointer properties support no override diff operation"); + BLI_assert_msg(0, "Pointer properties support no override diff operation"); break; case PROP_STRING: - BLI_assert(0 && "String properties support no override diff operation"); + BLI_assert_msg(0, "String properties support no override diff operation"); break; case PROP_COLLECTION: /* XXX TODO: support this of course... */ - BLI_assert(0 && "Collection properties support no override diff operation"); + BLI_assert_msg(0, "Collection properties support no override diff operation"); break; default: break; @@ -2364,7 +2364,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain), RNA_property_boolean_set_array(ptr_dst, prop_dst, array_a); break; default: - BLI_assert(0 && "Unsupported RNA override operation on boolean"); + BLI_assert_msg(0, "Unsupported RNA override operation on boolean"); return false; } @@ -2380,7 +2380,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain), RNA_PROPERTY_SET_SINGLE(boolean, ptr_dst, prop_dst, index, value); break; default: - BLI_assert(0 && "Unsupported RNA override operation on boolean"); + BLI_assert_msg(0, "Unsupported RNA override operation on boolean"); return false; } } @@ -2421,7 +2421,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain), } break; default: - BLI_assert(0 && "Unsupported RNA override operation on integer"); + BLI_assert_msg(0, "Unsupported RNA override operation on integer"); return false; } @@ -2459,7 +2459,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain), storage_value); break; default: - BLI_assert(0 && "Unsupported RNA override operation on integer"); + BLI_assert_msg(0, "Unsupported RNA override operation on integer"); return false; } } @@ -2506,7 +2506,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain), } break; default: - BLI_assert(0 && "Unsupported RNA override operation on float"); + BLI_assert_msg(0, "Unsupported RNA override operation on float"); return false; } @@ -2552,7 +2552,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain), storage_value); break; default: - BLI_assert(0 && "Unsupported RNA override operation on float"); + BLI_assert_msg(0, "Unsupported RNA override operation on float"); return false; } } @@ -2566,7 +2566,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain), break; /* TODO: support add/sub, for bitflags? */ default: - BLI_assert(0 && "Unsupported RNA override operation on enum"); + BLI_assert_msg(0, "Unsupported RNA override operation on enum"); return false; } return true; @@ -2579,7 +2579,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain), RNA_property_pointer_set(ptr_dst, prop_dst, value, NULL); break; default: - BLI_assert(0 && "Unsupported RNA override operation on pointer"); + BLI_assert_msg(0, "Unsupported RNA override operation on pointer"); return false; } return true; @@ -2593,7 +2593,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain), RNA_property_string_set(ptr_dst, prop_dst, value); break; default: - BLI_assert(0 && "Unsupported RNA override operation on string"); + BLI_assert_msg(0, "Unsupported RNA override operation on string"); return false; } @@ -2609,7 +2609,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain), const bool is_dst_idprop = (prop_dst->magic != RNA_MAGIC) || (prop_dst->flag & PROP_IDPROPERTY) != 0; if (!(is_src_idprop && is_dst_idprop)) { - BLI_assert(0 && "You need to define a specific override apply callback for collections"); + BLI_assert_msg(0, "You need to define a specific override apply callback for collections"); return false; } @@ -2668,7 +2668,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain), return RNA_property_collection_move(ptr_dst, prop_dst, item_index_added, item_index_dst); } default: - BLI_assert(0 && "Unsupported RNA override operation on collection"); + BLI_assert_msg(0, "Unsupported RNA override operation on collection"); return false; } } diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index b1f0b0d760f..9939e17d258 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1921,16 +1921,6 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_def_property_update( prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); - prop = RNA_def_property(srna, "speed_factor", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "speed_fader"); - RNA_def_property_ui_text( - prop, - "Speed Factor", - "Multiply the current speed of the sequence with this number or remap current frame " - "to this frame"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); - /* modifiers */ prop = RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "SequenceModifier"); @@ -2787,24 +2777,48 @@ static void rna_def_speed_control(StructRNA *srna) RNA_def_struct_sdna_from(srna, "SpeedControlVars", "effectdata"); - prop = RNA_def_property(srna, "multiply_speed", PROP_FLOAT, PROP_UNSIGNED); - RNA_def_property_float_sdna(prop, NULL, "globalSpeed"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); /* seq->facf0 is used to animate this */ - RNA_def_property_ui_text( - prop, "Multiply Speed", "Multiply the resulting speed after the speed factor"); - RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, -1); + static const EnumPropertyItem speed_control_items[] = { + {SEQ_SPEED_STRETCH, + "STRETCH", + 0, + "Stretch", + "Adjust input playback speed, so its duration fits strip length"}, + {SEQ_SPEED_MULTIPLY, "MULTIPLY", 0, "Multiply", "Multiply with the speed factor"}, + {SEQ_SPEED_FRAME_NUMBER, + "FRAME_NUMBER", + 0, + "Frame Number", + "Frame number of the input strip"}, + {SEQ_SPEED_LENGTH, "LENGTH", 0, "Length", "Percentage of the input strip length"}, + {0, NULL, 0, NULL, NULL}, + }; + + prop = RNA_def_property(srna, "speed_control", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "speed_control_type"); + RNA_def_property_enum_items(prop, speed_control_items); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Speed Control", "Speed control method"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); - prop = RNA_def_property(srna, "use_as_speed", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_INTEGRATE); + prop = RNA_def_property(srna, "speed_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "speed_fader"); RNA_def_property_ui_text( - prop, "Use as Speed", "Interpret the value as speed instead of a frame number"); + prop, + "Multiply Factor", + "Multiply the current speed of the sequence with this number or remap current frame " + "to this frame"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); - prop = RNA_def_property(srna, "use_scale_to_length", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_COMPRESS_IPO_Y); - RNA_def_property_ui_text( - prop, "Scale to Length", "Scale values from 0.0 to 1.0 to target sequence length"); + prop = RNA_def_property(srna, "speed_frame_number", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "speed_fader_frame_number"); + RNA_def_property_ui_text(prop, "Frame Number", "Frame number of input strip"); + RNA_def_property_ui_range(prop, 0.0, MAXFRAME, 1.0, -1); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); + + prop = RNA_def_property(srna, "speed_length", PROP_FLOAT, PROP_PERCENTAGE); + RNA_def_property_float_sdna(prop, NULL, "speed_fader_length"); + RNA_def_property_ui_text(prop, "Length", "Percentage of input strip length"); + RNA_def_property_ui_range(prop, 0.0, 100.0, 1, -1); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "use_frame_interpolate", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 8aab0c079a3..4895ab11618 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -30,6 +30,8 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "SEQ_edit.h" + #include "rna_internal.h" #ifdef RNA_RUNTIME @@ -99,6 +101,24 @@ static void rna_Sequences_move_strip_to_meta( WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); } +static Sequence *rna_Sequence_split( + ID *id, Sequence *seq, Main *bmain, int frame, int split_method) +{ + Scene *scene = (Scene *)id; + Editing *ed = SEQ_editing_get(scene, false); + ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); + + Sequence *r_seq = SEQ_edit_strip_split(bmain, scene, seqbase, seq, frame, split_method); + + /* Update depsgraph. */ + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); + + WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); + + return r_seq; +} + static Sequence *rna_Sequences_new_clip(ID *id, ListBase *seqbase, Main *bmain, @@ -635,6 +655,12 @@ void RNA_api_sequence_strip(StructRNA *srna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem seq_split_method_items[] = { + {SEQ_SPLIT_SOFT, "SOFT", 0, "Soft", ""}, + {SEQ_SPLIT_HARD, "HARD", 0, "Hard", ""}, + {0, NULL, 0, NULL, NULL}, + }; + func = RNA_def_function(srna, "update", "rna_Sequence_update_rnafunc"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Update the strip dimensions"); @@ -676,6 +702,18 @@ void RNA_api_sequence_strip(StructRNA *srna) "Invalidate cached images for strip and all dependent strips"); parm = RNA_def_enum(func, "type", seq_cahce_type_items, 0, "Type", "Cache Type"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + + func = RNA_def_function(srna, "split", "rna_Sequence_split"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); + RNA_def_function_ui_description(func, "Split Sequence"); + parm = RNA_def_int( + func, "frame", 0, INT_MIN, INT_MAX, "", "Frame where to split the strip", INT_MIN, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_enum(func, "split_method", seq_split_method_items, 0, "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + /* Return type. */ + parm = RNA_def_pointer(func, "sequence", "Sequence", "", "Right side Sequence"); + RNA_def_function_return(func, parm); } void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop) diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index f2d2b190d87..a213b418e0e 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -359,7 +359,7 @@ static const EnumPropertyItem display_channels_items[] = { "Color and Alpha", "Display image with RGB colors and alpha transparency"}, {0, "COLOR", ICON_IMAGE_RGB, "Color", "Display image with RGB colors"}, - {SI_SHOW_ALPHA, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", "Display alpha transparency channel"}, + {SI_SHOW_ALPHA, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", "Display alpha transparency channel"}, {SI_SHOW_ZBUF, "Z_BUFFER", ICON_IMAGE_ZDEPTH, @@ -536,6 +536,7 @@ static const EnumPropertyItem rna_enum_curve_display_handle_items[] = { # include "DEG_depsgraph_build.h" # include "ED_anim_api.h" +# include "ED_asset.h" # include "ED_buttons.h" # include "ED_clip.h" # include "ED_fileselect.h" @@ -2562,112 +2563,19 @@ static PointerRNA rna_FileSelectParams_filter_id_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_FileSelectIDFilter, ptr->data); } -/* TODO use rna_def_asset_library_reference_common() */ - static int rna_FileAssetSelectParams_asset_library_get(PointerRNA *ptr) { FileAssetSelectParams *params = ptr->data; /* Just an extra sanity check to ensure this isn't somehow called for RNA_FileSelectParams. */ BLI_assert(ptr->type == &RNA_FileAssetSelectParams); - /* Simple case: Predefined repo, just set the value. */ - if (params->asset_library.type < ASSET_LIBRARY_CUSTOM) { - return params->asset_library.type; - } - - /* Note that the path isn't checked for validity here. If an invalid library path is used, the - * Asset Browser can give a nice hint on what's wrong. */ - const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index( - &U, params->asset_library.custom_library_index); - if (user_library) { - return ASSET_LIBRARY_CUSTOM + params->asset_library.custom_library_index; - } - - BLI_assert(0); - return ASSET_LIBRARY_LOCAL; + return ED_asset_library_reference_to_enum_value(¶ms->asset_library); } static void rna_FileAssetSelectParams_asset_library_set(PointerRNA *ptr, int value) { FileAssetSelectParams *params = ptr->data; - - /* Simple case: Predefined repo, just set the value. */ - if (value < ASSET_LIBRARY_CUSTOM) { - params->asset_library.type = value; - params->asset_library.custom_library_index = -1; - BLI_assert(ELEM(value, ASSET_LIBRARY_LOCAL)); - return; - } - - const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index( - &U, value - ASSET_LIBRARY_CUSTOM); - - /* Note that the path isn't checked for validity here. If an invalid library path is used, the - * Asset Browser can give a nice hint on what's wrong. */ - const bool is_valid = (user_library->name[0] && user_library->path[0]); - if (!user_library) { - params->asset_library.type = ASSET_LIBRARY_LOCAL; - params->asset_library.custom_library_index = -1; - } - else if (user_library && is_valid) { - params->asset_library.custom_library_index = value - ASSET_LIBRARY_CUSTOM; - params->asset_library.type = ASSET_LIBRARY_CUSTOM; - } -} - -static const EnumPropertyItem *rna_FileAssetSelectParams_asset_library_itemf( - bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - const EnumPropertyItem predefined_items[] = { - /* For the future. */ - // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"}, - {ASSET_LIBRARY_LOCAL, - "LOCAL", - ICON_BLENDER, - "Current File", - "Show the assets currently available in this Blender session"}, - {0, NULL, 0, NULL, NULL}, - }; - - EnumPropertyItem *item = NULL; - int totitem = 0; - - /* Add separator if needed. */ - if (!BLI_listbase_is_empty(&U.asset_libraries)) { - const EnumPropertyItem sepr = {0, "", 0, "Custom", NULL}; - RNA_enum_item_add(&item, &totitem, &sepr); - } - - int i = 0; - for (bUserAssetLibrary *user_library = U.asset_libraries.first; user_library; - user_library = user_library->next, i++) { - /* Note that the path itself isn't checked for validity here. If an invalid library path is - * used, the Asset Browser can give a nice hint on what's wrong. */ - const bool is_valid = (user_library->name[0] && user_library->path[0]); - if (!is_valid) { - continue; - } - - /* Use library path as description, it's a nice hint for users. */ - EnumPropertyItem tmp = {ASSET_LIBRARY_CUSTOM + i, - user_library->name, - ICON_NONE, - user_library->name, - user_library->path}; - RNA_enum_item_add(&item, &totitem, &tmp); - } - - if (totitem) { - const EnumPropertyItem sepr = {0, "", 0, "Built-in", NULL}; - RNA_enum_item_add(&item, &totitem, &sepr); - } - - /* Add predefined items. */ - RNA_enum_items_add(&item, &totitem, predefined_items); - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - return item; + params->asset_library = ED_asset_library_reference_from_enum_value(value); } static void rna_FileAssetSelectParams_asset_category_set(PointerRNA *ptr, uint64_t value) @@ -6559,12 +6467,9 @@ static void rna_def_fileselect_asset_params(BlenderRNA *brna) RNA_def_struct_ui_text( srna, "Asset Select Parameters", "Settings for the file selection in Asset Browser mode"); - prop = RNA_def_property(srna, "asset_library", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, DummyRNA_NULL_items); - RNA_def_property_enum_funcs(prop, - "rna_FileAssetSelectParams_asset_library_get", - "rna_FileAssetSelectParams_asset_library_set", - "rna_FileAssetSelectParams_asset_library_itemf"); + prop = rna_def_asset_library_reference_common(srna, + "rna_FileAssetSelectParams_asset_library_get", + "rna_FileAssetSelectParams_asset_library_set"); RNA_def_property_ui_text(prop, "Asset Library", ""); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); diff --git a/source/blender/makesrna/intern/rna_volume.c b/source/blender/makesrna/intern/rna_volume.c index 76db6f3e325..8ed53c9f70f 100644 --- a/source/blender/makesrna/intern/rna_volume.c +++ b/source/blender/makesrna/intern/rna_volume.c @@ -495,7 +495,7 @@ static void rna_def_volume_render(BlenderRNA *brna) prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, space_items); RNA_def_property_ui_text( - prop, "Space", "Specify volume density and step size in object or world space"); + prop, "Space", "Specify volume density and step size in object or world space"); RNA_def_property_update(prop, 0, "rna_Volume_update_display"); prop = RNA_def_property(srna, "step_size", PROP_FLOAT, PROP_DISTANCE); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 2a4abac04f8..9b4089b272c 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -1825,7 +1825,7 @@ static void rna_KeyMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi #else /* RNA_RUNTIME */ /** - * expose ``Operator.options`` as its own type so we can control each flags use + * expose `Operator.options` as its own type so we can control each flags use * (some are read-only). */ static void rna_def_operator_options_runtime(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c index b053bb0ff62..95f62d7de16 100644 --- a/source/blender/makesrna/intern/rna_workspace.c +++ b/source/blender/makesrna/intern/rna_workspace.c @@ -45,6 +45,8 @@ # include "DNA_screen_types.h" # include "DNA_space_types.h" +# include "ED_asset.h" + # include "RNA_access.h" # include "WM_toolsystem.h" @@ -107,16 +109,16 @@ static void rna_WorkSpace_owner_ids_clear(WorkSpace *workspace) WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, workspace); } -static int rna_WorkSpace_active_asset_library_get(PointerRNA *ptr) +static int rna_WorkSpace_asset_library_get(PointerRNA *ptr) { const WorkSpace *workspace = ptr->data; - return rna_asset_library_reference_get(&workspace->active_asset_library); + return ED_asset_library_reference_to_enum_value(&workspace->asset_library); } -static void rna_WorkSpace_active_asset_library_set(PointerRNA *ptr, int value) +static void rna_WorkSpace_asset_library_set(PointerRNA *ptr, int value) { WorkSpace *workspace = ptr->data; - rna_asset_library_reference_set(&workspace->active_asset_library, value); + workspace->asset_library = ED_asset_library_reference_from_enum_value(value); } static bToolRef *rna_WorkSpace_tools_from_tkey(WorkSpace *workspace, @@ -420,7 +422,7 @@ static void rna_def_workspace(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_window_update_all"); prop = rna_def_asset_library_reference_common( - srna, "rna_WorkSpace_active_asset_library_get", "rna_WorkSpace_active_asset_library_set"); + srna, "rna_WorkSpace_asset_library_get", "rna_WorkSpace_asset_library_set"); RNA_def_property_ui_text(prop, "Asset Library", "Active asset library to show in the UI, not used by the Asset Browser " diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c index 04a8500d136..56e8418972c 100644 --- a/source/blender/makesrna/intern/rna_xr.c +++ b/source/blender/makesrna/intern/rna_xr.c @@ -34,6 +34,63 @@ # include "WM_api.h" +# ifdef WITH_XR_OPENXR +static wmXrData *rna_XrSession_wm_xr_data_get(PointerRNA *ptr) +{ + /* Callers could also get XrSessionState pointer through ptr->data, but prefer if we just + * consistently pass wmXrData pointers to the WM_xr_xxx() API. */ + + BLI_assert((ptr->type == &RNA_XrSessionSettings) || (ptr->type == &RNA_XrSessionState)); + + wmWindowManager *wm = (wmWindowManager *)ptr->owner_id; + BLI_assert(wm && (GS(wm->id.name) == ID_WM)); + + return &wm->xr; +} +# endif + +static bool rna_XrSessionSettings_use_positional_tracking_get(PointerRNA *ptr) +{ +# ifdef WITH_XR_OPENXR + const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr); + return (xr->session_settings.flag & XR_SESSION_USE_POSITION_TRACKING) != 0; +# else + UNUSED_VARS(ptr); + return false; +# endif +} + +static void rna_XrSessionSettings_use_positional_tracking_set(PointerRNA *ptr, bool value) +{ +# ifdef WITH_XR_OPENXR + wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr); + SET_FLAG_FROM_TEST(xr->session_settings.flag, value, XR_SESSION_USE_POSITION_TRACKING); +# else + UNUSED_VARS(ptr, value); +# endif +} + +static bool rna_XrSessionSettings_use_absolute_tracking_get(PointerRNA *ptr) +{ +# ifdef WITH_XR_OPENXR + const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr); + return (xr->session_settings.flag & XR_SESSION_USE_ABSOLUTE_TRACKING) != 0; +# else + UNUSED_VARS(ptr); + return false; +# endif +} + +static void rna_XrSessionSettings_use_absolute_tracking_set(PointerRNA *ptr, bool value) +{ +# ifdef WITH_XR_OPENXR + wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr); + SET_FLAG_FROM_TEST(xr->session_settings.flag, value, XR_SESSION_USE_ABSOLUTE_TRACKING); +# else + UNUSED_VARS(ptr, value); +# endif +} + static bool rna_XrSessionState_is_running(bContext *C) { # ifdef WITH_XR_OPENXR @@ -55,25 +112,10 @@ static void rna_XrSessionState_reset_to_base_pose(bContext *C) # endif } -# ifdef WITH_XR_OPENXR -static wmXrData *rna_XrSessionState_wm_xr_data_get(PointerRNA *ptr) -{ - /* Callers could also get XrSessionState pointer through ptr->data, but prefer if we just - * consistently pass wmXrData pointers to the WM_xr_xxx() API. */ - - BLI_assert(ptr->type == &RNA_XrSessionState); - - wmWindowManager *wm = (wmWindowManager *)ptr->owner_id; - BLI_assert(wm && (GS(wm->id.name) == ID_WM)); - - return &wm->xr; -} -# endif - static void rna_XrSessionState_viewer_pose_location_get(PointerRNA *ptr, float *r_values) { # ifdef WITH_XR_OPENXR - const wmXrData *xr = rna_XrSessionState_wm_xr_data_get(ptr); + const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr); WM_xr_session_state_viewer_pose_location_get(xr, r_values); # else UNUSED_VARS(ptr); @@ -84,7 +126,7 @@ static void rna_XrSessionState_viewer_pose_location_get(PointerRNA *ptr, float * static void rna_XrSessionState_viewer_pose_rotation_get(PointerRNA *ptr, float *r_values) { # ifdef WITH_XR_OPENXR - const wmXrData *xr = rna_XrSessionState_wm_xr_data_get(ptr); + const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr); WM_xr_session_state_viewer_pose_rotation_get(xr, r_values); # else UNUSED_VARS(ptr); @@ -181,12 +223,22 @@ static void rna_def_xr_session_settings(BlenderRNA *brna) RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL); prop = RNA_def_property(srna, "use_positional_tracking", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", XR_SESSION_USE_POSITION_TRACKING); + RNA_def_property_boolean_funcs(prop, + "rna_XrSessionSettings_use_positional_tracking_get", + "rna_XrSessionSettings_use_positional_tracking_set"); RNA_def_property_ui_text( prop, "Positional Tracking", "Allow VR headsets to affect the location in virtual space, in addition to the rotation"); RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL); + + prop = RNA_def_property(srna, "use_absolute_tracking", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, + "rna_XrSessionSettings_use_absolute_tracking_get", + "rna_XrSessionSettings_use_absolute_tracking_set"); + RNA_def_property_ui_text( + prop, "Absolute Tracking", "Use unadjusted location/rotation as defined by the XR runtime"); + RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL); } static void rna_def_xr_session_state(BlenderRNA *brna) diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 722614c4831..6a9c9715994 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -194,8 +194,8 @@ static void dm_mvert_map_doubles(int *doubles_map, i_target_low_bound = 0; target_scan_completed = false; - /* Scan source vertices, in SortVertsElem sorted array, */ - /* all the while maintaining the lower bound of possible doubles in target vertices */ + /* Scan source vertices, in #SortVertsElem sorted array, + * all the while maintaining the lower bound of possible doubles in target vertices. */ for (i_source = 0, sve_source = sorted_verts_source; i_source < source_num_verts; i_source++, sve_source++) { int best_target_vertex = -1; diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 87fce26c45e..5fa11ffdd10 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -10,7 +10,7 @@ * 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, + * 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) 2005 by the Blender Foundation. @@ -1133,6 +1133,18 @@ static void panel_draw(const bContext *C, Panel *panel) } } + /* Draw node warnings. */ + if (nmd->runtime_eval_log != nullptr) { + const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log); + log.foreach_node_log([layout](const geo_log::NodeLog &node_log) { + for (const geo_log::NodeWarning &warning : node_log.warnings()) { + if (warning.type != geo_log::NodeWarningType::Info) { + uiItemL(layout, warning.message.c_str(), ICON_ERROR); + } + } + }); + } + modifier_panel_end(layout, ptr); } diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 54bb68dc21a..e7750f0a0d1 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -257,10 +257,10 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd, generate_vert_coordinates(mesh, ob, ob_target, enmd->offset, num_verts, cos, size); /** - * size gives us our spheroid coefficients ``(A, B, C)``. + * size gives us our spheroid coefficients `(A, B, C)`. * Then, we want to find out for each vert its (a, b, c) triple (proportional to (A, B, C) one). * - * Ellipsoid basic equation: ``(x^2/a^2) + (y^2/b^2) + (z^2/c^2) = 1.`` + * Ellipsoid basic equation: `(x^2/a^2) + (y^2/b^2) + (z^2/c^2) = 1`. * Since we want to find (a, b, c) matching this equation and proportional to (A, B, C), * we can do: * <pre> diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index ef70f3fe6f4..71fc7f3e424 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -282,13 +282,13 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) { if (ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB)) { uiItemO(layout, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert"), + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Instances Real"), ICON_NONE, "OBJECT_OT_duplicates_make_real"); } else if (psys->part->ren_as == PART_DRAW_PATH) { uiItemO(layout, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert"), + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert to Mesh"), ICON_NONE, "OBJECT_OT_modifier_convert"); } diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index dd011a293ee..ec6de8f8387 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -94,6 +94,11 @@ typedef struct SDefBindCalcData { float imat[4][4]; const float falloff; int success; + /** Vertex group lookup data. */ + const MDeformVert *const dvert; + int const defgrp_index; + bool const invert_vgroup; + bool const sparse_bind; } SDefBindCalcData; /** @@ -218,7 +223,7 @@ static void freeData(ModifierData *md) SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; if (smd->verts) { - for (int i = 0; i < smd->numverts; i++) { + for (int i = 0; i < smd->num_bind_verts; i++) { if (smd->verts[i].binds) { for (int j = 0; j < smd->verts[i].numbinds; j++) { MEM_SAFE_FREE(smd->verts[i].binds[j].vert_inds); @@ -243,7 +248,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla if (smd->verts) { tsmd->verts = MEM_dupallocN(smd->verts); - for (int i = 0; i < smd->numverts; i++) { + for (int i = 0; i < smd->num_bind_verts; i++) { if (smd->verts[i].binds) { tsmd->verts[i].binds = MEM_dupallocN(smd->verts[i].binds); @@ -963,12 +968,32 @@ static void bindVert(void *__restrict userdata, SDefBindPoly *bpoly; SDefBind *sdbind; + sdvert->vertex_idx = index; + if (data->success != MOD_SDEF_BIND_RESULT_SUCCESS) { sdvert->binds = NULL; sdvert->numbinds = 0; return; } + if (data->sparse_bind) { + float weight = 0.0f; + + if (data->dvert && data->defgrp_index != -1) { + weight = BKE_defvert_find_weight(&data->dvert[index], data->defgrp_index); + } + + if (data->invert_vgroup) { + weight = 1.0f - weight; + } + + if (weight <= 0) { + sdvert->binds = NULL; + sdvert->numbinds = 0; + return; + } + } + copy_v3_v3(point_co, data->vertexCos[index]); bwdata = computeBindWeights(data, point_co); @@ -1135,6 +1160,21 @@ static void bindVert(void *__restrict userdata, freeBindData(bwdata); } +/* Remove vertices without bind data from the bind array. */ +static void compactSparseBinds(SurfaceDeformModifierData *smd) +{ + smd->num_bind_verts = 0; + + for (uint i = 0; i < smd->num_mesh_verts; i++) { + if (smd->verts[i].numbinds > 0) { + smd->verts[smd->num_bind_verts++] = smd->verts[i]; + } + } + + smd->verts = MEM_reallocN_id( + smd->verts, sizeof(*smd->verts) * smd->num_bind_verts, "SDefBindVerts (sparse)"); +} + static bool surfacedeformBind(Object *ob, SurfaceDeformModifierData *smd_orig, SurfaceDeformModifierData *smd_eval, @@ -1142,7 +1182,8 @@ static bool surfacedeformBind(Object *ob, uint numverts, uint tnumpoly, uint tnumverts, - Mesh *target) + Mesh *target, + Mesh *mesh) { BVHTreeFromMesh treeData = {NULL}; const MVert *mvert = target->mvert; @@ -1205,9 +1246,15 @@ static bool surfacedeformBind(Object *ob, return false; } - smd_orig->numverts = numverts; + smd_orig->num_mesh_verts = numverts; smd_orig->numpoly = tnumpoly; + int defgrp_index; + MDeformVert *dvert; + MOD_get_vgroup(ob, mesh, smd_orig->defgrp_name, &dvert, &defgrp_index); + const bool invert_vgroup = (smd_orig->flags & MOD_SDEF_INVERT_VGROUP) != 0; + const bool sparse_bind = (smd_orig->flags & MOD_SDEF_SPARSE_BIND) != 0; + SDefBindCalcData data = { .treeData = &treeData, .vert_edges = vert_edges, @@ -1221,6 +1268,10 @@ static bool surfacedeformBind(Object *ob, .vertexCos = vertexCos, .falloff = smd_orig->falloff, .success = MOD_SDEF_BIND_RESULT_SUCCESS, + .dvert = dvert, + .defgrp_index = defgrp_index, + .invert_vgroup = invert_vgroup, + .sparse_bind = sparse_bind, }; if (data.targetCos == NULL) { @@ -1242,6 +1293,13 @@ static bool surfacedeformBind(Object *ob, MEM_freeN(data.targetCos); + if (sparse_bind) { + compactSparseBinds(smd_orig); + } + else { + smd_orig->num_bind_verts = numverts; + } + if (data.success == MOD_SDEF_BIND_RESULT_MEM_ERR) { BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory"); freeData((ModifierData *)smd_orig); @@ -1267,6 +1325,11 @@ static bool surfacedeformBind(Object *ob, BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Target contains invalid polygons"); freeData((ModifierData *)smd_orig); } + else if (smd_orig->num_bind_verts == 0 || !smd_orig->verts) { + data.success = MOD_SDEF_BIND_RESULT_GENERIC_ERR; + BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "No vertices were bound"); + freeData((ModifierData *)smd_orig); + } freeAdjacencyMap(vert_edges, adj_array, edge_polys); free_bvhtree_from_mesh(&treeData); @@ -1281,14 +1344,15 @@ static void deformVert(void *__restrict userdata, const SDefDeformData *const data = (SDefDeformData *)userdata; const SDefBind *sdbind = data->bind_verts[index].binds; const int num_binds = data->bind_verts[index].numbinds; - float *const vertexCos = data->vertexCos[index]; + const unsigned int vertex_idx = data->bind_verts[index].vertex_idx; + float *const vertexCos = data->vertexCos[vertex_idx]; float norm[3], temp[3], offset[3]; /* Retrieve the value of the weight vertex group if specified. */ float weight = 1.0f; if (data->dvert && data->defgrp_index != -1) { - weight = BKE_defvert_find_weight(&data->dvert[index], data->defgrp_index); + weight = BKE_defvert_find_weight(&data->dvert[vertex_idx], data->defgrp_index); if (data->invert_vgroup) { weight = 1.0f - weight; @@ -1423,7 +1487,8 @@ static void surfacedeformModifier_do(ModifierData *md, /* Avoid converting edit-mesh data, binding is an exception. */ BKE_mesh_wrapper_ensure_mdata(target); - if (!surfacedeformBind(ob, smd_orig, smd, vertexCos, numverts, tnumpoly, tnumverts, target)) { + if (!surfacedeformBind( + ob, smd_orig, smd, vertexCos, numverts, tnumpoly, tnumverts, target, mesh)) { smd->flags &= ~MOD_SDEF_BIND; } /* Early abort, this is binding 'call', no need to perform whole evaluation. */ @@ -1431,8 +1496,9 @@ static void surfacedeformModifier_do(ModifierData *md, } /* Poly count checks */ - if (smd->numverts != numverts) { - BKE_modifier_set_error(ob, md, "Vertices changed from %u to %u", smd->numverts, numverts); + if (smd->num_mesh_verts != numverts) { + BKE_modifier_set_error( + ob, md, "Vertices changed from %u to %u", smd->num_mesh_verts, numverts); return; } if (smd->numpoly != tnumpoly) { @@ -1468,8 +1534,8 @@ static void surfacedeformModifier_do(ModifierData *md, TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (numverts > 10000); - BLI_task_parallel_range(0, numverts, &data, deformVert, &settings); + settings.use_threading = (smd->num_bind_verts > 10000); + BLI_task_parallel_range(0, smd->num_bind_verts, &data, deformVert, &settings); MEM_freeN(data.targetCos); } @@ -1554,6 +1620,11 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); + col = uiLayoutColumn(layout, false); + uiLayoutSetEnabled(col, !is_bound); + uiLayoutSetActive(col, !is_bound && RNA_string_length(ptr, "vertex_group") != 0); + uiItemR(col, ptr, "use_sparse_bind", 0, NULL, ICON_NONE); + uiItemS(layout); col = uiLayoutColumn(layout, false); @@ -1576,10 +1647,10 @@ static void blendWrite(BlendWriter *writer, const ModifierData *md) { const SurfaceDeformModifierData *smd = (const SurfaceDeformModifierData *)md; - BLO_write_struct_array(writer, SDefVert, smd->numverts, smd->verts); + BLO_write_struct_array(writer, SDefVert, smd->num_bind_verts, smd->verts); if (smd->verts) { - for (int i = 0; i < smd->numverts; i++) { + for (int i = 0; i < smd->num_bind_verts; i++) { BLO_write_struct_array(writer, SDefBind, smd->verts[i].numbinds, smd->verts[i].binds); if (smd->verts[i].binds) { @@ -1607,7 +1678,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md) BLO_read_data_address(reader, &smd->verts); if (smd->verts) { - for (int i = 0; i < smd->numverts; i++) { + for (int i = 0; i < smd->num_bind_verts; i++) { BLO_read_data_address(reader, &smd->verts[i].binds); if (smd->verts[i].binds) { diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c index 9245afdb096..6239ee45e59 100644 --- a/source/blender/modifiers/intern/MOD_ui_common.c +++ b/source/blender/modifiers/intern/MOD_ui_common.c @@ -9,7 +9,7 @@ * 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, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index bbdd7d0e647..3b147c69716 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -623,7 +623,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * CustomData *ldata = &result->ldata; clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL); - /* Keep info whether we had clnors, + /* Keep info whether we had clnors, * it helps when generating clnor spaces and default normals. */ const bool has_clnors = clnors != NULL; if (!clnors) { diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c index 696c4c855c7..e403051d1be 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.c +++ b/source/blender/modifiers/intern/MOD_weightvg_util.c @@ -167,9 +167,9 @@ void weightvg_do_mask(const ModifierEvalContext *ctx, const int numVerts = mesh->totvert; /* Use new generic get_texture_coords, but do not modify our DNA struct for it... - * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ? - * What e.g. if a modifier wants to use several textures ? - * Why use only v_co, and not MVert (or both) ? + * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters? + * What e.g. if a modifier wants to use several textures? + * Why use only v_co, and not MVert (or both)? */ t_map.texture = texture; t_map.map_object = tex_map_object; diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c index fe2d699aea8..b1fa2a7d912 100644 --- a/source/blender/modifiers/intern/MOD_weld.c +++ b/source/blender/modifiers/intern/MOD_weld.c @@ -1735,6 +1735,9 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, uint v1 = me->v1; uint v2 = me->v2; + if (wmd->flag & MOD_WELD_LOOSE_EDGES && (me->flag & ME_LOOSEEDGE) == 0) { + continue; + } while (v1 != vert_dest_map[v1]) { v1 = vert_dest_map[v1]; } @@ -2019,11 +2022,15 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) PointerRNA ob_ptr; PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr); + int weld_mode = RNA_enum_get(ptr, "mode"); uiLayoutSetPropSep(layout, true); uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE); uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE); + if (weld_mode == MOD_WELD_MODE_CONNECTED) { + uiItemR(layout, ptr, "loose_edges", 0, NULL, ICON_NONE); + } modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); modifier_panel_end(layout, ptr); diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index dc19508be04..36e5be6a292 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -175,9 +175,11 @@ set(SRC geometry/nodes/node_geo_curve_primitive_star.cc geometry/nodes/node_geo_curve_resample.cc geometry/nodes/node_geo_curve_reverse.cc + geometry/nodes/node_geo_curve_set_handles.cc geometry/nodes/node_geo_curve_subdivide.cc geometry/nodes/node_geo_curve_to_mesh.cc geometry/nodes/node_geo_curve_to_points.cc + geometry/nodes/node_geo_curve_trim.cc geometry/nodes/node_geo_delete_geometry.cc geometry/nodes/node_geo_edge_split.cc geometry/nodes/node_geo_input_material.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index ad3a838f4c0..868fcbb33af 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -62,9 +62,11 @@ void register_node_type_geo_curve_primitive_spiral(void); void register_node_type_geo_curve_primitive_star(void); void register_node_type_geo_curve_resample(void); void register_node_type_geo_curve_reverse(void); +void register_node_type_geo_curve_set_handles(void); void register_node_type_geo_curve_subdivide(void); void register_node_type_geo_curve_to_mesh(void); void register_node_type_geo_curve_to_points(void); +void register_node_type_geo_curve_trim(void); void register_node_type_geo_delete_geometry(void); void register_node_type_geo_edge_split(void); void register_node_type_geo_input_material(void); diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh index b85862a0176..00d97b24646 100644 --- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh +++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh @@ -31,6 +31,7 @@ */ #include "BLI_enumerable_thread_specific.hh" +#include "BLI_function_ref.hh" #include "BLI_linear_allocator.hh" #include "BLI_map.hh" @@ -267,6 +268,7 @@ class TreeLog { const NodeLog *lookup_node_log(StringRef node_name) const; const NodeLog *lookup_node_log(const bNode &node) const; const TreeLog *lookup_child_log(StringRef node_name) const; + void foreach_node_log(FunctionRef<void(const NodeLog &)> fn) const; }; /** Contains information about an entire geometry nodes evaluation. */ @@ -296,6 +298,7 @@ class ModifierLog { const bNodeSocket &socket); static const NodeLog *find_node_by_spreadsheet_editor_context( const SpaceSpreadsheet &sspreadsheet); + void foreach_node_log(FunctionRef<void(const NodeLog &)> fn) const; private: using LogByTreeContext = Map<const DTreeContext *, TreeLog *>; diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 73d4a002991..1298acf475d 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -156,7 +156,7 @@ DefNode(CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SA DefNode(CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" ) DefNode(CompositorNode, CMP_NODE_R_LAYERS, def_cmp_render_layers, "R_LAYERS", RLayers, "Render Layers", "" ) DefNode(CompositorNode, CMP_NODE_COMPOSITE, def_cmp_composite, "COMPOSITE", Composite, "Composite", "" ) -/* NB: OutputFile node has special rna setup function called in rna_nodetree.c */ +/* NOTE: #OutputFile node has special RNA setup function called in rna_nodetree.c */ DefNode(CompositorNode, CMP_NODE_OUTPUT_FILE, 0, "OUTPUT_FILE", OutputFile, "File Output", "" ) DefNode(CompositorNode, CMP_NODE_TEXTURE, def_texture, "TEXTURE", Texture, "Texture", "" ) DefNode(CompositorNode, CMP_NODE_TRANSLATE, def_cmp_translate, "TRANSLATE", Translate, "Translate", "" ) @@ -300,8 +300,10 @@ DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, 0, "CURVE_PRIMI DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "") DefNode(GeometryNode, GEO_NODE_CURVE_RESAMPLE, def_geo_curve_resample, "CURVE_RESAMPLE", CurveResample, "Resample Curve", "") +DefNode(GeometryNode, GEO_NODE_CURVE_SET_HANDLES, def_geo_curve_set_handles, "CURVE_SET_HANDLES", CurveSetHandles, "Set Handle Type", "") DefNode(GeometryNode, GEO_NODE_CURVE_SUBDIVIDE, def_geo_curve_subdivide, "CURVE_SUBDIVIDE", CurveSubdivide, "Curve Subdivide", "") DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "") +DefNode(GeometryNode, GEO_NODE_CURVE_TRIM, def_geo_curve_trim, "CURVE_TRIM", CurveTrim, "Curve Trim", "") DefNode(GeometryNode, GEO_NODE_CURVE_REVERSE, 0, "CURVE_REVERSE", CurveReverse, "Curve Reverse", "") DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "") DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINTS, 0, "CURVE_ENDPOINTS", CurveEndpoints, "Curve Endpoints", "") diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c index 013d196e1c8..d21e0938356 100644 --- a/source/blender/nodes/composite/node_composite_tree.c +++ b/source/blender/nodes/composite/node_composite_tree.c @@ -264,14 +264,15 @@ void ntreeCompositExecTree(Scene *scene, /* *********************************************** */ -/* Update the outputs of the render layer nodes. +/** + * Update the outputs of the render layer nodes. * Since the outputs depend on the render engine, this part is a bit complex: - * - ntreeCompositUpdateRLayers is called and loops over all render layer nodes. + * - #ntreeCompositUpdateRLayers is called and loops over all render layer nodes. * - Each render layer node calls the update function of the * render engine that's used for its scene. * - The render engine calls RE_engine_register_pass for each pass. - * - RE_engine_register_pass calls ntreeCompositRegisterPass,. - * which calls node_cmp_rlayers_register_pass for every render layer node. + * - #RE_engine_register_pass calls #ntreeCompositRegisterPass, + * which calls #node_cmp_rlayers_register_pass for every render layer node. */ void ntreeCompositUpdateRLayers(bNodeTree *ntree) { diff --git a/source/blender/nodes/composite/nodes/node_composite_common.c b/source/blender/nodes/composite/nodes/node_composite_common.c index f5eaaef8a31..61abc80fe93 100644 --- a/source/blender/nodes/composite/nodes/node_composite_common.c +++ b/source/blender/nodes/composite/nodes/node_composite_common.c @@ -36,9 +36,8 @@ void register_node_type_cmp_group(void) { static bNodeType ntype; - /* NB: cannot use sh_node_type_base for node group, because it would map the node type - * to the shared NODE_GROUP integer type id. - */ + /* NOTE: Cannot use sh_node_type_base for node group, because it would map the node type + * to the shared NODE_GROUP integer type id. */ node_type_base_custom( &ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT); ntype.type = NODE_GROUP; diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc index 756f93f154f..6a23443d3ab 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc @@ -370,10 +370,12 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry, break; } case ATTR_DOMAIN_CORNER: { - use_mesh = true; - mesh_indices.reinitialize(tot_samples); - mesh_distances_sq.reinitialize(tot_samples); - get_closest_mesh_corners(*mesh, dst_positions, mesh_indices, mesh_distances_sq, {}); + if (mesh->totloop > 0) { + use_mesh = true; + mesh_indices.reinitialize(tot_samples); + mesh_distances_sq.reinitialize(tot_samples); + get_closest_mesh_corners(*mesh, dst_positions, mesh_indices, mesh_distances_sq, {}); + } break; } default: { diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc index e167219ea6b..78b5b109419 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc @@ -74,7 +74,7 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve( if (mode == GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION) { spline->add_point(start, BezierSpline::HandleType::Align, - start - (start_handle_right - start) * -1.0f, + 2.0f * start - start_handle_right, BezierSpline::HandleType::Align, start_handle_right, 1.0f, @@ -83,7 +83,7 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve( BezierSpline::HandleType::Align, end_handle_left, BezierSpline::HandleType::Align, - end - (end_handle_left - end) * -1.0f, + 2.0f * end - end_handle_left, 1.0f, 0.0f); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc new file mode 100644 index 00000000000..72bd8ab188d --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc @@ -0,0 +1,149 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BKE_spline.hh" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_geometry_util.hh" + +static bNodeSocketTemplate geo_node_curve_set_handles_in[] = { + {SOCK_GEOMETRY, N_("Curve")}, + {SOCK_STRING, N_("Selection")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_curve_set_handles_out[] = { + {SOCK_GEOMETRY, N_("Curve")}, + {-1, ""}, +}; + +static void geo_node_curve_set_handles_layout(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); + uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); +} + +namespace blender::nodes { + +static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN( + sizeof(NodeGeometryCurveSetHandles), __func__); + + data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO; + data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT; + node->storage = data; +} + +static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHandleType type) +{ + switch (type) { + case GEO_NODE_CURVE_HANDLE_AUTO: + return BezierSpline::HandleType::Auto; + case GEO_NODE_CURVE_HANDLE_ALIGN: + return BezierSpline::HandleType::Align; + case GEO_NODE_CURVE_HANDLE_FREE: + return BezierSpline::HandleType::Free; + case GEO_NODE_CURVE_HANDLE_VECTOR: + return BezierSpline::HandleType::Vector; + } + BLI_assert_unreachable(); + return BezierSpline::HandleType::Auto; +} + +static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) +{ + const NodeGeometryCurveSetHandles *node_storage = + (NodeGeometryCurveSetHandles *)params.node().storage; + const GeometryNodeCurveHandleType type = (GeometryNodeCurveHandleType)node_storage->handle_type; + const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode; + + GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); + geometry_set = bke::geometry_set_realize_instances(geometry_set); + if (!geometry_set.has_curve()) { + params.set_output("Curve", geometry_set); + return; + } + + /* Retrieve data for write access so we can avoid new allocations for the handles data. */ + CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>(); + CurveEval &curve = *curve_component.get_for_write(); + MutableSpan<SplinePtr> splines = curve.splines(); + + const std::string selection_name = params.extract_input<std::string>("Selection"); + GVArray_Typed<bool> selection = curve_component.attribute_get_for_read( + selection_name, ATTR_DOMAIN_POINT, true); + + const BezierSpline::HandleType new_handle_type = handle_type_from_input_type(type); + int point_index = 0; + bool has_bezier_spline = false; + for (SplinePtr &spline : splines) { + if (spline->type() != Spline::Type::Bezier) { + point_index += spline->positions().size(); + continue; + } + + BezierSpline &bezier_spline = static_cast<BezierSpline &>(*spline); + if (ELEM(new_handle_type, BezierSpline::HandleType::Free, BezierSpline::HandleType::Align)) { + /* In this case the automatically calculated handle types need to be "baked", because + * they're possibly changing from a type that is calculated automatically to a type that + * is positioned manually. */ + bezier_spline.ensure_auto_handles(); + } + has_bezier_spline = true; + for (int i_point : IndexRange(bezier_spline.size())) { + if (selection[point_index]) { + if (mode & GEO_NODE_CURVE_HANDLE_LEFT) { + bezier_spline.handle_types_left()[i_point] = new_handle_type; + } + if (mode & GEO_NODE_CURVE_HANDLE_RIGHT) { + bezier_spline.handle_types_right()[i_point] = new_handle_type; + } + } + point_index++; + } + bezier_spline.mark_cache_invalid(); + } + + if (!has_bezier_spline) { + params.error_message_add(NodeWarningType::Info, TIP_("No Bezier splines in input curve")); + } + + params.set_output("Curve", geometry_set); +} +} // namespace blender::nodes + +void register_node_type_geo_curve_set_handles() +{ + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates( + &ntype, geo_node_curve_set_handles_in, geo_node_curve_set_handles_out); + ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec; + node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init); + node_type_storage(&ntype, + "NodeGeometryCurveSetHandles", + node_free_standard_storage, + node_copy_standard_storage); + ntype.draw_buttons = geo_node_curve_set_handles_layout; + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc index f1bcb4ed47f..ae5ad4e350b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc @@ -47,27 +47,27 @@ static void vert_extrude_to_mesh_data(const Spline &spline, const float3 profile_vert, MutableSpan<MVert> r_verts, MutableSpan<MEdge> r_edges, - int vert_offset, - int edge_offset) + const int vert_offset, + const int edge_offset) { Span<float3> positions = spline.evaluated_positions(); for (const int i : IndexRange(positions.size() - 1)) { - MEdge &edge = r_edges[edge_offset++]; + MEdge &edge = r_edges[edge_offset + i]; edge.v1 = vert_offset + i; edge.v2 = vert_offset + i + 1; edge.flag = ME_LOOSEEDGE; } if (spline.is_cyclic() && spline.evaluated_edges_size() > 1) { - MEdge &edge = r_edges[edge_offset++]; + MEdge &edge = r_edges[edge_offset + spline.evaluated_edges_size() - 1]; edge.v1 = vert_offset; edge.v2 = vert_offset + positions.size() - 1; edge.flag = ME_LOOSEEDGE; } for (const int i : positions.index_range()) { - MVert &vert = r_verts[vert_offset++]; + MVert &vert = r_verts[vert_offset + i]; copy_v3_v3(vert.co, positions[i] + profile_vert); } } @@ -81,14 +81,14 @@ static void mark_edges_sharp(MutableSpan<MEdge> edges) static void spline_extrude_to_mesh_data(const Spline &spline, const Spline &profile_spline, + const int vert_offset, + const int edge_offset, + const int loop_offset, + const int poly_offset, MutableSpan<MVert> r_verts, MutableSpan<MEdge> r_edges, MutableSpan<MLoop> r_loops, - MutableSpan<MPoly> r_polys, - int vert_offset, - int edge_offset, - int loop_offset, - int poly_offset) + MutableSpan<MPoly> r_polys) { const int spline_vert_len = spline.evaluated_points_size(); const int spline_edge_len = spline.evaluated_edges_size(); @@ -111,13 +111,14 @@ static void spline_extrude_to_mesh_data(const Spline &spline, /* Add the edges running along the length of the curve, starting at each profile vertex. */ const int spline_edges_start = edge_offset; for (const int i_profile : IndexRange(profile_vert_len)) { + const int profile_edge_offset = spline_edges_start + i_profile * spline_edge_len; for (const int i_ring : IndexRange(spline_edge_len)) { const int i_next_ring = (i_ring == spline_vert_len - 1) ? 0 : i_ring + 1; const int ring_vert_offset = vert_offset + profile_vert_len * i_ring; const int next_ring_vert_offset = vert_offset + profile_vert_len * i_next_ring; - MEdge &edge = r_edges[edge_offset++]; + MEdge &edge = r_edges[profile_edge_offset + i_ring]; edge.v1 = ring_vert_offset + i_profile; edge.v2 = next_ring_vert_offset + i_profile; edge.flag = ME_EDGEDRAW | ME_EDGERENDER; @@ -125,14 +126,15 @@ static void spline_extrude_to_mesh_data(const Spline &spline, } /* Add the edges running along each profile ring. */ - const int profile_edges_start = edge_offset; + const int profile_edges_start = spline_edges_start + profile_vert_len * spline_edge_len; for (const int i_ring : IndexRange(spline_vert_len)) { const int ring_vert_offset = vert_offset + profile_vert_len * i_ring; + const int ring_edge_offset = profile_edges_start + i_ring * profile_edge_len; for (const int i_profile : IndexRange(profile_edge_len)) { const int i_next_profile = (i_profile == profile_vert_len - 1) ? 0 : i_profile + 1; - MEdge &edge = r_edges[edge_offset++]; + MEdge &edge = r_edges[ring_edge_offset + i_profile]; edge.v1 = ring_vert_offset + i_profile; edge.v2 = ring_vert_offset + i_next_profile; edge.flag = ME_EDGEDRAW | ME_EDGERENDER; @@ -149,29 +151,33 @@ static void spline_extrude_to_mesh_data(const Spline &spline, const int ring_edge_start = profile_edges_start + profile_edge_len * i_ring; const int next_ring_edge_offset = profile_edges_start + profile_edge_len * i_next_ring; + const int ring_poly_offset = poly_offset + i_ring * profile_edge_len; + const int ring_loop_offset = loop_offset + i_ring * profile_edge_len * 4; + for (const int i_profile : IndexRange(profile_edge_len)) { + const int ring_segment_loop_offset = ring_loop_offset + i_profile * 4; const int i_next_profile = (i_profile == profile_vert_len - 1) ? 0 : i_profile + 1; const int spline_edge_start = spline_edges_start + spline_edge_len * i_profile; const int next_spline_edge_start = spline_edges_start + spline_edge_len * i_next_profile; - MPoly &poly = r_polys[poly_offset++]; - poly.loopstart = loop_offset; + MPoly &poly = r_polys[ring_poly_offset + i_profile]; + poly.loopstart = ring_segment_loop_offset; poly.totloop = 4; poly.flag = ME_SMOOTH; - MLoop &loop_a = r_loops[loop_offset++]; + MLoop &loop_a = r_loops[ring_segment_loop_offset]; loop_a.v = ring_vert_offset + i_profile; - loop_a.e = ring_edge_start + i_profile; - MLoop &loop_b = r_loops[loop_offset++]; - loop_b.v = ring_vert_offset + i_next_profile; - loop_b.e = next_spline_edge_start + i_ring; - MLoop &loop_c = r_loops[loop_offset++]; + loop_a.e = spline_edge_start + i_ring; + MLoop &loop_b = r_loops[ring_segment_loop_offset + 1]; + loop_b.v = next_ring_vert_offset + i_profile; + loop_b.e = next_ring_edge_offset + i_profile; + MLoop &loop_c = r_loops[ring_segment_loop_offset + 2]; loop_c.v = next_ring_vert_offset + i_next_profile; - loop_c.e = next_ring_edge_offset + i_profile; - MLoop &loop_d = r_loops[loop_offset++]; - loop_d.v = next_ring_vert_offset + i_profile; - loop_d.e = spline_edge_start + i_ring; + loop_c.e = next_spline_edge_start + i_ring; + MLoop &loop_d = r_loops[ring_segment_loop_offset + 3]; + loop_d.v = ring_vert_offset + i_next_profile; + loop_d.e = ring_edge_start + i_profile; } } @@ -185,11 +191,11 @@ static void spline_extrude_to_mesh_data(const Spline &spline, for (const int i_ring : IndexRange(spline_vert_len)) { float4x4 point_matrix = float4x4::from_normalized_axis_data( positions[i_ring], normals[i_ring], tangents[i_ring]); - point_matrix.apply_scale(radii[i_ring]); + const int ring_vert_start = vert_offset + i_ring * profile_vert_len; for (const int i_profile : IndexRange(profile_vert_len)) { - MVert &vert = r_verts[vert_offset++]; + MVert &vert = r_verts[ring_vert_start + i_profile]; copy_v3_v3(vert.co, point_matrix * profile_positions[i_profile]); } } @@ -275,7 +281,7 @@ static ResultOffsets calculate_result_offsets(Span<SplinePtr> profiles, Span<Spl * Although it would be a sensible decision to use the better topology information available while * generating the mesh to also generate the normals, that work may wasted if the output mesh is * changed anyway in a way that affects the normals. So currently this code uses the safer / - * simpler solution of not calculating normals. + * simpler solution of deferring normal calculation to the rest of Blender. */ static Mesh *curve_to_mesh_calculate(const CurveEval &curve, const CurveEval &profile) { @@ -303,14 +309,14 @@ static Mesh *curve_to_mesh_calculate(const CurveEval &curve, const CurveEval &pr const int i_mesh = spline_start_index + i_profile; spline_extrude_to_mesh_data(*curves[i_spline], *profiles[i_profile], - {mesh->mvert, mesh->totvert}, - {mesh->medge, mesh->totedge}, - {mesh->mloop, mesh->totloop}, - {mesh->mpoly, mesh->totpoly}, offsets.vert[i_mesh], offsets.edge[i_mesh], offsets.loop[i_mesh], - offsets.poly[i_mesh]); + offsets.poly[i_mesh], + {mesh->mvert, mesh->totvert}, + {mesh->medge, mesh->totedge}, + {mesh->mloop, mesh->totloop}, + {mesh->mpoly, mesh->totpoly}); } }); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc new file mode 100644 index 00000000000..f9415c6d27b --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc @@ -0,0 +1,410 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BKE_spline.hh" +#include "BLI_task.hh" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_geometry_util.hh" + +using blender::attribute_math::mix2; + +static bNodeSocketTemplate geo_node_curve_trim_in[] = { + {SOCK_GEOMETRY, N_("Curve")}, + {SOCK_FLOAT, N_("Start"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + {SOCK_FLOAT, N_("End"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR}, + {SOCK_FLOAT, N_("Start"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10000.0f, PROP_DISTANCE}, + {SOCK_FLOAT, N_("End"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_DISTANCE}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_curve_trim_out[] = { + {SOCK_GEOMETRY, N_("Curve")}, + {-1, ""}, +}; + +static void geo_node_curve_trim_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); +} + +static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeGeometryCurveTrim *data = (NodeGeometryCurveTrim *)MEM_callocN(sizeof(NodeGeometryCurveTrim), + __func__); + + data->mode = GEO_NODE_CURVE_INTERPOLATE_FACTOR; + node->storage = data; +} + +static void geo_node_curve_trim_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)node->storage; + const GeometryNodeCurveInterpolateMode mode = (GeometryNodeCurveInterpolateMode) + node_storage.mode; + + bNodeSocket *start_fac = ((bNodeSocket *)node->inputs.first)->next; + bNodeSocket *end_fac = start_fac->next; + bNodeSocket *start_len = end_fac->next; + bNodeSocket *end_len = start_len->next; + + nodeSetSocketAvailability(start_fac, mode == GEO_NODE_CURVE_INTERPOLATE_FACTOR); + nodeSetSocketAvailability(end_fac, mode == GEO_NODE_CURVE_INTERPOLATE_FACTOR); + nodeSetSocketAvailability(start_len, mode == GEO_NODE_CURVE_INTERPOLATE_LENGTH); + nodeSetSocketAvailability(end_len, mode == GEO_NODE_CURVE_INTERPOLATE_LENGTH); +} + +namespace blender::nodes { + +struct TrimLocation { + /* Control point index at the start side of the trim location. */ + int left_index; + /* Control point index at the end of the trim location's segment. */ + int right_index; + /* The factor between the left and right indices. */ + float factor; +}; + +template<typename T> +static void shift_slice_to_start(MutableSpan<T> data, const int start_index, const int size) +{ + BLI_assert(start_index + size - 1 <= data.size()); + memmove(data.data(), &data[start_index], sizeof(T) * size); +} + +/* Shift slice to start of span and modifies start and end data. */ +template<typename T> +static void linear_trim_data(const TrimLocation &start, + const TrimLocation &end, + MutableSpan<T> data) +{ + const int size = end.right_index - start.left_index + 1; + + if (start.left_index > 0) { + shift_slice_to_start<T>(data, start.left_index, size); + } + + const T start_data = mix2<T>(start.factor, data.first(), data[1]); + const T end_data = mix2<T>(end.factor, data[size - 2], data[size - 1]); + + data.first() = start_data; + data[size - 1] = end_data; +} + +/** + * Identical operation as #linear_trim_data, but copy data to a new #MutableSpan rather than + * modifying the original data. + */ +template<typename T> +static void linear_trim_to_output_data(const TrimLocation &start, + const TrimLocation &end, + Span<T> src, + MutableSpan<T> dst) +{ + const int size = end.right_index - start.left_index + 1; + + const T start_data = mix2<T>(start.factor, src[start.left_index], src[start.right_index]); + const T end_data = mix2<T>(end.factor, src[end.left_index], src[end.right_index]); + + dst.copy_from(src.slice(start.left_index, size)); + dst.first() = start_data; + dst.last() = end_data; +} + +/* Look up the control points to the left and right of factor, and get the factor between them. */ +static TrimLocation lookup_control_point_position(const Spline::LookupResult &lookup, + Span<int> control_point_offsets) +{ + const int *left_offset = std::lower_bound( + control_point_offsets.begin(), control_point_offsets.end(), lookup.evaluated_index); + const int index = left_offset - control_point_offsets.begin(); + const int left = control_point_offsets[index] > lookup.evaluated_index ? index - 1 : index; + const int right = left + 1; + + const float factor = std::clamp( + (lookup.evaluated_index + lookup.factor - control_point_offsets[left]) / + (control_point_offsets[right] - control_point_offsets[left]), + 0.0f, + 1.0f); + + return {left, right, factor}; +} + +static void trim_poly_spline(Spline &spline, + const Spline::LookupResult &start_lookup, + const Spline::LookupResult &end_lookup) +{ + /* Poly splines have a 1 to 1 mapping between control points and evaluated points. */ + const TrimLocation start = { + start_lookup.evaluated_index, start_lookup.next_evaluated_index, start_lookup.factor}; + const TrimLocation end = { + end_lookup.evaluated_index, end_lookup.next_evaluated_index, end_lookup.factor}; + + const int size = end.right_index - start.left_index + 1; + + linear_trim_data<float3>(start, end, spline.positions()); + linear_trim_data<float>(start, end, spline.radii()); + linear_trim_data<float>(start, end, spline.tilts()); + + spline.attributes.foreach_attribute( + [&](StringRefNull name, const AttributeMetaData &UNUSED(meta_data)) { + std::optional<GMutableSpan> src = spline.attributes.get_for_write(name); + BLI_assert(src); + attribute_math::convert_to_static_type(src->type(), [&](auto dummy) { + using T = decltype(dummy); + linear_trim_data<T>(start, end, src->typed<T>()); + }); + return true; + }, + ATTR_DOMAIN_POINT); + + spline.resize(size); +} + +/** + * Trim NURB splines by converting to a poly spline. + */ +static PolySpline trim_nurbs_spline(const Spline &spline, + const Spline::LookupResult &start_lookup, + const Spline::LookupResult &end_lookup) +{ + /* Since this outputs a poly spline, the evaluated indices are the control point indices. */ + const TrimLocation start = { + start_lookup.evaluated_index, start_lookup.next_evaluated_index, start_lookup.factor}; + const TrimLocation end = { + end_lookup.evaluated_index, end_lookup.next_evaluated_index, end_lookup.factor}; + + const int size = end.right_index - start.left_index + 1; + + /* Create poly spline and copy trimmed data to it. */ + PolySpline new_spline; + new_spline.resize(size); + + /* Copy generic attribute data. */ + spline.attributes.foreach_attribute( + [&](StringRefNull name, const AttributeMetaData &meta_data) { + std::optional<GSpan> src = spline.attributes.get_for_read(name); + BLI_assert(src); + if (!new_spline.attributes.create(name, meta_data.data_type)) { + BLI_assert_unreachable(); + return false; + } + std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(name); + BLI_assert(dst); + + attribute_math::convert_to_static_type(src->type(), [&](auto dummy) { + using T = decltype(dummy); + GVArray_Typed<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); + linear_trim_to_output_data<T>( + start, end, eval_data->get_internal_span(), dst->typed<T>()); + }); + return true; + }, + ATTR_DOMAIN_POINT); + + linear_trim_to_output_data<float3>( + start, end, spline.evaluated_positions(), new_spline.positions()); + + GVArray_Typed<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); + linear_trim_to_output_data<float>( + start, end, evaluated_radii->get_internal_span(), new_spline.radii()); + + GVArray_Typed<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); + linear_trim_to_output_data<float>( + start, end, evaluated_tilts->get_internal_span(), new_spline.tilts()); + + return new_spline; +} + +/** + * Trim Bezier splines by adjusting the first and last handles + * and control points to maintain the original shape. + */ +static void trim_bezier_spline(Spline &spline, + const Spline::LookupResult &start_lookup, + const Spline::LookupResult &end_lookup) +{ + BezierSpline &bezier_spline = static_cast<BezierSpline &>(spline); + Span<int> control_offsets = bezier_spline.control_point_offsets(); + + const TrimLocation start = lookup_control_point_position(start_lookup, control_offsets); + TrimLocation end = lookup_control_point_position(end_lookup, control_offsets); + + /* The number of control points in the resulting spline. */ + const int size = end.right_index - start.left_index + 1; + + /* Trim the spline attributes. Done before end.factor recalculation as it needs + * the original end.factor value. */ + linear_trim_data<float>(start, end, bezier_spline.radii()); + linear_trim_data<float>(start, end, bezier_spline.tilts()); + spline.attributes.foreach_attribute( + [&](StringRefNull name, const AttributeMetaData &UNUSED(meta_data)) { + std::optional<GMutableSpan> src = spline.attributes.get_for_write(name); + BLI_assert(src); + attribute_math::convert_to_static_type(src->type(), [&](auto dummy) { + using T = decltype(dummy); + linear_trim_data<T>(start, end, src->typed<T>()); + }); + return true; + }, + ATTR_DOMAIN_POINT); + + /* Recalculate end.factor if the size is two, because the adjustment in the + * position of the control point of the spline to the left of the new end point will change the + * factor between them. */ + if (size == 2) { + if (start_lookup.factor == 1.0f) { + end.factor = 0.0f; + } + else { + end.factor = (end_lookup.evaluated_index + end_lookup.factor - + (start_lookup.evaluated_index + start_lookup.factor)) / + (control_offsets[end.right_index] - + (start_lookup.evaluated_index + start_lookup.factor)); + end.factor = std::clamp(end.factor, 0.0f, 1.0f); + } + } + + BezierSpline::InsertResult start_point = bezier_spline.calculate_segment_insertion( + start.left_index, start.right_index, start.factor); + + /* Update the start control point parameters so they are used calculating the new end point. */ + bezier_spline.positions()[start.left_index] = start_point.position; + bezier_spline.handle_positions_right()[start.left_index] = start_point.right_handle; + bezier_spline.handle_positions_left()[start.right_index] = start_point.handle_next; + + const BezierSpline::InsertResult end_point = bezier_spline.calculate_segment_insertion( + end.left_index, end.right_index, end.factor); + + /* If size is two, then the start point right handle needs to change to reflect the end point + * previous handle update. */ + if (size == 2) { + start_point.right_handle = end_point.handle_prev; + } + + /* Shift control point position data to start at beginning of array. */ + if (start.left_index > 0) { + shift_slice_to_start(bezier_spline.positions(), start.left_index, size); + shift_slice_to_start(bezier_spline.handle_positions_left(), start.left_index, size); + shift_slice_to_start(bezier_spline.handle_positions_right(), start.left_index, size); + } + + bezier_spline.positions().first() = start_point.position; + bezier_spline.positions()[size - 1] = end_point.position; + + bezier_spline.handle_positions_left().first() = start_point.left_handle; + bezier_spline.handle_positions_left()[size - 1] = end_point.left_handle; + + bezier_spline.handle_positions_right().first() = start_point.right_handle; + bezier_spline.handle_positions_right()[size - 1] = end_point.right_handle; + + /* If there is at least one control point between the endpoints, update the control + * point handle to the right of the start point and to the left of the end point. */ + if (size > 2) { + bezier_spline.handle_positions_left()[start.right_index - start.left_index] = + start_point.handle_next; + bezier_spline.handle_positions_right()[end.left_index - start.left_index] = + end_point.handle_prev; + } + + bezier_spline.resize(size); +} + +static void geo_node_curve_trim_exec(GeoNodeExecParams params) +{ + const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)params.node().storage; + const GeometryNodeCurveInterpolateMode mode = (GeometryNodeCurveInterpolateMode) + node_storage.mode; + + GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); + geometry_set = bke::geometry_set_realize_instances(geometry_set); + if (!geometry_set.has_curve()) { + params.set_output("Curve", std::move(geometry_set)); + return; + } + + CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>(); + CurveEval &curve = *curve_component.get_for_write(); + MutableSpan<SplinePtr> splines = curve.splines(); + + const float start = mode == GEO_NODE_CURVE_INTERPOLATE_FACTOR ? + params.extract_input<float>("Start") : + params.extract_input<float>("Start_001"); + const float end = mode == GEO_NODE_CURVE_INTERPOLATE_FACTOR ? + params.extract_input<float>("End") : + params.extract_input<float>("End_001"); + + threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { + for (const int i : range) { + Spline &spline = *splines[i]; + + /* Currently this node doesn't support cyclic splines, it could in the future though. */ + if (spline.is_cyclic()) { + continue; + } + + /* Return a spline with one point instead of implicitly + * reversing the spline or switching the parameters. */ + if (end < start) { + spline.resize(1); + continue; + } + + const Spline::LookupResult start_lookup = + (mode == GEO_NODE_CURVE_INTERPOLATE_LENGTH) ? + spline.lookup_evaluated_length(std::clamp(start, 0.0f, spline.length())) : + spline.lookup_evaluated_factor(std::clamp(start, 0.0f, 1.0f)); + const Spline::LookupResult end_lookup = + (mode == GEO_NODE_CURVE_INTERPOLATE_LENGTH) ? + spline.lookup_evaluated_length(std::clamp(end, 0.0f, spline.length())) : + spline.lookup_evaluated_factor(std::clamp(end, 0.0f, 1.0f)); + + switch (spline.type()) { + case Spline::Type::Bezier: + trim_bezier_spline(spline, start_lookup, end_lookup); + break; + case Spline::Type::Poly: + trim_poly_spline(spline, start_lookup, end_lookup); + break; + case Spline::Type::NURBS: + splines[i] = std::make_unique<PolySpline>( + trim_nurbs_spline(spline, start_lookup, end_lookup)); + break; + } + splines[i]->mark_cache_invalid(); + } + }); + + params.set_output("Curve", std::move(geometry_set)); +} + +} // namespace blender::nodes + +void register_node_type_geo_curve_trim() +{ + static bNodeType ntype; + geo_node_type_base(&ntype, GEO_NODE_CURVE_TRIM, "Curve Trim", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, geo_node_curve_trim_in, geo_node_curve_trim_out); + ntype.geometry_node_execute = blender::nodes::geo_node_curve_trim_exec; + ntype.draw_buttons = geo_node_curve_trim_layout; + node_type_storage( + &ntype, "NodeGeometryCurveTrim", node_free_standard_storage, node_copy_standard_storage); + node_type_init(&ntype, geo_node_curve_trim_init); + node_type_update(&ntype, geo_node_curve_trim_update); + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index 3d5557d4049..f7279cf7524 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -73,7 +73,9 @@ void DerivedNodeTree::destruct_context_recursively(DTreeContext *context) context->~DTreeContext(); } -/* Returns true if there are any cycles in the node tree. */ +/** + * \return True when there is a link cycle. Unavailable sockets are ignored. + */ bool DerivedNodeTree::has_link_cycles() const { for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index 3024cc51cad..7487f11d77d 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -99,6 +99,13 @@ SocketLog &ModifierLog::lookup_or_add_socket_log(LogByTreeContext &log_by_tree_c return socket_log; } +void ModifierLog::foreach_node_log(FunctionRef<void(const NodeLog &)> fn) const +{ + if (root_tree_logs_) { + root_tree_logs_->foreach_node_log(fn); + } +} + const NodeLog *TreeLog::lookup_node_log(StringRef node_name) const { const destruct_ptr<NodeLog> *node_log = node_logs_.lookup_ptr_as(node_name); @@ -122,6 +129,17 @@ const TreeLog *TreeLog::lookup_child_log(StringRef node_name) const return tree_log->get(); } +void TreeLog::foreach_node_log(FunctionRef<void(const NodeLog &)> fn) const +{ + for (auto node_log : node_logs_.items()) { + fn(*node_log.value); + } + + for (auto child : child_logs_.items()) { + child.value->foreach_node_log(fn); + } +} + const SocketLog *NodeLog::lookup_socket_log(eNodeSocketInOut in_out, int index) const { BLI_assert(index >= 0); diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc index 9ce9d6fc273..641d02af902 100644 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ b/source/blender/nodes/intern/node_tree_ref.cc @@ -423,7 +423,13 @@ static bool has_link_cycles_recursive(const NodeRef &node, is_in_stack[node_id] = true; for (const OutputSocketRef *from_socket : node.outputs()) { + if (!from_socket->is_available()) { + continue; + } for (const InputSocketRef *to_socket : from_socket->directly_linked_sockets()) { + if (!to_socket->is_available()) { + continue; + } const NodeRef &to_node = to_socket->node(); if (has_link_cycles_recursive(to_node, visited, is_in_stack)) { return true; @@ -435,6 +441,9 @@ static bool has_link_cycles_recursive(const NodeRef &node, return false; } +/** + * \return True when there is a link cycle. Unavailable sockets are ignored. + */ bool NodeTreeRef::has_link_cycles() const { const int node_amount = nodes_by_id_.size(); diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c index a864bef60d9..4df5add7151 100644 --- a/source/blender/nodes/shader/nodes/node_shader_common.c +++ b/source/blender/nodes/shader/nodes/node_shader_common.c @@ -229,9 +229,9 @@ void register_node_type_sh_group(void) { static bNodeType ntype; - /* NB: cannot use sh_node_type_base for node group, because it would map the node type - * to the shared NODE_GROUP integer type id. - */ + /* NOTE: cannot use #sh_node_type_base for node group, because it would map the node type + * to the shared #NODE_GROUP integer type id. */ + node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT); ntype.type = NODE_GROUP; ntype.poll = sh_node_poll_default; diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c index b87720be5b0..2de64779ea6 100644 --- a/source/blender/nodes/texture/nodes/node_texture_common.c +++ b/source/blender/nodes/texture/nodes/node_texture_common.c @@ -158,9 +158,9 @@ void register_node_type_tex_group(void) { static bNodeType ntype; - /* NB: cannot use sh_node_type_base for node group, because it would map the node type - * to the shared NODE_GROUP integer type id. - */ + /* NOTE: Cannot use #sh_node_type_base for node group, because it would map the node type + * to the shared #NODE_GROUP integer type id. */ + node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT); ntype.type = NODE_GROUP; ntype.poll = tex_node_poll_default; diff --git a/source/blender/nodes/texture/nodes/node_texture_rotate.c b/source/blender/nodes/texture/nodes/node_texture_rotate.c index 06eb632378c..9985499772e 100644 --- a/source/blender/nodes/texture/nodes/node_texture_rotate.c +++ b/source/blender/nodes/texture/nodes/node_texture_rotate.c @@ -47,7 +47,7 @@ static void rotate(float new_co[3], float a, const float ax[3], const float co[3 float cos_a = cosf(a * (float)(2 * M_PI)); float sin_a = sinf(a * (float)(2 * M_PI)); - // x' = xcosa + n(n.x)(1-cosa) + (x*n)sina + /* `x' = xcosa + n(n.x)(1-cosa) + (x*n)sina`. */ mul_v3_v3fl(perp, co, cos_a); mul_v3_v3fl(para, ax, dot_v3v3(co, ax) * (1 - cos_a)); diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index 84d804f8bdf..43a73363c98 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -30,7 +30,7 @@ struct PathResolvedRNA; struct Text; /* defined in DNA_text_types.h */ struct bConstraint; /* DNA_constraint_types.h */ struct bConstraintOb; /* DNA_constraint_types.h */ -struct bConstraintTarget; /* DNA_constraint_types.h*/ +struct bConstraintTarget; /* DNA_constraint_types.h */ struct bContext; struct bContextDataResult; struct bPythonConstraint; /* DNA_constraint_types.h */ diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index a27ef30c849..68fefee4a61 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -525,7 +525,7 @@ PyObject *PyC_FrozenSetFromStrings(const char **strings) * * Implementation - we can't actually prepend the existing exception, * because it could have _any_ arguments given to it, so instead we get its - * ``__str__`` output and raise our own exception including it. + * `__str__` output and raise our own exception including it. */ PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...) { diff --git a/source/blender/python/gpu/gpu_py.c b/source/blender/python/gpu/gpu_py.c index 7aea940da94..e6ba46b2b05 100644 --- a/source/blender/python/gpu/gpu_py.c +++ b/source/blender/python/gpu/gpu_py.c @@ -17,8 +17,8 @@ /** \file * \ingroup bpygpu * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_api.c b/source/blender/python/gpu/gpu_py_api.c index 5119b3612f8..db84e03adcb 100644 --- a/source/blender/python/gpu/gpu_py_api.c +++ b/source/blender/python/gpu/gpu_py_api.c @@ -20,8 +20,8 @@ * Experimental Python API, not considered public yet (called '_gpu'), * we may re-expose as public later. * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c index 5214d156adf..c0c0aa0028d 100644 --- a/source/blender/python/gpu/gpu_py_batch.c +++ b/source/blender/python/gpu/gpu_py_batch.c @@ -19,11 +19,11 @@ /** \file * \ingroup bpygpu * - * This file defines the offscreen functionalities of the 'gpu' module + * This file defines the off-screen functionalities of the 'gpu' module * used for off-screen OpenGL rendering. * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c index 5c004459b44..a1fc89e772e 100644 --- a/source/blender/python/gpu/gpu_py_buffer.c +++ b/source/blender/python/gpu/gpu_py_buffer.c @@ -19,8 +19,8 @@ * * This file defines the gpu.state API. * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_capabilities.c b/source/blender/python/gpu/gpu_py_capabilities.c index cedce485253..f3fb93021b2 100644 --- a/source/blender/python/gpu/gpu_py_capabilities.c +++ b/source/blender/python/gpu/gpu_py_capabilities.c @@ -17,8 +17,8 @@ /** \file * \ingroup bpygpu * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_element.c b/source/blender/python/gpu/gpu_py_element.c index 0cb5e9a2785..2dd8d1c379e 100644 --- a/source/blender/python/gpu/gpu_py_element.c +++ b/source/blender/python/gpu/gpu_py_element.c @@ -17,8 +17,8 @@ /** \file * \ingroup bpygpu * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_framebuffer.c b/source/blender/python/gpu/gpu_py_framebuffer.c index 2f081fcfd8c..a9347b71723 100644 --- a/source/blender/python/gpu/gpu_py_framebuffer.c +++ b/source/blender/python/gpu/gpu_py_framebuffer.c @@ -20,8 +20,8 @@ * This file defines the framebuffer functionalities of the 'gpu' module * used for off-screen OpenGL rendering. * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> @@ -489,7 +489,7 @@ static PyObject *pygpu_framebuffer_read_color(BPyGPUFrameBuffer *self, static const char *_keywords[] = { "x", "y", "xsize", "ysize", "channels", "slot", "format", "data", NULL}; - static _PyArg_Parser _parser = {"iiiiiIO&|$O!:GPUTexture.__new__", _keywords, 0}; + static _PyArg_Parser _parser = {"iiiiiIO&|$O!:read_color", _keywords, 0}; if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, @@ -551,6 +551,57 @@ static PyObject *pygpu_framebuffer_read_color(BPyGPUFrameBuffer *self, return (PyObject *)py_buffer; } +PyDoc_STRVAR(pygpu_framebuffer_read_depth_doc, + ".. function:: read_depth(x, y, xsize, ysize, data=data)\n" + "\n" + " Read a pixel depth block from the frame buffer.\n" + "\n" + " :param x, y: Lower left corner of a rectangular block of pixels.\n" + " :param xsize, ysize: Dimensions of the pixel rectangle.\n" + " :type x, y, xsize, ysize: int\n" + " :arg data: Optional Buffer object to fill with the pixels values.\n" + " :type data: :class:`gpu.types.Buffer`\n" + " :return: The Buffer with the read pixels.\n" + " :rtype: :class:`gpu.types.Buffer`\n"); +static PyObject *pygpu_framebuffer_read_depth(BPyGPUFrameBuffer *self, + PyObject *args, + PyObject *kwds) +{ + PYGPU_FRAMEBUFFER_CHECK_OBJ(self); + int x, y, w, h; + BPyGPUBuffer *py_buffer = NULL; + + static const char *_keywords[] = {"x", "y", "xsize", "ysize", "data", NULL}; + static _PyArg_Parser _parser = {"iiii|$O!:read_depth", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, &x, &y, &w, &h, &BPyGPU_BufferType, &py_buffer)) { + return NULL; + } + + if (py_buffer) { + if (py_buffer->format != GPU_DATA_FLOAT) { + PyErr_SetString(PyExc_AttributeError, "the format of the buffer must be 'GPU_DATA_FLOAT'"); + return NULL; + } + + size_t size_curr = bpygpu_Buffer_size(py_buffer); + size_t size_expected = w * h * GPU_texture_dataformat_size(GPU_DATA_FLOAT); + if (size_curr < size_expected) { + PyErr_SetString(PyExc_BufferError, "the buffer size is smaller than expected"); + return NULL; + } + } + else { + py_buffer = BPyGPU_Buffer_CreatePyObject(GPU_DATA_FLOAT, (Py_ssize_t[]){h, w}, 2, NULL); + BLI_assert(bpygpu_Buffer_size(py_buffer) == + w * h * GPU_texture_dataformat_size(GPU_DATA_FLOAT)); + } + + GPU_framebuffer_read_depth(self->fb, x, y, w, h, GPU_DATA_FLOAT, py_buffer->buf.as_void); + + return (PyObject *)py_buffer; +} + #ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD PyDoc_STRVAR(pygpu_framebuffer_free_doc, ".. method:: free()\n" @@ -598,6 +649,10 @@ static struct PyMethodDef pygpu_framebuffer__tp_methods[] = { (PyCFunction)pygpu_framebuffer_read_color, METH_VARARGS | METH_KEYWORDS, pygpu_framebuffer_read_color_doc}, + {"read_depth", + (PyCFunction)pygpu_framebuffer_read_depth, + METH_VARARGS | METH_KEYWORDS, + pygpu_framebuffer_read_depth_doc}, #ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD {"free", (PyCFunction)pygpu_framebuffer_free, METH_NOARGS, pygpu_framebuffer_free_doc}, #endif diff --git a/source/blender/python/gpu/gpu_py_matrix.c b/source/blender/python/gpu/gpu_py_matrix.c index b379600d33c..cc9b3d702e2 100644 --- a/source/blender/python/gpu/gpu_py_matrix.c +++ b/source/blender/python/gpu/gpu_py_matrix.c @@ -22,8 +22,8 @@ * \warning While these functions attempt to ensure correct stack usage. * Mixing Python and C functions may still crash on invalid use. * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index 0a8b294ea41..457f00b1267 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -22,8 +22,8 @@ * This file defines the offscreen functionalities of the 'gpu' module * used for off-screen OpenGL rendering. * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c index e49ad18dfd8..132052b6f1d 100644 --- a/source/blender/python/gpu/gpu_py_platform.c +++ b/source/blender/python/gpu/gpu_py_platform.c @@ -17,8 +17,8 @@ /** \file * \ingroup bpygpu * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_select.c b/source/blender/python/gpu/gpu_py_select.c index b72aca6a792..4db102118f1 100644 --- a/source/blender/python/gpu/gpu_py_select.c +++ b/source/blender/python/gpu/gpu_py_select.c @@ -22,8 +22,8 @@ * \note Currently only used for gizmo selection, * will need to add begin/end and a way to access the hits. * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c index fc3a7d1360b..00e876aee7d 100644 --- a/source/blender/python/gpu/gpu_py_shader.c +++ b/source/blender/python/gpu/gpu_py_shader.c @@ -17,8 +17,8 @@ /** \file * \ingroup bpygpu * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_state.c b/source/blender/python/gpu/gpu_py_state.c index 173c5afba56..7b7a61cc338 100644 --- a/source/blender/python/gpu/gpu_py_state.c +++ b/source/blender/python/gpu/gpu_py_state.c @@ -19,8 +19,8 @@ * * This file defines the gpu.state API. * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_texture.c b/source/blender/python/gpu/gpu_py_texture.c index 2181c09b537..ca41662db9d 100644 --- a/source/blender/python/gpu/gpu_py_texture.c +++ b/source/blender/python/gpu/gpu_py_texture.c @@ -19,8 +19,8 @@ * * This file defines the texture functionalities of the 'gpu' module * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_types.c b/source/blender/python/gpu/gpu_py_types.c index fdd589d788e..a8787cf5c7f 100644 --- a/source/blender/python/gpu/gpu_py_types.c +++ b/source/blender/python/gpu/gpu_py_types.c @@ -17,8 +17,8 @@ /** \file * \ingroup bpygpu * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_uniformbuffer.c b/source/blender/python/gpu/gpu_py_uniformbuffer.c index cfef20e2e4d..616ef65a5d1 100644 --- a/source/blender/python/gpu/gpu_py_uniformbuffer.c +++ b/source/blender/python/gpu/gpu_py_uniformbuffer.c @@ -19,8 +19,8 @@ * * This file defines the uniform buffer functionalities of the 'gpu' module * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.c b/source/blender/python/gpu/gpu_py_vertex_buffer.c index 3c7038186b9..949086378a8 100644 --- a/source/blender/python/gpu/gpu_py_vertex_buffer.c +++ b/source/blender/python/gpu/gpu_py_vertex_buffer.c @@ -17,8 +17,8 @@ /** \file * \ingroup bpygpu * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/gpu/gpu_py_vertex_format.c b/source/blender/python/gpu/gpu_py_vertex_format.c index 39c91966cab..c344429576a 100644 --- a/source/blender/python/gpu/gpu_py_vertex_format.c +++ b/source/blender/python/gpu/gpu_py_vertex_format.c @@ -17,8 +17,8 @@ /** \file * \ingroup bpygpu * - * - Use ``bpygpu_`` for local API. - * - Use ``BPyGPU`` for public API. + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. */ #include <Python.h> diff --git a/source/blender/python/intern/bpy_app_ffmpeg.c b/source/blender/python/intern/bpy_app_ffmpeg.c index d2261ee7311..5f277b0ef07 100644 --- a/source/blender/python/intern/bpy_app_ffmpeg.c +++ b/source/blender/python/intern/bpy_app_ffmpeg.c @@ -36,7 +36,7 @@ static PyTypeObject BlenderAppFFmpegType; #define DEF_FFMPEG_LIB_VERSION(lib) \ - {(#lib "_version"), ("The " #lib " version as a tuple of 3 numbers")}, \ + {(#lib "_version"), ("The " #lib " version as a tuple of 3 numbers")}, \ { \ (#lib "_version_string"), ("The " #lib " version formatted as a string") \ } diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 9ee9f2e477f..d5afb2334f0 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -339,7 +339,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) return NULL; } - /* When calling bpy.ops.wm.read_factory_settings() bpy.data's main pointer + /* When calling `bpy.ops.wm.read_factory_settings()` `bpy.data's` main pointer * is freed by clear_globals(), further access will crash blender. * Setting context is not needed in this case, only calling because this * function corrects bpy.data (internal Main pointer) */ diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index e6f3e509469..7ecdbe4b4d9 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -4254,7 +4254,7 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA *self) } PyDoc_STRVAR(pyrna_struct_id_properties_ensure_doc, - ".. method:: id_properties_ensure()\n" + ".. method:: id_properties_ensure()\n\n" " :return: the parent group for an RNA struct's custom IDProperties.\n" " :rtype: :class:`bpy.types.IDPropertyGroup`\n"); static PyObject *pyrna_struct_id_properties_ensure(BPy_StructRNA *self) @@ -4282,7 +4282,7 @@ static PyObject *pyrna_struct_id_properties_ensure(BPy_StructRNA *self) } PyDoc_STRVAR(pyrna_struct_id_properties_clear_doc, - ".. method:: id_properties_clear()\n" + ".. method:: id_properties_clear()\n\n" " :return: Remove the parent group for an RNA struct's custom IDProperties.\n"); static PyObject *pyrna_struct_id_properties_clear(BPy_StructRNA *self) { @@ -7424,10 +7424,13 @@ static PyObject *pyrna_srna_Subtype(StructRNA *srna) PyObject *metaclass; const char *idname = RNA_struct_identifier(srna); - /* Remove __doc__ for now. */ - // const char *descr = RNA_struct_ui_description(srna); - // if (!descr) descr = "(no docs)"; - // "__doc__", descr + /* Remove `__doc__` for now because we don't need it to generate docs. */ +#if 0 + const char *descr = RNA_struct_ui_description(srna); + if (!descr) { + descr = "(no docs)"; + } +#endif if (RNA_struct_idprops_check(srna) && !PyObject_IsSubclass(py_base, (PyObject *)&pyrna_struct_meta_idprop_Type)) { diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 9745f39b6b8..a716f4ab9e5 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -605,7 +605,7 @@ PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args) DEG_relations_tag_update(CTX_data_main(context)); } else { - /* XXX, should be handled by reports, */ + /* XXX: should be handled by reports. */ PyErr_SetString(PyExc_TypeError, "bpy_struct.driver_add(): failed because of an internal error"); return NULL; diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c index 66044311321..1bb68babc3c 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.c +++ b/source/blender/python/intern/bpy_rna_id_collection.c @@ -377,9 +377,16 @@ static PyObject *bpy_orphans_purge(PyObject *UNUSED(self), PyObject *args, PyObj bool do_recursive_cleanup = false; static const char *_keywords[] = {"do_local_ids", "do_linked_ids", "do_recursive", NULL}; - static _PyArg_Parser _parser = {"|$ppp:orphans_purge", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast( - args, kwds, &_parser, &do_local_ids, &do_linked_ids, &do_recursive_cleanup)) { + static _PyArg_Parser _parser = {"|O&O&O&:orphans_purge", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, + kwds, + &_parser, + PyC_ParseBool, + &do_local_ids, + PyC_ParseBool, + &do_linked_ids, + PyC_ParseBool, + &do_recursive_cleanup)) { return NULL; } diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c index e5ac1ba9a95..aa8cf8f2a9f 100644 --- a/source/blender/python/intern/bpy_utils_units.c +++ b/source/blender/python/intern/bpy_utils_units.c @@ -67,7 +67,7 @@ static const char *bpyunits_ucategorie_items[] = { /** * These fields are just empty placeholders, actual values get set in initializations functions. * This allows us to avoid many handwriting, and above all, - * to keep all systems/categories definition stuff in ``BKE_unit.h``. + * to keep all systems/categories definition stuff in `BKE_unit.h`. */ static PyStructSequence_Field bpyunits_systems_fields[ARRAY_SIZE(bpyunits_usystem_items)]; static PyStructSequence_Field bpyunits_categories_fields[ARRAY_SIZE(bpyunits_ucategorie_items)]; diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 16bf7120606..5beca7bd71a 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -78,7 +78,7 @@ static int mathutils_array_parse_fast(float *array, } /** - * helper function that returns a Python ``__hash__``. + * helper function that returns a Python `__hash__`. * * \note consistent with the equivalent tuple of floats (CPython's 'tuplehash') */ diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 8b8130f3cc2..36b8b0b6d35 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -1174,7 +1174,7 @@ static void matrix_invert_with_det_n_internal(float *mat_dst, } /** - * \param r_mat: can be from ``self->matrix`` or not. + * \param r_mat: can be from `self->matrix` or not. */ static bool matrix_invert_internal(const MatrixObject *self, float *r_mat) { @@ -1191,8 +1191,8 @@ static bool matrix_invert_internal(const MatrixObject *self, float *r_mat) } /** - * Similar to ``matrix_invert_internal`` but should never error. - * \param r_mat: can be from ``self->matrix`` or not. + * Similar to `matrix_invert_internal` but should never error. + * \param r_mat: can be from `self->matrix` or not. */ static void matrix_invert_safe_internal(const MatrixObject *self, float *r_mat) { diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 88b3bddddf6..c73dea79aac 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -1505,6 +1505,9 @@ static PyObject *list_of_lists_from_arrays(const int *array, PyObject *ret, *sublist; int i, j, sublist_len, sublist_start, val; + if (array == NULL) { + return PyList_New(0); + } ret = PyList_New(toplevel_len); for (i = 0; i < toplevel_len; i++) { sublist_len = len_table[i]; @@ -1521,7 +1524,8 @@ static PyObject *list_of_lists_from_arrays(const int *array, PyDoc_STRVAR( M_Geometry_delaunay_2d_cdt_doc, - ".. function:: delaunay_2d_cdt(vert_coords, edges, faces, output_type, epsilon)\n" + ".. function:: delaunay_2d_cdt(vert_coords, edges, faces, output_type, epsilon, " + "need_ids=True)\n" "\n" " Computes the Constrained Delaunay Triangulation of a set of vertices,\n" " with edges and faces that must appear in the triangulation.\n" @@ -1533,6 +1537,8 @@ PyDoc_STRVAR( " input element indices corresponding to the positionally same output element.\n" " For edges, the orig indices start with the input edges and then continue\n" " with the edges implied by each of the faces (n of them for an n-gon).\n" + " If the need_ids argument is supplied, and False, then the code skips the preparation\n" + " of the orig arrays, which may save some time." "\n" " :arg vert_coords: Vertex coordinates (2d)\n" " :type vert_coords: list of :class:`mathutils.Vector`\n" @@ -1543,10 +1549,14 @@ PyDoc_STRVAR( " :arg output_type: What output looks like. 0 => triangles with convex hull. " "1 => triangles inside constraints. " "2 => the input constraints, intersected. " - "3 => like 2 but with extra edges to make valid BMesh faces.\n" + "3 => like 2 but detect holes and omit them from output. " + "4 => like 2 but with extra edges to make valid BMesh faces. " + "5 => like 4 but detect holes and omit them from output.\n" " :type output_type: int\\n" " :arg epsilon: For nearness tests; should not be zero\n" " :type epsilon: float\n" + " :arg need_ids: are the orig output arrays needed?\n" + " :type need_args: bool\n" " :return: Output tuple, (vert_coords, edges, faces, orig_verts, orig_edges, orig_faces)\n" " :rtype: (list of `mathutils.Vector`, " "list of (int, int), " @@ -1561,6 +1571,7 @@ static PyObject *M_Geometry_delaunay_2d_cdt(PyObject *UNUSED(self), PyObject *ar PyObject *vert_coords, *edges, *faces, *item; int output_type; float epsilon; + bool need_ids = true; float(*in_coords)[2] = NULL; int(*in_edges)[2] = NULL; int *in_faces = NULL; @@ -1578,8 +1589,14 @@ static PyObject *M_Geometry_delaunay_2d_cdt(PyObject *UNUSED(self), PyObject *ar PyObject *ret_value = NULL; int i; - if (!PyArg_ParseTuple( - args, "OOOif:delaunay_2d_cdt", &vert_coords, &edges, &faces, &output_type, &epsilon)) { + if (!PyArg_ParseTuple(args, + "OOOif|p:delaunay_2d_cdt", + &vert_coords, + &edges, + &faces, + &output_type, + &epsilon, + &need_ids)) { return NULL; } @@ -1609,6 +1626,7 @@ static PyObject *M_Geometry_delaunay_2d_cdt(PyObject *UNUSED(self), PyObject *ar in.faces_start_table = in_faces_start_table; in.faces_len_table = in_faces_len_table; in.epsilon = epsilon; + in.need_ids = need_ids; res = BLI_delaunay_2d_cdt_calc(&in, output_type); diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c index 707fd40e9d0..69d37b345c6 100644 --- a/source/blender/python/mathutils/mathutils_noise.c +++ b/source/blender/python/mathutils/mathutils_noise.c @@ -131,8 +131,7 @@ static void next_state(void) ulong *p = state; int j; - /* if init_genrand() has not been called, */ - /* a default initial seed is used */ + /* If init_genrand() has not been called, a default initial seed is used. */ if (initf == 0) { init_genrand(5489UL); } diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c index d5653f87c2b..74e57989f47 100644 --- a/source/blender/render/intern/bake.c +++ b/source/blender/render/intern/bake.c @@ -26,7 +26,7 @@ * The Bake API is fully implemented with Python rna functions. * The operator expects/call a function: * - * ``def bake(scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result)`` + * `def bake(scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result)` * - scene: current scene (Python object) * - object: object to render (Python object) * - pass_type: pass to render (string, e.g., "COMBINED", "AO", "NORMAL", ...) @@ -53,10 +53,10 @@ * \endcode * * In python you have access to: - * - ``primitive_id``, ``object_id``, ``uv``, ``du_dx``, ``du_dy``, ``next`` - * - ``next()`` is a function that returns the next #BakePixel in the array. + * - `primitive_id`, `object_id`, `uv`, `du_dx`, `du_dy`, `next`. + * - `next()` is a function that returns the next #BakePixel in the array. * - * \note Pixels that should not be baked have ``primitive_id == -1`` + * \note Pixels that should not be baked have `primitive_id == -1`. * * For a complete implementation example look at the Cycles Bake commit. */ diff --git a/source/blender/render/intern/texture_image.c b/source/blender/render/intern/texture_image.c index c4ee16a0ecc..62aee564626 100644 --- a/source/blender/render/intern/texture_image.c +++ b/source/blender/render/intern/texture_image.c @@ -932,8 +932,8 @@ static void feline_eval(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata #endif /* `const int out =` */ ibuf_get_color_clip_bilerp( tc, ibuf, ibuf->x * u, ibuf->y * v, AFD->intpol, AFD->extflag); - /* TXF alpha: clip |= out; - * TXF alpha: cw += out ? 0.0f : wt; */ + /* TXF alpha: `clip |= out;` + * TXF alpha: `cw += out ? 0.0f : wt;` */ texr->tr += tc[0] * wt; texr->tg += tc[1] * wt; texr->tb += tc[2] * wt; diff --git a/source/blender/sequencer/SEQ_effects.h b/source/blender/sequencer/SEQ_effects.h index 79a36be5a0b..4bd5b54b36b 100644 --- a/source/blender/sequencer/SEQ_effects.h +++ b/source/blender/sequencer/SEQ_effects.h @@ -70,9 +70,6 @@ struct SeqEffectHandle { * 2: out = ibuf2 */ int (*early_out)(struct Sequence *seq, float facf0, float facf1); - /* stores the y-range of the effect IPO */ - void (*store_icu_yrange)(struct Sequence *seq, short adrcode, float *ymin, float *ymax); - /* stores the default facf0 and facf1 if no IPO is present */ void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *facf0, float *facf1); diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index 0a8be3b33ae..7757271a2e5 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -1428,10 +1428,9 @@ static void do_mul_effect_byte(float facf0, fac1 = (int)(256.0f * facf0); fac3 = (int)(256.0f * facf1); - /* formula: - * fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + axaux = c * px + py * s; //+centx - * yaux = -s * px + c * py; //+centy - */ + /* Formula: + * `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + axaux = c * px + py * s;` // + centx + * `yaux = -s * px + c * py;` // + centy */ while (y--) { @@ -1483,9 +1482,8 @@ static void do_mul_effect_float( fac1 = facf0; fac3 = facf1; - /* formula: - * fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + a - */ + /* Formula: + * `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + a`. */ while (y--) { x = xo; @@ -3086,10 +3084,12 @@ static void init_speed_effect(Sequence *seq) seq->effectdata = MEM_callocN(sizeof(SpeedControlVars), "speedcontrolvars"); v = (SpeedControlVars *)seq->effectdata; - v->globalSpeed = 1.0; v->frameMap = NULL; - v->flags |= SEQ_SPEED_INTEGRATE; /* should be default behavior */ v->length = 0; + v->speed_control_type = SEQ_SPEED_STRETCH; + v->speed_fader = 1.0f; + v->speed_fader_length = 0.0f; + v->speed_fader_frame_number = 0.0f; } static void load_speed_effect(Sequence *seq) @@ -3131,29 +3131,6 @@ static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNU return EARLY_DO_EFFECT; } -static void store_icu_yrange_speed(Sequence *seq, short UNUSED(adrcode), float *ymin, float *ymax) -{ - SpeedControlVars *v = (SpeedControlVars *)seq->effectdata; - - /* if not already done, load / initialize data */ - SEQ_effect_handle_get(seq); - - if ((v->flags & SEQ_SPEED_INTEGRATE) != 0) { - *ymin = -100.0; - *ymax = 100.0; - } - else { - if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) { - *ymin = 0.0; - *ymax = 1.0; - } - else { - *ymin = 0.0; - *ymax = seq->len; - } - } -} - /** * Generator strips with zero inputs have their length set to 1 permanently. In some cases it is * useful to use speed effect on these strips because they can be animated. This can be done by @@ -3174,7 +3151,6 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force) float fallback_fac = 1.0f; SpeedControlVars *v = (SpeedControlVars *)seq->effectdata; FCurve *fcu = NULL; - int flags = v->flags; /* if not already done, load / initialize data */ SEQ_effect_handle_get(seq); @@ -3189,7 +3165,20 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force) /* XXX(campbell): new in 2.5x. should we use the animation system this way? * The fcurve is needed because many frames need evaluating at once. */ - fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL); + switch (v->speed_control_type) { + case SEQ_SPEED_MULTIPLY: { + fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL); + break; + } + case SEQ_SPEED_FRAME_NUMBER: { + fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_frame_number", 0, NULL); + break; + } + case SEQ_SPEED_LENGTH: { + fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_length", 0, NULL); + break; + } + } if (!v->frameMap || v->length != seq->len) { if (v->frameMap) { MEM_freeN(v->frameMap); @@ -3204,21 +3193,33 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force) const int target_strip_length = seq_effect_speed_get_strip_content_length(seq->seq1); - if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) { + if (v->speed_control_type == SEQ_SPEED_STRETCH) { if ((seq->seq1->enddisp != seq->seq1->start) && (target_strip_length != 0)) { fallback_fac = (float)target_strip_length / (float)(seq->seq1->enddisp - seq->seq1->start); - flags = SEQ_SPEED_INTEGRATE; fcu = NULL; } } else { /* if there is no fcurve, use value as simple multiplier */ if (!fcu) { - fallback_fac = seq->speed_fader; /* Same as speed_factor in RNA. */ + switch (v->speed_control_type) { + case SEQ_SPEED_MULTIPLY: { + fallback_fac = v->speed_fader; + break; + } + case SEQ_SPEED_FRAME_NUMBER: { + fallback_fac = v->speed_fader_frame_number; + break; + } + case SEQ_SPEED_LENGTH: { + fallback_fac = v->speed_fader_length; + break; + } + } } } - if (flags & SEQ_SPEED_INTEGRATE) { + if (ELEM(v->speed_control_type, SEQ_SPEED_MULTIPLY, SEQ_SPEED_STRETCH)) { float cursor = 0; float facf; @@ -3232,7 +3233,6 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force) else { facf = fallback_fac; } - facf *= v->globalSpeed; cursor += facf; @@ -3258,10 +3258,10 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force) facf = fallback_fac; } - if (flags & SEQ_SPEED_COMPRESS_IPO_Y) { + if (v->speed_control_type == SEQ_SPEED_LENGTH) { facf *= target_strip_length; + facf /= 100.0f; } - facf *= v->globalSpeed; if (facf >= target_strip_length) { facf = target_strip_length - 1; @@ -4083,14 +4083,6 @@ static int early_out_mul_input2(Sequence *UNUSED(seq), float facf0, float facf1) return EARLY_DO_EFFECT; } -static void store_icu_yrange_noop(Sequence *UNUSED(seq), - short UNUSED(adrcode), - float *UNUSED(ymin), - float *UNUSED(ymax)) -{ - /* defaults are fine */ -} - static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_frame), float *facf0, @@ -4130,7 +4122,6 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.free = free_noop; rval.early_out = early_out_noop; rval.get_default_fac = get_default_fac_noop; - rval.store_icu_yrange = store_icu_yrange_noop; rval.execute = NULL; rval.init_execution = init_execution; rval.execute_slice = NULL; @@ -4244,7 +4235,6 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.copy = copy_speed_effect; rval.execute = do_speed_effect; rval.early_out = early_out_speed; - rval.store_icu_yrange = store_icu_yrange_speed; break; case SEQ_TYPE_COLOR: rval.init = init_solid_color; diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index b9278b9f971..e92afee08cd 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -112,8 +112,8 @@ static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, i Sequence *seq; int seqmute; - /* for sound we go over full meta tree to update muted state, - * since sound is played outside of evaluating the imbufs, */ + /* For sound we go over full meta tree to update muted state, + * since sound is played outside of evaluating the imbufs. */ for (seq = seqbasep->first; seq; seq = seq->next) { seqmute = (mute || (seq->flag & SEQ_MUTE)); @@ -407,6 +407,8 @@ Sequence *SEQ_edit_strip_split(Main *bmain, BLI_addtail(&left_strips, seq); } + SEQ_collection_free(collection); + /* Sort list, so that no strip can depend on next strip in list. * This is important for SEQ_time_update_sequence functionality. */ SEQ_sort(&left_strips); diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index 20e2421ea88..68128690773 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -111,8 +111,8 @@ static void seq_update_sound_bounds_recursive_impl(Scene *scene, { Sequence *seq; - /* for sound we go over full meta tree to update bounds of the sound strips, - * since sound is played outside of evaluating the imbufs, */ + /* For sound we go over full meta tree to update bounds of the sound strips, + * since sound is played outside of evaluating the imbufs. */ for (seq = metaseq->seqbase.first; seq; seq = seq->next) { if (seq->type == SEQ_TYPE_META) { seq_update_sound_bounds_recursive_impl( diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index b7989349ebe..c9af2fced65 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -269,9 +269,9 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep, } test->machine += channel_delta; - SEQ_time_update_sequence( - evil_scene, - test); // XXX: I don't think this is needed since were only moving vertically, Campbell. + + /* XXX: I don't think this is needed since were only moving vertically, Campbell. */ + SEQ_time_update_sequence(evil_scene, test); } if ((test->machine < 1) || (test->machine > MAXSEQ)) { diff --git a/source/blender/shader_fx/intern/FX_ui_common.c b/source/blender/shader_fx/intern/FX_ui_common.c index 8a259c6aaff..8cb1ea6b66c 100644 --- a/source/blender/shader_fx/intern/FX_ui_common.c +++ b/source/blender/shader_fx/intern/FX_ui_common.c @@ -9,7 +9,7 @@ * 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, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/source/blender/simulation/intern/SIM_mass_spring.cpp b/source/blender/simulation/intern/SIM_mass_spring.cpp index ca01120eecb..f9a22276363 100644 --- a/source/blender/simulation/intern/SIM_mass_spring.cpp +++ b/source/blender/simulation/intern/SIM_mass_spring.cpp @@ -213,7 +213,8 @@ int SIM_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd) return 1; } -void SIM_mass_spring_set_implicit_vertex_mass(Implicit_Data *data, int index, float mass){ +void SIM_mass_spring_set_implicit_vertex_mass(Implicit_Data *data, int index, float mass) +{ SIM_mass_spring_set_vertex_mass(data, index, mass); } @@ -1051,18 +1052,22 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt) SIM_hair_volume_grid_interpolate(grid, x, &gdensity, gvel, gvel_smooth, NULL, NULL); - // BKE_sim_debug_data_add_circle( - // clmd->debug_data, x, gdensity, 0.7, 0.3, 1, - // "grid density", i, j, 3111); +# if 0 + BKE_sim_debug_data_add_circle( + clmd->debug_data, x, gdensity, 0.7, 0.3, 1, + "grid density", i, j, 3111); +# endif if (!is_zero_v3(gvel) || !is_zero_v3(gvel_smooth)) { float dvel[3]; sub_v3_v3v3(dvel, gvel_smooth, gvel); - // BKE_sim_debug_data_add_vector( - // clmd->debug_data, x, gvel, 0.4, 0, 1, - // "grid velocity", i, j, 3112); - // BKE_sim_debug_data_add_vector( - // clmd->debug_data, x, gvel_smooth, 0.6, 1, 1, - // "grid velocity", i, j, 3113); +# if 0 + BKE_sim_debug_data_add_vector( + clmd->debug_data, x, gvel, 0.4, 0, 1, + "grid velocity", i, j, 3112); + BKE_sim_debug_data_add_vector( + clmd->debug_data, x, gvel_smooth, 0.6, 1, 1, + "grid velocity", i, j, 3113); +# endif BKE_sim_debug_data_add_vector( clmd->debug_data, x, dvel, 0.4, 1, 0.7, "grid velocity", i, j, 3114); # if 0 @@ -1073,12 +1078,14 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt) interp_v3_v3v3(col, col0, col1, CLAMPIS(gdensity * clmd->sim_parms->density_strength, 0.0, 1.0)); - // BKE_sim_debug_data_add_circle( - // clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4, - // "grid velocity", i, j, 3115); - // BKE_sim_debug_data_add_dot( - // clmd->debug_data, x, col[0], col[1], col[2], - // "grid velocity", i, j, 3115); +# if 0 + BKE_sim_debug_data_add_circle( + clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4, + "grid velocity", i, j, 3115); + BKE_sim_debug_data_add_dot( + clmd->debug_data, x, col[0], col[1], col[2], + "grid velocity", i, j, 3115); +# endif BKE_sim_debug_data_add_circle( clmd->debug_data, x, 0.01f, col[0], col[1], col[2], "grid velocity", i, j, 3115); } diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp index 4966fa2510d..348c8683be9 100644 --- a/source/blender/simulation/intern/hair_volume.cpp +++ b/source/blender/simulation/intern/hair_volume.cpp @@ -112,9 +112,11 @@ BLI_INLINE int hair_grid_interp_weights( uvw[1] = (vec[1] - gmin[1]) * scale - (float)j; uvw[2] = (vec[2] - gmin[2]) * scale - (float)k; - // BLI_assert(0.0f <= uvw[0] && uvw[0] <= 1.0001f); - // BLI_assert(0.0f <= uvw[1] && uvw[1] <= 1.0001f); - // BLI_assert(0.0f <= uvw[2] && uvw[2] <= 1.0001f); +#if 0 + BLI_assert(0.0f <= uvw[0] && uvw[0] <= 1.0001f); + BLI_assert(0.0f <= uvw[1] && uvw[1] <= 1.0001f); + BLI_assert(0.0f <= uvw[2] && uvw[2] <= 1.0001f); +#endif return offset; } @@ -350,7 +352,7 @@ BLI_INLINE int hair_grid_weights( weights[6] = dist_tent_v3f3(uvw, (float)i, (float)(j + 1), (float)(k + 1)); weights[7] = dist_tent_v3f3(uvw, (float)(i + 1), (float)(j + 1), (float)(k + 1)); - // BLI_assert(fabsf(weights_sum(weights) - 1.0f) < 0.0001f); + // BLI_assert(fabsf(weights_sum(weights) - 1.0f) < 0.0001f); return offset; } @@ -488,9 +490,10 @@ BLI_INLINE void hair_volume_add_segment_2D(HairGrid *grid, BKE_sim_debug_data_add_dot(x2w, 0.1, 0.1, 0.7, "grid", 649, debug_i, j, k); BKE_sim_debug_data_add_line(wloc, x2w, 0.3, 0.8, 0.3, "grid", 253, debug_i, j, k); BKE_sim_debug_data_add_line(wloc, x3w, 0.8, 0.3, 0.3, "grid", 254, debug_i, j, k); - // BKE_sim_debug_data_add_circle( - // x2w, len_v3v3(wloc, x2w), 0.2, 0.7, 0.2, - // "grid", 255, i, j, k); +# if 0 + BKE_sim_debug_data_add_circle( + x2w, len_v3v3(wloc, x2w), 0.2, 0.7, 0.2, "grid", 255, i, j, k); +# endif } } # endif @@ -1003,9 +1006,10 @@ bool SIM_hair_volume_solve_divergence(HairGrid *grid, if (!is_margin) { float dvel[3]; sub_v3_v3v3(dvel, vert->velocity_smooth, vert->velocity); - // BKE_sim_debug_data_add_vector( - // grid->debug_data, wloc, dvel, 1, 1, 1, - // "grid", 5566, i, j, k); +# if 0 + BKE_sim_debug_data_add_vector( + grid->debug_data, wloc, dvel, 1, 1, 1, "grid", 5566, i, j, k); +# endif } if (!is_margin) { @@ -1015,11 +1019,12 @@ bool SIM_hair_volume_solve_divergence(HairGrid *grid, float col[3]; interp_v3_v3v3(col, col0, colp, d); - // if (d > 0.05f) { - // BKE_sim_debug_data_add_dot( - // grid->debug_data, wloc, col[0], col[1], col[2], - // "grid", 5544, i, j, k); - // } +# if 0 + if (d > 0.05f) { + BKE_sim_debug_data_add_dot( + grid->debug_data, wloc, col[0], col[1], col[2], "grid", 5544, i, j, k); + } +# endif } } } diff --git a/source/blender/simulation/intern/implicit_blender.c b/source/blender/simulation/intern/implicit_blender.c index 8aa3774a3f2..10a5f153662 100644 --- a/source/blender/simulation/intern/implicit_blender.c +++ b/source/blender/simulation/intern/implicit_blender.c @@ -180,8 +180,8 @@ DO_INLINE void mul_lfvectorS(float (*to)[3], mul_fvector_S(to[i], fLongVector[i], scalar); } } -/* Multiply long vector with scalar. */ -/* A -= B * float */ +/* Multiply long vector with scalar. + * `A -= B * float` */ DO_INLINE void submul_lfvectorS(float (*to)[3], float (*fLongVector)[3], float scalar, @@ -209,7 +209,7 @@ DO_INLINE float dot_lfvector(float (*fLongVectorA)[3], } return temp; } -/* A = B + C --> for big vector */ +/* `A = B + C` -> for big vector. */ DO_INLINE void add_lfvector_lfvector(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], @@ -221,7 +221,7 @@ DO_INLINE void add_lfvector_lfvector(float (*to)[3], add_v3_v3v3(to[i], fLongVectorA[i], fLongVectorB[i]); } } -/* A = B + C * float --> for big vector */ +/* `A = B + C * float` -> for big vector. */ DO_INLINE void add_lfvector_lfvectorS(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], @@ -234,7 +234,7 @@ DO_INLINE void add_lfvector_lfvectorS(float (*to)[3], VECADDS(to[i], fLongVectorA[i], fLongVectorB[i], bS); } } -/* A = B * float + C * float --> for big vector */ +/* `A = B * float + C * float` -> for big vector */ DO_INLINE void add_lfvectorS_lfvectorS(float (*to)[3], float (*fLongVectorA)[3], float aS, @@ -248,7 +248,7 @@ DO_INLINE void add_lfvectorS_lfvectorS(float (*to)[3], VECADDSS(to[i], fLongVectorA[i], aS, fLongVectorB[i], bS); } } -/* A = B - C * float --> for big vector */ +/* `A = B - C * float` -> for big vector. */ DO_INLINE void sub_lfvector_lfvectorS(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], @@ -260,7 +260,7 @@ DO_INLINE void sub_lfvector_lfvectorS(float (*to)[3], VECSUBS(to[i], fLongVectorA[i], fLongVectorB[i], bS); } } -/* A = B - C --> for big vector */ +/* `A = B - C` -> for big vector. */ DO_INLINE void sub_lfvector_lfvector(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], @@ -455,7 +455,7 @@ DO_INLINE void add_fmatrix_fmatrix(float to[3][3], add_v3_v3v3(to[1], matrixA[1], matrixB[1]); add_v3_v3v3(to[2], matrixA[2], matrixB[2]); } -/* A -= B*x + C*y (3x3 matrix sub-addition with 3x3 matrix) */ +/* `A -= B*x + (C * y)` (3x3 matrix sub-addition with 3x3 matrix). */ DO_INLINE void subadd_fmatrixS_fmatrixS( float to[3][3], const float matrixA[3][3], float aS, const float matrixB[3][3], float bS) { @@ -463,7 +463,7 @@ DO_INLINE void subadd_fmatrixS_fmatrixS( VECSUBADDSS(to[1], matrixA[1], aS, matrixB[1], bS); VECSUBADDSS(to[2], matrixA[2], aS, matrixB[2], bS); } -/* A = B - C (3x3 matrix subtraction with 3x3 matrix) */ +/* `A = B - C` (3x3 matrix subtraction with 3x3 matrix). */ DO_INLINE void sub_fmatrix_fmatrix(float to[3][3], const float matrixA[3][3], const float matrixB[3][3]) @@ -1439,7 +1439,7 @@ void SIM_mass_spring_force_drag(Implicit_Data *data, float drag) for (i = 0; i < numverts; i++) { float tmp[3][3]; - /* NB: uses root space velocity, no need to transform */ + /* NOTE: Uses root space velocity, no need to transform. */ madd_v3_v3fl(data->F[i], data->V[i], -drag); copy_m3_m3(tmp, I); @@ -1683,8 +1683,8 @@ BLI_INLINE void dfdx_damp(float to[3][3], float rest, float damping) { - /* inner spring damping vel is the relative velocity of the endpoints. */ - // return (I-outerprod(dir, dir)) * (-damping * -(dot(dir, vel)/Max(length, rest))); + /* Inner spring damping `vel` is the relative velocity of the endpoints. */ + // return (I - outerprod(dir, dir)) * (-damping * -(dot(dir, vel) / Max(length, rest))); mul_fvectorT_fvector(to, dir, dir); sub_fmatrix_fmatrix(to, I, to); mul_fmatrix_S(to, (-damping * -(dot_v3v3(dir, vel) / MAX2(length, rest)))); diff --git a/source/blender/simulation/intern/implicit_eigen.cpp b/source/blender/simulation/intern/implicit_eigen.cpp index aa9d5d1d34d..d509b3db873 100644 --- a/source/blender/simulation/intern/implicit_eigen.cpp +++ b/source/blender/simulation/intern/implicit_eigen.cpp @@ -797,7 +797,7 @@ void SIM_mass_spring_force_drag(Implicit_Data *data, float drag) for (int i = 0; i < numverts; i++) { float tmp[3][3]; - /* NB: uses root space velocity, no need to transform */ + /* NOTE: Uses root space velocity, no need to transform. */ madd_v3_v3fl(data->F.v3(i), data->V.v3(i), -drag); copy_m3_m3(tmp, I); @@ -894,8 +894,8 @@ BLI_INLINE void dfdx_damp(float to[3][3], float rest, float damping) { - /* inner spring damping vel is the relative velocity of the endpoints. */ - // return (I-outerprod(dir, dir)) * (-damping * -(dot(dir, vel)/Max(length, rest))); + /* Inner spring damping vel is the relative velocity of the endpoints. */ + // return (I - outerprod(dir, dir)) * (-damping * -(dot(dir, vel) / Max(length, rest))); mul_fvectorT_fvector(to, dir, dir); sub_fmatrix_fmatrix(to, I, to); mul_fmatrix_S(to, (-damping * -(dot_v3v3(dir, vel) / MAX2(length, rest)))); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 2b48a5f6648..cc8fb307c92 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -924,10 +924,10 @@ typedef struct wmDragID { } wmDragID; typedef struct wmDragAsset { - char name[64]; /* MAX_NAME */ + /* Owning pointer. Contains the file with all the asset data (name, local ID, etc.) */ + struct AssetHandle *asset_handle; /* Always freed. */ const char *path; - int id_type; int import_type; /* eFileAssetImportType */ } wmDragAsset; diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index 6a328679c2e..5ec26a7b208 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -91,7 +91,7 @@ enum { /* -------------------------------------------------------------------- */ /** \name wmGizmoMap Selection Array API * - * Just handle ``wm_gizmomap_select_array_*``, not flags or callbacks. + * Just handle `wm_gizmomap_select_array_*`, not flags or callbacks. * * \{ */ diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index da40040ce56..319e83f667f 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -42,6 +42,8 @@ #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "ED_asset.h" + #include "GPU_shader.h" #include "GPU_state.h" #include "GPU_viewport.h" @@ -196,6 +198,7 @@ void WM_drag_data_free(int dragtype, void *poin) /* Not too nice, could become a callback. */ if (dragtype == WM_DRAG_ASSET) { wmDragAsset *asset_drag = poin; + MEM_SAFE_FREE(asset_drag->asset_handle); MEM_freeN((void *)asset_drag->path); } MEM_freeN(poin); @@ -373,18 +376,20 @@ wmDragAsset *WM_drag_get_asset_data(const wmDrag *drag, int idcode) } wmDragAsset *asset_drag = drag->poin; - return (ELEM(idcode, 0, asset_drag->id_type)) ? asset_drag : NULL; + ID_Type idtype = ED_asset_handle_get_id_type(asset_drag->asset_handle); + return (ELEM(idcode, 0, (int)idtype)) ? asset_drag : NULL; } static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag) { + const char *name = ED_asset_handle_get_name(asset_drag->asset_handle); + ID_Type idtype = ED_asset_handle_get_id_type(asset_drag->asset_handle); + switch ((eFileAssetImportType)asset_drag->import_type) { case FILE_ASSET_IMPORT_LINK: - return WM_file_link_datablock( - G_MAIN, NULL, NULL, NULL, asset_drag->path, asset_drag->id_type, asset_drag->name); + return WM_file_link_datablock(G_MAIN, NULL, NULL, NULL, asset_drag->path, idtype, name); case FILE_ASSET_IMPORT_APPEND: - return WM_file_append_datablock( - G_MAIN, NULL, NULL, NULL, asset_drag->path, asset_drag->id_type, asset_drag->name); + return WM_file_append_datablock(G_MAIN, NULL, NULL, NULL, asset_drag->path, idtype, name); } BLI_assert_unreachable(); @@ -444,7 +449,8 @@ void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox * return; } - ID *id = BKE_libblock_find_name(bmain, asset_drag->id_type, name); + ID_Type idtype = ED_asset_handle_get_id_type(asset_drag->asset_handle); + ID *id = BKE_libblock_find_name(bmain, idtype, name); if (id) { BKE_id_delete(bmain, id); } @@ -478,7 +484,7 @@ static const char *wm_drag_name(wmDrag *drag) } case WM_DRAG_ASSET: { const wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, 0); - return asset_drag->name; + return ED_asset_handle_get_name(asset_drag->asset_handle); } case WM_DRAG_PATH: case WM_DRAG_NAME: diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 0922aaaee53..f01e28f8822 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -457,6 +457,7 @@ static void wm_draw_region_buffer_create(ARegion *region, bool stereo, bool use_ GPUOffScreen *offscreen = GPU_offscreen_create( region->winx, region->winy, false, false, NULL); if (!offscreen) { + WM_report(RPT_ERROR, "Region could not be drawn!"); return; } diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c index e7603a02cff..006dc220a56 100644 --- a/source/blender/windowmanager/intern/wm_event_query.c +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -85,10 +85,10 @@ void WM_event_print(const wmEvent *event) event_ids_from_type_and_value(event->prevtype, event->prevval, &prev_type_id, &prev_val_id); printf( - "wmEvent type:%d / %s, val:%d / %s,\n" - " prev_type:%d / %s, prev_val:%d / %s,\n" - " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, is_repeat:%d,\n" - " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p\n", + "wmEvent type:%d / %s, val:%d / %s,\n" + " prev_type:%d / %s, prev_val:%d / %s,\n" + " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, is_repeat:%d,\n" + " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p\n", event->type, type_id, event->val, diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 3633d3c07d3..06aaf95f232 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -987,7 +987,7 @@ const char *WM_init_state_app_template_get(void) * or called for 'New File' both startup.blend and userpref.blend are checked. * * \param use_factory_settings: - * Ignore on-disk startup file, use bundled ``datatoc_startup_blend`` instead. + * Ignore on-disk startup file, use bundled `datatoc_startup_blend` instead. * Used for "Restore Factory Settings". * * \param use_userdef: Load factory settings as well as startup file. diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c index 9da901d6c4e..92ca0b87527 100644 --- a/source/blender/windowmanager/intern/wm_gesture_ops.c +++ b/source/blender/windowmanager/intern/wm_gesture_ops.c @@ -23,8 +23,8 @@ * Default operator callbacks for use with gestures (border/circle/lasso/straightline). * Operators themselves are defined elsewhere. * - * - Keymaps are in ``wm_operators.c``. - * - Property definitions are in ``wm_operator_props.c``. + * - Keymaps are in `wm_operators.c`. + * - Property definitions are in `wm_operator_props.c`. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c index b0b4f0f5904..795f78e215f 100644 --- a/source/blender/windowmanager/intern/wm_keymap_utils.c +++ b/source/blender/windowmanager/intern/wm_keymap_utils.c @@ -207,7 +207,7 @@ wmKeyMap *WM_keymap_guess_from_context(const bContext *C) /* Needs to be kept up to date with Keymap and Operator naming */ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) { - /* Op types purposely skipped for now: + /* Op types purposely skipped for now: * BRUSH_OT * BOID_OT * BUTTONS_OT diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c index e17d5a9ae70..39435721d1a 100644 --- a/source/blender/windowmanager/intern/wm_operator_type.c +++ b/source/blender/windowmanager/intern/wm_operator_type.c @@ -498,12 +498,11 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, ot->cancel = wm_macro_cancel; ot->poll = NULL; - if (!ot->description) { - /* XXX All ops should have a description but for now allow them not to. */ - ot->description = UNDOCUMENTED_OPERATOR_TIP; - } + /* XXX All ops should have a description but for now allow them not to. */ + BLI_assert((ot->description == NULL) || (ot->description[0])); - RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); + RNA_def_struct_ui_text( + ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP); RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); /* Use i18n context from rna_ext.srna if possible (py operators). */ i18n_context = ot->rna_ext.srna ? RNA_struct_translation_context(ot->rna_ext.srna) : @@ -530,16 +529,16 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *), ot->cancel = wm_macro_cancel; ot->poll = NULL; - if (!ot->description) { - ot->description = UNDOCUMENTED_OPERATOR_TIP; - } + /* XXX All ops should have a description but for now allow them not to. */ + BLI_assert((ot->description == NULL) || (ot->description[0])); /* Set the default i18n context now, so that opfunc can redefine it if needed! */ RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT); ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT; opfunc(ot, userdata); - RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); + RNA_def_struct_ui_text( + ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP); RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); diff --git a/source/blender/windowmanager/wm_surface.h b/source/blender/windowmanager/wm_surface.h index 06c29231361..36d74f612fc 100644 --- a/source/blender/windowmanager/wm_surface.h +++ b/source/blender/windowmanager/wm_surface.h @@ -42,9 +42,9 @@ typedef struct wmSurface { /** Free customdata, not the surface itself (done by wm_surface API) */ void (*free_data)(struct wmSurface *); - /** Called when surface is activated for drawing (made drawable). */ + /** Called when surface is activated for drawing (made drawable). */ void (*activate)(void); - /** Called when surface is deactivated for drawing (current drawable cleared). */ + /** Called when surface is deactivated for drawing (current drawable cleared). */ void (*deactivate)(void); } wmSurface; diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c index 1f722855696..4ac05e339b9 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c @@ -24,6 +24,7 @@ #include <string.h> +#include "BLI_listbase.h" #include "BLI_math.h" #include "ED_view3d_offscreen.h" @@ -61,10 +62,12 @@ static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data, copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat); copy_v3_v3(eye_pose.position, draw_view->eye_pose.position); - sub_v3_v3(eye_pose.position, draw_data->eye_position_ofs); if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) { sub_v3_v3(eye_pose.position, draw_view->local_pose.position); } + if ((session_settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) { + sub_v3_v3(eye_pose.position, draw_data->eye_position_ofs); + } perspective_m4_fov(r_proj_mat, draw_view->fov.angle_left, @@ -89,6 +92,9 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer( const wmXrSurfaceData *surface_data, const GHOST_XrDrawViewInfo *draw_view) { + const wmXrViewportPair *vp = BLI_findlink(&surface_data->viewports, draw_view->view_idx); + BLI_assert(vp && vp->viewport); + const bool is_upside_down = GHOST_XrSessionNeedsUpsideDownDrawing(runtime_data->context); rcti rect = {.xmin = 0, .ymin = 0, .xmax = draw_view->width - 1, .ymax = draw_view->height - 1}; @@ -98,8 +104,7 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer( if (is_upside_down) { SWAP(int, rect.ymin, rect.ymax); } - GPU_viewport_draw_to_screen_ex( - surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer, true); + GPU_viewport_draw_to_screen_ex(vp->viewport, 0, &rect, draw_view->expects_srgb_buffer, true); } /** @@ -130,6 +135,9 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata) return; } + const wmXrViewportPair *vp = BLI_findlink(&surface_data->viewports, draw_view->view_idx); + BLI_assert(vp && vp->offscreen && vp->viewport); + /* In case a framebuffer is still bound from drawing the last eye. */ GPU_framebuffer_restore(); /* Some systems have drawing glitches without this. */ @@ -151,8 +159,8 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata) true, NULL, false, - surface_data->offscreen, - surface_data->viewport); + vp->offscreen, + vp->viewport); /* The draw-manager uses both GPUOffscreen and GPUViewport to manage frame and texture buffers. A * call to GPU_viewport_draw_to_screen() is still needed to get the final result from the @@ -162,7 +170,7 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata) * In a next step, Ghost-XR will use the currently bound frame-buffer to retrieve the image * to be submitted to the OpenXR swap-chain. So do not un-bind the off-screen yet! */ - GPU_offscreen_bind(surface_data->offscreen, false); + GPU_offscreen_bind(vp->offscreen, false); wm_xr_draw_viewport_buffers_to_active_framebuffer(xr_data->runtime, surface_data, draw_view); } diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h index 9bf63be61dd..24582388228 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h +++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h @@ -85,9 +85,15 @@ typedef struct wmXrRuntimeData { wmXrSessionExitFn exit_fn; } wmXrRuntimeData; -typedef struct { +typedef struct wmXrViewportPair { + struct wmXrViewportPair *next, *prev; struct GPUOffScreen *offscreen; struct GPUViewport *viewport; +} wmXrViewportPair; + +typedef struct { + /* Offscreen buffers/viewports for each view. */ + ListBase viewports; /* wmXrViewportPair */ } wmXrSurfaceData; typedef struct wmXrDrawData { diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c index 1ddbe228e05..252f358c798 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_session.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -225,7 +225,7 @@ typedef enum wmXrSessionStateEvent { SESSION_STATE_EVENT_NONE = 0, SESSION_STATE_EVENT_START, SESSION_STATE_EVENT_RESET_TO_BASE_POSE, - SESSION_STATE_EVENT_POSITON_TRACKING_TOGGLE, + SESSION_STATE_EVENT_POSITION_TRACKING_TOGGLE, } wmXrSessionStateEvent; static bool wm_xr_session_draw_data_needs_reset_to_base_pose(const wmXrSessionState *state, @@ -253,7 +253,7 @@ static wmXrSessionStateEvent wm_xr_session_state_to_event(const wmXrSessionState XR_SESSION_USE_POSITION_TRACKING) != (settings->flag & XR_SESSION_USE_POSITION_TRACKING)); if (position_tracking_toggled) { - return SESSION_STATE_EVENT_POSITON_TRACKING_TOGGLE; + return SESSION_STATE_EVENT_POSITION_TRACKING_TOGGLE; } return SESSION_STATE_EVENT_NONE; @@ -288,7 +288,7 @@ void wm_xr_session_draw_data_update(const wmXrSessionState *state, copy_v3_fl(draw_data->eye_position_ofs, 0.0f); } break; - case SESSION_STATE_EVENT_POSITON_TRACKING_TOGGLE: + case SESSION_STATE_EVENT_POSITION_TRACKING_TOGGLE: if (use_position_tracking) { /* Keep the current position, and let the user move from there. */ copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs); @@ -317,6 +317,7 @@ void wm_xr_session_state_update(const XrSessionSettings *settings, { GHOST_XrPose viewer_pose; const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING; + const bool use_absolute_tracking = settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING; mul_qt_qtqt(viewer_pose.orientation_quat, draw_data->base_pose.orientation_quat, @@ -324,14 +325,16 @@ void wm_xr_session_state_update(const XrSessionSettings *settings, copy_v3_v3(viewer_pose.position, draw_data->base_pose.position); /* The local pose and the eye pose (which is copied from an earlier local pose) both are view * space, so Y-up. In this case we need them in regular Z-up. */ - viewer_pose.position[0] -= draw_data->eye_position_ofs[0]; - viewer_pose.position[1] += draw_data->eye_position_ofs[2]; - viewer_pose.position[2] -= draw_data->eye_position_ofs[1]; if (use_position_tracking) { viewer_pose.position[0] += draw_view->local_pose.position[0]; viewer_pose.position[1] -= draw_view->local_pose.position[2]; viewer_pose.position[2] += draw_view->local_pose.position[1]; } + if (!use_absolute_tracking) { + viewer_pose.position[0] -= draw_data->eye_position_ofs[0]; + viewer_pose.position[1] += draw_data->eye_position_ofs[2]; + viewer_pose.position[2] -= draw_data->eye_position_ofs[1]; + } copy_v3_v3(state->viewer_pose.position, viewer_pose.position); copy_qt_qt(state->viewer_pose.orientation_quat, viewer_pose.orientation_quat); @@ -451,9 +454,14 @@ static void wm_xr_session_controller_mats_update(const XrSessionSettings *settin float base_inv[4][4]; float tmp[4][4]; - zero_v3(view_ofs); if ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) { - add_v3_v3(view_ofs, state->prev_local_pose.position); + copy_v3_v3(view_ofs, state->prev_local_pose.position); + } + else { + zero_v3(view_ofs); + } + if ((settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) { + add_v3_v3(view_ofs, state->prev_eye_position_ofs); } wm_xr_pose_to_viewmat(&state->prev_base_pose, base_inv); @@ -538,7 +546,6 @@ void wm_xr_session_controller_data_clear(wmXrSessionState *state) */ static void wm_xr_session_surface_draw(bContext *C) { - wmXrSurfaceData *surface_data = g_xr_surface->customdata; wmWindowManager *wm = CTX_wm_manager(C); Main *bmain = CTX_data_main(C); wmXrDrawData draw_data; @@ -554,38 +561,50 @@ static void wm_xr_session_surface_draw(bContext *C) GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data); - GPU_offscreen_unbind(surface_data->offscreen, false); + GPU_framebuffer_restore(); } bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, const GHOST_XrDrawViewInfo *draw_view) { - const bool size_changed = surface_data->offscreen && - (GPU_offscreen_width(surface_data->offscreen) != draw_view->width) && - (GPU_offscreen_height(surface_data->offscreen) != draw_view->height); + wmXrViewportPair *vp = NULL; + if (draw_view->view_idx >= BLI_listbase_count(&surface_data->viewports)) { + vp = MEM_callocN(sizeof(*vp), __func__); + BLI_addtail(&surface_data->viewports, vp); + } + else { + vp = BLI_findlink(&surface_data->viewports, draw_view->view_idx); + } + BLI_assert(vp); + + GPUOffScreen *offscreen = vp->offscreen; + GPUViewport *viewport = vp->viewport; + const bool size_changed = offscreen && (GPU_offscreen_width(offscreen) != draw_view->width) && + (GPU_offscreen_height(offscreen) != draw_view->height); char err_out[256] = "unknown"; bool failure = false; - if (surface_data->offscreen) { - BLI_assert(surface_data->viewport); + if (offscreen) { + BLI_assert(viewport); if (!size_changed) { return true; } - GPU_viewport_free(surface_data->viewport); - GPU_offscreen_free(surface_data->offscreen); - } - - if (!(surface_data->offscreen = GPU_offscreen_create( - draw_view->width, draw_view->height, true, false, err_out))) { - failure = true; - } - - if (failure) { - /* Pass. */ + GPU_viewport_free(viewport); + GPU_offscreen_free(offscreen); + } + + offscreen = vp->offscreen = GPU_offscreen_create( + draw_view->width, draw_view->height, true, false, err_out); + if (offscreen) { + viewport = vp->viewport = GPU_viewport_create(); + if (!viewport) { + GPU_offscreen_free(offscreen); + offscreen = vp->offscreen = NULL; + failure = true; + } } - else if (!(surface_data->viewport = GPU_viewport_create())) { - GPU_offscreen_free(surface_data->offscreen); + else { failure = true; } @@ -600,12 +619,17 @@ bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, static void wm_xr_session_surface_free_data(wmSurface *surface) { wmXrSurfaceData *data = surface->customdata; + ListBase *lb = &data->viewports; + wmXrViewportPair *vp; - if (data->viewport) { - GPU_viewport_free(data->viewport); - } - if (data->offscreen) { - GPU_offscreen_free(data->offscreen); + while ((vp = BLI_pophead(lb))) { + if (vp->viewport) { + GPU_viewport_free(vp->viewport); + } + if (vp->offscreen) { + GPU_offscreen_free(vp->offscreen); + } + BLI_freelinkN(lb, vp); } MEM_freeN(surface->customdata); diff --git a/source/tools b/source/tools -Subproject 01f51a0e551ab730f0934dc6488613690ac4bf8 +Subproject c8579c5cf43229843df505da9644b5b0b720197 diff --git a/tests/performance/api/config.py b/tests/performance/api/config.py index 68f4df8d487..d3a79eede14 100644 --- a/tests/performance/api/config.py +++ b/tests/performance/api/config.py @@ -31,6 +31,7 @@ class TestEntry: device_id: str = 'CPU' device_name: str = 'Unknown CPU' status: str = 'queued' + error_msg: str = '' output: Dict = field(default_factory=dict) benchmark_type: str = 'comparison' @@ -42,7 +43,8 @@ class TestEntry: def from_json(self, json_dict): for field in self.__dataclass_fields__: - setattr(self, field, json_dict[field]) + if field in json_dict: + setattr(self, field, json_dict[field]) class TestQueue: @@ -112,7 +114,7 @@ class TestConfig: self.base_dir = env.base_dir / name self.logs_dir = self.base_dir / 'logs' - config = self._read_config_module() + config = TestConfig._read_config_module(self.base_dir) self.tests = TestCollection(env, getattr(config, 'tests', ['*']), getattr(config, 'categories', ['*'])) @@ -154,10 +156,17 @@ class TestConfig: with open(config_file, 'w') as f: f.write(default_config) - def _read_config_module(self) -> None: + @staticmethod + def read_blender_executables(env, name) -> List: + config = TestConfig._read_config_module(env.base_dir / name) + builds = getattr(config, 'builds', {}) + return [pathlib.Path(build) for build in builds.values()] + + @staticmethod + def _read_config_module(base_dir: pathlib.Path) -> None: # Import config.py as a module. import importlib.util - spec = importlib.util.spec_from_file_location("testconfig", self.base_dir / 'config.py') + spec = importlib.util.spec_from_file_location("testconfig", base_dir / 'config.py') mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod @@ -195,14 +204,14 @@ class TestConfig: # Get entries for revisions based on existing builds. for revision_name, executable in self.builds.items(): - executable_path = pathlib.Path(executable) - if not executable_path.exists(): + executable_path = env._blender_executable_from_path(pathlib.Path(executable)) + if not executable_path: sys.stderr.write(f'Error: build {executable} not found\n') sys.exit(1) env.set_blender_executable(executable_path) git_hash, _ = env.run_in_blender(get_build_hash, {}) - env.unset_blender_executable() + env.set_default_blender_executable() mtime = executable_path.stat().st_mtime entries += self._get_entries(revision_name, git_hash, executable, mtime) diff --git a/tests/performance/api/environment.py b/tests/performance/api/environment.py index c9ddd493394..3a9b3eaf936 100644 --- a/tests/performance/api/environment.py +++ b/tests/performance/api/environment.py @@ -27,9 +27,10 @@ class TestEnvironment: self.git_executable = 'git' self.cmake_executable = 'cmake' self.cmake_options = ['-DWITH_INTERNATIONAL=OFF', '-DWITH_BUILDINFO=OFF'] - self.unset_blender_executable() self.log_file = None self.machine = None + self._init_default_blender_executable() + self.set_default_blender_executable() def get_machine(self, need_gpus: bool=True) -> None: if not self.machine or (need_gpus and not self.machine.has_gpus): @@ -46,7 +47,7 @@ class TestEnvironment: print(f'Init {self.base_dir}') self.base_dir.mkdir(parents=True, exist_ok=True) - if len(self.get_configs(names_only=True)) == 0: + if len(self.get_configs_names()) == 0: config_dir = self.base_dir / 'default' print(f'Creating default configuration in {config_dir}') TestConfig.write_default_config(self, config_dir) @@ -77,7 +78,7 @@ class TestEnvironment: print('Done') - def checkout(self) -> None: + def checkout(self, git_hash) -> None: # Checkout Blender revision if not self.blender_dir.exists(): sys.stderr.write('\n\nError: no build set up, run `./benchmark init --build` first\n') @@ -87,32 +88,68 @@ class TestEnvironment: self.call([self.git_executable, 'reset', '--hard', 'HEAD'], self.blender_dir) self.call([self.git_executable, 'checkout', '--detach', git_hash], self.blender_dir) - self.build() - - def build(self) -> None: + def build(self) -> bool: # Build Blender revision if not self.build_dir.exists(): sys.stderr.write('\n\nError: no build set up, run `./benchmark init --build` first\n') sys.exit(1) jobs = str(multiprocessing.cpu_count()) - self.call([self.cmake_executable, '.'] + self.cmake_options, self.build_dir) - self.call([self.cmake_executable, '--build', '.', '-j', jobs, '--target', 'install'], self.build_dir) + try: + self.call([self.cmake_executable, '.'] + self.cmake_options, self.build_dir) + self.call([self.cmake_executable, '--build', '.', '-j', jobs, '--target', 'install'], self.build_dir) + except: + return False + + self._init_default_blender_executable() + return True def set_blender_executable(self, executable_path: pathlib.Path) -> None: # Run all Blender commands with this executable. self.blender_executable = executable_path - def unset_blender_executable(self) -> None: + def _blender_executable_name(self) -> pathlib.Path: if platform.system() == "Windows": - self.blender_executable = self.build_dir / 'bin' / 'blender.exe' + return pathlib.Path('blender.exe') elif platform.system() == "Darwin": - self.blender_executable = self.build_dir / 'bin' / 'Blender.app' / 'Contents' / 'MacOS' / 'Blender' + return pathlib.Path('Blender.app') / 'Contents' / 'MacOS' / 'Blender' else: - self.blender_executable = self.build_dir / 'bin' / 'blender' - - if not self.blender_executable.exists(): - self.blender_executable = 'blender' + return pathlib.Path('blender') + + def _blender_executable_from_path(self, executable: pathlib.Path) -> pathlib.Path: + if executable.is_dir(): + # Directory + executable = executable / self._blender_executable_name() + elif not executable.is_file() and executable.name == 'blender': + # Executable path without proper path on Windows or macOS. + executable = executable.parent() / self._blender_executable_name() + + if executable.is_file(): + return executable + + return None + + def _init_default_blender_executable(self) -> None: + # Find a default executable to run commands independent of testing a specific build. + # Try own built executable. + built_executable = self._blender_executable_from_path(self.build_dir / 'bin') + if built_executable: + self.default_blender_executable = built_executable + return + + # Try find an executable in the configs. + for config_name in self.get_config_names(): + for executable in TestConfig.read_blender_executables(self, config_name): + executable = self._blender_executable_from_path(executable) + if executable: + self.default_blender_executable = executable + return + + # Fallback to a "blender" command in the hope it's available. + self.default_blender_executable = pathlib.Path("blender") + + def set_default_blender_executable(self) -> None: + self.blender_executable = self.default_blender_executable def set_log_file(self, filepath: pathlib.Path, clear=True) -> None: # Log all commands and output to this file. @@ -219,26 +256,36 @@ class TestEnvironment: filepaths.append(pathlib.Path(filename)) return filepaths + def get_config_names(self) -> List: + names = [] + + if self.base_dir.exists(): + for dirname in os.listdir(self.base_dir): + dirpath = self.base_dir / dirname / 'config.py' + if dirpath.exists(): + names.append(dirname) + + return names + def get_configs(self, name: str=None, names_only: bool=False) -> List: # Get list of configurations in the benchmarks directory. configs = [] - if self.base_dir.exists(): - for dirname in os.listdir(self.base_dir): - if not name or dirname == name: - dirpath = self.base_dir / dirname / 'config.py' - if dirpath.exists(): - if names_only: - configs.append(dirname) - else: - configs.append(TestConfig(self, dirname)) + for config_name in self.get_config_names(): + if not name or config_name == name: + if names_only: + configs.append(config_name) + else: + configs.append(TestConfig(self, config_name)) return configs def resolve_git_hash(self, revision): # Get git hash for a tag or branch. - return self.call([self.git_executable, 'rev-parse', revision], self.blender_git_dir)[0].strip() + lines = self.call([self.git_executable, 'rev-parse', revision], self.blender_git_dir) + return lines[0].strip() if len(lines) else revision def git_hash_date(self, git_hash): # Get commit data for a git hash. - return int(self.call([self.git_executable, 'log', '-n1', git_hash, '--format=%at'], self.blender_git_dir)[0].strip()) + lines = self.call([self.git_executable, 'log', '-n1', git_hash, '--format=%at'], self.blender_git_dir) + return int(lines[0].strip()) if len(lines) else 0 diff --git a/tests/performance/api/graph.py b/tests/performance/api/graph.py index b3c8329ff27..4ee5ae7cf0e 100644 --- a/tests/performance/api/graph.py +++ b/tests/performance/api/graph.py @@ -30,6 +30,7 @@ class TestGraph: data = [] for device_name, device_entries in devices.items(): + # Gather used categories. categories = {} for entry in device_entries: @@ -57,6 +58,8 @@ class TestGraph: self.json = json.dumps(data, indent=2) def chart(self, device_name: str, chart_name: str, entries: List, chart_type: str, output: str) -> Dict: + entries = sorted(entries, key=lambda entry: entry.date) + # Gather used tests. tests = {} for entry in entries: diff --git a/tests/performance/benchmark b/tests/performance/benchmark index 3b43bd0aa96..eb01b6053a7 100755 --- a/tests/performance/benchmark +++ b/tests/performance/benchmark @@ -66,6 +66,8 @@ def print_row(config: api.TestConfig, entries: List, end='\n') -> None: if status == 'outdated': result += " (outdated)" + elif status == 'failed': + result = "failed: " + entry.error_msg else: result = status @@ -105,20 +107,37 @@ def run_entry(env: api.TestEnvironment, config: api.TestConfig, row: List, entry logname += '_' + device_id env.set_log_file(config.logs_dir / (logname + '.log'), clear=True) + # Clear output + entry.output = None + entry.error_msg = '' + # Build revision, or just set path to existing executable. entry.status = 'building' print_row(config, row, end='\r') + executable_ok = True if len(entry.executable): env.set_blender_executable(pathlib.Path(entry.executable)) else: env.checkout(git_hash) - env.build(git_hash) + executable_ok = env.build() + if not executable_ok: + entry.status = 'failed' + entry.error_msg = 'Failed to build' # Run test and update output and status. entry.status = 'running' print_row(config, row, end='\r') - entry.output = test.run(env, device_id) - entry.status = 'done' if entry.output else 'failed' + + if executable_ok: + try: + entry.output = test.run(env, device_id) + if not entry.output: + raise Exception("Test produced no output") + entry.status = 'done' + except Exception as e: + entry.status = 'failed' + entry.error_msg = str(e) + print_row(config, row, end='\r') # Update device name in case the device changed since the entry was created. @@ -126,7 +145,7 @@ def run_entry(env: api.TestEnvironment, config: api.TestConfig, row: List, entry # Restore default logging and Blender executable. env.unset_log_file() - env.unset_blender_executable() + env.set_default_blender_executable() return True @@ -155,7 +174,7 @@ def cmd_list(env: api.TestEnvironment, argv: List) -> None: print('') print('CONFIGS') - configs = env.get_configs(names_only=True) + configs = env.get_config_names() for config_name in configs: print(config_name) |