WIP: Brush assets project #106303
|
@ -1718,10 +1718,12 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
|||
col.prop(self, "metalrt")
|
||||
|
||||
if compute_device_type == 'HIP':
|
||||
has_cuda, has_optix, has_hip, has_metal, has_oneapi, has_hiprt = _cycles.get_device_types()
|
||||
row = layout.row()
|
||||
row.enabled = has_hiprt
|
||||
row.prop(self, "use_hiprt")
|
||||
import platform
|
||||
if platform.system() == "Windows": # HIP-RT is currently only supported on Windows
|
||||
has_cuda, has_optix, has_hip, has_metal, has_oneapi, has_hiprt = _cycles.get_device_types()
|
||||
row = layout.row()
|
||||
row.enabled = has_hiprt
|
||||
row.prop(self, "use_hiprt")
|
||||
|
||||
elif compute_device_type == 'ONEAPI' and _cycles.with_embree_gpu:
|
||||
row = layout.row()
|
||||
|
|
|
@ -650,6 +650,9 @@ static bool bake_setup_pass(Scene *scene, const string &bake_type, const int bak
|
|||
integrator->set_use_direct_light(use_direct_light);
|
||||
integrator->set_use_indirect_light(use_indirect_light);
|
||||
|
||||
const PassInfo pass_info = Pass::get_info(type);
|
||||
integrator->set_use_denoise(pass_info.support_denoise);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -4711,9 +4711,9 @@ def km_object_mode(params):
|
|||
("object.join", {"type": 'J', "value": 'PRESS', "ctrl": True}, None),
|
||||
("wm.context_toggle", {"type": 'PERIOD', "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("data_path", 'tool_settings.use_transform_data_origin')]}),
|
||||
("anim.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None),
|
||||
("anim.keyframe_insert_menu", {"type": 'K', "value": 'PRESS'}, {"properties": [("always_prompt", True)]}),
|
||||
("anim.keyframe_delete_v3d", {"type": 'I', "value": 'PRESS', "alt": True}, None),
|
||||
("anim.keying_set_active_set", {"type": 'I', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
|
||||
("anim.keying_set_active_set", {"type": 'K', "value": 'PRESS', "shift": True}, None),
|
||||
("collection.create", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),
|
||||
("collection.objects_remove", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True}, None),
|
||||
("collection.objects_remove_all",
|
||||
|
@ -4730,6 +4730,16 @@ def km_object_mode(params):
|
|||
*_template_items_context_menu("VIEW3D_MT_object_context_menu", params.context_menu_event),
|
||||
])
|
||||
|
||||
if params.use_pie_click_drag:
|
||||
items.extend([
|
||||
("anim.keyframe_insert", {"type": 'I', "value": 'CLICK'}, None),
|
||||
op_menu_pie("ANIM_MT_keyframe_insert_pie", {"type": 'I', "value": 'CLICK_DRAG'}),
|
||||
])
|
||||
else:
|
||||
items.extend([
|
||||
("anim.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None),
|
||||
])
|
||||
|
||||
if params.legacy:
|
||||
items.extend([
|
||||
("object.select_mirror", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, None),
|
||||
|
@ -4850,9 +4860,9 @@ def km_pose(params):
|
|||
("armature.assign_to_collection", {"type": 'M', "value": 'PRESS', "shift": True}, None),
|
||||
("armature.move_to_collection", {"type": 'M', "value": 'PRESS'}, None),
|
||||
("transform.bbone_resize", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
|
||||
("anim.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None),
|
||||
("anim.keyframe_insert_menu", {"type": 'K', "value": 'PRESS'}, {"properties": [("always_prompt", True)]}),
|
||||
("anim.keyframe_delete_v3d", {"type": 'I', "value": 'PRESS', "alt": True}, None),
|
||||
("anim.keying_set_active_set", {"type": 'I', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
|
||||
("anim.keying_set_active_set", {"type": 'K', "value": 'PRESS', "shift": True}, None),
|
||||
("pose.push", {"type": 'E', "value": 'PRESS', "ctrl": True}, None),
|
||||
("pose.relax", {"type": 'E', "value": 'PRESS', "alt": True}, None),
|
||||
("pose.breakdown", {"type": 'E', "value": 'PRESS', "shift": True}, None),
|
||||
|
@ -4861,6 +4871,16 @@ def km_pose(params):
|
|||
*_template_items_context_menu("VIEW3D_MT_pose_context_menu", params.context_menu_event),
|
||||
])
|
||||
|
||||
if params.use_pie_click_drag:
|
||||
items.extend([
|
||||
("anim.keyframe_insert", {"type": 'I', "value": 'CLICK'}, None),
|
||||
op_menu_pie("ANIM_MT_keyframe_insert_pie", {"type": 'I', "value": 'CLICK_DRAG'}),
|
||||
])
|
||||
else:
|
||||
items.extend([
|
||||
("anim.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ if "bpy" in locals():
|
|||
del reload
|
||||
|
||||
_modules = [
|
||||
"anim",
|
||||
"asset_shelf",
|
||||
"node_add_menu",
|
||||
"node_add_menu_compositor",
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
from bpy.types import Menu
|
||||
|
||||
|
||||
class ANIM_MT_keyframe_insert_pie(Menu):
|
||||
bl_label = "Keyframe Insert Pie"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
pie = layout.menu_pie()
|
||||
|
||||
prop = pie.operator("anim.keyframe_insert_by_name", text="Location")
|
||||
prop.type = "Location"
|
||||
|
||||
prop = pie.operator("anim.keyframe_insert_by_name", text="Scale")
|
||||
prop.type = "Scaling"
|
||||
|
||||
prop = pie.operator("anim.keyframe_insert_by_name", text="Available")
|
||||
prop.type = "Available"
|
||||
|
||||
prop = pie.operator("anim.keyframe_insert_by_name", text="Rotation")
|
||||
prop.type = "Rotation"
|
||||
|
||||
|
||||
classes = (
|
||||
ANIM_MT_keyframe_insert_pie,
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
from bpy.utils import register_class
|
||||
for cls in classes:
|
||||
register_class(cls)
|
|
@ -29,7 +29,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 14
|
||||
#define BLENDER_FILE_SUBVERSION 15
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
|
|
@ -23,8 +23,7 @@
|
|||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
||||
/* Allow using deprecated functionality for .blend file I/O. */
|
||||
#define DNA_DEPRECATED_ALLOW
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "DNA_listBase.h"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
#include "IMB_openexr.hh"
|
||||
|
||||
#include "GPU_texture.h"
|
||||
|
@ -35,6 +35,8 @@
|
|||
|
||||
#include <cstring>
|
||||
|
||||
using blender::float4;
|
||||
|
||||
/* Statics */
|
||||
static ListBase studiolights;
|
||||
static int last_studiolight_id = 0;
|
||||
|
@ -487,11 +489,11 @@ static void studiolight_create_matcap_specular_gputexture(StudioLight *sl)
|
|||
sl->flag |= STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE;
|
||||
}
|
||||
|
||||
static void studiolight_calculate_radiance(ImBuf *ibuf, float color[4], const float direction[3])
|
||||
static float4 studiolight_calculate_radiance(ImBuf *ibuf, const float direction[3])
|
||||
{
|
||||
float uv[2];
|
||||
direction_to_equirect(uv, direction);
|
||||
nearest_interpolation_color_wrap(ibuf, nullptr, color, uv[0] * ibuf->x, uv[1] * ibuf->y);
|
||||
return blender::imbuf::interpolate_nearest_fl(ibuf, uv[0] * ibuf->x, uv[1] * ibuf->y);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -692,7 +694,7 @@ static void studiolight_radiance_preview(uint *icon_buffer, StudioLight *sl)
|
|||
|
||||
uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
|
||||
if (alphamask != 0) {
|
||||
float normal[3], direction[3], color[4];
|
||||
float normal[3], direction[3];
|
||||
const float incoming[3] = {0.0f, 0.0f, -1.0f};
|
||||
sphere_normal_from_uv(normal, dx, dy);
|
||||
reflect_v3_v3v3(direction, incoming, normal);
|
||||
|
@ -700,7 +702,7 @@ static void studiolight_radiance_preview(uint *icon_buffer, StudioLight *sl)
|
|||
SWAP(float, direction[1], direction[2]);
|
||||
direction[1] = -direction[1];
|
||||
|
||||
studiolight_calculate_radiance(sl->equirect_radiance_buffer, color, direction);
|
||||
float4 color = studiolight_calculate_radiance(sl->equirect_radiance_buffer, direction);
|
||||
|
||||
*pixel = rgb_to_cpack(linearrgb_to_srgb(color[0]),
|
||||
linearrgb_to_srgb(color[1]),
|
||||
|
@ -716,6 +718,8 @@ static void studiolight_radiance_preview(uint *icon_buffer, StudioLight *sl)
|
|||
|
||||
static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool flipped)
|
||||
{
|
||||
using namespace blender;
|
||||
|
||||
BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
|
||||
|
||||
ImBuf *diffuse_buffer = sl->matcap_diffuse.ibuf;
|
||||
|
@ -728,14 +732,12 @@ static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool
|
|||
dx = 1.0f - dx;
|
||||
}
|
||||
|
||||
float color[4];
|
||||
float u = dx * diffuse_buffer->x - 1.0f;
|
||||
float v = dy * diffuse_buffer->y - 1.0f;
|
||||
nearest_interpolation_color(diffuse_buffer, nullptr, color, u, v);
|
||||
float4 color = imbuf::interpolate_nearest_fl(diffuse_buffer, u, v);
|
||||
|
||||
if (specular_buffer) {
|
||||
float specular[4];
|
||||
nearest_interpolation_color(specular_buffer, nullptr, specular, u, v);
|
||||
float4 specular = imbuf::interpolate_nearest_fl(specular_buffer, u, v);
|
||||
add_v3_v3(color, specular);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "IMB_colormanagement.hh"
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
/* == Parameterization constants == */
|
||||
|
@ -1286,34 +1287,79 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip,
|
|||
discard_stabilization_working_context(ctx);
|
||||
}
|
||||
|
||||
using interpolation_func = void (*)(const ImBuf *, ImBuf *, float, float, int, int);
|
||||
|
||||
struct TrackingStabilizeFrameInterpolationData {
|
||||
ImBuf *ibuf;
|
||||
ImBuf *tmpibuf;
|
||||
float (*mat)[4];
|
||||
|
||||
interpolation_func interpolation;
|
||||
int tracking_filter;
|
||||
};
|
||||
|
||||
static void tracking_stabilize_frame_interpolation_cb(void *__restrict userdata,
|
||||
const int j,
|
||||
const int y,
|
||||
const TaskParallelTLS *__restrict /*tls*/)
|
||||
{
|
||||
using namespace blender;
|
||||
|
||||
TrackingStabilizeFrameInterpolationData *data =
|
||||
static_cast<TrackingStabilizeFrameInterpolationData *>(userdata);
|
||||
ImBuf *ibuf = data->ibuf;
|
||||
ImBuf *tmpibuf = data->tmpibuf;
|
||||
float(*mat)[4] = data->mat;
|
||||
|
||||
interpolation_func interpolation = data->interpolation;
|
||||
float vec[3] = {0.0f, float(y), 0.0f};
|
||||
float rvec[3];
|
||||
|
||||
for (int i = 0; i < tmpibuf->x; i++) {
|
||||
float vec[3] = {float(i), float(j), 0.0f};
|
||||
|
||||
mul_v3_m4v3(vec, mat, vec);
|
||||
|
||||
interpolation(ibuf, tmpibuf, vec[0], vec[1], i, j);
|
||||
if (ibuf->float_buffer.data) {
|
||||
/* Float image. */
|
||||
float4 *dst = reinterpret_cast<float4 *>(tmpibuf->float_buffer.data) + y * tmpibuf->x;
|
||||
if (data->tracking_filter == TRACKING_FILTER_BILINEAR) {
|
||||
for (int x = 0; x < tmpibuf->x; x++, dst++) {
|
||||
vec[0] = float(x);
|
||||
mul_v3_m4v3(rvec, mat, vec);
|
||||
*dst = imbuf::interpolate_bilinear_fl(ibuf, rvec[0], rvec[1]);
|
||||
}
|
||||
}
|
||||
else if (data->tracking_filter == TRACKING_FILTER_BICUBIC) {
|
||||
for (int x = 0; x < tmpibuf->x; x++, dst++) {
|
||||
vec[0] = float(x);
|
||||
mul_v3_m4v3(rvec, mat, vec);
|
||||
*dst = imbuf::interpolate_cubic_bspline_fl(ibuf, rvec[0], rvec[1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Nearest or fallback to nearest. */
|
||||
for (int x = 0; x < tmpibuf->x; x++, dst++) {
|
||||
vec[0] = float(x);
|
||||
mul_v3_m4v3(rvec, mat, vec);
|
||||
*dst = imbuf::interpolate_nearest_fl(ibuf, rvec[0], rvec[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ibuf->byte_buffer.data) {
|
||||
/* Byte image. */
|
||||
uchar4 *dst = reinterpret_cast<uchar4 *>(tmpibuf->byte_buffer.data) + y * tmpibuf->x;
|
||||
if (data->tracking_filter == TRACKING_FILTER_BILINEAR) {
|
||||
for (int x = 0; x < tmpibuf->x; x++, dst++) {
|
||||
vec[0] = float(x);
|
||||
mul_v3_m4v3(rvec, mat, vec);
|
||||
*dst = imbuf::interpolate_bilinear_byte(ibuf, rvec[0], rvec[1]);
|
||||
}
|
||||
}
|
||||
else if (data->tracking_filter == TRACKING_FILTER_BICUBIC) {
|
||||
for (int x = 0; x < tmpibuf->x; x++, dst++) {
|
||||
vec[0] = float(x);
|
||||
mul_v3_m4v3(rvec, mat, vec);
|
||||
*dst = imbuf::interpolate_cubic_bspline_byte(ibuf, rvec[0], rvec[1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Nearest or fallback to nearest. */
|
||||
for (int x = 0; x < tmpibuf->x; x++, dst++) {
|
||||
vec[0] = float(x);
|
||||
mul_v3_m4v3(rvec, mat, vec);
|
||||
*dst = imbuf::interpolate_nearest_byte(ibuf, rvec[0], rvec[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1327,8 +1373,6 @@ ImBuf *BKE_tracking_stabilize_frame(
|
|||
int width = ibuf->x, height = ibuf->y;
|
||||
float pixel_aspect = tracking->camera.pixel_aspect;
|
||||
float mat[4][4];
|
||||
int filter = tracking->stabilization.filter;
|
||||
interpolation_func interpolation = nullptr;
|
||||
int ibuf_flags;
|
||||
|
||||
if (translation) {
|
||||
|
@ -1378,25 +1422,11 @@ ImBuf *BKE_tracking_stabilize_frame(
|
|||
* thus we need the inverse of the transformation to apply. */
|
||||
invert_m4(mat);
|
||||
|
||||
if (filter == TRACKING_FILTER_NEAREST) {
|
||||
interpolation = nearest_interpolation;
|
||||
}
|
||||
else if (filter == TRACKING_FILTER_BILINEAR) {
|
||||
interpolation = bilinear_interpolation;
|
||||
}
|
||||
else if (filter == TRACKING_FILTER_BICUBIC) {
|
||||
interpolation = bicubic_interpolation;
|
||||
}
|
||||
else {
|
||||
/* fallback to default interpolation method */
|
||||
interpolation = nearest_interpolation;
|
||||
}
|
||||
|
||||
TrackingStabilizeFrameInterpolationData data = {};
|
||||
data.ibuf = ibuf;
|
||||
data.tmpibuf = tmpibuf;
|
||||
data.mat = mat;
|
||||
data.interpolation = interpolation;
|
||||
data.tracking_filter = tracking->stabilization.filter;
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
|
|
|
@ -289,18 +289,24 @@ MINLINE uint ceil_to_multiple_u(uint a, uint b);
|
|||
MINLINE uint64_t ceil_to_multiple_ul(uint64_t a, uint64_t b);
|
||||
|
||||
/**
|
||||
* modulo that handles negative numbers, works the same as Python's.
|
||||
* Floored modulo that is useful for wrapping numbers over \a n,
|
||||
* including when \a i is negative.
|
||||
*
|
||||
* This is the same as Python % or GLSL mod(): `mod_i(-5, 3) = 1`.
|
||||
*
|
||||
* \return an integer in the interval [0, n), same sign as n.
|
||||
*/
|
||||
MINLINE int mod_i(int i, int n);
|
||||
|
||||
/**
|
||||
* Modulo that returns a positive result, regardless of the sign of \a f.
|
||||
* Floored modulo that is useful for wrapping numbers over \a n,
|
||||
* including when \a f is negative.
|
||||
*
|
||||
* For example, mod_f_positive(-0.1, 1.0) => 0.9.
|
||||
* This is the same as Python % or GLSL mod(): `floored_fmod(-0.2, 1.0) = 0.8`.
|
||||
*
|
||||
* \returns a float in the interval [0, n).
|
||||
* \return a float in the interval [0, n), same sign as n.
|
||||
*/
|
||||
MINLINE float mod_f_positive(float f, float n);
|
||||
MINLINE float floored_fmod(float f, float n);
|
||||
|
||||
/**
|
||||
* Round to closest even number, halfway cases are rounded away from zero.
|
||||
|
|
|
@ -6,33 +6,204 @@
|
|||
|
||||
/** \file
|
||||
* \ingroup bli
|
||||
*
|
||||
* 2D image sampling with filtering functions.
|
||||
*
|
||||
* All functions take (u, v) texture coordinate, non-normalized (i.e. ranging
|
||||
* from (0,0) to (width,height) over the image).
|
||||
*
|
||||
* Any filtering done on texel values just blends them without color space or
|
||||
* gamma conversions.
|
||||
*
|
||||
* Sampling completely outside the image returns transparent black.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
void BLI_bicubic_interpolation_fl(
|
||||
namespace blender::math {
|
||||
|
||||
/**
|
||||
* Nearest (point) sampling.
|
||||
*
|
||||
* Returns texel at floor(u,v) integer index -- note that it is not "nearest
|
||||
* to u,v coordinate", but rather with fractional part truncated (it would be
|
||||
* "nearest" if subtracting 0.5 from input u,v).
|
||||
*/
|
||||
|
||||
inline void interpolate_nearest_byte(
|
||||
const uchar *buffer, uchar *output, int width, int height, float u, float v)
|
||||
{
|
||||
BLI_assert(buffer);
|
||||
int x = int(u);
|
||||
int y = int(v);
|
||||
|
||||
/* Outside image? */
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) {
|
||||
output[0] = output[1] = output[2] = output[3] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const uchar *data = buffer + (int64_t(width) * y + x) * 4;
|
||||
output[0] = data[0];
|
||||
output[1] = data[1];
|
||||
output[2] = data[2];
|
||||
output[3] = data[3];
|
||||
}
|
||||
|
||||
[[nodiscard]] inline uchar4 interpolate_nearest_byte(
|
||||
const uchar *buffer, int width, int height, float u, float v)
|
||||
{
|
||||
uchar4 res;
|
||||
interpolate_nearest_byte(buffer, res, width, height, u, v);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void interpolate_nearest_fl(
|
||||
const float *buffer, float *output, int width, int height, int components, float u, float v)
|
||||
{
|
||||
BLI_assert(buffer);
|
||||
int x = int(u);
|
||||
int y = int(v);
|
||||
|
||||
/* Outside image? */
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) {
|
||||
for (int i = 0; i < components; i++) {
|
||||
output[i] = 0.0f;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const float *data = buffer + (int64_t(width) * y + x) * components;
|
||||
for (int i = 0; i < components; i++) {
|
||||
output[i] = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline float4 interpolate_nearest_fl(
|
||||
const float *buffer, int width, int height, float u, float v)
|
||||
{
|
||||
float4 res;
|
||||
interpolate_nearest_fl(buffer, res, width, height, 4, u, v);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapped nearest sampling. (u,v) is repeated to be inside the image size.
|
||||
*/
|
||||
|
||||
inline void interpolate_nearest_wrap_byte(
|
||||
const uchar *buffer, uchar *output, int width, int height, float u, float v)
|
||||
{
|
||||
BLI_assert(buffer);
|
||||
u = floored_fmod(u, float(width));
|
||||
v = floored_fmod(v, float(height));
|
||||
int x = int(u);
|
||||
int y = int(v);
|
||||
BLI_assert(x >= 0 && y >= 0 && x < width && y < height);
|
||||
|
||||
const uchar *data = buffer + (int64_t(width) * y + x) * 4;
|
||||
output[0] = data[0];
|
||||
output[1] = data[1];
|
||||
output[2] = data[2];
|
||||
output[3] = data[3];
|
||||
}
|
||||
|
||||
[[nodiscard]] inline uchar4 interpolate_nearest_wrap_byte(
|
||||
const uchar *buffer, int width, int height, float u, float v)
|
||||
{
|
||||
uchar4 res;
|
||||
interpolate_nearest_wrap_byte(buffer, res, width, height, u, v);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void interpolate_nearest_wrap_fl(
|
||||
const float *buffer, float *output, int width, int height, int components, float u, float v)
|
||||
{
|
||||
BLI_assert(buffer);
|
||||
u = floored_fmod(u, float(width));
|
||||
v = floored_fmod(v, float(height));
|
||||
int x = int(u);
|
||||
int y = int(v);
|
||||
BLI_assert(x >= 0 && y >= 0 && x < width && y < height);
|
||||
|
||||
const float *data = buffer + (int64_t(width) * y + x) * components;
|
||||
for (int i = 0; i < components; i++) {
|
||||
output[i] = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline float4 interpolate_nearest_wrap_fl(
|
||||
const float *buffer, int width, int height, float u, float v)
|
||||
{
|
||||
float4 res;
|
||||
interpolate_nearest_wrap_fl(buffer, res, width, height, 4, u, v);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bilinear sampling.
|
||||
*
|
||||
* Takes four image samples at floor(u,v) and floor(u,v)+1, and blends them
|
||||
* based on fractional parts of u,v. Samples outside the image are turned
|
||||
* into transparent black.
|
||||
*
|
||||
* Note that you probably want to subtract 0.5 from u,v before this function,
|
||||
* to get proper filtering.
|
||||
*/
|
||||
|
||||
[[nodiscard]] uchar4 interpolate_bilinear_byte(
|
||||
const uchar *buffer, int width, int height, float u, float v);
|
||||
|
||||
[[nodiscard]] float4 interpolate_bilinear_fl(
|
||||
const float *buffer, int width, int height, float u, float v);
|
||||
|
||||
void interpolate_bilinear_fl(
|
||||
const float *buffer, float *output, int width, int height, int components, float u, float v);
|
||||
|
||||
void BLI_bicubic_interpolation_char(
|
||||
const unsigned char *buffer, unsigned char *output, int width, int height, float u, float v);
|
||||
/**
|
||||
* Wrapped bilinear sampling. (u,v) is repeated to be inside the image size,
|
||||
* including properly wrapping samples that are right on the edges.
|
||||
*/
|
||||
|
||||
void BLI_bilinear_interpolation_fl(
|
||||
[[nodiscard]] uchar4 interpolate_bilinear_wrap_byte(
|
||||
const uchar *buffer, int width, int height, float u, float v);
|
||||
|
||||
[[nodiscard]] float4 interpolate_bilinear_wrap_fl(
|
||||
const float *buffer, int width, int height, float u, float v);
|
||||
|
||||
void interpolate_bilinear_wrap_fl(const float *buffer,
|
||||
float *output,
|
||||
int width,
|
||||
int height,
|
||||
int components,
|
||||
float u,
|
||||
float v,
|
||||
bool wrap_x,
|
||||
bool wrap_y);
|
||||
|
||||
/**
|
||||
* Cubic B-Spline sampling.
|
||||
*
|
||||
* Takes 4x4 image samples at floor(u,v)-1 .. floor(u,v)+2, and blends them
|
||||
* based on fractional parts of u,v. Uses B-Spline variant Mitchell-Netravali
|
||||
* filter (B=1, C=0), which has no ringing but introduces quite a lot of blur.
|
||||
* Samples outside the image are clamped to texels at image edge.
|
||||
*
|
||||
* Note that you probably want to subtract 0.5 from u,v before this function,
|
||||
* to get proper filtering.
|
||||
*/
|
||||
|
||||
[[nodiscard]] uchar4 interpolate_cubic_bspline_byte(
|
||||
const uchar *buffer, int width, int height, float u, float v);
|
||||
|
||||
[[nodiscard]] float4 interpolate_cubic_bspline_fl(
|
||||
const float *buffer, int width, int height, float u, float v);
|
||||
|
||||
void interpolate_cubic_bspline_fl(
|
||||
const float *buffer, float *output, int width, int height, int components, float u, float v);
|
||||
|
||||
void BLI_bilinear_interpolation_char(
|
||||
const unsigned char *buffer, unsigned char *output, int width, int height, float u, float v);
|
||||
|
||||
void BLI_bilinear_interpolation_wrap_fl(const float *buffer,
|
||||
float *output,
|
||||
int width,
|
||||
int height,
|
||||
int components,
|
||||
float u,
|
||||
float v,
|
||||
bool wrap_x,
|
||||
bool wrap_y);
|
||||
} // namespace blender::math
|
||||
|
||||
#define EWA_MAXIDX 255
|
||||
extern const float EWA_WTS[EWA_MAXIDX + 1];
|
||||
|
@ -56,7 +227,3 @@ void BLI_ewa_filter(int width,
|
|||
ewa_filter_read_pixel_cb read_pixel_cb,
|
||||
void *userdata,
|
||||
float result[4]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -310,14 +310,9 @@ MINLINE int mod_i(int i, int n)
|
|||
return (i % n + n) % n;
|
||||
}
|
||||
|
||||
MINLINE float mod_f_positive(const float f, const float n)
|
||||
MINLINE float floored_fmod(const float f, const float n)
|
||||
{
|
||||
const float modulo = fmodf(f, n);
|
||||
if (modulo < 0) {
|
||||
/* fmodf returns a value in the interval (-n, n). */
|
||||
return modulo + n;
|
||||
}
|
||||
return modulo;
|
||||
return f - n * floorf(f / n);
|
||||
}
|
||||
|
||||
MINLINE float fractf(float a)
|
||||
|
|
|
@ -117,6 +117,8 @@ static void bicubic_interpolation(
|
|||
{
|
||||
using namespace blender;
|
||||
|
||||
BLI_assert(src_buffer && output);
|
||||
|
||||
#if BLI_HAVE_SSE2
|
||||
if constexpr (std::is_same_v<T, uchar>) {
|
||||
if (components == 4) {
|
||||
|
@ -203,33 +205,28 @@ static void bicubic_interpolation(
|
|||
}
|
||||
}
|
||||
|
||||
void BLI_bicubic_interpolation_fl(
|
||||
const float *buffer, float *output, int width, int height, int components, float u, float v)
|
||||
{
|
||||
bicubic_interpolation<float>(buffer, output, width, height, components, u, v);
|
||||
}
|
||||
|
||||
void BLI_bicubic_interpolation_char(
|
||||
const uchar *buffer, uchar *output, int width, int height, float u, float v)
|
||||
{
|
||||
bicubic_interpolation<uchar>(buffer, output, width, height, 4, u, v);
|
||||
}
|
||||
|
||||
/* BILINEAR INTERPOLATION */
|
||||
BLI_INLINE void bilinear_interpolation_fl(const float *float_buffer,
|
||||
float *float_output,
|
||||
int width,
|
||||
int height,
|
||||
int components,
|
||||
float u,
|
||||
float v,
|
||||
bool wrap_x,
|
||||
bool wrap_y)
|
||||
BLI_INLINE void bilinear_fl_impl(const float *buffer,
|
||||
float *output,
|
||||
int width,
|
||||
int height,
|
||||
int components,
|
||||
float u,
|
||||
float v,
|
||||
bool wrap_x = false,
|
||||
bool wrap_y = false)
|
||||
{
|
||||
BLI_assert(buffer && output);
|
||||
float a, b;
|
||||
float a_b, ma_b, a_mb, ma_mb;
|
||||
int y1, y2, x1, x2;
|
||||
|
||||
if (wrap_x) {
|
||||
u = floored_fmod(u, float(width));
|
||||
}
|
||||
if (wrap_y) {
|
||||
v = floored_fmod(v, float(height));
|
||||
}
|
||||
|
||||
float uf = floorf(u);
|
||||
float vf = floorf(v);
|
||||
|
||||
|
@ -241,60 +238,54 @@ BLI_INLINE void bilinear_interpolation_fl(const float *float_buffer,
|
|||
const float *row1, *row2, *row3, *row4;
|
||||
const float empty[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
|
||||
/* pixel value must be already wrapped, however values at boundaries may flip */
|
||||
/* Check if +1 samples need wrapping, or we we don't do wrapping then if
|
||||
* we are sampling completely outside the image. */
|
||||
if (wrap_x) {
|
||||
if (x1 < 0) {
|
||||
x1 = width - 1;
|
||||
}
|
||||
if (x2 >= width) {
|
||||
x2 = 0;
|
||||
}
|
||||
}
|
||||
else if (x2 < 0 || x1 >= width) {
|
||||
copy_vn_fl(float_output, components, 0.0f);
|
||||
copy_vn_fl(output, components, 0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wrap_y) {
|
||||
if (y1 < 0) {
|
||||
y1 = height - 1;
|
||||
}
|
||||
if (y2 >= height) {
|
||||
y2 = 0;
|
||||
}
|
||||
}
|
||||
else if (y2 < 0 || y1 >= height) {
|
||||
copy_vn_fl(float_output, components, 0.0f);
|
||||
copy_vn_fl(output, components, 0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
/* sample including outside of edges of image */
|
||||
/* Sample including outside of edges of image. */
|
||||
if (x1 < 0 || y1 < 0) {
|
||||
row1 = empty;
|
||||
}
|
||||
else {
|
||||
row1 = float_buffer + width * y1 * components + components * x1;
|
||||
row1 = buffer + width * y1 * components + components * x1;
|
||||
}
|
||||
|
||||
if (x1 < 0 || y2 > height - 1) {
|
||||
row2 = empty;
|
||||
}
|
||||
else {
|
||||
row2 = float_buffer + width * y2 * components + components * x1;
|
||||
row2 = buffer + width * y2 * components + components * x1;
|
||||
}
|
||||
|
||||
if (x2 > width - 1 || y1 < 0) {
|
||||
row3 = empty;
|
||||
}
|
||||
else {
|
||||
row3 = float_buffer + width * y1 * components + components * x2;
|
||||
row3 = buffer + width * y1 * components + components * x2;
|
||||
}
|
||||
|
||||
if (x2 > width - 1 || y2 > height - 1) {
|
||||
row4 = empty;
|
||||
}
|
||||
else {
|
||||
row4 = float_buffer + width * y2 * components + components * x2;
|
||||
row4 = buffer + width * y2 * components + components * x2;
|
||||
}
|
||||
|
||||
a = u - uf;
|
||||
|
@ -305,12 +296,12 @@ BLI_INLINE void bilinear_interpolation_fl(const float *float_buffer,
|
|||
ma_mb = (1.0f - a) * (1.0f - b);
|
||||
|
||||
if (components == 1) {
|
||||
float_output[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0];
|
||||
output[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0];
|
||||
}
|
||||
else if (components == 3) {
|
||||
float_output[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0];
|
||||
float_output[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1];
|
||||
float_output[2] = ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2];
|
||||
output[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0];
|
||||
output[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1];
|
||||
output[2] = ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2];
|
||||
}
|
||||
else {
|
||||
#if BLI_HAVE_SSE2
|
||||
|
@ -325,19 +316,23 @@ BLI_INLINE void bilinear_interpolation_fl(const float *float_buffer,
|
|||
__m128 rgba13 = _mm_add_ps(rgba1, rgba3);
|
||||
__m128 rgba24 = _mm_add_ps(rgba2, rgba4);
|
||||
__m128 rgba = _mm_add_ps(rgba13, rgba24);
|
||||
_mm_storeu_ps(float_output, rgba);
|
||||
_mm_storeu_ps(output, rgba);
|
||||
#else
|
||||
float_output[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0];
|
||||
float_output[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1];
|
||||
float_output[2] = ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2];
|
||||
float_output[3] = ma_mb * row1[3] + a_mb * row3[3] + ma_b * row2[3] + a_b * row4[3];
|
||||
output[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0];
|
||||
output[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1];
|
||||
output[2] = ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2];
|
||||
output[3] = ma_mb * row1[3] + a_mb * row3[3] + ma_b * row2[3] + a_b * row4[3];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void BLI_bilinear_interpolation_char(
|
||||
const uchar *buffer, uchar *output, int width, int height, float u, float v)
|
||||
namespace blender::math {
|
||||
|
||||
uchar4 interpolate_bilinear_byte(const uchar *buffer, int width, int height, float u, float v)
|
||||
{
|
||||
BLI_assert(buffer);
|
||||
uchar4 res;
|
||||
|
||||
#if BLI_HAVE_SSE2
|
||||
/* Bilinear interpolation needs to read and blend four image pixels, while
|
||||
* also handling conditions of sample coordinate being outside of the
|
||||
|
@ -375,7 +370,7 @@ void BLI_bilinear_interpolation_char(
|
|||
int ycoord[4];
|
||||
_mm_storeu_ps((float *)xcoord, _mm_castsi128_ps(x1234));
|
||||
_mm_storeu_ps((float *)ycoord, _mm_castsi128_ps(y1234));
|
||||
int sample1 = ((const int *)buffer)[ycoord[0] * (int64_t)width + xcoord[0]];
|
||||
int sample1 = ((const int *)buffer)[ycoord[0] * int64_t(width) + xcoord[0]];
|
||||
int sample2 = ((const int *)buffer)[ycoord[1] * int64_t(width) + xcoord[1]];
|
||||
int sample3 = ((const int *)buffer)[ycoord[2] * int64_t(width) + xcoord[2]];
|
||||
int sample4 = ((const int *)buffer)[ycoord[3] * int64_t(width) + xcoord[3]];
|
||||
|
@ -414,37 +409,26 @@ void BLI_bilinear_interpolation_char(
|
|||
__m128i rgba32 = _mm_cvttps_epi32(rgba);
|
||||
__m128i rgba16 = _mm_packs_epi32(rgba32, _mm_setzero_si128());
|
||||
__m128i rgba8 = _mm_packus_epi16(rgba16, _mm_setzero_si128());
|
||||
_mm_store_ss((float *)output, _mm_castsi128_ps(rgba8));
|
||||
_mm_store_ss((float *)&res, _mm_castsi128_ps(rgba8));
|
||||
|
||||
#else
|
||||
|
||||
float a, b;
|
||||
float a_b, ma_b, a_mb, ma_mb;
|
||||
int y1, y2, x1, x2;
|
||||
|
||||
float uf = floorf(u);
|
||||
float vf = floorf(v);
|
||||
|
||||
x1 = (int)uf;
|
||||
x2 = x1 + 1;
|
||||
y1 = (int)vf;
|
||||
y2 = y1 + 1;
|
||||
int x1 = (int)uf;
|
||||
int x2 = x1 + 1;
|
||||
int y1 = (int)vf;
|
||||
int y2 = y1 + 1;
|
||||
|
||||
/* Completely outside of the image? */
|
||||
if (x2 < 0 || x1 >= width || y2 < 0 || y1 >= height) {
|
||||
return uchar4(0);
|
||||
}
|
||||
|
||||
/* Sample including outside of edges of image. */
|
||||
const uchar *row1, *row2, *row3, *row4;
|
||||
uchar empty[4] = {0, 0, 0, 0};
|
||||
|
||||
/* completely outside of the image? */
|
||||
if (x2 < 0 || x1 >= width) {
|
||||
copy_vn_uchar(output, 4, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (y2 < 0 || y1 >= height) {
|
||||
copy_vn_uchar(output, 4, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* sample including outside of edges of image */
|
||||
if (x1 < 0 || y1 < 0) {
|
||||
row1 = empty;
|
||||
}
|
||||
|
@ -473,39 +457,119 @@ void BLI_bilinear_interpolation_char(
|
|||
row4 = buffer + width * y2 * 4 + 4 * x2;
|
||||
}
|
||||
|
||||
a = u - uf;
|
||||
b = v - vf;
|
||||
a_b = a * b;
|
||||
ma_b = (1.0f - a) * b;
|
||||
a_mb = a * (1.0f - b);
|
||||
ma_mb = (1.0f - a) * (1.0f - b);
|
||||
float a = u - uf;
|
||||
float b = v - vf;
|
||||
float a_b = a * b;
|
||||
float ma_b = (1.0f - a) * b;
|
||||
float a_mb = a * (1.0f - b);
|
||||
float ma_mb = (1.0f - a) * (1.0f - b);
|
||||
|
||||
output[0] = (uchar)(ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0] + 0.5f);
|
||||
output[1] = (uchar)(ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1] + 0.5f);
|
||||
output[2] = (uchar)(ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2] + 0.5f);
|
||||
output[3] = (uchar)(ma_mb * row1[3] + a_mb * row3[3] + ma_b * row2[3] + a_b * row4[3] + 0.5f);
|
||||
res.x = (uchar)(ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0] + 0.5f);
|
||||
res.y = (uchar)(ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1] + 0.5f);
|
||||
res.z = (uchar)(ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2] + 0.5f);
|
||||
res.w = (uchar)(ma_mb * row1[3] + a_mb * row3[3] + ma_b * row2[3] + a_b * row4[3] + 0.5f);
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void BLI_bilinear_interpolation_fl(
|
||||
float4 interpolate_bilinear_fl(const float *buffer, int width, int height, float u, float v)
|
||||
{
|
||||
float4 res;
|
||||
bilinear_fl_impl(buffer, res, width, height, 4, u, v);
|
||||
return res;
|
||||
}
|
||||
|
||||
void interpolate_bilinear_fl(
|
||||
const float *buffer, float *output, int width, int height, int components, float u, float v)
|
||||
{
|
||||
bilinear_interpolation_fl(buffer, output, width, height, components, u, v, false, false);
|
||||
bilinear_fl_impl(buffer, output, width, height, components, u, v);
|
||||
}
|
||||
|
||||
void BLI_bilinear_interpolation_wrap_fl(const float *buffer,
|
||||
float *output,
|
||||
int width,
|
||||
int height,
|
||||
int components,
|
||||
float u,
|
||||
float v,
|
||||
bool wrap_x,
|
||||
bool wrap_y)
|
||||
void interpolate_bilinear_wrap_fl(const float *buffer,
|
||||
float *output,
|
||||
int width,
|
||||
int height,
|
||||
int components,
|
||||
float u,
|
||||
float v,
|
||||
bool wrap_x,
|
||||
bool wrap_y)
|
||||
{
|
||||
bilinear_interpolation_fl(buffer, output, width, height, components, u, v, wrap_x, wrap_y);
|
||||
bilinear_fl_impl(buffer, output, width, height, components, u, v, wrap_x, wrap_y);
|
||||
}
|
||||
|
||||
uchar4 interpolate_bilinear_wrap_byte(const uchar *buffer, int width, int height, float u, float v)
|
||||
{
|
||||
u = floored_fmod(u, float(width));
|
||||
v = floored_fmod(v, float(height));
|
||||
float uf = floorf(u);
|
||||
float vf = floorf(v);
|
||||
|
||||
int x1 = (int)uf;
|
||||
int x2 = x1 + 1;
|
||||
int y1 = (int)vf;
|
||||
int y2 = y1 + 1;
|
||||
|
||||
/* Wrap interpolation pixels if needed. */
|
||||
BLI_assert(x1 >= 0 && x1 < width && y1 >= 0 && y1 < height);
|
||||
if (x2 >= width) {
|
||||
x2 = 0;
|
||||
}
|
||||
if (y2 >= height) {
|
||||
y2 = 0;
|
||||
}
|
||||
|
||||
float a = u - uf;
|
||||
float b = v - vf;
|
||||
float a_b = a * b;
|
||||
float ma_b = (1.0f - a) * b;
|
||||
float a_mb = a * (1.0f - b);
|
||||
float ma_mb = (1.0f - a) * (1.0f - b);
|
||||
|
||||
/* Blend samples. */
|
||||
const uchar *row1 = buffer + (int64_t(width) * y1 + x1) * 4;
|
||||
const uchar *row2 = buffer + (int64_t(width) * y2 + x1) * 4;
|
||||
const uchar *row3 = buffer + (int64_t(width) * y1 + x2) * 4;
|
||||
const uchar *row4 = buffer + (int64_t(width) * y2 + x2) * 4;
|
||||
|
||||
uchar4 res;
|
||||
res.x = uchar(ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0] + 0.5f);
|
||||
res.y = uchar(ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1] + 0.5f);
|
||||
res.z = uchar(ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2] + 0.5f);
|
||||
res.w = uchar(ma_mb * row1[3] + a_mb * row3[3] + ma_b * row2[3] + a_b * row4[3] + 0.5f);
|
||||
return res;
|
||||
}
|
||||
|
||||
float4 interpolate_bilinear_wrap_fl(const float *buffer, int width, int height, float u, float v)
|
||||
{
|
||||
float4 res;
|
||||
bilinear_fl_impl(buffer, res, width, height, 4, u, v, true, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
uchar4 interpolate_cubic_bspline_byte(const uchar *buffer, int width, int height, float u, float v)
|
||||
{
|
||||
uchar4 res;
|
||||
bicubic_interpolation<uchar>(buffer, res, width, height, 4, u, v);
|
||||
return res;
|
||||
}
|
||||
|
||||
float4 interpolate_cubic_bspline_fl(const float *buffer, int width, int height, float u, float v)
|
||||
{
|
||||
float4 res;
|
||||
bicubic_interpolation<float>(buffer, res, width, height, 4, u, v);
|
||||
return res;
|
||||
}
|
||||
|
||||
void interpolate_cubic_bspline_fl(
|
||||
const float *buffer, float *output, int width, int height, int components, float u, float v)
|
||||
{
|
||||
bicubic_interpolation<float>(buffer, output, width, height, components, u, v);
|
||||
}
|
||||
|
||||
} // namespace blender::math
|
||||
|
||||
/**************************************************************************
|
||||
* Filtering method based on
|
||||
* "Creating raster omnimax images from multiple perspective views
|
||||
|
|
|
@ -183,11 +183,17 @@ TEST(math_base, InterpolateInt)
|
|||
EXPECT_EQ(math::interpolate(100, 200, 0.4f), 140);
|
||||
}
|
||||
|
||||
TEST(math_base, ModFPositive)
|
||||
TEST(math_base, FlooredFMod)
|
||||
{
|
||||
EXPECT_FLOAT_EQ(mod_f_positive(3.27f, 1.57f), 0.12999988f);
|
||||
EXPECT_FLOAT_EQ(mod_f_positive(327.f, 47.f), 45.f);
|
||||
EXPECT_FLOAT_EQ(mod_f_positive(-0.1f, 1.0f), 0.9f);
|
||||
EXPECT_FLOAT_EQ(floored_fmod(3.27f, 1.57f), 0.12999988f);
|
||||
EXPECT_FLOAT_EQ(floored_fmod(327.f, 47.f), 45.f);
|
||||
EXPECT_FLOAT_EQ(floored_fmod(-0.1f, 1.0f), 0.9f);
|
||||
EXPECT_FLOAT_EQ(floored_fmod(-0.9f, 1.0f), 0.1f);
|
||||
EXPECT_FLOAT_EQ(floored_fmod(-100.1f, 1.0f), 0.90000153f);
|
||||
EXPECT_FLOAT_EQ(floored_fmod(-0.1f, 12345.0f), 12344.9f);
|
||||
EXPECT_FLOAT_EQ(floored_fmod(12345.1f, 12345.0f), 0.099609375f);
|
||||
EXPECT_FLOAT_EQ(floored_fmod(12344.999f, 12345.0f), 12344.999f);
|
||||
EXPECT_FLOAT_EQ(floored_fmod(12345.0f, 12345.0f), 0.0f);
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
#include "BLI_math_interp.hh"
|
||||
|
||||
using namespace blender;
|
||||
using namespace blender::math;
|
||||
|
||||
static constexpr float float_tolerance = 0.00005f;
|
||||
static constexpr int image_width = 3;
|
||||
static constexpr int image_height = 3;
|
||||
static constexpr unsigned char image_char[image_height][image_width][4] = {
|
||||
|
@ -16,147 +18,241 @@ static constexpr unsigned char image_char[image_height][image_width][4] = {
|
|||
{{0, 1, 2, 3}, {62, 72, 82, 92}, {126, 127, 128, 129}},
|
||||
{{1, 2, 3, 4}, {73, 108, 153, 251}, {128, 129, 130, 131}},
|
||||
};
|
||||
static constexpr float image_fl[image_height][image_width][4] = {
|
||||
{{255, 254, 217, 216}, {230, 230, 230, 230}, {240, 160, 90, 20}},
|
||||
{{0, 1, 2, 3}, {62, 72, 82, 92}, {126, 127, 128, 129}},
|
||||
{{1, 2, 3, 4}, {73, 108, 153, 251}, {128, 129, 130, 131}},
|
||||
};
|
||||
|
||||
TEST(math_interp, BilinearCharExactSamples)
|
||||
{
|
||||
unsigned char res[4];
|
||||
unsigned char exp1[4] = {73, 108, 153, 251};
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 1.0f, 2.0f);
|
||||
EXPECT_EQ_ARRAY(exp1, res, 4);
|
||||
unsigned char exp2[4] = {240, 160, 90, 20};
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 2.0f, 0.0f);
|
||||
EXPECT_EQ_ARRAY(exp2, res, 4);
|
||||
uchar4 res;
|
||||
uchar4 exp1 = {73, 108, 153, 251};
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 1.0f, 2.0f);
|
||||
EXPECT_EQ(exp1, res);
|
||||
uchar4 exp2 = {240, 160, 90, 20};
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 2.0f, 0.0f);
|
||||
EXPECT_EQ(exp2, res);
|
||||
}
|
||||
|
||||
TEST(math_interp, BilinearCharHalfwayUSamples)
|
||||
{
|
||||
unsigned char res[4];
|
||||
unsigned char exp1[4] = {31, 37, 42, 48};
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 0.5f, 1.0f);
|
||||
EXPECT_EQ_ARRAY(exp1, res, 4);
|
||||
unsigned char exp2[4] = {243, 242, 224, 223};
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 0.5f, 0.0f);
|
||||
EXPECT_EQ_ARRAY(exp2, res, 4);
|
||||
uchar4 res;
|
||||
uchar4 exp1 = {31, 37, 42, 48};
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0.5f, 1.0f);
|
||||
EXPECT_EQ(exp1, res);
|
||||
uchar4 exp2 = {243, 242, 224, 223};
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0.5f, 0.0f);
|
||||
EXPECT_EQ(exp2, res);
|
||||
}
|
||||
|
||||
TEST(math_interp, BilinearCharHalfwayVSamples)
|
||||
{
|
||||
unsigned char res[4];
|
||||
unsigned char exp1[4] = {1, 2, 3, 4};
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 0.0f, 1.5f);
|
||||
EXPECT_EQ_ARRAY(exp1, res, 4);
|
||||
unsigned char exp2[4] = {127, 128, 129, 130};
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 2.0f, 1.5f);
|
||||
EXPECT_EQ_ARRAY(exp2, res, 4);
|
||||
uchar4 res;
|
||||
uchar4 exp1 = {1, 2, 3, 4};
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0.0f, 1.5f);
|
||||
EXPECT_EQ(exp1, res);
|
||||
uchar4 exp2 = {127, 128, 129, 130};
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 2.0f, 1.5f);
|
||||
EXPECT_EQ(exp2, res);
|
||||
}
|
||||
|
||||
TEST(math_interp, BilinearCharSamples)
|
||||
{
|
||||
unsigned char res[4];
|
||||
unsigned char exp1[4] = {136, 133, 132, 130};
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 1.25f, 0.625f);
|
||||
EXPECT_EQ_ARRAY(exp1, res, 4);
|
||||
unsigned char exp2[4] = {219, 191, 167, 142};
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 1.4f, 0.1f);
|
||||
EXPECT_EQ_ARRAY(exp2, res, 4);
|
||||
uchar4 res;
|
||||
uchar4 exp1 = {136, 133, 132, 130};
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 1.25f, 0.625f);
|
||||
EXPECT_EQ(exp1, res);
|
||||
uchar4 exp2 = {219, 191, 167, 142};
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 1.4f, 0.1f);
|
||||
EXPECT_EQ(exp2, res);
|
||||
}
|
||||
|
||||
TEST(math_interp, BilinearFloatSamples)
|
||||
{
|
||||
float4 res;
|
||||
float4 exp1 = {135.9375f, 133.28125f, 131.5625f, 129.84375f};
|
||||
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 1.25f, 0.625f);
|
||||
EXPECT_V4_NEAR(exp1, res, float_tolerance);
|
||||
float4 exp2 = {219.36f, 191.2f, 166.64f, 142.08f};
|
||||
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 1.4f, 0.1f);
|
||||
EXPECT_V4_NEAR(exp2, res, float_tolerance);
|
||||
}
|
||||
|
||||
TEST(math_interp, BilinearCharPartiallyOutsideImage)
|
||||
{
|
||||
unsigned char res[4];
|
||||
unsigned char exp1[4] = {1, 1, 2, 2};
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, -0.5f, 2.0f);
|
||||
EXPECT_EQ_ARRAY(exp1, res, 4);
|
||||
unsigned char exp2[4] = {9, 11, 15, 22};
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 1.25f, 2.9f);
|
||||
EXPECT_EQ_ARRAY(exp2, res, 4);
|
||||
unsigned char exp3[4] = {173, 115, 65, 14};
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 2.2f, -0.1f);
|
||||
EXPECT_EQ_ARRAY(exp3, res, 4);
|
||||
uchar4 res;
|
||||
uchar4 exp1 = {1, 1, 2, 2};
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, -0.5f, 2.0f);
|
||||
EXPECT_EQ(exp1, res);
|
||||
uchar4 exp2 = {9, 11, 15, 22};
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 1.25f, 2.9f);
|
||||
EXPECT_EQ(exp2, res);
|
||||
uchar4 exp3 = {173, 115, 65, 14};
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 2.2f, -0.1f);
|
||||
EXPECT_EQ(exp3, res);
|
||||
}
|
||||
|
||||
TEST(math_interp, BilinearCharPartiallyOutsideImageWrap)
|
||||
{
|
||||
uchar4 res;
|
||||
uchar4 exp1 = {65, 66, 67, 68};
|
||||
res = interpolate_bilinear_wrap_byte(image_char[0][0], image_width, image_height, -0.5f, 2.0f);
|
||||
EXPECT_EQ(exp1, res);
|
||||
uchar4 exp2 = {218, 203, 190, 182};
|
||||
res = interpolate_bilinear_wrap_byte(image_char[0][0], image_width, image_height, 1.25f, 2.9f);
|
||||
EXPECT_EQ(exp2, res);
|
||||
uchar4 exp3 = {229, 171, 114, 64};
|
||||
res = interpolate_bilinear_wrap_byte(image_char[0][0], image_width, image_height, 2.2f, -0.1f);
|
||||
EXPECT_EQ(exp3, res);
|
||||
}
|
||||
|
||||
TEST(math_interp, BilinearFloatPartiallyOutsideImage)
|
||||
{
|
||||
float4 res;
|
||||
float4 exp1 = {0.5f, 1, 1.5f, 2};
|
||||
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, -0.5f, 2.0f);
|
||||
EXPECT_V4_NEAR(exp1, res, float_tolerance);
|
||||
float4 exp2 = {8.675f, 11.325f, 14.725f, 22.1f};
|
||||
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 1.25f, 2.9f);
|
||||
EXPECT_V4_NEAR(exp2, res, float_tolerance);
|
||||
float4 exp3 = {172.8f, 115.2f, 64.8f, 14.4f};
|
||||
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 2.2f, -0.1f);
|
||||
EXPECT_V4_NEAR(exp3, res, float_tolerance);
|
||||
}
|
||||
|
||||
TEST(math_interp, BilinearFloatPartiallyOutsideImageWrap)
|
||||
{
|
||||
float4 res;
|
||||
float4 exp1 = {64.5f, 65.5f, 66.5f, 67.5f};
|
||||
interpolate_bilinear_wrap_fl(
|
||||
image_fl[0][0], res, image_width, image_height, 4, -0.5f, 2.0f, true, true);
|
||||
EXPECT_V4_NEAR(exp1, res, float_tolerance);
|
||||
res = interpolate_bilinear_wrap_fl(image_fl[0][0], image_width, image_height, -0.5f, 2.0f);
|
||||
EXPECT_V4_NEAR(exp1, res, float_tolerance);
|
||||
|
||||
float4 exp2 = {217.92502f, 202.57501f, 190.22501f, 181.85f};
|
||||
interpolate_bilinear_wrap_fl(
|
||||
image_fl[0][0], res, image_width, image_height, 4, 1.25f, 2.9f, true, true);
|
||||
EXPECT_V4_NEAR(exp2, res, float_tolerance);
|
||||
res = interpolate_bilinear_wrap_fl(image_fl[0][0], image_width, image_height, 1.25f, 2.9f);
|
||||
EXPECT_V4_NEAR(exp2, res, float_tolerance);
|
||||
|
||||
float4 exp3 = {228.96f, 171.27998f, 114.32f, 63.84f};
|
||||
interpolate_bilinear_wrap_fl(
|
||||
image_fl[0][0], res, image_width, image_height, 4, 2.2f, -0.1f, true, true);
|
||||
EXPECT_V4_NEAR(exp3, res, float_tolerance);
|
||||
res = interpolate_bilinear_wrap_fl(image_fl[0][0], image_width, image_height, 2.2f, -0.1f);
|
||||
EXPECT_V4_NEAR(exp3, res, float_tolerance);
|
||||
}
|
||||
|
||||
TEST(math_interp, BilinearCharFullyOutsideImage)
|
||||
{
|
||||
unsigned char res[4];
|
||||
unsigned char exp[4] = {0, 0, 0, 0};
|
||||
uchar4 res;
|
||||
uchar4 exp = {0, 0, 0, 0};
|
||||
/* Out of range on U */
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, -1.5f, 0);
|
||||
EXPECT_EQ_ARRAY(exp, res, 4);
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, -1.1f, 0);
|
||||
EXPECT_EQ_ARRAY(exp, res, 4);
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 3, 0);
|
||||
EXPECT_EQ_ARRAY(exp, res, 4);
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 5, 0);
|
||||
EXPECT_EQ_ARRAY(exp, res, 4);
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, -1.5f, 0);
|
||||
EXPECT_EQ(exp, res);
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, -1.1f, 0);
|
||||
EXPECT_EQ(exp, res);
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 3, 0);
|
||||
EXPECT_EQ(exp, res);
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 5, 0);
|
||||
EXPECT_EQ(exp, res);
|
||||
|
||||
/* Out of range on V */
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 0, -3.2f);
|
||||
EXPECT_EQ_ARRAY(exp, res, 4);
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 0, -1.5f);
|
||||
EXPECT_EQ_ARRAY(exp, res, 4);
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 0, 3.1f);
|
||||
EXPECT_EQ_ARRAY(exp, res, 4);
|
||||
BLI_bilinear_interpolation_char(image_char[0][0], res, image_width, image_height, 0, 500.0f);
|
||||
EXPECT_EQ_ARRAY(exp, res, 4);
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0, -3.2f);
|
||||
EXPECT_EQ(exp, res);
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0, -1.5f);
|
||||
EXPECT_EQ(exp, res);
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0, 3.1f);
|
||||
EXPECT_EQ(exp, res);
|
||||
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0, 500.0f);
|
||||
EXPECT_EQ(exp, res);
|
||||
}
|
||||
|
||||
TEST(math_interp, BicubicCharExactSamples)
|
||||
TEST(math_interp, CubicBSplineCharExactSamples)
|
||||
{
|
||||
ColorTheme4b res;
|
||||
ColorTheme4b exp1 = {69, 90, 116, 172};
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, 1.0f, 2.0f);
|
||||
uchar4 res;
|
||||
uchar4 exp1 = {69, 90, 116, 172};
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, 1.0f, 2.0f);
|
||||
EXPECT_EQ(exp1, res);
|
||||
ColorTheme4b exp2 = {218, 163, 115, 66};
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, 2.0f, 0.0f);
|
||||
uchar4 exp2 = {218, 163, 115, 66};
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, 2.0f, 0.0f);
|
||||
EXPECT_EQ(exp2, res);
|
||||
}
|
||||
|
||||
TEST(math_interp, BicubicCharSamples)
|
||||
TEST(math_interp, CubicBSplineCharSamples)
|
||||
{
|
||||
ColorTheme4b res;
|
||||
ColorTheme4b exp1 = {142, 136, 131, 128};
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, 1.25f, 0.625f);
|
||||
uchar4 res;
|
||||
uchar4 exp1 = {142, 136, 131, 128};
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, 1.25f, 0.625f);
|
||||
EXPECT_EQ(exp1, res);
|
||||
ColorTheme4b exp2 = {202, 177, 154, 132};
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, 1.4f, 0.1f);
|
||||
uchar4 exp2 = {202, 177, 154, 132};
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, 1.4f, 0.1f);
|
||||
EXPECT_EQ(exp2, res);
|
||||
}
|
||||
|
||||
TEST(math_interp, BicubicCharPartiallyOutsideImage)
|
||||
TEST(math_interp, CubicBSplineFloatSamples)
|
||||
{
|
||||
ColorTheme4b res;
|
||||
ColorTheme4b exp1 = {2, 4, 6, 8};
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, -0.5f, 2.0f);
|
||||
float4 res;
|
||||
float4 exp1 = {142.14418f, 136.255798f, 130.87924f, 127.85243f};
|
||||
res = interpolate_cubic_bspline_fl(image_fl[0][0], image_width, image_height, 1.25f, 0.625f);
|
||||
EXPECT_V4_NEAR(exp1, res, float_tolerance);
|
||||
float4 exp2 = {202.36082f, 177.13397f, 154.21078f, 132.30153f};
|
||||
res = interpolate_cubic_bspline_fl(image_fl[0][0], image_width, image_height, 1.4f, 0.1f);
|
||||
EXPECT_V4_NEAR(exp2, res, float_tolerance);
|
||||
}
|
||||
|
||||
TEST(math_interp, CubicBSplineCharPartiallyOutsideImage)
|
||||
{
|
||||
uchar4 res;
|
||||
uchar4 exp1 = {2, 4, 6, 8};
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, -0.5f, 2.0f);
|
||||
EXPECT_EQ(exp1, res);
|
||||
ColorTheme4b exp2 = {85, 107, 135, 195};
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, 1.25f, 2.9f);
|
||||
uchar4 exp2 = {85, 107, 135, 195};
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, 1.25f, 2.9f);
|
||||
EXPECT_EQ(exp2, res);
|
||||
ColorTheme4b exp3 = {225, 161, 105, 49};
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, 2.2f, -0.1f);
|
||||
uchar4 exp3 = {225, 161, 105, 49};
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, 2.2f, -0.1f);
|
||||
EXPECT_EQ(exp3, res);
|
||||
}
|
||||
|
||||
TEST(math_interp, BicubicCharFullyOutsideImage)
|
||||
TEST(math_interp, CubicBSplineFloatPartiallyOutsideImage)
|
||||
{
|
||||
ColorTheme4b res;
|
||||
ColorTheme4b exp = {0, 0, 0, 0};
|
||||
float4 res;
|
||||
float4 exp1 = {2.29861f, 3.92014f, 5.71528f, 8.430554f};
|
||||
res = interpolate_cubic_bspline_fl(image_fl[0][0], image_width, image_height, -0.5f, 2.0f);
|
||||
EXPECT_V4_NEAR(exp1, res, float_tolerance);
|
||||
float4 exp2 = {85.41022f, 107.21497f, 135.13849f, 195.49146f};
|
||||
res = interpolate_cubic_bspline_fl(image_fl[0][0], image_width, image_height, 1.25f, 2.9f);
|
||||
EXPECT_V4_NEAR(exp2, res, float_tolerance);
|
||||
float4 exp3 = {224.73579f, 160.66783f, 104.63521f, 48.60260f};
|
||||
res = interpolate_cubic_bspline_fl(image_fl[0][0], image_width, image_height, 2.2f, -0.1f);
|
||||
EXPECT_V4_NEAR(exp3, res, float_tolerance);
|
||||
}
|
||||
|
||||
TEST(math_interp, CubicBSplineCharFullyOutsideImage)
|
||||
{
|
||||
uchar4 res;
|
||||
uchar4 exp = {0, 0, 0, 0};
|
||||
/* Out of range on U */
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, -1.5f, 0);
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, -1.5f, 0);
|
||||
EXPECT_EQ(exp, res);
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, -1.1f, 0);
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, -1.1f, 0);
|
||||
EXPECT_EQ(exp, res);
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, 3, 0);
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, 3, 0);
|
||||
EXPECT_EQ(exp, res);
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, 5, 0);
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, 5, 0);
|
||||
EXPECT_EQ(exp, res);
|
||||
|
||||
/* Out of range on V */
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, 0, -3.2f);
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, 0, -3.2f);
|
||||
EXPECT_EQ(exp, res);
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, 0, -1.5f);
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, 0, -1.5f);
|
||||
EXPECT_EQ(exp, res);
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, 0, 3.1f);
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, 0, 3.1f);
|
||||
EXPECT_EQ(exp, res);
|
||||
BLI_bicubic_interpolation_char(image_char[0][0], res, image_width, image_height, 0, 500.0f);
|
||||
res = interpolate_cubic_bspline_byte(image_char[0][0], image_width, image_height, 0, 500.0f);
|
||||
EXPECT_EQ(exp, res);
|
||||
}
|
||||
|
|
|
@ -2714,6 +2714,20 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 401, 15)) {
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
if (ntree->type == NTREE_COMPOSIT) {
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
if (node->type == CMP_NODE_KEYING) {
|
||||
NodeKeyingData &keying_data = *static_cast<NodeKeyingData *>(node->storage);
|
||||
keying_data.edge_kernel_radius = max_ii(keying_data.edge_kernel_radius - 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
|
|
@ -249,11 +249,11 @@ class MemoryBuffer {
|
|||
single_y = rel_y - last_y;
|
||||
}
|
||||
|
||||
BLI_bilinear_interpolation_fl(buffer_, out, 1, 1, num_channels_, single_x, single_y);
|
||||
math::interpolate_bilinear_fl(buffer_, out, 1, 1, num_channels_, single_x, single_y);
|
||||
return;
|
||||
}
|
||||
|
||||
BLI_bilinear_interpolation_fl(buffer_,
|
||||
math::interpolate_bilinear_fl(buffer_,
|
||||
out,
|
||||
get_width(),
|
||||
get_height(),
|
||||
|
@ -451,10 +451,7 @@ class MemoryBuffer {
|
|||
}
|
||||
break;
|
||||
case MemoryBufferExtend::Repeat:
|
||||
x = fmodf(x, w);
|
||||
if (x < 0.0f) {
|
||||
x += w;
|
||||
}
|
||||
x = floored_fmod(x, w);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -470,10 +467,7 @@ class MemoryBuffer {
|
|||
}
|
||||
break;
|
||||
case MemoryBufferExtend::Repeat:
|
||||
y = fmodf(y, h);
|
||||
if (y < 0.0f) {
|
||||
y += h;
|
||||
}
|
||||
y = floored_fmod(y, h);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -547,7 +541,7 @@ class MemoryBuffer {
|
|||
memcpy(result, buffer_, sizeof(float) * num_channels_);
|
||||
}
|
||||
else {
|
||||
BLI_bilinear_interpolation_wrap_fl(buffer_,
|
||||
math::interpolate_bilinear_wrap_fl(buffer_,
|
||||
result,
|
||||
get_width(),
|
||||
get_height(),
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
#include "BKE_scene.h"
|
||||
|
||||
#include "IMB_colormanagement.hh"
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
|
@ -102,27 +101,27 @@ static void sample_image_at_location(ImBuf *ibuf,
|
|||
if (ibuf->float_buffer.data) {
|
||||
switch (sampler) {
|
||||
case PixelSampler::Nearest:
|
||||
nearest_interpolation_color(ibuf, nullptr, color, x, y);
|
||||
imbuf::interpolate_nearest_fl(ibuf, color, x, y);
|
||||
break;
|
||||
case PixelSampler::Bilinear:
|
||||
bilinear_interpolation_color(ibuf, nullptr, color, x, y);
|
||||
imbuf::interpolate_bilinear_fl(ibuf, color, x, y);
|
||||
break;
|
||||
case PixelSampler::Bicubic:
|
||||
bicubic_interpolation_color(ibuf, nullptr, color, x, y);
|
||||
imbuf::interpolate_cubic_bspline_fl(ibuf, color, x, y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uchar byte_color[4];
|
||||
uchar4 byte_color;
|
||||
switch (sampler) {
|
||||
case PixelSampler::Nearest:
|
||||
nearest_interpolation_color(ibuf, byte_color, nullptr, x, y);
|
||||
byte_color = imbuf::interpolate_nearest_byte(ibuf, x, y);
|
||||
break;
|
||||
case PixelSampler::Bilinear:
|
||||
bilinear_interpolation_color(ibuf, byte_color, nullptr, x, y);
|
||||
byte_color = imbuf::interpolate_bilinear_byte(ibuf, x, y);
|
||||
break;
|
||||
case PixelSampler::Bicubic:
|
||||
bicubic_interpolation_color(ibuf, byte_color, nullptr, x, y);
|
||||
byte_color = imbuf::interpolate_cubic_bspline_byte(ibuf, x, y);
|
||||
break;
|
||||
}
|
||||
rgba_uchar_to_float(color, byte_color);
|
||||
|
|
|
@ -44,11 +44,13 @@ void KeyingClipOperation::execute_pixel(float output[4], int x, int y, void *dat
|
|||
float value = buffer[(y * buffer_width + x)];
|
||||
|
||||
bool ok = false;
|
||||
int start_x = max_ff(0, x - delta + 1), start_y = max_ff(0, y - delta + 1),
|
||||
end_x = min_ff(x + delta - 1, buffer_width - 1),
|
||||
end_y = min_ff(y + delta - 1, buffer_height - 1);
|
||||
|
||||
int count = 0, total_count = (end_x - start_x + 1) * (end_y - start_y + 1) - 1;
|
||||
const int start_x = max_ff(0, x - delta);
|
||||
const int start_y = max_ff(0, y - delta);
|
||||
const int end_x = min_ff(x + delta, buffer_width - 1);
|
||||
const int end_y = min_ff(y + delta, buffer_height - 1);
|
||||
|
||||
int count = 0, total_count = (end_x - start_x + 1) * (end_y - start_y + 1);
|
||||
int threshold_count = ceil(float(total_count) * 0.9f);
|
||||
|
||||
if (delta == 0) {
|
||||
|
@ -57,10 +59,6 @@ void KeyingClipOperation::execute_pixel(float output[4], int x, int y, void *dat
|
|||
|
||||
for (int cx = start_x; ok == false && cx <= end_x; cx++) {
|
||||
for (int cy = start_y; ok == false && cy <= end_y; cy++) {
|
||||
if (UNLIKELY(cx == x && cy == y)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int buffer_index = (cy * buffer_width + cx);
|
||||
float current_value = buffer[buffer_index];
|
||||
|
||||
|
@ -141,14 +139,14 @@ void KeyingClipOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
|||
const int x = it.x;
|
||||
const int y = it.y;
|
||||
|
||||
const int start_x = std::max(0, x - delta + 1);
|
||||
const int start_y = std::max(0, y - delta + 1);
|
||||
const int end_x = std::min(x + delta, width);
|
||||
const int end_y = std::min(y + delta, height);
|
||||
const int x_len = end_x - start_x;
|
||||
const int y_len = end_y - start_y;
|
||||
const int start_x = std::max(0, x - delta);
|
||||
const int start_y = std::max(0, y - delta);
|
||||
const int end_x = std::min(x + delta, width - 1);
|
||||
const int end_y = std::min(y + delta, height - 1);
|
||||
const int x_len = end_x - start_x + 1;
|
||||
const int y_len = end_y - start_y + 1;
|
||||
|
||||
const int total_count = x_len * y_len - 1;
|
||||
const int total_count = x_len * y_len;
|
||||
const int threshold_count = ceil(float(total_count) * 0.9f);
|
||||
bool ok = false;
|
||||
if (delta == 0) {
|
||||
|
@ -163,10 +161,6 @@ void KeyingClipOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
|||
for (; ok == false && row < end_row; row += row_stride) {
|
||||
const float *end_elem = row + x_len * elem_stride;
|
||||
for (const float *elem = row; ok == false && elem < end_elem; elem += elem_stride) {
|
||||
if (UNLIKELY(elem == main_elem)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float current_value = *elem;
|
||||
if (fabsf(current_value - value) < tolerance) {
|
||||
count++;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "BKE_movieclip.h"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
|
@ -81,13 +82,13 @@ void MovieClipBaseOperation::execute_pixel_sampled(float output[4],
|
|||
else {
|
||||
switch (sampler) {
|
||||
case PixelSampler::Nearest:
|
||||
nearest_interpolation_color(ibuf, nullptr, output, x, y);
|
||||
imbuf::interpolate_nearest_fl(ibuf, output, x, y);
|
||||
break;
|
||||
case PixelSampler::Bilinear:
|
||||
bilinear_interpolation_color(ibuf, nullptr, output, x, y);
|
||||
imbuf::interpolate_bilinear_fl(ibuf, output, x, y);
|
||||
break;
|
||||
case PixelSampler::Bicubic:
|
||||
bicubic_interpolation_color(ibuf, nullptr, output, x, y);
|
||||
imbuf::interpolate_cubic_bspline_fl(ibuf, output, x, y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
|
@ -88,13 +88,13 @@ void MultilayerColorOperation::execute_pixel_sampled(float output[4],
|
|||
if (number_of_channels_ == 4) {
|
||||
switch (sampler) {
|
||||
case PixelSampler::Nearest:
|
||||
nearest_interpolation_color(buffer_, nullptr, output, x, y);
|
||||
imbuf::interpolate_nearest_fl(buffer_, output, x, y);
|
||||
break;
|
||||
case PixelSampler::Bilinear:
|
||||
bilinear_interpolation_color(buffer_, nullptr, output, x, y);
|
||||
imbuf::interpolate_bilinear_fl(buffer_, output, x, y);
|
||||
break;
|
||||
case PixelSampler::Bicubic:
|
||||
bicubic_interpolation_color(buffer_, nullptr, output, x, y);
|
||||
imbuf::interpolate_cubic_bspline_fl(buffer_, output, x, y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "COM_RenderLayersProg.h"
|
||||
|
||||
#include "BLI_math_interp.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_image.h"
|
||||
|
@ -55,7 +56,6 @@ void RenderLayersProg::init_execution()
|
|||
|
||||
void RenderLayersProg::do_interpolation(float output[4], float x, float y, PixelSampler sampler)
|
||||
{
|
||||
uint offset;
|
||||
int width = this->get_width(), height = this->get_height();
|
||||
|
||||
int ix = x, iy = y;
|
||||
|
@ -73,27 +73,14 @@ void RenderLayersProg::do_interpolation(float output[4], float x, float y, Pixel
|
|||
}
|
||||
|
||||
switch (sampler) {
|
||||
case PixelSampler::Nearest: {
|
||||
offset = (iy * width + ix) * elementsize_;
|
||||
|
||||
if (elementsize_ == 1) {
|
||||
output[0] = input_buffer_[offset];
|
||||
}
|
||||
else if (elementsize_ == 3) {
|
||||
copy_v3_v3(output, &input_buffer_[offset]);
|
||||
}
|
||||
else {
|
||||
copy_v4_v4(output, &input_buffer_[offset]);
|
||||
}
|
||||
case PixelSampler::Nearest:
|
||||
math::interpolate_nearest_fl(input_buffer_, output, width, height, elementsize_, x, y);
|
||||
break;
|
||||
}
|
||||
|
||||
case PixelSampler::Bilinear:
|
||||
BLI_bilinear_interpolation_fl(input_buffer_, output, width, height, elementsize_, x, y);
|
||||
math::interpolate_bilinear_fl(input_buffer_, output, width, height, elementsize_, x, y);
|
||||
break;
|
||||
|
||||
case PixelSampler::Bicubic:
|
||||
BLI_bicubic_interpolation_fl(input_buffer_, output, width, height, elementsize_, x, y);
|
||||
math::interpolate_cubic_bspline_fl(input_buffer_, output, width, height, elementsize_, x, y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "BKE_image_partial_update.hh"
|
||||
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
@ -503,11 +504,10 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
|
|||
float xf = x / (float)texture_width;
|
||||
float u = info.clipping_uv_bounds.xmax * xf +
|
||||
info.clipping_uv_bounds.xmin * (1.0 - xf) - tile_offset_x;
|
||||
nearest_interpolation_color(tile_buffer,
|
||||
nullptr,
|
||||
&extracted_buffer.float_buffer.data[offset * 4],
|
||||
u * tile_buffer->x,
|
||||
v * tile_buffer->y);
|
||||
imbuf::interpolate_nearest_fl(tile_buffer,
|
||||
&extracted_buffer.float_buffer.data[offset * 4],
|
||||
u * tile_buffer->x,
|
||||
v * tile_buffer->y);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -936,7 +936,7 @@ void time_offset_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float
|
|||
/* This simulates the fcu curve moving in time. */
|
||||
const float time = fcu->bezt[segment->start_index + i].vec[1][0] + frame_offset;
|
||||
/* Need to normalize time to first_key to specify that as the wrapping point. */
|
||||
const float wrapped_time = mod_f_positive(time - first_key_x, fcu_x_range) + first_key_x;
|
||||
const float wrapped_time = floored_fmod(time - first_key_x, fcu_x_range) + first_key_x;
|
||||
const float delta_y = fcu_y_range * floorf((time - first_key_x) / fcu_x_range);
|
||||
|
||||
const float key_y_value = evaluate_fcurve(fcu, wrapped_time) + delta_y;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "BLI_math_bits.h"
|
||||
#include "BLI_math_color_blend.h"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_threads.h"
|
||||
|
@ -37,7 +38,7 @@
|
|||
#include "BLT_translation.h"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_customdata_types.h"
|
||||
|
@ -715,35 +716,17 @@ static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], f
|
|||
return best_tri_index;
|
||||
}
|
||||
|
||||
/* Converts a uv coord into a pixel location wrapping if the uv is outside 0-1 range */
|
||||
static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, float *x, float *y)
|
||||
{
|
||||
/* use */
|
||||
*x = fmodf(uv[0], 1.0f);
|
||||
*y = fmodf(uv[1], 1.0f);
|
||||
|
||||
if (*x < 0.0f) {
|
||||
*x += 1.0f;
|
||||
}
|
||||
if (*y < 0.0f) {
|
||||
*y += 1.0f;
|
||||
}
|
||||
|
||||
*x = *x * ibuf_x - 0.5f;
|
||||
*y = *y * ibuf_y - 0.5f;
|
||||
}
|
||||
|
||||
/* Set the top-most face color that the screen space coord 'pt' touches
|
||||
* (or return 0 if none touch) */
|
||||
static bool project_paint_PickColor(
|
||||
const ProjPaintState *ps, const float pt[2], float *rgba_fp, uchar *rgba, const bool interp)
|
||||
{
|
||||
using namespace blender;
|
||||
const float *tri_uv[3];
|
||||
float w[3], uv[2];
|
||||
int tri_index;
|
||||
Image *ima;
|
||||
ImBuf *ibuf;
|
||||
int xi, yi;
|
||||
|
||||
tri_index = project_paint_PickFace(ps, pt, w);
|
||||
|
||||
|
@ -770,58 +753,32 @@ static bool project_paint_PickColor(
|
|||
return false;
|
||||
}
|
||||
|
||||
float x = uv[0] * ibuf->x;
|
||||
float y = uv[1] * ibuf->y;
|
||||
if (interp) {
|
||||
float x, y;
|
||||
uvco_to_wrapped_pxco(uv, ibuf->x, ibuf->y, &x, &y);
|
||||
x -= 0.5f;
|
||||
y -= 0.5f;
|
||||
}
|
||||
|
||||
if (ibuf->float_buffer.data) {
|
||||
if (rgba_fp) {
|
||||
bilinear_interpolation_color_wrap(ibuf, nullptr, rgba_fp, x, y);
|
||||
}
|
||||
else {
|
||||
float rgba_tmp_f[4];
|
||||
bilinear_interpolation_color_wrap(ibuf, nullptr, rgba_tmp_f, x, y);
|
||||
premul_float_to_straight_uchar(rgba, rgba_tmp_f);
|
||||
}
|
||||
if (ibuf->float_buffer.data) {
|
||||
float4 col = interp ? imbuf::interpolate_bilinear_wrap_fl(ibuf, x, y) :
|
||||
imbuf::interpolate_nearest_wrap_fl(ibuf, x, y);
|
||||
col = math::clamp(col, 0.0f, 1.0f);
|
||||
if (rgba_fp) {
|
||||
memcpy(rgba_fp, &col, sizeof(col));
|
||||
}
|
||||
else {
|
||||
if (rgba) {
|
||||
bilinear_interpolation_color_wrap(ibuf, rgba, nullptr, x, y);
|
||||
}
|
||||
else {
|
||||
uchar rgba_tmp[4];
|
||||
bilinear_interpolation_color_wrap(ibuf, rgba_tmp, nullptr, x, y);
|
||||
straight_uchar_to_premul_float(rgba_fp, rgba_tmp);
|
||||
}
|
||||
premul_float_to_straight_uchar(rgba, col);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// xi = int((uv[0]*ibuf->x) + 0.5f);
|
||||
// yi = int((uv[1]*ibuf->y) + 0.5f);
|
||||
// if (xi < 0 || xi >= ibuf->x || yi < 0 || yi >= ibuf->y) return false;
|
||||
|
||||
/* wrap */
|
||||
xi = mod_i(int(uv[0] * ibuf->x), ibuf->x);
|
||||
yi = mod_i(int(uv[1] * ibuf->y), ibuf->y);
|
||||
|
||||
uchar4 col = interp ? imbuf::interpolate_bilinear_wrap_byte(ibuf, x, y) :
|
||||
imbuf::interpolate_nearest_wrap_byte(ibuf, x, y);
|
||||
if (rgba) {
|
||||
if (ibuf->float_buffer.data) {
|
||||
const float *rgba_tmp_fp = ibuf->float_buffer.data + (xi + yi * ibuf->x * 4);
|
||||
premul_float_to_straight_uchar(rgba, rgba_tmp_fp);
|
||||
}
|
||||
else {
|
||||
*((uint *)rgba) = *(uint *)(((char *)ibuf->byte_buffer.data) + ((xi + yi * ibuf->x) * 4));
|
||||
}
|
||||
memcpy(rgba, &col, sizeof(col));
|
||||
}
|
||||
|
||||
if (rgba_fp) {
|
||||
if (ibuf->float_buffer.data) {
|
||||
copy_v4_v4(rgba_fp, (ibuf->float_buffer.data + ((xi + yi * ibuf->x) * 4)));
|
||||
}
|
||||
else {
|
||||
uchar *tmp_ch = ibuf->byte_buffer.data + ((xi + yi * ibuf->x) * 4);
|
||||
straight_uchar_to_premul_float(rgba_fp, tmp_ch);
|
||||
}
|
||||
else {
|
||||
straight_uchar_to_premul_float(rgba_fp, col);
|
||||
}
|
||||
}
|
||||
BKE_image_release_ibuf(ima, ibuf, nullptr);
|
||||
|
@ -1657,18 +1614,22 @@ static float screen_px_line_point_factor_v2_persp(const ProjPaintState *ps,
|
|||
static void project_face_pixel(
|
||||
const float *tri_uv[3], ImBuf *ibuf_other, const float w[3], uchar rgba_ub[4], float rgba_f[4])
|
||||
{
|
||||
float uv_other[2], x, y;
|
||||
using namespace blender;
|
||||
float uv_other[2];
|
||||
|
||||
interp_v2_v2v2v2(uv_other, UNPACK3(tri_uv), w);
|
||||
|
||||
/* use */
|
||||
uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y);
|
||||
float x = uv_other[0] * ibuf_other->x - 0.5f;
|
||||
float y = uv_other[1] * ibuf_other->y - 0.5f;
|
||||
|
||||
if (ibuf_other->float_buffer.data) { /* from float to float */
|
||||
bilinear_interpolation_color_wrap(ibuf_other, nullptr, rgba_f, x, y);
|
||||
if (ibuf_other->float_buffer.data) {
|
||||
float4 col = imbuf::interpolate_bilinear_wrap_fl(ibuf_other, x, y);
|
||||
col = math::clamp(col, 0.0f, 1.0f);
|
||||
memcpy(rgba_f, &col, sizeof(col));
|
||||
}
|
||||
else { /* from char to float */
|
||||
bilinear_interpolation_color_wrap(ibuf_other, rgba_ub, nullptr, x, y);
|
||||
else {
|
||||
uchar4 col = imbuf::interpolate_bilinear_wrap_byte(ibuf_other, x, y);
|
||||
memcpy(rgba_ub, &col, sizeof(col));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5388,11 +5349,10 @@ static void do_projectpaint_thread(TaskPool *__restrict /*pool*/, void *ph_v)
|
|||
if (is_floatbuf) {
|
||||
BLI_assert(ps->reproject_ibuf->float_buffer.data != nullptr);
|
||||
|
||||
bicubic_interpolation_color(ps->reproject_ibuf,
|
||||
nullptr,
|
||||
projPixel->newColor.f,
|
||||
projPixel->projCoSS[0],
|
||||
projPixel->projCoSS[1]);
|
||||
blender::imbuf::interpolate_cubic_bspline_fl(ps->reproject_ibuf,
|
||||
projPixel->newColor.f,
|
||||
projPixel->projCoSS[0],
|
||||
projPixel->projCoSS[1]);
|
||||
if (projPixel->newColor.f[3]) {
|
||||
float mask = float(projPixel->mask) * (1.0f / 65535.0f);
|
||||
|
||||
|
@ -5404,12 +5364,10 @@ static void do_projectpaint_thread(TaskPool *__restrict /*pool*/, void *ph_v)
|
|||
}
|
||||
else {
|
||||
BLI_assert(ps->reproject_ibuf->byte_buffer.data != nullptr);
|
||||
|
||||
bicubic_interpolation_color(ps->reproject_ibuf,
|
||||
projPixel->newColor.ch,
|
||||
nullptr,
|
||||
projPixel->projCoSS[0],
|
||||
projPixel->projCoSS[1]);
|
||||
blender::imbuf::interpolate_cubic_bspline_byte(ps->reproject_ibuf,
|
||||
projPixel->newColor.ch,
|
||||
projPixel->projCoSS[0],
|
||||
projPixel->projCoSS[1]);
|
||||
if (projPixel->newColor.ch[3]) {
|
||||
float mask = float(projPixel->mask) * (1.0f / 65535.0f);
|
||||
projPixel->newColor.ch[3] *= mask;
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_customdata_types.h"
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_color.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
|
@ -51,6 +52,7 @@
|
|||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
||||
#include "RE_texture.h"
|
||||
|
||||
|
@ -372,6 +374,7 @@ static int imapaint_pick_face(ViewContext *vc, const int mval[2], uint *r_index,
|
|||
void paint_sample_color(
|
||||
bContext *C, ARegion *region, int x, int y, bool texpaint_proj, bool use_palette)
|
||||
{
|
||||
using namespace blender;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
Paint *paint = BKE_paint_get_active_from_context(C);
|
||||
|
@ -445,46 +448,31 @@ void paint_sample_color(
|
|||
}
|
||||
|
||||
if (image) {
|
||||
float uv[2];
|
||||
float u, v;
|
||||
/* XXX get appropriate ImageUser instead */
|
||||
ImageUser iuser;
|
||||
BKE_imageuser_default(&iuser);
|
||||
iuser.framenr = image->lastframe;
|
||||
|
||||
float uv[2];
|
||||
imapaint_pick_uv(me_eval, scene, ob_eval, faceindex, mval, uv);
|
||||
|
||||
if (image->source == IMA_SRC_TILED) {
|
||||
float new_uv[2];
|
||||
iuser.tile = BKE_image_get_tile_from_pos(image, uv, new_uv, nullptr);
|
||||
u = new_uv[0];
|
||||
v = new_uv[1];
|
||||
}
|
||||
else {
|
||||
u = fmodf(uv[0], 1.0f);
|
||||
v = fmodf(uv[1], 1.0f);
|
||||
|
||||
if (u < 0.0f) {
|
||||
u += 1.0f;
|
||||
}
|
||||
if (v < 0.0f) {
|
||||
v += 1.0f;
|
||||
}
|
||||
uv[0] = new_uv[0];
|
||||
uv[1] = new_uv[1];
|
||||
}
|
||||
|
||||
ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, nullptr);
|
||||
if (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data)) {
|
||||
u = u * ibuf->x;
|
||||
v = v * ibuf->y;
|
||||
float u = uv[0] * ibuf->x;
|
||||
float v = uv[1] * ibuf->y;
|
||||
|
||||
if (ibuf->float_buffer.data) {
|
||||
float rgba_f[4];
|
||||
if (interp == SHD_INTERP_CLOSEST) {
|
||||
nearest_interpolation_color_wrap(ibuf, nullptr, rgba_f, u, v);
|
||||
}
|
||||
else {
|
||||
bilinear_interpolation_color_wrap(ibuf, nullptr, rgba_f, u, v);
|
||||
}
|
||||
float4 rgba_f = interp == SHD_INTERP_CLOSEST ?
|
||||
imbuf::interpolate_nearest_wrap_fl(ibuf, u, v) :
|
||||
imbuf::interpolate_bilinear_wrap_fl(ibuf, u, v);
|
||||
rgba_f = math::clamp(rgba_f, 0.0f, 1.0f);
|
||||
straight_to_premul_v4(rgba_f);
|
||||
if (use_palette) {
|
||||
linearrgb_to_srgb_v3_v3(color->rgb, rgba_f);
|
||||
|
@ -495,13 +483,9 @@ void paint_sample_color(
|
|||
}
|
||||
}
|
||||
else {
|
||||
uchar rgba[4];
|
||||
if (interp == SHD_INTERP_CLOSEST) {
|
||||
nearest_interpolation_color_wrap(ibuf, rgba, nullptr, u, v);
|
||||
}
|
||||
else {
|
||||
bilinear_interpolation_color_wrap(ibuf, rgba, nullptr, u, v);
|
||||
}
|
||||
uchar4 rgba = interp == SHD_INTERP_CLOSEST ?
|
||||
imbuf::interpolate_nearest_wrap_byte(ibuf, u, v) :
|
||||
imbuf::interpolate_bilinear_wrap_byte(ibuf, u, v);
|
||||
if (use_palette) {
|
||||
rgb_uchar_to_float(color->rgb, rgba);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ set(SRC
|
|||
intern/format_tiff.cc
|
||||
intern/imageprocess.cc
|
||||
intern/indexer.cc
|
||||
intern/interp.cc
|
||||
intern/iris.cc
|
||||
intern/jpeg.cc
|
||||
intern/metadata.cc
|
||||
|
@ -58,6 +59,7 @@ set(SRC
|
|||
IMB_imbuf.hh
|
||||
IMB_imbuf_enums.h
|
||||
IMB_imbuf_types.hh
|
||||
IMB_interp.hh
|
||||
IMB_metadata.hh
|
||||
IMB_moviecache.hh
|
||||
IMB_openexr.hh
|
||||
|
|
|
@ -512,47 +512,9 @@ void IMB_buffer_byte_from_byte(unsigned char *rect_to,
|
|||
*/
|
||||
void IMB_convert_rgba_to_abgr(ImBuf *ibuf);
|
||||
|
||||
void bicubic_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout);
|
||||
void nearest_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout);
|
||||
void bilinear_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout);
|
||||
|
||||
typedef void (*InterpolationColorFunction)(
|
||||
const ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
|
||||
void bicubic_interpolation_color(
|
||||
const ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
|
||||
|
||||
/* Functions assumes out to be zeroed, only does RGBA. */
|
||||
|
||||
void nearest_interpolation_color_char(
|
||||
const ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
|
||||
void nearest_interpolation_color_fl(
|
||||
const ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
|
||||
void nearest_interpolation_color(
|
||||
const ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
|
||||
void nearest_interpolation_color_wrap(
|
||||
const ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
|
||||
void bilinear_interpolation_color(
|
||||
const ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
|
||||
void bilinear_interpolation_color_char(const ImBuf *in, unsigned char outI[4], float u, float v);
|
||||
void bilinear_interpolation_color_fl(const ImBuf *in, float outF[4], float u, float v);
|
||||
/**
|
||||
* Note about wrapping, the u/v still needs to be within the image bounds,
|
||||
* just the interpolation is wrapped.
|
||||
* This the same as bilinear_interpolation_color except it wraps
|
||||
* rather than using empty and emptyI.
|
||||
*/
|
||||
void bilinear_interpolation_color_wrap(
|
||||
const ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
|
||||
|
||||
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3]);
|
||||
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float backcol[3]);
|
||||
|
||||
/**
|
||||
* Sample pixel of image using NEAREST method.
|
||||
*/
|
||||
void IMB_sampleImageAtLocation(
|
||||
ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4]);
|
||||
|
||||
ImBuf *IMB_loadifffile(int file, int flags, char colorspace[IM_MAX_SPACE], const char *descr);
|
||||
|
||||
ImBuf *IMB_half_x(ImBuf *ibuf1);
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/* 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 {
|
||||
|
||||
[[nodiscard]] inline uchar4 interpolate_nearest_byte(const ImBuf *in, float u, float v)
|
||||
{
|
||||
return math::interpolate_nearest_byte(in->byte_buffer.data, in->x, in->y, u, v);
|
||||
}
|
||||
[[nodiscard]] inline float4 interpolate_nearest_fl(const ImBuf *in, float u, float v)
|
||||
{
|
||||
return math::interpolate_nearest_fl(in->float_buffer.data, in->x, in->y, u, v);
|
||||
}
|
||||
inline void interpolate_nearest_byte(const ImBuf *in, uchar output[4], float u, float v)
|
||||
{
|
||||
math::interpolate_nearest_byte(in->byte_buffer.data, output, in->x, in->y, u, v);
|
||||
}
|
||||
inline void interpolate_nearest_fl(const ImBuf *in, float output[4], float u, float v)
|
||||
{
|
||||
math::interpolate_nearest_fl(in->float_buffer.data, output, in->x, in->y, 4, u, v);
|
||||
}
|
||||
|
||||
[[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);
|
||||
}
|
||||
|
||||
[[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));
|
||||
}
|
||||
|
||||
[[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);
|
||||
}
|
||||
|
||||
[[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));
|
||||
}
|
||||
|
||||
} // namespace blender::imbuf
|
||||
|
||||
/**
|
||||
* Sample pixel of image using NEAREST method.
|
||||
*/
|
||||
void IMB_sampleImageAtLocation(
|
||||
ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4]);
|
|
@ -1,14 +1,10 @@
|
|||
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
||||
* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup imbuf
|
||||
*
|
||||
* This file was moved here from the `src/` directory.
|
||||
* It is meant to deal with endianness. It resided in a general blending lib.
|
||||
* The other functions were only used during rendering. This single function remained.
|
||||
* It should probably move to `imbuf/intern/util.cc`, but we'll keep it here for the time being.
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
|
@ -16,7 +12,6 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_math_interp.hh"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
|
@ -59,286 +54,6 @@ void IMB_convert_rgba_to_abgr(ImBuf *ibuf)
|
|||
}
|
||||
}
|
||||
|
||||
static void pixel_from_buffer(const ImBuf *ibuf, uchar **outI, float **outF, int x, int y)
|
||||
|
||||
{
|
||||
size_t offset = size_t(ibuf->x) * y * 4 + 4 * x;
|
||||
|
||||
if (ibuf->byte_buffer.data) {
|
||||
*outI = ibuf->byte_buffer.data + offset;
|
||||
}
|
||||
|
||||
if (ibuf->float_buffer.data) {
|
||||
*outF = ibuf->float_buffer.data + offset;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Bi-Cubic Interpolation
|
||||
* \{ */
|
||||
|
||||
void bicubic_interpolation_color(const ImBuf *in, uchar outI[4], float outF[4], float u, float v)
|
||||
{
|
||||
if (outF) {
|
||||
BLI_bicubic_interpolation_fl(in->float_buffer.data, outF, in->x, in->y, 4, u, v);
|
||||
}
|
||||
else {
|
||||
BLI_bicubic_interpolation_char(in->byte_buffer.data, outI, in->x, in->y, u, v);
|
||||
}
|
||||
}
|
||||
|
||||
void bicubic_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
|
||||
{
|
||||
uchar *outI = nullptr;
|
||||
float *outF = nullptr;
|
||||
|
||||
if (in == nullptr || (in->byte_buffer.data == nullptr && in->float_buffer.data == nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* GCC warns these could be uninitialized, but its ok. */
|
||||
pixel_from_buffer(out, &outI, &outF, xout, yout);
|
||||
|
||||
bicubic_interpolation_color(in, outI, outF, u, v);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Bi-Linear Interpolation
|
||||
* \{ */
|
||||
|
||||
void bilinear_interpolation_color_fl(const ImBuf *in, float outF[4], float u, float v)
|
||||
{
|
||||
BLI_assert(outF);
|
||||
BLI_assert(in->float_buffer.data);
|
||||
BLI_bilinear_interpolation_fl(in->float_buffer.data, outF, in->x, in->y, 4, u, v);
|
||||
}
|
||||
|
||||
void bilinear_interpolation_color_char(const ImBuf *in, uchar outI[4], float u, float v)
|
||||
{
|
||||
BLI_assert(outI);
|
||||
BLI_assert(in->byte_buffer.data);
|
||||
BLI_bilinear_interpolation_char(in->byte_buffer.data, outI, in->x, in->y, u, v);
|
||||
}
|
||||
|
||||
void bilinear_interpolation_color(const ImBuf *in, uchar outI[4], float outF[4], float u, float v)
|
||||
{
|
||||
if (outF) {
|
||||
BLI_bilinear_interpolation_fl(in->float_buffer.data, outF, in->x, in->y, 4, u, v);
|
||||
}
|
||||
else {
|
||||
BLI_bilinear_interpolation_char(in->byte_buffer.data, outI, in->x, in->y, u, v);
|
||||
}
|
||||
}
|
||||
|
||||
/* Function assumes out to be zeroed, only does RGBA. */
|
||||
/* BILINEAR INTERPOLATION */
|
||||
|
||||
void bilinear_interpolation_color_wrap(
|
||||
const ImBuf *in, uchar outI[4], float outF[4], float u, float v)
|
||||
{
|
||||
float *row1, *row2, *row3, *row4, a, b;
|
||||
uchar *row1I, *row2I, *row3I, *row4I;
|
||||
float a_b, ma_b, a_mb, ma_mb;
|
||||
int y1, y2, x1, x2;
|
||||
|
||||
/* ImBuf in must have a valid rect or rect_float, assume this is already checked */
|
||||
|
||||
x1 = int(floor(u));
|
||||
x2 = int(ceil(u));
|
||||
y1 = int(floor(v));
|
||||
y2 = int(ceil(v));
|
||||
|
||||
/* sample area entirely outside image? */
|
||||
if (x2 < 0 || x1 > in->x - 1 || y2 < 0 || y1 > in->y - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wrap interpolation pixels - main difference from #bilinear_interpolation_color. */
|
||||
if (x1 < 0) {
|
||||
x1 = in->x + x1;
|
||||
}
|
||||
if (y1 < 0) {
|
||||
y1 = in->y + y1;
|
||||
}
|
||||
|
||||
if (x2 >= in->x) {
|
||||
x2 = x2 - in->x;
|
||||
}
|
||||
if (y2 >= in->y) {
|
||||
y2 = y2 - in->y;
|
||||
}
|
||||
|
||||
a = u - floorf(u);
|
||||
b = v - floorf(v);
|
||||
a_b = a * b;
|
||||
ma_b = (1.0f - a) * b;
|
||||
a_mb = a * (1.0f - b);
|
||||
ma_mb = (1.0f - a) * (1.0f - b);
|
||||
|
||||
if (outF) {
|
||||
float *in_rect_float = in->float_buffer.data;
|
||||
/* sample including outside of edges of image */
|
||||
row1 = in_rect_float + size_t(in->x) * y1 * 4 + 4 * x1;
|
||||
row2 = in_rect_float + size_t(in->x) * y2 * 4 + 4 * x1;
|
||||
row3 = in_rect_float + size_t(in->x) * y1 * 4 + 4 * x2;
|
||||
row4 = in_rect_float + size_t(in->x) * y2 * 4 + 4 * x2;
|
||||
|
||||
outF[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0];
|
||||
outF[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1];
|
||||
outF[2] = ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2];
|
||||
outF[3] = ma_mb * row1[3] + a_mb * row3[3] + ma_b * row2[3] + a_b * row4[3];
|
||||
|
||||
/* clamp here or else we can easily get off-range */
|
||||
clamp_v4(outF, 0.0f, 1.0f);
|
||||
}
|
||||
if (outI) {
|
||||
uchar *in_rect = in->byte_buffer.data;
|
||||
/* sample including outside of edges of image */
|
||||
row1I = in_rect + size_t(in->x) * y1 * 4 + 4 * x1;
|
||||
row2I = in_rect + size_t(in->x) * y2 * 4 + 4 * x1;
|
||||
row3I = in_rect + size_t(in->x) * y1 * 4 + 4 * x2;
|
||||
row4I = in_rect + size_t(in->x) * y2 * 4 + 4 * x2;
|
||||
|
||||
/* Tested with white images and this should not wrap back to zero. */
|
||||
outI[0] = roundf(ma_mb * row1I[0] + a_mb * row3I[0] + ma_b * row2I[0] + a_b * row4I[0]);
|
||||
outI[1] = roundf(ma_mb * row1I[1] + a_mb * row3I[1] + ma_b * row2I[1] + a_b * row4I[1]);
|
||||
outI[2] = roundf(ma_mb * row1I[2] + a_mb * row3I[2] + ma_b * row2I[2] + a_b * row4I[2]);
|
||||
outI[3] = roundf(ma_mb * row1I[3] + a_mb * row3I[3] + ma_b * row2I[3] + a_b * row4I[3]);
|
||||
}
|
||||
}
|
||||
|
||||
void bilinear_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
|
||||
{
|
||||
uchar *outI = nullptr;
|
||||
float *outF = nullptr;
|
||||
|
||||
if (in == nullptr || (in->byte_buffer.data == nullptr && in->float_buffer.data == nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* GCC warns these could be uninitialized, but its ok. */
|
||||
pixel_from_buffer(out, &outI, &outF, xout, yout);
|
||||
|
||||
bilinear_interpolation_color(in, outI, outF, u, v);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Nearest Interpolation
|
||||
* \{ */
|
||||
|
||||
void nearest_interpolation_color_char(
|
||||
const ImBuf *in, uchar outI[4], float /*outF*/[4], float u, float v)
|
||||
{
|
||||
BLI_assert(outI);
|
||||
BLI_assert(in->byte_buffer.data);
|
||||
/* ImBuf in must have a valid rect or rect_float, assume this is already checked */
|
||||
int x1 = int(u);
|
||||
int y1 = int(v);
|
||||
|
||||
/* sample area entirely outside image? */
|
||||
if (x1 < 0 || x1 >= in->x || y1 < 0 || y1 >= in->y) {
|
||||
outI[0] = outI[1] = outI[2] = outI[3] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t offset = (size_t(in->x) * y1 + x1) * 4;
|
||||
const uchar *dataI = in->byte_buffer.data + offset;
|
||||
outI[0] = dataI[0];
|
||||
outI[1] = dataI[1];
|
||||
outI[2] = dataI[2];
|
||||
outI[3] = dataI[3];
|
||||
}
|
||||
|
||||
void nearest_interpolation_color_fl(
|
||||
const ImBuf *in, uchar /*outI*/[4], float outF[4], float u, float v)
|
||||
{
|
||||
BLI_assert(outF);
|
||||
BLI_assert(in->float_buffer.data);
|
||||
/* ImBuf in must have a valid rect or rect_float, assume this is already checked */
|
||||
int x1 = int(u);
|
||||
int y1 = int(v);
|
||||
|
||||
/* sample area entirely outside image? */
|
||||
if (x1 < 0 || x1 >= in->x || y1 < 0 || y1 >= in->y) {
|
||||
zero_v4(outF);
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t offset = (size_t(in->x) * y1 + x1) * 4;
|
||||
const float *dataF = in->float_buffer.data + offset;
|
||||
copy_v4_v4(outF, dataF);
|
||||
}
|
||||
|
||||
void nearest_interpolation_color(const ImBuf *in, uchar outI[4], float outF[4], float u, float v)
|
||||
{
|
||||
if (outF) {
|
||||
nearest_interpolation_color_fl(in, outI, outF, u, v);
|
||||
}
|
||||
else {
|
||||
nearest_interpolation_color_char(in, outI, outF, u, v);
|
||||
}
|
||||
}
|
||||
|
||||
void nearest_interpolation_color_wrap(
|
||||
const ImBuf *in, uchar outI[4], float outF[4], float u, float v)
|
||||
{
|
||||
const float *dataF;
|
||||
uchar *dataI;
|
||||
int y, x;
|
||||
|
||||
/* ImBuf in must have a valid rect or rect_float, assume this is already checked */
|
||||
|
||||
x = int(floor(u));
|
||||
y = int(floor(v));
|
||||
|
||||
x = x % in->x;
|
||||
y = y % in->y;
|
||||
|
||||
/* Wrap interpolation pixels - main difference from #nearest_interpolation_color. */
|
||||
if (x < 0) {
|
||||
x += in->x;
|
||||
}
|
||||
if (y < 0) {
|
||||
y += in->y;
|
||||
}
|
||||
|
||||
dataI = in->byte_buffer.data + size_t(in->x) * y * 4 + 4 * x;
|
||||
if (outI) {
|
||||
outI[0] = dataI[0];
|
||||
outI[1] = dataI[1];
|
||||
outI[2] = dataI[2];
|
||||
outI[3] = dataI[3];
|
||||
}
|
||||
dataF = in->float_buffer.data + size_t(in->x) * y * 4 + 4 * x;
|
||||
if (outF) {
|
||||
outF[0] = dataF[0];
|
||||
outF[1] = dataF[1];
|
||||
outF[2] = dataF[2];
|
||||
outF[3] = dataF[3];
|
||||
}
|
||||
}
|
||||
|
||||
void nearest_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
|
||||
{
|
||||
uchar *outI = nullptr;
|
||||
float *outF = nullptr;
|
||||
|
||||
if (in == nullptr || (in->byte_buffer.data == nullptr && in->float_buffer.data == nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* gcc warns these could be uninitialized, but its ok. */
|
||||
pixel_from_buffer(out, &outI, &outF, xout, yout);
|
||||
|
||||
nearest_interpolation_color(in, outI, outF, u, v);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Threaded Image Processing
|
||||
* \{ */
|
||||
|
@ -472,25 +187,3 @@ void IMB_alpha_under_color_byte(uchar *rect, int x, int y, const float backcol[3
|
|||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Sample Pixel
|
||||
* \{ */
|
||||
|
||||
void IMB_sampleImageAtLocation(ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4])
|
||||
{
|
||||
if (ibuf->float_buffer.data) {
|
||||
nearest_interpolation_color(ibuf, nullptr, color, x, y);
|
||||
}
|
||||
else {
|
||||
uchar byte_color[4];
|
||||
nearest_interpolation_color(ibuf, byte_color, nullptr, x, y);
|
||||
rgba_uchar_to_float(color, byte_color);
|
||||
if (make_linear_rgb) {
|
||||
IMB_colormanagement_colorspace_to_scene_linear_v4(
|
||||
color, false, ibuf->byte_buffer.colorspace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup imbuf
|
||||
*/
|
||||
|
||||
#include "BLI_math_vector.h"
|
||||
#include "IMB_colormanagement.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
||||
void IMB_sampleImageAtLocation(ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4])
|
||||
{
|
||||
using namespace blender;
|
||||
if (ibuf->float_buffer.data) {
|
||||
imbuf::interpolate_nearest_fl(ibuf, color, x, y);
|
||||
}
|
||||
else {
|
||||
uchar4 byte_color = imbuf::interpolate_nearest_byte(ibuf, x, y);
|
||||
rgba_uchar_to_float(color, byte_color);
|
||||
if (make_linear_rgb) {
|
||||
IMB_colormanagement_colorspace_to_scene_linear_v4(
|
||||
color, false, ibuf->byte_buffer.colorspace);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,16 +9,15 @@
|
|||
#include <cmath>
|
||||
|
||||
#include "BLI_math_color.h"
|
||||
#include "BLI_math_interp.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "IMB_filter.hh"
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
#include "imbuf.hh"
|
||||
|
||||
#include "IMB_filter.hh"
|
||||
|
||||
#include "BLI_sys_types.h" /* for intptr_t support */
|
||||
|
||||
static void imb_half_x_no_alloc(ImBuf *ibuf2, ImBuf *ibuf1)
|
||||
|
@ -1745,6 +1744,7 @@ static void scale_thread_init(void *data_v, int start_line, int tot_line, void *
|
|||
|
||||
static void *do_scale_thread(void *data_v)
|
||||
{
|
||||
using namespace blender::imbuf;
|
||||
ScaleThreadData *data = (ScaleThreadData *)data_v;
|
||||
ImBuf *ibuf = data->ibuf;
|
||||
int i;
|
||||
|
@ -1761,13 +1761,12 @@ static void *do_scale_thread(void *data_v)
|
|||
int offset = y * data->newx + x;
|
||||
|
||||
if (data->byte_buffer) {
|
||||
uchar *pixel = data->byte_buffer + 4 * offset;
|
||||
BLI_bilinear_interpolation_char(ibuf->byte_buffer.data, pixel, ibuf->x, ibuf->y, u, v);
|
||||
interpolate_bilinear_byte(ibuf, data->byte_buffer + 4 * offset, u, v);
|
||||
}
|
||||
|
||||
if (data->float_buffer) {
|
||||
float *pixel = data->float_buffer + ibuf->channels * offset;
|
||||
BLI_bilinear_interpolation_fl(
|
||||
blender::math::interpolate_bilinear_fl(
|
||||
ibuf->float_buffer.data, pixel, ibuf->x, ibuf->y, ibuf->channels, u, v);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
||||
* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
|
@ -17,7 +18,10 @@
|
|||
#include "BLI_vector.hh"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
||||
using blender::float4;
|
||||
using blender::uchar4;
|
||||
|
||||
namespace blender::imbuf::transform {
|
||||
|
||||
|
@ -134,27 +138,6 @@ static float wrap_uv(float value, int size)
|
|||
return x;
|
||||
}
|
||||
|
||||
template<int NumChannels>
|
||||
static void sample_nearest_float(const ImBuf *source, float u, float v, float *r_sample)
|
||||
{
|
||||
int x1 = int(u);
|
||||
int y1 = int(v);
|
||||
|
||||
/* Break when sample outside image is requested. */
|
||||
if (x1 < 0 || x1 >= source->x || y1 < 0 || y1 >= source->y) {
|
||||
for (int i = 0; i < NumChannels; i++) {
|
||||
r_sample[i] = 0.0f;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
size_t offset = (size_t(source->x) * y1 + x1) * NumChannels;
|
||||
const float *dataF = source->float_buffer.data + offset;
|
||||
for (int i = 0; i < NumChannels; i++) {
|
||||
r_sample[i] = dataF[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Read a pixel from an image buffer, with filtering/wrapping parameters. */
|
||||
template<eIMBInterpolationFilterMode Filter, typename T, int NumChannels, bool WrapUV>
|
||||
static void sample_image(const ImBuf *source, float u, float v, T *r_sample)
|
||||
|
@ -171,19 +154,19 @@ static void sample_image(const ImBuf *source, float u, float v, T *r_sample)
|
|||
v -= 0.5f;
|
||||
}
|
||||
if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<T, float> && NumChannels == 4) {
|
||||
bilinear_interpolation_color_fl(source, r_sample, u, v);
|
||||
interpolate_bilinear_fl(source, r_sample, u, v);
|
||||
}
|
||||
else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<T, uchar> && NumChannels == 4)
|
||||
{
|
||||
nearest_interpolation_color_char(source, r_sample, nullptr, u, v);
|
||||
interpolate_nearest_byte(source, r_sample, u, v);
|
||||
}
|
||||
else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<T, uchar> && NumChannels == 4)
|
||||
{
|
||||
bilinear_interpolation_color_char(source, r_sample, u, v);
|
||||
interpolate_bilinear_byte(source, r_sample, u, v);
|
||||
}
|
||||
else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<T, float>) {
|
||||
if constexpr (WrapUV) {
|
||||
BLI_bilinear_interpolation_wrap_fl(source->float_buffer.data,
|
||||
math::interpolate_bilinear_wrap_fl(source->float_buffer.data,
|
||||
r_sample,
|
||||
source->x,
|
||||
source->y,
|
||||
|
@ -194,20 +177,21 @@ static void sample_image(const ImBuf *source, float u, float v, T *r_sample)
|
|||
true);
|
||||
}
|
||||
else {
|
||||
BLI_bilinear_interpolation_fl(
|
||||
math::interpolate_bilinear_fl(
|
||||
source->float_buffer.data, r_sample, source->x, source->y, NumChannels, u, v);
|
||||
}
|
||||
}
|
||||
else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<T, float>) {
|
||||
sample_nearest_float<NumChannels>(source, u, v, r_sample);
|
||||
math::interpolate_nearest_fl(
|
||||
source->float_buffer.data, r_sample, source->x, source->y, NumChannels, u, v);
|
||||
}
|
||||
else if constexpr (Filter == IMB_FILTER_BICUBIC && std::is_same_v<T, float>) {
|
||||
BLI_bicubic_interpolation_fl(
|
||||
math::interpolate_cubic_bspline_fl(
|
||||
source->float_buffer.data, r_sample, source->x, source->y, NumChannels, u, v);
|
||||
}
|
||||
else if constexpr (Filter == IMB_FILTER_BICUBIC && std::is_same_v<T, uchar> && NumChannels == 4)
|
||||
{
|
||||
BLI_bicubic_interpolation_char(source->byte_buffer.data, r_sample, source->x, source->y, u, v);
|
||||
interpolate_cubic_bspline_byte(source, r_sample, u, v);
|
||||
}
|
||||
else {
|
||||
/* Unsupported sampler. */
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "BKE_mesh_mapping.hh"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
|
@ -221,9 +221,12 @@ class TextureMarginMap {
|
|||
*/
|
||||
void lookup_pixels(ImBuf *ibuf, char *mask, int maxPolygonSteps)
|
||||
{
|
||||
float4 *ibuf_ptr_fl = reinterpret_cast<float4 *>(ibuf->float_buffer.data);
|
||||
uchar4 *ibuf_ptr_ch = reinterpret_cast<uchar4 *>(ibuf->byte_buffer.data);
|
||||
size_t pixel_index = 0;
|
||||
for (int y = 0; y < h_; y++) {
|
||||
for (int x = 0; x < w_; x++) {
|
||||
uint32_t dp = get_pixel(x, y);
|
||||
uint32_t dp = pixel_data_[pixel_index];
|
||||
if (IsDijkstraPixel(dp) && !DijkstraPixelIsUnset(dp)) {
|
||||
int dist = DijkstraPixelGetDistance(dp);
|
||||
int direction = DijkstraPixelGetDirection(dp);
|
||||
|
@ -270,9 +273,14 @@ class TextureMarginMap {
|
|||
}
|
||||
|
||||
if (found_pixel_in_polygon) {
|
||||
bilinear_interpolation(ibuf, ibuf, destX, destY, x, y);
|
||||
if (ibuf_ptr_fl) {
|
||||
ibuf_ptr_fl[pixel_index] = imbuf::interpolate_bilinear_fl(ibuf, destX, destY);
|
||||
}
|
||||
if (ibuf_ptr_ch) {
|
||||
ibuf_ptr_ch[pixel_index] = imbuf::interpolate_bilinear_byte(ibuf, destX, destY);
|
||||
}
|
||||
/* Add our new pixels to the assigned pixel map. */
|
||||
mask[y * w_ + x] = 1;
|
||||
mask[pixel_index] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,8 +288,9 @@ class TextureMarginMap {
|
|||
/* These are not margin pixels, make sure the extend filter which is run after this step
|
||||
* leaves them alone.
|
||||
*/
|
||||
mask[y * w_ + x] = 1;
|
||||
mask[pixel_index] = 1;
|
||||
}
|
||||
pixel_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
||||
* SPDX-FileCopyrightText: 2003-2009 Blender Authors
|
||||
* SPDX-FileCopyrightText: 2003-2024 Blender Authors
|
||||
* SPDX-FileCopyrightText: 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
@ -40,6 +40,7 @@
|
|||
#include "IMB_colormanagement.hh"
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
#include "IMB_metadata.hh"
|
||||
|
||||
#include "BLI_math_color_blend.h"
|
||||
|
@ -64,7 +65,7 @@
|
|||
#include "strip_time.hh"
|
||||
#include "utils.hh"
|
||||
|
||||
using blender::float4;
|
||||
using namespace blender;
|
||||
|
||||
static SeqEffectHandle get_sequence_effect_impl(int seq_type);
|
||||
|
||||
|
@ -1536,7 +1537,7 @@ static void transform_image(int x,
|
|||
int y,
|
||||
int start_line,
|
||||
int total_lines,
|
||||
ImBuf *ibuf1,
|
||||
ImBuf *ibuf,
|
||||
ImBuf *out,
|
||||
float scale_x,
|
||||
float scale_y,
|
||||
|
@ -1549,6 +1550,10 @@ static void transform_image(int x,
|
|||
float s = sinf(rotate);
|
||||
float c = cosf(rotate);
|
||||
|
||||
float4 *dst_fl = reinterpret_cast<float4 *>(out->float_buffer.data);
|
||||
uchar4 *dst_ch = reinterpret_cast<uchar4 *>(out->byte_buffer.data);
|
||||
|
||||
size_t offset = size_t(x) * start_line;
|
||||
for (int yi = start_line; yi < start_line + total_lines; yi++) {
|
||||
for (int xi = 0; xi < x; xi++) {
|
||||
/* Translate point. */
|
||||
|
@ -1570,15 +1575,31 @@ static void transform_image(int x,
|
|||
/* interpolate */
|
||||
switch (interpolation) {
|
||||
case 0:
|
||||
nearest_interpolation(ibuf1, out, xt, yt, xi, yi);
|
||||
if (dst_fl) {
|
||||
dst_fl[offset] = imbuf::interpolate_nearest_fl(ibuf, xt, yt);
|
||||
}
|
||||
else {
|
||||
dst_ch[offset] = imbuf::interpolate_nearest_byte(ibuf, xt, yt);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
bilinear_interpolation(ibuf1, out, xt, yt, xi, yi);
|
||||
if (dst_fl) {
|
||||
dst_fl[offset] = imbuf::interpolate_bilinear_fl(ibuf, xt, yt);
|
||||
}
|
||||
else {
|
||||
dst_ch[offset] = imbuf::interpolate_bilinear_byte(ibuf, xt, yt);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
bicubic_interpolation(ibuf1, out, xt, yt, xi, yi);
|
||||
if (dst_fl) {
|
||||
dst_fl[offset] = imbuf::interpolate_cubic_bspline_fl(ibuf, xt, yt);
|
||||
}
|
||||
else {
|
||||
dst_ch[offset] = imbuf::interpolate_cubic_bspline_byte(ibuf, xt, yt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -411,7 +411,7 @@ class Report:
|
|||
shutil.copy(new_img, old_img)
|
||||
failed = False
|
||||
|
||||
# Generate diff image.
|
||||
# Generate color diff image.
|
||||
command = (
|
||||
self.oiiotool,
|
||||
ref_img,
|
||||
|
@ -423,7 +423,24 @@ class Report:
|
|||
"--mulc", "16",
|
||||
"-o", diff_color_img,
|
||||
)
|
||||
try:
|
||||
subprocess.check_output(command)
|
||||
except subprocess.CalledProcessError as e:
|
||||
if self.verbose:
|
||||
print_message(e.output.decode("utf-8", 'ignore'))
|
||||
|
||||
# Generate alpha diff image.
|
||||
command = (
|
||||
self.oiiotool,
|
||||
ref_img,
|
||||
"--ch", "A",
|
||||
tmp_filepath,
|
||||
"--ch", "A",
|
||||
"--sub",
|
||||
"--abs",
|
||||
"--mulc", "16",
|
||||
"-o", diff_alpha_img,
|
||||
)
|
||||
try:
|
||||
subprocess.check_output(command)
|
||||
except subprocess.CalledProcessError as e:
|
||||
|
|
Loading…
Reference in New Issue