Blender V5.0
scaling.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 * SPDX-FileCopyrightText: 2024 Blender Authors
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later */
5
9
10#include "BLI_math_vector.hh"
11#include "BLI_task.hh"
12#include "BLI_utildefines.h"
13
14#include "MEM_guardedalloc.h"
15
16#include "IMB_filter.hh"
17#include "IMB_imbuf.hh"
18#include "IMB_imbuf_types.hh"
19#include "IMB_interp.hh"
20#include "IMB_metadata.hh"
21
22#include "BLI_sys_types.h" /* for intptr_t support */
23
24using blender::float2;
25using blender::float3;
26using blender::float4;
27using blender::uchar4;
28
30 const ImBuf *ibuf, uint newx, uint newy, uchar4 **r_dst_byte, float **r_dst_float)
31{
32 *r_dst_byte = nullptr;
33 if (ibuf->byte_buffer.data != nullptr) {
34 *r_dst_byte = MEM_malloc_arrayN<uchar4>(size_t(newx) * size_t(newy), "scale_buf_byte");
35 if (*r_dst_byte == nullptr) {
36 return;
37 }
38 }
39 *r_dst_float = nullptr;
40 if (ibuf->float_buffer.data != nullptr) {
41 *r_dst_float = MEM_malloc_arrayN<float>(size_t(ibuf->channels) * newx * newy,
42 "scale_buf_float");
43 if (*r_dst_float == nullptr) {
44 if (*r_dst_byte) {
45 MEM_freeN(*r_dst_byte);
46 }
47 return;
48 }
49 }
50}
51
52static inline float4 load_pixel(const uchar4 *ptr)
53{
54 return float4(ptr[0]);
55}
56static inline float4 load_pixel(const float *ptr)
57{
58 return float4(ptr[0]);
59}
60static inline float4 load_pixel(const float2 *ptr)
61{
62 return float4(ptr[0], 0.0f, 1.0f);
63}
64static inline float4 load_pixel(const float3 *ptr)
65{
66 return float4(ptr[0], 1.0f);
67}
68static inline float4 load_pixel(const float4 *ptr)
69{
70 return float4(ptr[0]);
71}
72static inline void store_pixel(float4 pix, uchar4 *ptr)
73{
75}
76static inline void store_pixel(float4 pix, float *ptr)
77{
78 *ptr = pix.x;
79}
80static inline void store_pixel(float4 pix, float2 *ptr)
81{
82 memcpy(ptr, &pix, sizeof(*ptr));
83}
84static inline void store_pixel(float4 pix, float3 *ptr)
85{
86 memcpy(ptr, &pix, sizeof(*ptr));
87}
88static inline void store_pixel(float4 pix, float4 *ptr)
89{
90 *ptr = pix;
91}
92
93struct ScaleDownX {
94 template<typename T>
95 static void op(const T *src, T *dst, int ibufx, int ibufy, int newx, int /*newy*/, bool threaded)
96 {
97 using namespace blender;
98 const float add = (ibufx - 0.01f) / newx;
99 const float inv_add = 1.0f / add;
100
101 const int grain_size = threaded ? 32 : ibufy;
102 threading::parallel_for(IndexRange(ibufy), grain_size, [&](IndexRange range) {
103 for (const int y : range) {
104 const T *src_ptr = src + (int64_t(y) * ibufx);
105 T *dst_ptr = dst + (int64_t(y) * newx);
106 float sample = 0.0f;
107 float4 val(0.0f);
108
109 for (int x = 0; x < newx; x++) {
110 float4 nval = -val * sample;
111 sample += add;
112 while (sample >= 1.0f) {
113 sample -= 1.0f;
114 nval += load_pixel(src_ptr);
115 src_ptr++;
116 }
117
118 val = load_pixel(src_ptr);
119 src_ptr++;
120
121 float4 pix = (nval + sample * val) * inv_add;
122 store_pixel(pix, dst_ptr);
123 dst_ptr++;
124
125 sample -= 1.0f;
126 }
127 }
128 });
129 }
130};
131
133 template<typename T>
134 static void op(const T *src, T *dst, int ibufx, int ibufy, int /*newx*/, int newy, bool threaded)
135 {
136 using namespace blender;
137 const float add = (ibufy - 0.01f) / newy;
138 const float inv_add = 1.0f / add;
139
140 const int grain_size = threaded ? 32 : ibufx;
141 threading::parallel_for(IndexRange(ibufx), grain_size, [&](IndexRange range) {
142 for (const int x : range) {
143 const T *src_ptr = src + x;
144 T *dst_ptr = dst + x;
145 float sample = 0.0f;
146 float4 val(0.0f);
147
148 for (int y = 0; y < newy; y++) {
149 float4 nval = -val * sample;
150 sample += add;
151 while (sample >= 1.0f) {
152 sample -= 1.0f;
153 nval += load_pixel(src_ptr);
154 src_ptr += ibufx;
155 }
156
157 val = load_pixel(src_ptr);
158 src_ptr += ibufx;
159
160 float4 pix = (nval + sample * val) * inv_add;
161 store_pixel(pix, dst_ptr);
162 dst_ptr += ibufx;
163
164 sample -= 1.0f;
165 }
166 }
167 });
168 }
169};
170
171struct ScaleUpX {
172 template<typename T>
173 static void op(const T *src, T *dst, int ibufx, int ibufy, int newx, int /*newy*/, bool threaded)
174 {
175 using namespace blender;
176 const float add = (ibufx - 0.001f) / newx;
177 /* Special case: source is 1px wide (see #70356). */
178 if (UNLIKELY(ibufx == 1)) {
179 for (int y = ibufy; y > 0; y--) {
180 for (int x = newx; x > 0; x--) {
181 *dst = *src;
182 dst++;
183 }
184 src++;
185 }
186 }
187 else {
188 const int grain_size = threaded ? 32 : ibufy;
189 threading::parallel_for(IndexRange(ibufy), grain_size, [&](IndexRange range) {
190 for (const int y : range) {
191 float sample = -0.5f + add * 0.5f;
192 int counter = 0;
193 const T *src_ptr = src + (int64_t(y) * ibufx);
194 T *dst_ptr = dst + (int64_t(y) * newx);
195 float4 val = load_pixel(src_ptr);
196 float4 nval = load_pixel(src_ptr + 1);
197 float4 diff = nval - val;
198 if (ibufx > 2) {
199 src_ptr += 2;
200 counter += 2;
201 }
202 for (int x = 0; x < newx; x++) {
203 if (sample >= 1.0f) {
204 sample -= 1.0f;
205 val = nval;
206 nval = load_pixel(src_ptr);
207 diff = nval - val;
208 if (counter + 1 < ibufx) {
209 src_ptr++;
210 counter++;
211 }
212 }
213 float4 pix = val + blender::math::max(sample, 0.0f) * diff;
214 store_pixel(pix, dst_ptr);
215 dst_ptr++;
216 sample += add;
217 }
218 }
219 });
220 }
221 }
222};
223
224struct ScaleUpY {
225 template<typename T>
226 static void op(const T *src, T *dst, int ibufx, int ibufy, int /*newx*/, int newy, bool threaded)
227 {
228 using namespace blender;
229 const float add = (ibufy - 0.001f) / newy;
230 /* Special case: source is 1px high (see #70356). */
231 if (UNLIKELY(ibufy == 1)) {
232 for (int y = newy; y > 0; y--) {
233 memcpy(dst, src, sizeof(T) * ibufx);
234 dst += ibufx;
235 }
236 }
237 else {
238 const int grain_size = threaded ? 32 : ibufx;
239 threading::parallel_for(IndexRange(ibufx), grain_size, [&](IndexRange range) {
240 for (const int x : range) {
241 float sample = -0.5f + add * 0.5f;
242 int counter = 0;
243 const T *src_ptr = src + x;
244 T *dst_ptr = dst + x;
245
246 float4 val = load_pixel(src_ptr);
247 float4 nval = load_pixel(src_ptr + ibufx);
248 float4 diff = nval - val;
249 if (ibufy > 2) {
250 src_ptr += ibufx * 2;
251 counter += 2;
252 }
253
254 for (int y = 0; y < newy; y++) {
255 if (sample >= 1.0f) {
256 sample -= 1.0f;
257 val = nval;
258 nval = load_pixel(src_ptr);
259 diff = nval - val;
260 if (counter + 1 < ibufy) {
261 src_ptr += ibufx;
262 ++counter;
263 }
264 }
265 float4 pix = val + blender::math::max(sample, 0.0f) * diff;
266 store_pixel(pix, dst_ptr);
267 dst_ptr += ibufx;
268 sample += add;
269 }
270 }
271 });
272 }
273 }
274};
275
276template<typename T>
277static void instantiate_pixel_op(T & /*op*/,
278 const ImBuf *ibuf,
279 int newx,
280 int newy,
281 uchar4 *dst_byte,
282 float *dst_float,
283 bool threaded)
284{
285 if (dst_byte != nullptr) {
286 const uchar4 *src = (const uchar4 *)ibuf->byte_buffer.data;
287 T::op(src, dst_byte, ibuf->x, ibuf->y, newx, newy, threaded);
288 }
289 if (dst_float != nullptr) {
290 if (ibuf->channels == 1) {
291 T::op(ibuf->float_buffer.data, dst_float, ibuf->x, ibuf->y, newx, newy, threaded);
292 }
293 else if (ibuf->channels == 2) {
294 const float2 *src = (const float2 *)ibuf->float_buffer.data;
295 T::op(src, (float2 *)dst_float, ibuf->x, ibuf->y, newx, newy, threaded);
296 }
297 else if (ibuf->channels == 3) {
298 const float3 *src = (const float3 *)ibuf->float_buffer.data;
299 T::op(src, (float3 *)dst_float, ibuf->x, ibuf->y, newx, newy, threaded);
300 }
301 else if (ibuf->channels == 4) {
302 const float4 *src = (const float4 *)ibuf->float_buffer.data;
303 T::op(src, (float4 *)dst_float, ibuf->x, ibuf->y, newx, newy, threaded);
304 }
305 }
306}
307
309 const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
310{
311 ScaleDownX op;
312 instantiate_pixel_op(op, ibuf, newx, newy, dst_byte, dst_float, threaded);
313}
314
316 const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
317{
318 ScaleDownY op;
319 instantiate_pixel_op(op, ibuf, newx, newy, dst_byte, dst_float, threaded);
320}
321
322static void scale_up_x_func(
323 const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
324{
325 ScaleUpX op;
326 instantiate_pixel_op(op, ibuf, newx, newy, dst_byte, dst_float, threaded);
327}
328
329static void scale_up_y_func(
330 const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
331{
332 ScaleUpY op;
333 instantiate_pixel_op(op, ibuf, newx, newy, dst_byte, dst_float, threaded);
334}
335
336using ScaleFunction = void (*)(
337 const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded);
338
339static void scale_with_function(ImBuf *ibuf, int newx, int newy, ScaleFunction func, bool threaded)
340{
341 /* Allocate destination buffers. */
342 uchar4 *dst_byte = nullptr;
343 float *dst_float = nullptr;
344 alloc_scale_dst_buffers(ibuf, newx, newy, &dst_byte, &dst_float);
345 if (dst_byte == nullptr && dst_float == nullptr) {
346 return;
347 }
348
349 /* Do actual processing. */
350 func(ibuf, newx, newy, dst_byte, dst_float, threaded);
351
352 /* Modify image to point to new destination. */
353 if (dst_byte != nullptr) {
355 IMB_assign_byte_buffer(ibuf, reinterpret_cast<uint8_t *>(dst_byte), IB_TAKE_OWNERSHIP);
356 }
357 if (dst_float != nullptr) {
360 }
361 ibuf->x = newx;
362 ibuf->y = newy;
363}
364
365static void imb_scale_box(ImBuf *ibuf, uint newx, uint newy, bool threaded)
366{
367 if (newx != 0 && (newx < ibuf->x)) {
368 scale_with_function(ibuf, newx, ibuf->y, scale_down_x_func, threaded);
369 }
370 if (newy != 0 && (newy < ibuf->y)) {
371 scale_with_function(ibuf, ibuf->x, newy, scale_down_y_func, threaded);
372 }
373 if (newx != 0 && (newx > ibuf->x)) {
374 scale_with_function(ibuf, newx, ibuf->y, scale_up_x_func, threaded);
375 }
376 if (newy != 0 && (newy > ibuf->y)) {
377 scale_with_function(ibuf, ibuf->x, newy, scale_up_y_func, threaded);
378 }
379}
380
381template<typename T>
382static void scale_nearest(
383 const T *src, T *dst, int ibufx, int ibufy, int newx, int newy, blender::IndexRange y_range)
384{
385 /* Nearest sample scaling. Step through pixels in fixed point coordinates. */
386 constexpr int FRAC_BITS = 16;
387 int64_t stepx = ((int64_t(ibufx) << FRAC_BITS) + newx / 2) / newx;
388 int64_t stepy = ((int64_t(ibufy) << FRAC_BITS) + newy / 2) / newy;
389 int64_t posy = y_range.first() * stepy;
390 dst += y_range.first() * newx;
391 for (const int y : y_range) {
392 UNUSED_VARS(y);
393 const T *row = src + (posy >> FRAC_BITS) * ibufx;
394 int64_t posx = 0;
395 for (int x = 0; x < newx; x++, posx += stepx) {
396 *dst = row[posx >> FRAC_BITS];
397 dst++;
398 }
399 posy += stepy;
400 }
401}
402
404 const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
405{
406 using namespace blender;
407
408 const int grain_size = threaded ? 64 : newy;
409 threading::parallel_for(IndexRange(newy), grain_size, [&](IndexRange y_range) {
410 /* Byte pixels. */
411 if (dst_byte != nullptr) {
412 const uchar4 *src = (const uchar4 *)ibuf->byte_buffer.data;
413 scale_nearest(src, dst_byte, ibuf->x, ibuf->y, newx, newy, y_range);
414 }
415 /* Float pixels. */
416 if (dst_float != nullptr) {
417 if (ibuf->channels == 1) {
418 scale_nearest(ibuf->float_buffer.data, dst_float, ibuf->x, ibuf->y, newx, newy, y_range);
419 }
420 else if (ibuf->channels == 2) {
421 const float2 *src = (const float2 *)ibuf->float_buffer.data;
422 scale_nearest(src, (float2 *)dst_float, ibuf->x, ibuf->y, newx, newy, y_range);
423 }
424 else if (ibuf->channels == 3) {
425 const float3 *src = (const float3 *)ibuf->float_buffer.data;
426 scale_nearest(src, (float3 *)dst_float, ibuf->x, ibuf->y, newx, newy, y_range);
427 }
428 else if (ibuf->channels == 4) {
429 const float4 *src = (const float4 *)ibuf->float_buffer.data;
430 scale_nearest(src, (float4 *)dst_float, ibuf->x, ibuf->y, newx, newy, y_range);
431 }
432 }
433 });
434}
435
437 const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
438{
439 using namespace blender;
440 using namespace blender::imbuf;
441
442 const int grain_size = threaded ? 32 : newy;
443 threading::parallel_for(IndexRange(newy), grain_size, [&](IndexRange y_range) {
444 float factor_x = float(ibuf->x) / newx;
445 float factor_y = float(ibuf->y) / newy;
446
447 for (const int y : y_range) {
448 float v = (float(y) + 0.5f) * factor_y - 0.5f;
449 for (int x = 0; x < newx; x++) {
450 float u = (float(x) + 0.5f) * factor_x - 0.5f;
451 int64_t offset = int64_t(y) * newx + x;
452 if (dst_byte) {
453 interpolate_bilinear_byte(ibuf, (uchar *)(dst_byte + offset), u, v);
454 }
455 if (dst_float) {
456 float *pixel = dst_float + ibuf->channels * offset;
458 ibuf->float_buffer.data, pixel, ibuf->x, ibuf->y, ibuf->channels, u, v);
459 }
460 }
461 }
462 });
463}
464
465bool IMB_scale(ImBuf *ibuf, uint newx, uint newy, IMBScaleFilter filter, bool threaded)
466{
467 BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
468 if (ibuf == nullptr) {
469 return false;
470 }
471 if (newx == ibuf->x && newy == ibuf->y) {
472 return false;
473 }
474
475 switch (filter) {
477 scale_with_function(ibuf, newx, newy, scale_nearest_func, threaded);
478 break;
480 scale_with_function(ibuf, newx, newy, scale_bilinear_func, threaded);
481 break;
483 imb_scale_box(ibuf, newx, newy, threaded);
484 break;
485 }
486 return true;
487}
488
490 const ImBuf *ibuf, uint newx, uint newy, IMBScaleFilter filter, bool threaded)
491{
492 BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
493 if (ibuf == nullptr) {
494 return nullptr;
495 }
496 /* Size same as source: just copy source image. */
497 if (newx == ibuf->x && newy == ibuf->y) {
498 ImBuf *dst = IMB_dupImBuf(ibuf);
499 IMB_metadata_copy(dst, ibuf);
500 return dst;
501 }
502
503 /* Allocate destination buffers. */
504 uchar4 *dst_byte = nullptr;
505 float *dst_float = nullptr;
506 alloc_scale_dst_buffers(ibuf, newx, newy, &dst_byte, &dst_float);
507 if (dst_byte == nullptr && dst_float == nullptr) {
508 return nullptr;
509 }
510
511 switch (filter) {
513 scale_nearest_func(ibuf, newx, newy, dst_byte, dst_float, threaded);
514 break;
516 scale_bilinear_func(ibuf, newx, newy, dst_byte, dst_float, threaded);
517 break;
518 case IMBScaleFilter::Box: {
519 /* Horizontal scale. */
520 uchar4 *tmp_byte = nullptr;
521 float *tmp_float = nullptr;
522 alloc_scale_dst_buffers(ibuf, newx, ibuf->y, &tmp_byte, &tmp_float);
523 if (tmp_byte == nullptr && tmp_float == nullptr) {
524 if (dst_byte != nullptr) {
525 MEM_freeN(dst_byte);
526 }
527 if (dst_byte != nullptr) {
528 MEM_freeN(dst_float);
529 }
530 return nullptr;
531 }
532 if (newx < ibuf->x) {
533 scale_down_x_func(ibuf, newx, ibuf->y, tmp_byte, tmp_float, threaded);
534 }
535 else {
536 scale_up_x_func(ibuf, newx, ibuf->y, tmp_byte, tmp_float, threaded);
537 }
538
539 /* Vertical scale. */
540 ImBuf tmpbuf;
541 IMB_initImBuf(&tmpbuf, newx, ibuf->y, ibuf->planes, 0);
542 if (tmp_byte != nullptr) {
544 &tmpbuf, reinterpret_cast<uint8_t *>(tmp_byte), IB_DO_NOT_TAKE_OWNERSHIP);
545 }
546 if (tmp_float != nullptr) {
548 }
549 if (newy < ibuf->y) {
550 scale_down_y_func(&tmpbuf, newx, newy, dst_byte, dst_float, threaded);
551 }
552 else {
553 scale_up_y_func(&tmpbuf, newx, newy, dst_byte, dst_float, threaded);
554 }
555
556 if (tmp_byte != nullptr) {
557 MEM_freeN(tmp_byte);
558 }
559 if (tmp_float != nullptr) {
560 MEM_freeN(tmp_float);
561 }
562 } break;
563 }
564
565 /* Create result image. */
566 ImBuf *dst = IMB_allocImBuf(newx, newy, ibuf->planes, IB_uninitialized_pixels);
567 dst->channels = ibuf->channels;
568 IMB_metadata_copy(dst, ibuf);
570 if (dst_byte != nullptr) {
571 IMB_assign_byte_buffer(dst, reinterpret_cast<uint8_t *>(dst_byte), IB_TAKE_OWNERSHIP);
573 }
574 if (dst_float != nullptr) {
577 }
578 return dst;
579}
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
unsigned char uchar
unsigned int uint
#define UNUSED_VARS(...)
#define UNLIKELY(x)
Function declarations for filter.cc.
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
IMBScaleFilter
Definition IMB_imbuf.hh:305
void IMB_assign_float_buffer(ImBuf *ibuf, float *buffer_data, ImBufOwnership ownership)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
void IMB_free_float_pixels(ImBuf *ibuf)
void IMB_free_byte_pixels(ImBuf *ibuf)
bool IMB_initImBuf(ImBuf *ibuf, unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
void IMB_assign_byte_buffer(ImBuf *ibuf, uint8_t *buffer_data, ImBufOwnership ownership)
@ IB_DO_NOT_TAKE_OWNERSHIP
@ IB_TAKE_OWNERSHIP
@ IB_uninitialized_pixels
void IMB_metadata_copy(ImBuf *ibuf_dst, const ImBuf *ibuf_src)
Definition metadata.cc:59
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v
long long int int64_t
constexpr int64_t first() const
nullptr float
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
Definition frames.inl:1166
#define filter
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define T
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:222
uchar4 interpolate_bilinear_byte(const ImBuf *in, float u, float v)
Definition IMB_interp.hh:53
float4 interpolate_bilinear_fl(const float *buffer, int width, int height, float u, float v)
T max(const T &a, const T &b)
T round(const T &a)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
blender::VecBase< uint8_t, 4 > uchar4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
VecBase< float, 3 > float3
static void alloc_scale_dst_buffers(const ImBuf *ibuf, uint newx, uint newy, uchar4 **r_dst_byte, float **r_dst_float)
Definition scaling.cc:29
static void scale_nearest(const T *src, T *dst, int ibufx, int ibufy, int newx, int newy, blender::IndexRange y_range)
Definition scaling.cc:382
ImBuf * IMB_scale_into_new(const ImBuf *ibuf, uint newx, uint newy, IMBScaleFilter filter, bool threaded)
Definition scaling.cc:489
bool IMB_scale(ImBuf *ibuf, uint newx, uint newy, IMBScaleFilter filter, bool threaded)
Definition scaling.cc:465
void(*)( const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded) ScaleFunction
Definition scaling.cc:336
static void scale_with_function(ImBuf *ibuf, int newx, int newy, ScaleFunction func, bool threaded)
Definition scaling.cc:339
static void imb_scale_box(ImBuf *ibuf, uint newx, uint newy, bool threaded)
Definition scaling.cc:365
static void scale_up_y_func(const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
Definition scaling.cc:329
static void scale_down_y_func(const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
Definition scaling.cc:315
static void store_pixel(float4 pix, uchar4 *ptr)
Definition scaling.cc:72
static void scale_bilinear_func(const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
Definition scaling.cc:436
static void scale_nearest_func(const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
Definition scaling.cc:403
static void scale_down_x_func(const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
Definition scaling.cc:308
static void instantiate_pixel_op(T &, const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
Definition scaling.cc:277
static void scale_up_x_func(const ImBuf *ibuf, int newx, int newy, uchar4 *dst_byte, float *dst_float, bool threaded)
Definition scaling.cc:322
static float4 load_pixel(const uchar4 *ptr)
Definition scaling.cc:52
const ColorSpace * colorspace
const ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
int colormanage_flag
unsigned char planes
static void op(const T *src, T *dst, int ibufx, int ibufy, int newx, int, bool threaded)
Definition scaling.cc:95
static void op(const T *src, T *dst, int ibufx, int ibufy, int, int newy, bool threaded)
Definition scaling.cc:134
static void op(const T *src, T *dst, int ibufx, int ibufy, int newx, int, bool threaded)
Definition scaling.cc:173
static void op(const T *src, T *dst, int ibufx, int ibufy, int, int newy, bool threaded)
Definition scaling.cc:226
float x
Definition sky_math.h:225
PointerRNA * ptr
Definition wm_files.cc:4238