diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 412a6d961f3..028fa2cc263 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -764,6 +764,13 @@ extern void GHOST_SetMultitouchGestures(GHOST_SystemHandle systemhandle, const b */ extern void GHOST_SetTabletAPI(GHOST_SystemHandle systemhandle, GHOST_TTabletAPI api); +/** + * Get the color of the pixel at the current mouse cursor location + * \param r_color: returned sRGB float colors + * \return Success value (true == successful and supported by platform) + */ +extern GHOST_TSuccess GHOST_GetPixelAtCursor(float r_color[3]); + /** * Access to rectangle width. * \param rectanglehandle: The handle to the rectangle. diff --git a/intern/ghost/GHOST_ISystem.hh b/intern/ghost/GHOST_ISystem.hh index ef4495096d2..0e145c9eac6 100644 --- a/intern/ghost/GHOST_ISystem.hh +++ b/intern/ghost/GHOST_ISystem.hh @@ -441,6 +441,13 @@ class GHOST_ISystem { */ virtual void setTabletAPI(GHOST_TTabletAPI api) = 0; + /** + * Get the color of the pixel at the current mouse cursor location + * \param r_color: returned sRGB float colors + * \return Success value (true == successful and supported by platform) + */ + virtual GHOST_TSuccess getPixelAtCursor(float r_color[3]) const = 0; + #ifdef WITH_INPUT_NDOF /** * Sets 3D mouse deadzone diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 356ff0674b2..0bc79b2ac5c 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -107,6 +107,10 @@ typedef enum { * Set when there is support for system clipboard copy/paste. */ GHOST_kCapabilityClipboardImages = (1 << 4), + /** + * Support for sampling a color outside of the Blender windows. + */ + GHOST_kCapabilityDesktopSample = (1 << 5), } GHOST_TCapabilityFlag; /** @@ -115,7 +119,8 @@ typedef enum { */ #define GHOST_CAPABILITY_FLAG_ALL \ (GHOST_kCapabilityCursorWarp | GHOST_kCapabilityWindowPosition | \ - GHOST_kCapabilityPrimaryClipboard | GHOST_kCapabilityGPUReadFrontBuffer) + GHOST_kCapabilityPrimaryClipboard | GHOST_kCapabilityGPUReadFrontBuffer | \ + GHOST_kCapabilityClipboardImages | GHOST_kCapabilityDesktopSample) /* Xtilt and Ytilt represent how much the pen is tilted away from * vertically upright in either the X or Y direction, with X and Y the diff --git a/intern/ghost/intern/GHOST_C-api.cc b/intern/ghost/intern/GHOST_C-api.cc index 22c17c624e1..1e5599bfa0c 100644 --- a/intern/ghost/intern/GHOST_C-api.cc +++ b/intern/ghost/intern/GHOST_C-api.cc @@ -768,6 +768,12 @@ void GHOST_SetTabletAPI(GHOST_SystemHandle systemhandle, GHOST_TTabletAPI api) system->setTabletAPI(api); } +GHOST_TSuccess GHOST_GetPixelAtCursor(float r_color[3]) +{ + GHOST_ISystem *system = GHOST_ISystem::getSystem(); + return system->getPixelAtCursor(r_color); +} + int32_t GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle) { return ((GHOST_Rect *)rectanglehandle)->getWidth(); diff --git a/intern/ghost/intern/GHOST_System.cc b/intern/ghost/intern/GHOST_System.cc index f86867df50c..65d1323938b 100644 --- a/intern/ghost/intern/GHOST_System.cc +++ b/intern/ghost/intern/GHOST_System.cc @@ -341,6 +341,11 @@ GHOST_TTabletAPI GHOST_System::getTabletAPI() return m_tabletAPI; } +GHOST_TSuccess GHOST_System::getPixelAtCursor(float[3] /* r_color */) const +{ + return GHOST_kFailure; +} + #ifdef WITH_INPUT_NDOF void GHOST_System::setNDOFDeadZone(float deadzone) { diff --git a/intern/ghost/intern/GHOST_System.hh b/intern/ghost/intern/GHOST_System.hh index bba17c44bb0..bb4688f865f 100644 --- a/intern/ghost/intern/GHOST_System.hh +++ b/intern/ghost/intern/GHOST_System.hh @@ -256,6 +256,13 @@ class GHOST_System : public GHOST_ISystem { virtual void setTabletAPI(GHOST_TTabletAPI api); GHOST_TTabletAPI getTabletAPI(void); + /** + * Get the color of the pixel at the current mouse cursor location + * \param r_color: returned sRGB float colors + * \return Success value (true == successful and supported by platform) + */ + GHOST_TSuccess getPixelAtCursor(float r_color[3]) const; + #ifdef WITH_INPUT_NDOF /*************************************************************************************** * Access to 3D mouse. diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index bf3e2e435bc..b2fa4de47b9 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -921,6 +921,8 @@ GHOST_TCapabilityFlag GHOST_SystemCocoa::getCapabilities() const ~( /* Cocoa has no support for a primary selection clipboard. */ GHOST_kCapabilityPrimaryClipboard | + /* Cocoa has no support for sampling colors from the desktop. */ + GHOST_kCapabilityDesktopSample | /* This Cocoa back-end has not yet implemented image copy/paste. */ GHOST_kCapabilityClipboardImages)); } diff --git a/intern/ghost/intern/GHOST_SystemHeadless.hh b/intern/ghost/intern/GHOST_SystemHeadless.hh index 8cd3828595d..59406ca44f2 100644 --- a/intern/ghost/intern/GHOST_SystemHeadless.hh +++ b/intern/ghost/intern/GHOST_SystemHeadless.hh @@ -50,6 +50,7 @@ class GHOST_SystemHeadless : public GHOST_System { /* No windowing functionality supported. */ ~(GHOST_kCapabilityWindowPosition | GHOST_kCapabilityCursorWarp | GHOST_kCapabilityPrimaryClipboard | + GHOST_kCapabilityDesktopSample | GHOST_kCapabilityClipboardImages)); } char *getClipboard(bool /*selection*/) const override diff --git a/intern/ghost/intern/GHOST_SystemSDL.cc b/intern/ghost/intern/GHOST_SystemSDL.cc index e54b7e27c54..ad6efef1a1c 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.cc +++ b/intern/ghost/intern/GHOST_SystemSDL.cc @@ -772,6 +772,8 @@ GHOST_TCapabilityFlag GHOST_SystemSDL::getCapabilities() const ~( /* This SDL back-end has not yet implemented primary clipboard. */ GHOST_kCapabilityPrimaryClipboard | + /* This SDL back-end has not yet implemented color sampling the desktop. */ + GHOST_kCapabilityDesktopSample | /* This SDL back-end has not yet implemented image copy/paste. */ GHOST_kCapabilityClipboardImages)); } diff --git a/intern/ghost/intern/GHOST_SystemWayland.cc b/intern/ghost/intern/GHOST_SystemWayland.cc index b3d194c5856..e08049cb0ba 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cc +++ b/intern/ghost/intern/GHOST_SystemWayland.cc @@ -6843,6 +6843,8 @@ GHOST_TCapabilityFlag GHOST_SystemWayland::getCapabilities() const * screen-shot and eye-dropper sampling logic, both operations where the overhead * is negligible. */ GHOST_kCapabilityGPUReadFrontBuffer | + /* This WAYLAND back-end has not yet implemented desktop color sample. */ + GHOST_kCapabilityDesktopSample | /* This WAYLAND back-end has not yet implemented image copy/paste. */ GHOST_kCapabilityClipboardImages)); } diff --git a/intern/ghost/intern/GHOST_SystemWin32.cc b/intern/ghost/intern/GHOST_SystemWin32.cc index 993115cbffe..9d13e73c28a 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cc +++ b/intern/ghost/intern/GHOST_SystemWin32.cc @@ -448,6 +448,31 @@ GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(int32_t x, int32_t y) return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure; } +GHOST_TSuccess GHOST_SystemWin32::getPixelAtCursor(float r_color[3]) const +{ + POINT point; + if (!GetCursorPos(&point)) { + return GHOST_kFailure; + } + + HDC dc = GetDC(NULL); + if (dc == NULL) { + return GHOST_kFailure; + } + + COLORREF color = GetPixel(dc, point.x, point.y); + ReleaseDC(NULL, dc); + + if (color == CLR_INVALID) { + return GHOST_kFailure; + } + + r_color[0] = GetRValue(color) / 255.0f; + r_color[1] = GetGValue(color) / 255.0f; + r_color[2] = GetBValue(color) / 255.0f; + return GHOST_kSuccess; +} + GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys &keys) const { /* `GetAsyncKeyState` returns the current interrupt-level state of the hardware, which is needed diff --git a/intern/ghost/intern/GHOST_SystemWin32.hh b/intern/ghost/intern/GHOST_SystemWin32.hh index 5437e3667b7..8fa578f7cd3 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.hh +++ b/intern/ghost/intern/GHOST_SystemWin32.hh @@ -182,6 +182,13 @@ class GHOST_SystemWin32 : public GHOST_System { */ GHOST_TSuccess setCursorPosition(int32_t x, int32_t y); + /** + * Get the color of the pixel at the current mouse cursor location + * \param r_color: returned sRGB float colors + * \return Success value (true == successful and supported by platform) + */ + GHOST_TSuccess getPixelAtCursor(float r_color[3]) const; + /*************************************************************************************** ** Access to mouse button and keyboard states. ***************************************************************************************/ diff --git a/intern/ghost/intern/GHOST_SystemX11.cc b/intern/ghost/intern/GHOST_SystemX11.cc index 90939dda816..78d07331e3c 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cc +++ b/intern/ghost/intern/GHOST_SystemX11.cc @@ -1693,6 +1693,8 @@ GHOST_TCapabilityFlag GHOST_SystemX11::getCapabilities() const { return GHOST_TCapabilityFlag(GHOST_CAPABILITY_FLAG_ALL & ~( + /* No support yet for desktop sampling. */ + GHOST_kCapabilityDesktopSample | /* No support yet for image copy/paste. */ GHOST_kCapabilityClipboardImages)); } diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_color.cc b/source/blender/editors/interface/eyedroppers/eyedropper_color.cc index a88251fa736..ddd66202f9b 100644 --- a/source/blender/editors/interface/eyedroppers/eyedropper_color.cc +++ b/source/blender/editors/interface/eyedroppers/eyedropper_color.cc @@ -315,45 +315,35 @@ static bool eyedropper_cryptomatte_sample_fl(bContext *C, void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3]) { - /* we could use some clever */ - Main *bmain = CTX_data_main(C); - const char *display_device = CTX_data_scene(C)->display_settings.display_device; - ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); + wmWindowManager *wm = CTX_wm_manager(C); + ScrArea *area = nullptr; int mval[2]; - wmWindow *win; - ScrArea *area; - datadropper_win_area_find(C, m_xy, mval, &win, &area); + wmWindow *win = WM_window_find_under_cursor(CTX_wm_window(C), m_xy, mval); + if (win) { + bScreen *screen = WM_window_get_active_screen(win); + area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mval); + } if (area) { - if (area->spacetype == SPACE_IMAGE) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); - if (region) { + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); + if (region) { + const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; + if (area->spacetype == SPACE_IMAGE) { SpaceImage *sima = static_cast(area->spacedata.first); - const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; - if (ED_space_image_color_sample(sima, region, region_mval, r_col, nullptr)) { return; } } - } - else if (area->spacetype == SPACE_NODE) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); - if (region) { + else if (area->spacetype == SPACE_NODE) { SpaceNode *snode = static_cast(area->spacedata.first); - const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; - + Main *bmain = CTX_data_main(C); if (ED_space_node_color_sample(bmain, snode, region, region_mval, r_col)) { return; } } - } - else if (area->spacetype == SPACE_CLIP) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); - if (region) { + else if (area->spacetype == SPACE_CLIP) { SpaceClip *sc = static_cast(area->spacedata.first); - const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; - if (ED_space_clip_color_sample(sc, region, region_mval, r_col)) { return; } @@ -362,9 +352,20 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3]) } if (win) { - WM_window_pixels_read_sample(C, win, mval, r_col); + /* Other areas within a Blender window. */ + if (!WM_window_pixels_read_sample(C, win, mval, r_col)) { + WM_window_pixels_read_sample_from_offscreen(C, win, mval, r_col); + } + const char *display_device = CTX_data_scene(C)->display_settings.display_device; + ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); IMB_colormanagement_display_to_scene_linear_v3(r_col, display); } + else if ((WM_capabilities_flag() & WM_CAPABILITY_DESKTOP_SAMPLE) && + WM_desktop_cursor_sample_read(r_col)) + { + /* Outside of the Blender window if we support it. */ + IMB_colormanagement_srgb_to_scene_linear_v3(r_col, r_col); + } else { zero_v3(r_col); } diff --git a/source/blender/windowmanager/WM_api.hh b/source/blender/windowmanager/WM_api.hh index 3186d36cdb5..7f62a649ed0 100644 --- a/source/blender/windowmanager/WM_api.hh +++ b/source/blender/windowmanager/WM_api.hh @@ -170,6 +170,8 @@ enum eWM_CapabilitiesFlag { WM_CAPABILITY_GPU_FRONT_BUFFER_READ = (1 << 3), /** Ability to copy/paste system clipboard images. */ WM_CAPABILITY_CLIPBOARD_IMAGES = (1 << 4), + /** Ability to sample a color outside of Blender windows. */ + WM_CAPABILITY_DESKTOP_SAMPLE = (1 << 5), /** The initial value, indicates the value needs to be set by inspecting GHOST. */ WM_CAPABILITY_INITIALIZED = (1 << 31), }; @@ -194,6 +196,12 @@ wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mv */ wmWindow *WM_window_find_by_area(wmWindowManager *wm, const ScrArea *area); +/** + * Return the color of the pixel at the current mouse cursor position on the desktop, whether in a + * Blender window or not. Returns false on failure or if not supported by the platform. + */ +bool WM_desktop_cursor_sample_read(float r_col[3]); + /** * Read pixels from the front-buffer (fast). * diff --git a/source/blender/windowmanager/intern/wm_draw.cc b/source/blender/windowmanager/intern/wm_draw.cc index 63c8925b84a..ea8cecdb77f 100644 --- a/source/blender/windowmanager/intern/wm_draw.cc +++ b/source/blender/windowmanager/intern/wm_draw.cc @@ -1411,6 +1411,11 @@ bool WM_window_pixels_read_sample(bContext *C, wmWindow *win, const int pos[2], return WM_window_pixels_read_sample_from_offscreen(C, win, pos, r_col); } +bool WM_desktop_cursor_sample_read(float r_col[3]) +{ + return GHOST_GetPixelAtCursor(r_col); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/windowmanager/intern/wm_window.cc b/source/blender/windowmanager/intern/wm_window.cc index 990c5cc37ef..f32f15285bf 100644 --- a/source/blender/windowmanager/intern/wm_window.cc +++ b/source/blender/windowmanager/intern/wm_window.cc @@ -1887,6 +1887,9 @@ eWM_CapabilitiesFlag WM_capabilities_flag() if (ghost_flag & GHOST_kCapabilityClipboardImages) { flag |= WM_CAPABILITY_CLIPBOARD_IMAGES; } + if (ghost_flag & GHOST_kCapabilityDesktopSample) { + flag |= WM_CAPABILITY_DESKTOP_SAMPLE; + } return flag; }