UI: Allow Eyedropper Outside of Blender #105324

Merged
Harley Acheson merged 3 commits from Harley/blender:Eyedropper into main 2023-08-16 01:14:43 +02:00
17 changed files with 121 additions and 26 deletions

View File

@ -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
Harley marked this conversation as resolved Outdated

Can you change RGB -> sRGB to clarify the color space. Here and a few other places that repeat the same comment.

Can you change RGB -> sRGB to clarify the color space. Here and a few other places that repeat the same comment.
* \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.

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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)
{

View File

@ -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.

View File

@ -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));
}

View File

@ -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

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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

View File

@ -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.
***************************************************************************************/

View File

@ -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));
}

View File

@ -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<SpaceImage *>(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<SpaceNode *>(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<SpaceClip *>(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 {
Harley marked this conversation as resolved Outdated

Use IMB_colormanagement_srgb_to_scene_linear_v3 instead if the color came from another window.

When doing color picker of for a 3D viewport or render that Blender displays then taking into account the view transform makes sense. But from another window, it seems wrong to me.

Use `IMB_colormanagement_srgb_to_scene_linear_v3` instead if the color came from another window. When doing color picker of for a 3D viewport or render that Blender displays then taking into account the view transform makes sense. But from another window, it seems wrong to me.
zero_v3(r_col);
}

View File

@ -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).
*

View File

@ -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);
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -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;
}