Files
test2/source/blender/imbuf/IMB_interp.hh
Brecht Van Lommel 6aa11a304c Paint: Store brush and palette colors in scene linear colorspace
For historical reasons these were stored in sRGB space, which caused all
kinds of complexity.

* For image painting, it now properly uses the byte buffer colorspace
  instead of assuming sRGB or display colorspace. This can be more expensive,
  so there is a fast path for sRGB buffers (and for fixed brush colors).
* Lots of code was changed to remove conversion when painting float images
  or vertex colors, and added when painting byte images.
* For non-color data, there is now no colorspace conversion between the brush
  color and image pixels, and #143642 was basically reverted because of that.

Compatibility notes:

* Backwards compatibility is not perfect, as we can not determine if the
  brush has non-color data in isolation. We always convert sRGB to linear,
  and existing brushes configured with non-color data need to be manually
  fixed.
* There is forward compatibility, the old sRGB value is still stored next
  to the scene linear value.

Pull Request: https://projects.blender.org/blender/blender/pulls/144400
2025-08-26 17:10:16 +02:00

143 lines
5.1 KiB
C++

/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbuf
*
* Image buffer pixel sampling functions.
* Mostly convenience wrappers around lower level `BLI_math_interp.hh`.
*/
#pragma once
#include "BLI_math_interp.hh"
#include "IMB_imbuf_types.hh"
#include <cstring>
namespace blender::imbuf {
/* Nearest sampling. */
[[nodiscard]] inline uchar4 interpolate_nearest_border_byte(const ImBuf *in, float u, float v)
{
return math::interpolate_nearest_border_byte(in->byte_buffer.data, in->x, in->y, u, v);
}
[[nodiscard]] inline float4 interpolate_nearest_border_fl(const ImBuf *in, float u, float v)
{
return math::interpolate_nearest_border_fl(in->float_buffer.data, in->x, in->y, u, v);
}
inline void interpolate_nearest_border_byte(const ImBuf *in, uchar output[4], float u, float v)
{
math::interpolate_nearest_border_byte(in->byte_buffer.data, output, in->x, in->y, u, v);
}
inline void interpolate_nearest_border_fl(const ImBuf *in, float output[4], float u, float v)
{
math::interpolate_nearest_border_fl(in->float_buffer.data, output, in->x, in->y, 4, u, v);
}
/* Nearest sampling with UV wrapping. */
[[nodiscard]] inline uchar4 interpolate_nearest_wrap_byte(const ImBuf *in, float u, float v)
{
return math::interpolate_nearest_wrap_byte(in->byte_buffer.data, in->x, in->y, u, v);
}
[[nodiscard]] inline float4 interpolate_nearest_wrap_fl(const ImBuf *in, float u, float v)
{
return math::interpolate_nearest_wrap_fl(in->float_buffer.data, in->x, in->y, u, v);
}
/* Bilinear sampling. */
[[nodiscard]] inline uchar4 interpolate_bilinear_byte(const ImBuf *in, float u, float v)
{
return math::interpolate_bilinear_byte(in->byte_buffer.data, in->x, in->y, u, v);
}
[[nodiscard]] inline float4 interpolate_bilinear_fl(const ImBuf *in, float u, float v)
{
return math::interpolate_bilinear_fl(in->float_buffer.data, in->x, in->y, u, v);
}
inline void interpolate_bilinear_byte(const ImBuf *in, uchar output[4], float u, float v)
{
uchar4 col = math::interpolate_bilinear_byte(in->byte_buffer.data, in->x, in->y, u, v);
memcpy(output, &col, sizeof(col));
}
inline void interpolate_bilinear_fl(const ImBuf *in, float output[4], float u, float v)
{
float4 col = math::interpolate_bilinear_fl(in->float_buffer.data, in->x, in->y, u, v);
memcpy(output, &col, sizeof(col));
}
/* Bilinear sampling, samples near edge blend into transparency. */
[[nodiscard]] inline uchar4 interpolate_bilinear_border_byte(const ImBuf *in, float u, float v)
{
return math::interpolate_bilinear_border_byte(in->byte_buffer.data, in->x, in->y, u, v);
}
[[nodiscard]] inline float4 interpolate_bilinear_border_fl(const ImBuf *in, float u, float v)
{
return math::interpolate_bilinear_border_fl(in->float_buffer.data, in->x, in->y, u, v);
}
inline void interpolate_bilinear_border_byte(const ImBuf *in, uchar output[4], float u, float v)
{
uchar4 col = math::interpolate_bilinear_border_byte(in->byte_buffer.data, in->x, in->y, u, v);
memcpy(output, &col, sizeof(col));
}
inline void interpolate_bilinear_border_fl(const ImBuf *in, float output[4], float u, float v)
{
float4 col = math::interpolate_bilinear_border_fl(in->float_buffer.data, in->x, in->y, u, v);
memcpy(output, &col, sizeof(col));
}
/* Bilinear sampling with UV wrapping. */
[[nodiscard]] inline uchar4 interpolate_bilinear_wrap_byte(const ImBuf *in, float u, float v)
{
return math::interpolate_bilinear_wrap_byte(in->byte_buffer.data, in->x, in->y, u, v);
}
[[nodiscard]] inline float4 interpolate_bilinear_wrap_fl(const ImBuf *in, float u, float v)
{
return math::interpolate_bilinear_wrap_fl(in->float_buffer.data, in->x, in->y, u, v);
}
/* Cubic B-Spline sampling. */
[[nodiscard]] inline uchar4 interpolate_cubic_bspline_byte(const ImBuf *in, float u, float v)
{
return math::interpolate_cubic_bspline_byte(in->byte_buffer.data, in->x, in->y, u, v);
}
[[nodiscard]] inline float4 interpolate_cubic_bspline_fl(const ImBuf *in, float u, float v)
{
return math::interpolate_cubic_bspline_fl(in->float_buffer.data, in->x, in->y, u, v);
}
inline void interpolate_cubic_bspline_byte(const ImBuf *in, uchar output[4], float u, float v)
{
uchar4 col = math::interpolate_cubic_bspline_byte(in->byte_buffer.data, in->x, in->y, u, v);
memcpy(output, &col, sizeof(col));
}
inline void interpolate_cubic_bspline_fl(const ImBuf *in, float output[4], float u, float v)
{
float4 col = math::interpolate_cubic_bspline_fl(in->float_buffer.data, in->x, in->y, u, v);
memcpy(output, &col, sizeof(col));
}
/* Cubic Mitchell sampling. */
[[nodiscard]] inline uchar4 interpolate_cubic_mitchell_byte(const ImBuf *in, float u, float v)
{
return math::interpolate_cubic_mitchell_byte(in->byte_buffer.data, in->x, in->y, u, v);
}
inline void interpolate_cubic_mitchell_byte(const ImBuf *in, uchar output[4], float u, float v)
{
uchar4 col = math::interpolate_cubic_mitchell_byte(in->byte_buffer.data, in->x, in->y, u, v);
memcpy(output, &col, sizeof(col));
}
} // namespace blender::imbuf
/**
* Sample pixel of image using NEAREST method.
*/
void IMB_sampleImageAtLocation(ImBuf *ibuf, float x, float y, float scene_linear_rgb[3]);