Blender V4.3
texture_image.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <algorithm>
10#include <cfloat>
11#include <cmath>
12#include <cstdio>
13#include <cstring>
14#include <fcntl.h>
15#ifndef WIN32
16# include <unistd.h>
17#else
18# include <io.h>
19#endif
20
21#include "IMB_imbuf.hh"
22#include "IMB_imbuf_types.hh"
23
24#include "DNA_image_types.h"
25#include "DNA_texture_types.h"
26
27#include "BLI_math_color.h"
28#include "BLI_math_interp.hh"
29#include "BLI_math_vector.h"
30#include "BLI_threads.h"
31#include "BLI_utildefines.h"
32
33#include "BKE_image.hh"
34
35#include "RE_texture.h"
36
37#include "texture_common.h"
38
39static void boxsample(ImBuf *ibuf,
40 float minx,
41 float miny,
42 float maxx,
43 float maxy,
44 TexResult *texres,
45 const short imaprepeat,
46 const short imapextend);
47
48/* *********** IMAGEWRAPPING ****************** */
49
50/* x and y have to be checked for image size */
51static void ibuf_get_color(float col[4], ImBuf *ibuf, int x, int y)
52{
53 int ofs = y * ibuf->x + x;
54
55 if (ibuf->float_buffer.data) {
56 if (ibuf->channels == 4) {
57 const float *fp = ibuf->float_buffer.data + 4 * ofs;
58 copy_v4_v4(col, fp);
59 }
60 else if (ibuf->channels == 3) {
61 const float *fp = ibuf->float_buffer.data + 3 * ofs;
62 copy_v3_v3(col, fp);
63 col[3] = 1.0f;
64 }
65 else {
66 const float *fp = ibuf->float_buffer.data + ofs;
67 col[0] = col[1] = col[2] = col[3] = *fp;
68 }
69 }
70 else {
71 const uchar *rect = ibuf->byte_buffer.data + 4 * ofs;
72
73 col[0] = float(rect[0]) * (1.0f / 255.0f);
74 col[1] = float(rect[1]) * (1.0f / 255.0f);
75 col[2] = float(rect[2]) * (1.0f / 255.0f);
76 col[3] = float(rect[3]) * (1.0f / 255.0f);
77
78 /* Bytes are internally straight, however render pipeline seems to expect pre-multiplied. */
79 col[0] *= col[3];
80 col[1] *= col[3];
81 col[2] *= col[3];
82 }
83}
84
86 Image *ima,
87 const float texvec[3],
88 TexResult *texres,
89 ImagePool *pool,
90 const bool skip_load_image)
91{
92 float fx, fy;
93 int x, y, retval;
94 int xi, yi; /* original values */
95
96 texres->tin = texres->trgba[3] = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = 0.0f;
97
98 retval = TEX_RGB;
99
100 /* quick tests */
101 if (ima == nullptr) {
102 return retval;
103 }
104
105 /* hack for icon render */
106 if (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) {
107 return retval;
108 }
109
110 ImageUser *iuser = &tex->iuser;
111 ImageUser local_iuser;
112 if (ima->source == IMA_SRC_TILED) {
113 /* tex->iuser might be shared by threads, so create a local copy. */
114 local_iuser = tex->iuser;
115 iuser = &local_iuser;
116
117 float new_uv[2];
118 iuser->tile = BKE_image_get_tile_from_pos(ima, texvec, new_uv, nullptr);
119 fx = new_uv[0];
120 fy = new_uv[1];
121 }
122 else {
123 fx = texvec[0];
124 fy = texvec[1];
125 }
126
127 ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, iuser, pool);
128
130
131 if (ibuf == nullptr || (ibuf->byte_buffer.data == nullptr && ibuf->float_buffer.data == nullptr))
132 {
133 BKE_image_pool_release_ibuf(ima, ibuf, pool);
134 return retval;
135 }
136
137 /* setup mapping */
138 if (tex->imaflag & TEX_IMAROT) {
139 std::swap(fx, fy);
140 }
141
142 if (tex->extend == TEX_CHECKER) {
143 int xs, ys;
144
145 xs = int(floor(fx));
146 ys = int(floor(fy));
147 fx -= xs;
148 fy -= ys;
149
150 if ((tex->flag & TEX_CHECKER_ODD) == 0) {
151 if ((xs + ys) & 1) {
152 /* pass */
153 }
154 else {
155 if (ima) {
156 BKE_image_pool_release_ibuf(ima, ibuf, pool);
157 }
158 return retval;
159 }
160 }
161 if ((tex->flag & TEX_CHECKER_EVEN) == 0) {
162 if ((xs + ys) & 1) {
163 if (ima) {
164 BKE_image_pool_release_ibuf(ima, ibuf, pool);
165 }
166 return retval;
167 }
168 }
169 /* scale around center, (0.5, 0.5) */
170 if (tex->checkerdist < 1.0f) {
171 fx = (fx - 0.5f) / (1.0f - tex->checkerdist) + 0.5f;
172 fy = (fy - 0.5f) / (1.0f - tex->checkerdist) + 0.5f;
173 }
174 }
175
176 x = xi = int(floorf(fx * ibuf->x));
177 y = yi = int(floorf(fy * ibuf->y));
178
179 if (tex->extend == TEX_CLIPCUBE) {
180 if (x < 0 || y < 0 || x >= ibuf->x || y >= ibuf->y || texvec[2] < -1.0f || texvec[2] > 1.0f) {
181 if (ima) {
182 BKE_image_pool_release_ibuf(ima, ibuf, pool);
183 }
184 return retval;
185 }
186 }
187 else if (ELEM(tex->extend, TEX_CLIP, TEX_CHECKER)) {
188 if (x < 0 || y < 0 || x >= ibuf->x || y >= ibuf->y) {
189 if (ima) {
190 BKE_image_pool_release_ibuf(ima, ibuf, pool);
191 }
192 return retval;
193 }
194 }
195 else {
196 if (tex->extend == TEX_EXTEND) {
197 if (x >= ibuf->x) {
198 x = ibuf->x - 1;
199 }
200 else if (x < 0) {
201 x = 0;
202 }
203 }
204 else {
205 x = x % ibuf->x;
206 if (x < 0) {
207 x += ibuf->x;
208 }
209 }
210 if (tex->extend == TEX_EXTEND) {
211 if (y >= ibuf->y) {
212 y = ibuf->y - 1;
213 }
214 else if (y < 0) {
215 y = 0;
216 }
217 }
218 else {
219 y = y % ibuf->y;
220 if (y < 0) {
221 y += ibuf->y;
222 }
223 }
224 }
225
226 /* Keep this before interpolation #29761. */
227 if (ima) {
228 if ((tex->imaflag & TEX_USEALPHA) && (ima->alpha_mode != IMA_ALPHA_IGNORE)) {
229 if ((tex->imaflag & TEX_CALCALPHA) == 0) {
230 texres->talpha = true;
231 }
232 }
233 }
234
235 /* interpolate */
236 if (tex->imaflag & TEX_INTERPOL) {
237 float filterx, filtery;
238 filterx = (0.5f * tex->filtersize) / ibuf->x;
239 filtery = (0.5f * tex->filtersize) / ibuf->y;
240
241 /* Important that this value is wrapped #27782.
242 * this applies the modifications made by the checks above,
243 * back to the floating point values */
244 fx -= float(xi - x) / float(ibuf->x);
245 fy -= float(yi - y) / float(ibuf->y);
246
247 boxsample(ibuf,
248 fx - filterx,
249 fy - filtery,
250 fx + filterx,
251 fy + filtery,
252 texres,
253 (tex->extend == TEX_REPEAT),
254 (tex->extend == TEX_EXTEND));
255 }
256 else { /* no filtering */
257 ibuf_get_color(texres->trgba, ibuf, x, y);
258 }
259
260 if (texres->talpha) {
261 texres->tin = texres->trgba[3];
262 }
263 else if (tex->imaflag & TEX_CALCALPHA) {
264 texres->trgba[3] = texres->tin = max_fff(texres->trgba[0], texres->trgba[1], texres->trgba[2]);
265 }
266 else {
267 texres->trgba[3] = texres->tin = 1.0;
268 }
269
270 if (tex->flag & TEX_NEGALPHA) {
271 texres->trgba[3] = 1.0f - texres->trgba[3];
272 }
273
274 /* De-pre-multiply, this is being pre-multiplied in #shade_input_do_shade()
275 * do not de-pre-multiply for generated alpha, it is already in straight. */
276 if (texres->trgba[3] != 1.0f && texres->trgba[3] > 1e-4f && !(tex->imaflag & TEX_CALCALPHA)) {
277 fx = 1.0f / texres->trgba[3];
278 texres->trgba[0] *= fx;
279 texres->trgba[1] *= fx;
280 texres->trgba[2] *= fx;
281 }
282
283 if (ima) {
284 BKE_image_pool_release_ibuf(ima, ibuf, pool);
285 }
286
288
289 return retval;
290}
291
292static void clipx_rctf_swap(rctf *stack, short *count, float x1, float x2)
293{
294 rctf *rf, *newrct;
295 short a;
296
297 a = *count;
298 rf = stack;
299 for (; a > 0; a--) {
300 if (rf->xmin < x1) {
301 if (rf->xmax < x1) {
302 rf->xmin += (x2 - x1);
303 rf->xmax += (x2 - x1);
304 }
305 else {
306 if (rf->xmax > x2) {
307 rf->xmax = x2;
308 }
309 newrct = stack + *count;
310 (*count)++;
311
312 newrct->xmax = x2;
313 newrct->xmin = rf->xmin + (x2 - x1);
314 newrct->ymin = rf->ymin;
315 newrct->ymax = rf->ymax;
316
317 if (newrct->xmin == newrct->xmax) {
318 (*count)--;
319 }
320
321 rf->xmin = x1;
322 }
323 }
324 else if (rf->xmax > x2) {
325 if (rf->xmin > x2) {
326 rf->xmin -= (x2 - x1);
327 rf->xmax -= (x2 - x1);
328 }
329 else {
330 if (rf->xmin < x1) {
331 rf->xmin = x1;
332 }
333 newrct = stack + *count;
334 (*count)++;
335
336 newrct->xmin = x1;
337 newrct->xmax = rf->xmax - (x2 - x1);
338 newrct->ymin = rf->ymin;
339 newrct->ymax = rf->ymax;
340
341 if (newrct->xmin == newrct->xmax) {
342 (*count)--;
343 }
344
345 rf->xmax = x2;
346 }
347 }
348 rf++;
349 }
350}
351
352static void clipy_rctf_swap(rctf *stack, short *count, float y1, float y2)
353{
354 rctf *rf, *newrct;
355 short a;
356
357 a = *count;
358 rf = stack;
359 for (; a > 0; a--) {
360 if (rf->ymin < y1) {
361 if (rf->ymax < y1) {
362 rf->ymin += (y2 - y1);
363 rf->ymax += (y2 - y1);
364 }
365 else {
366 if (rf->ymax > y2) {
367 rf->ymax = y2;
368 }
369 newrct = stack + *count;
370 (*count)++;
371
372 newrct->ymax = y2;
373 newrct->ymin = rf->ymin + (y2 - y1);
374 newrct->xmin = rf->xmin;
375 newrct->xmax = rf->xmax;
376
377 if (newrct->ymin == newrct->ymax) {
378 (*count)--;
379 }
380
381 rf->ymin = y1;
382 }
383 }
384 else if (rf->ymax > y2) {
385 if (rf->ymin > y2) {
386 rf->ymin -= (y2 - y1);
387 rf->ymax -= (y2 - y1);
388 }
389 else {
390 if (rf->ymin < y1) {
391 rf->ymin = y1;
392 }
393 newrct = stack + *count;
394 (*count)++;
395
396 newrct->ymin = y1;
397 newrct->ymax = rf->ymax - (y2 - y1);
398 newrct->xmin = rf->xmin;
399 newrct->xmax = rf->xmax;
400
401 if (newrct->ymin == newrct->ymax) {
402 (*count)--;
403 }
404
405 rf->ymax = y2;
406 }
407 }
408 rf++;
409 }
410}
411
412static float square_rctf(const rctf *rf)
413{
414 float x, y;
415
416 x = BLI_rctf_size_x(rf);
417 y = BLI_rctf_size_y(rf);
418 return x * y;
419}
420
421static float clipx_rctf(rctf *rf, float x1, float x2)
422{
423 float size;
424
425 size = BLI_rctf_size_x(rf);
426
427 if (rf->xmin < x1) {
428 rf->xmin = x1;
429 }
430 if (rf->xmax > x2) {
431 rf->xmax = x2;
432 }
433 if (rf->xmin > rf->xmax) {
434 rf->xmin = rf->xmax;
435 return 0.0;
436 }
437 if (size != 0.0f) {
438 return BLI_rctf_size_x(rf) / size;
439 }
440 return 1.0;
441}
442
443static float clipy_rctf(rctf *rf, float y1, float y2)
444{
445 float size;
446
447 size = BLI_rctf_size_y(rf);
448
449 if (rf->ymin < y1) {
450 rf->ymin = y1;
451 }
452 if (rf->ymax > y2) {
453 rf->ymax = y2;
454 }
455
456 if (rf->ymin > rf->ymax) {
457 rf->ymin = rf->ymax;
458 return 0.0;
459 }
460 if (size != 0.0f) {
461 return BLI_rctf_size_y(rf) / size;
462 }
463 return 1.0;
464}
465
466static void boxsampleclip(ImBuf *ibuf, const rctf *rf, TexResult *texres)
467{
468 /* Sample box, is clipped already, and minx etc. have been set at ibuf size.
469 * Enlarge with anti-aliased edges of the pixels. */
470
471 float muly, mulx, div, col[4];
472 int x, y, startx, endx, starty, endy;
473
474 startx = int(floor(rf->xmin));
475 endx = int(floor(rf->xmax));
476 starty = int(floor(rf->ymin));
477 endy = int(floor(rf->ymax));
478
479 if (startx < 0) {
480 startx = 0;
481 }
482 if (starty < 0) {
483 starty = 0;
484 }
485 if (endx >= ibuf->x) {
486 endx = ibuf->x - 1;
487 }
488 if (endy >= ibuf->y) {
489 endy = ibuf->y - 1;
490 }
491
492 if (starty == endy && startx == endx) {
493 ibuf_get_color(texres->trgba, ibuf, startx, starty);
494 }
495 else {
496 div = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = texres->trgba[3] = 0.0;
497 for (y = starty; y <= endy; y++) {
498
499 muly = 1.0;
500
501 if (starty == endy) {
502 /* pass */
503 }
504 else {
505 if (y == starty) {
506 muly = 1.0f - (rf->ymin - y);
507 }
508 if (y == endy) {
509 muly = (rf->ymax - y);
510 }
511 }
512
513 if (startx == endx) {
514 mulx = muly;
515
516 ibuf_get_color(col, ibuf, startx, y);
517 madd_v4_v4fl(texres->trgba, col, mulx);
518 div += mulx;
519 }
520 else {
521 for (x = startx; x <= endx; x++) {
522 mulx = muly;
523 if (x == startx) {
524 mulx *= 1.0f - (rf->xmin - x);
525 }
526 if (x == endx) {
527 mulx *= (rf->xmax - x);
528 }
529
530 ibuf_get_color(col, ibuf, x, y);
531 /* TODO(jbakker): No need to do manual optimization. Branching is slower than multiplying
532 * with 1. */
533 if (mulx == 1.0f) {
534 add_v4_v4(texres->trgba, col);
535 div += 1.0f;
536 }
537 else {
538 madd_v4_v4fl(texres->trgba, col, mulx);
539 div += mulx;
540 }
541 }
542 }
543 }
544
545 if (div != 0.0f) {
546 div = 1.0f / div;
547 mul_v4_fl(texres->trgba, div);
548 }
549 else {
550 zero_v4(texres->trgba);
551 }
552 }
553}
554
555static void boxsample(ImBuf *ibuf,
556 float minx,
557 float miny,
558 float maxx,
559 float maxy,
560 TexResult *texres,
561 const short imaprepeat,
562 const short imapextend)
563{
564 /* Sample box, performs clip. minx etc are in range 0.0 - 1.0 .
565 * Enlarge with anti-aliased edges of pixels.
566 * If variable 'imaprepeat' has been set, the
567 * clipped-away parts are sampled as well.
568 */
569 /* NOTE: actually minx etc isn't in the proper range...
570 * this due to filter size and offset vectors for bump. */
571 /* NOTE: talpha must be initialized. */
572 /* NOTE: even when 'imaprepeat' is set, this can only repeat once in any direction.
573 * the point which min/max is derived from is assumed to be wrapped. */
574 TexResult texr;
575 rctf *rf, stack[8];
576 float opp, tot, alphaclip = 1.0;
577 short count = 1;
578
579 rf = stack;
580 rf->xmin = minx * (ibuf->x);
581 rf->xmax = maxx * (ibuf->x);
582 rf->ymin = miny * (ibuf->y);
583 rf->ymax = maxy * (ibuf->y);
584
585 texr.talpha = texres->talpha; /* is read by boxsample_clip */
586
587 if (imapextend) {
588 CLAMP(rf->xmin, 0.0f, ibuf->x - 1);
589 CLAMP(rf->xmax, 0.0f, ibuf->x - 1);
590 }
591 else if (imaprepeat) {
592 clipx_rctf_swap(stack, &count, 0.0, float(ibuf->x));
593 }
594 else {
595 alphaclip = clipx_rctf(rf, 0.0, float(ibuf->x));
596
597 if (alphaclip <= 0.0f) {
598 texres->trgba[0] = texres->trgba[2] = texres->trgba[1] = texres->trgba[3] = 0.0;
599 return;
600 }
601 }
602
603 if (imapextend) {
604 CLAMP(rf->ymin, 0.0f, ibuf->y - 1);
605 CLAMP(rf->ymax, 0.0f, ibuf->y - 1);
606 }
607 else if (imaprepeat) {
608 clipy_rctf_swap(stack, &count, 0.0, float(ibuf->y));
609 }
610 else {
611 alphaclip *= clipy_rctf(rf, 0.0, float(ibuf->y));
612
613 if (alphaclip <= 0.0f) {
614 texres->trgba[0] = texres->trgba[2] = texres->trgba[1] = texres->trgba[3] = 0.0;
615 return;
616 }
617 }
618
619 if (count > 1) {
620 tot = texres->trgba[0] = texres->trgba[2] = texres->trgba[1] = texres->trgba[3] = 0.0;
621 while (count--) {
622 boxsampleclip(ibuf, rf, &texr);
623
624 opp = square_rctf(rf);
625 tot += opp;
626
627 texres->trgba[0] += opp * texr.trgba[0];
628 texres->trgba[1] += opp * texr.trgba[1];
629 texres->trgba[2] += opp * texr.trgba[2];
630 if (texres->talpha) {
631 texres->trgba[3] += opp * texr.trgba[3];
632 }
633 rf++;
634 }
635 if (tot != 0.0f) {
636 texres->trgba[0] /= tot;
637 texres->trgba[1] /= tot;
638 texres->trgba[2] /= tot;
639 if (texres->talpha) {
640 texres->trgba[3] /= tot;
641 }
642 }
643 }
644 else {
645 boxsampleclip(ibuf, rf, texres);
646 }
647
648 if (texres->talpha == 0) {
649 texres->trgba[3] = 1.0;
650 }
651
652 if (alphaclip != 1.0f) {
653 /* Pre-multiply it all. */
654 texres->trgba[0] *= alphaclip;
655 texres->trgba[1] *= alphaclip;
656 texres->trgba[2] *= alphaclip;
657 texres->trgba[3] *= alphaclip;
658 }
659}
660
661/* -------------------------------------------------------------------- */
662/* from here, some functions only used for the new filtering */
663
664/* anisotropic filters, data struct used instead of long line of (possibly unused) func args */
665struct afdata_t {
666 float dxt[2], dyt[2];
668 /* feline only */
671 float dusc, dvsc;
672};
673
674/* this only used here to make it easier to pass extend flags as single int */
676
681static int ibuf_get_color_clip(float col[4], ImBuf *ibuf, int x, int y, int extflag)
682{
683 int clip = 0;
684 switch (extflag) {
685 case TXC_XMIR: /* y rep */
686 x %= 2 * ibuf->x;
687 x += x < 0 ? 2 * ibuf->x : 0;
688 x = x >= ibuf->x ? 2 * ibuf->x - x - 1 : x;
689 y %= ibuf->y;
690 y += y < 0 ? ibuf->y : 0;
691 break;
692 case TXC_YMIR: /* x rep */
693 x %= ibuf->x;
694 x += x < 0 ? ibuf->x : 0;
695 y %= 2 * ibuf->y;
696 y += y < 0 ? 2 * ibuf->y : 0;
697 y = y >= ibuf->y ? 2 * ibuf->y - y - 1 : y;
698 break;
699 case TXC_EXTD:
700 x = (x < 0) ? 0 : ((x >= ibuf->x) ? (ibuf->x - 1) : x);
701 y = (y < 0) ? 0 : ((y >= ibuf->y) ? (ibuf->y - 1) : y);
702 break;
703 case TXC_REPT:
704 x %= ibuf->x;
705 x += (x < 0) ? ibuf->x : 0;
706 y %= ibuf->y;
707 y += (y < 0) ? ibuf->y : 0;
708 break;
709 default: { /* as extend, if clipped, set alpha to 0.0 */
710 if (x < 0) {
711 x = 0;
712 } /* TXF alpha: clip = 1; } */
713 if (x >= ibuf->x) {
714 x = ibuf->x - 1;
715 } /* TXF alpha: clip = 1; } */
716 if (y < 0) {
717 y = 0;
718 } /* TXF alpha: clip = 1; } */
719 if (y >= ibuf->y) {
720 y = ibuf->y - 1;
721 } /* TXF alpha: clip = 1; } */
722 }
723 }
724
725 if (ibuf->float_buffer.data) {
726 const float *fp = ibuf->float_buffer.data + (x + y * ibuf->x) * ibuf->channels;
727 if (ibuf->channels == 1) {
728 col[0] = col[1] = col[2] = col[3] = *fp;
729 }
730 else {
731 col[0] = fp[0];
732 col[1] = fp[1];
733 col[2] = fp[2];
734 col[3] = clip ? 0.0f : (ibuf->channels == 4 ? fp[3] : 1.0f);
735 }
736 }
737 else {
738 const uchar *rect = ibuf->byte_buffer.data + 4 * (x + y * ibuf->x);
739 float inv_alpha_fac = (1.0f / 255.0f) * rect[3] * (1.0f / 255.0f);
740 col[0] = rect[0] * inv_alpha_fac;
741 col[1] = rect[1] * inv_alpha_fac;
742 col[2] = rect[2] * inv_alpha_fac;
743 col[3] = clip ? 0.0f : rect[3] * (1.0f / 255.0f);
744 }
745 return clip;
746}
747
748/* as above + bilerp */
750 float col[4], ImBuf *ibuf, float u, float v, int intpol, int extflag)
751{
752 if (intpol) {
753 float c00[4], c01[4], c10[4], c11[4];
754 const float ufl = floorf(u -= 0.5f), vfl = floorf(v -= 0.5f);
755 const float uf = u - ufl, vf = v - vfl;
756 const float w00 = (1.0f - uf) * (1.0f - vf), w10 = uf * (1.0f - vf), w01 = (1.0f - uf) * vf,
757 w11 = uf * vf;
758 const int x1 = int(ufl), y1 = int(vfl), x2 = x1 + 1, y2 = y1 + 1;
759 int clip = ibuf_get_color_clip(c00, ibuf, x1, y1, extflag);
760 clip |= ibuf_get_color_clip(c10, ibuf, x2, y1, extflag);
761 clip |= ibuf_get_color_clip(c01, ibuf, x1, y2, extflag);
762 clip |= ibuf_get_color_clip(c11, ibuf, x2, y2, extflag);
763 col[0] = w00 * c00[0] + w10 * c10[0] + w01 * c01[0] + w11 * c11[0];
764 col[1] = w00 * c00[1] + w10 * c10[1] + w01 * c01[1] + w11 * c11[1];
765 col[2] = w00 * c00[2] + w10 * c10[2] + w01 * c01[2] + w11 * c11[2];
766 col[3] = clip ? 0.0f : w00 * c00[3] + w10 * c10[3] + w01 * c01[3] + w11 * c11[3];
767 return clip;
768 }
769 return ibuf_get_color_clip(col, ibuf, int(u), int(v), extflag);
770}
771
772static void area_sample(TexResult *texr, ImBuf *ibuf, float fx, float fy, const afdata_t *AFD)
773{
774 int xs, ys, clip = 0;
775 float tc[4], xsd, ysd, cw = 0.0f;
776 const float ux = ibuf->x * AFD->dxt[0], uy = ibuf->y * AFD->dxt[1];
777 const float vx = ibuf->x * AFD->dyt[0], vy = ibuf->y * AFD->dyt[1];
778 int xsam = int(0.5f * sqrtf(ux * ux + uy * uy) + 0.5f);
779 int ysam = int(0.5f * sqrtf(vx * vx + vy * vy) + 0.5f);
780 const int minsam = AFD->intpol ? 2 : 4;
781 xsam = std::clamp(xsam, minsam, ibuf->x * 2);
782 ysam = std::clamp(ysam, minsam, ibuf->y * 2);
783 xsd = 1.0f / xsam;
784 ysd = 1.0f / ysam;
785 texr->trgba[0] = texr->trgba[1] = texr->trgba[2] = texr->trgba[3] = 0.0f;
786 for (ys = 0; ys < ysam; ys++) {
787 for (xs = 0; xs < xsam; xs++) {
788 const float su = (xs + ((ys & 1) + 0.5f) * 0.5f) * xsd - 0.5f;
789 const float sv = (ys + ((xs & 1) + 0.5f) * 0.5f) * ysd - 0.5f;
790 const float pu = fx + su * AFD->dxt[0] + sv * AFD->dyt[0];
791 const float pv = fy + su * AFD->dxt[1] + sv * AFD->dyt[1];
792 const int out = ibuf_get_color_clip_bilerp(
793 tc, ibuf, pu * ibuf->x, pv * ibuf->y, AFD->intpol, AFD->extflag);
794 clip |= out;
795 cw += out ? 0.0f : 1.0f;
796 texr->trgba[0] += tc[0];
797 texr->trgba[1] += tc[1];
798 texr->trgba[2] += tc[2];
799 texr->trgba[3] += texr->talpha ? tc[3] : 0.0f;
800 }
801 }
802 xsd *= ysd;
803 texr->trgba[0] *= xsd;
804 texr->trgba[1] *= xsd;
805 texr->trgba[2] *= xsd;
806 /* clipping can be ignored if alpha used, texr->trgba[3] already includes filtered edge */
807 texr->trgba[3] = texr->talpha ? texr->trgba[3] * xsd : (clip ? cw * xsd : 1.0f);
808}
809
812 const afdata_t *AFD;
813};
814
815static void ewa_read_pixel_cb(void *userdata, int x, int y, float result[4])
816{
817 ReadEWAData *data = (ReadEWAData *)userdata;
818 ibuf_get_color_clip(result, data->ibuf, x, y, data->AFD->extflag);
819}
820
821static void ewa_eval(TexResult *texr, ImBuf *ibuf, float fx, float fy, const afdata_t *AFD)
822{
824 const float uv[2] = {fx, fy};
825 data.ibuf = ibuf;
826 data.AFD = AFD;
827 BLI_ewa_filter(ibuf->x,
828 ibuf->y,
829 AFD->intpol != 0,
830 texr->talpha,
831 uv,
832 AFD->dxt,
833 AFD->dyt,
835 &data,
836 texr->trgba);
837}
838
839static void feline_eval(TexResult *texr, ImBuf *ibuf, float fx, float fy, const afdata_t *AFD)
840{
841 const int maxn = AFD->iProbes - 1;
842 const float ll = ((AFD->majrad == AFD->minrad) ? 2.0f * AFD->majrad :
843 2.0f * (AFD->majrad - AFD->minrad)) /
844 (maxn ? float(maxn) : 1.0f);
845 float du = maxn ? cosf(AFD->theta) * ll : 0.0f;
846 float dv = maxn ? sinf(AFD->theta) * ll : 0.0f;
847 // const float D = -0.5f*(du*du + dv*dv) / (AFD->majrad*AFD->majrad);
848 const float D = (EWA_MAXIDX + 1) * 0.25f * (du * du + dv * dv) / (AFD->majrad * AFD->majrad);
849 float d; /* TXF alpha: `cw = 0.0f`. */
850 int n; /* TXF alpha: `clip = 0`. */
851 /* Have to use same scaling for du/dv here as for Ux/Vx/Uy/Vy (*after* D is calculated.) */
852 du *= AFD->dusc;
853 dv *= AFD->dvsc;
854 d = texr->trgba[0] = texr->trgba[2] = texr->trgba[1] = texr->trgba[3] = 0.0f;
855 for (n = -maxn; n <= maxn; n += 2) {
856 float tc[4];
857 const float hn = n * 0.5f;
858 const float u = fx + hn * du, v = fy + hn * dv;
859/* Can use ewa table here too. */
860#if 0
861 const float wt = expf(n * n * D);
862#else
863 const float wt = EWA_WTS[int(n * n * D)];
864#endif
865 /* `const int out =` */ ibuf_get_color_clip_bilerp(
866 tc, ibuf, ibuf->x * u, ibuf->y * v, AFD->intpol, AFD->extflag);
867 /* TXF alpha: `clip |= out;`
868 * TXF alpha: `cw += out ? 0.0f : wt;` */
869 texr->trgba[0] += tc[0] * wt;
870 texr->trgba[1] += tc[1] * wt;
871 texr->trgba[2] += tc[2] * wt;
872 texr->trgba[3] += texr->talpha ? tc[3] * wt : 0.0f;
873 d += wt;
874 }
875
876 d = 1.0f / d;
877 texr->trgba[0] *= d;
878 texr->trgba[1] *= d;
879 texr->trgba[2] *= d;
880 /* Clipping can be ignored if alpha used, `texr->trgba[3]` already includes filtered edge */
881 texr->trgba[3] = texr->talpha ? texr->trgba[3] * d :
882 1.0f; /* TXF alpha: `(clip ? cw*d : 1.0f);` */
883}
884#undef EWA_MAXIDX
885
886static void alpha_clip_aniso(const ImBuf *ibuf,
887 float minx,
888 float miny,
889 float maxx,
890 float maxy,
891 int extflag,
892 TexResult *texres)
893{
894 float alphaclip;
895 rctf rf;
896
897 /* TXF alpha: we're doing the same alpha-clip here as box-sample, but I'm doubting
898 * if this is actually correct for the all the filtering algorithms. */
899
900 if (!ELEM(extflag, TXC_REPT, TXC_EXTD)) {
901 rf.xmin = minx * (ibuf->x);
902 rf.xmax = maxx * (ibuf->x);
903 rf.ymin = miny * (ibuf->y);
904 rf.ymax = maxy * (ibuf->y);
905
906 alphaclip = clipx_rctf(&rf, 0.0, float(ibuf->x));
907 alphaclip *= clipy_rctf(&rf, 0.0, float(ibuf->y));
908 alphaclip = max_ff(alphaclip, 0.0f);
909
910 if (alphaclip != 1.0f) {
911 /* Pre-multiply it all. */
912 texres->trgba[0] *= alphaclip;
913 texres->trgba[1] *= alphaclip;
914 texres->trgba[2] *= alphaclip;
915 texres->trgba[3] *= alphaclip;
916 }
917 }
918}
919
920static void image_mipmap_test(Tex *tex, ImBuf *ibuf)
921{
922 if (tex->imaflag & TEX_MIPMAP) {
923 if (ibuf->mipmap[0] && (ibuf->userflags & IB_MIPMAP_INVALID)) {
925 if (ibuf->userflags & IB_MIPMAP_INVALID) {
927 ibuf->userflags &= ~IB_MIPMAP_INVALID;
928 }
930 }
931 if (ibuf->mipmap[0] == nullptr) {
933 if (ibuf->mipmap[0] == nullptr) {
935 }
937 }
938 /* if no mipmap could be made, fall back on non-mipmap render */
939 if (ibuf->mipmap[0] == nullptr) {
940 tex->imaflag &= ~TEX_MIPMAP;
941 }
942 }
943}
944
946 Image *ima,
947 ImBuf *ibuf,
948 const float texvec[3],
949 float dxt[2],
950 float dyt[2],
951 TexResult *texres,
952 ImagePool *pool,
953 const bool skip_load_image)
954{
955 TexResult texr;
956 float fx, fy, minx, maxx, miny, maxy;
957 float maxd;
958 int curmap, retval, intpol, extflag = 0;
959 afdata_t AFD;
960
961 void (*filterfunc)(TexResult *, ImBuf *, float, float, const afdata_t *);
962 switch (tex->texfilter) {
963 case TXF_EWA:
964 filterfunc = ewa_eval;
965 break;
966 case TXF_FELINE:
967 filterfunc = feline_eval;
968 break;
969 case TXF_AREA:
970 default:
971 filterfunc = area_sample;
972 }
973
974 texres->tin = texres->trgba[3] = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = 0.0f;
975
976 retval = TEX_RGB;
977
978 /* quick tests */
979 if (ibuf == nullptr && ima == nullptr) {
980 return retval;
981 }
982
983 if (ima) { /* hack for icon render */
984 if (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) {
985 return retval;
986 }
987 ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);
988 }
989
990 if ((ibuf == nullptr) ||
991 ((ibuf->byte_buffer.data == nullptr) && (ibuf->float_buffer.data == nullptr)))
992 {
993 if (ima) {
994 BKE_image_pool_release_ibuf(ima, ibuf, pool);
995 }
996 return retval;
997 }
998
999 if (ima) {
1000 ima->flag |= IMA_USED_FOR_RENDER;
1001 }
1002
1003 /* mipmap test */
1004 image_mipmap_test(tex, ibuf);
1005
1006 if (ima) {
1007 if ((tex->imaflag & TEX_USEALPHA) && (ima->alpha_mode != IMA_ALPHA_IGNORE)) {
1008 if ((tex->imaflag & TEX_CALCALPHA) == 0) {
1009 texres->talpha = true;
1010 }
1011 }
1012 }
1013 texr.talpha = texres->talpha;
1014
1015 if (tex->imaflag & TEX_IMAROT) {
1016 fy = texvec[0];
1017 fx = texvec[1];
1018 }
1019 else {
1020 fx = texvec[0];
1021 fy = texvec[1];
1022 }
1023
1024 /* pixel coordinates */
1025 minx = min_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
1026 maxx = max_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
1027 miny = min_fff(dxt[1], dyt[1], dxt[1] + dyt[1]);
1028 maxy = max_fff(dxt[1], dyt[1], dxt[1] + dyt[1]);
1029
1030 /* tex_sharper has been removed */
1031 minx = (maxx - minx) * 0.5f;
1032 miny = (maxy - miny) * 0.5f;
1033
1034 if (tex->imaflag & TEX_FILTER_MIN) {
1035 /* Make sure the filtersize is minimal in pixels
1036 * (normal, ref map can have miniature pixel dx/dy). */
1037 const float addval = (0.5f * tex->filtersize) / float(std::min(ibuf->x, ibuf->y));
1038 if (addval > minx) {
1039 minx = addval;
1040 }
1041 if (addval > miny) {
1042 miny = addval;
1043 }
1044 }
1045 else if (tex->filtersize != 1.0f) {
1046 minx *= tex->filtersize;
1047 miny *= tex->filtersize;
1048 dxt[0] *= tex->filtersize;
1049 dxt[1] *= tex->filtersize;
1050 dyt[0] *= tex->filtersize;
1051 dyt[1] *= tex->filtersize;
1052 }
1053
1054 if (tex->imaflag & TEX_IMAROT) {
1055 float t;
1056 std::swap(minx, miny);
1057 /* must rotate dxt/dyt 90 deg
1058 * yet another blender problem is that swapping X/Y axes (or any tex projection switches)
1059 * should do something similar, but it doesn't, it only swaps coords,
1060 * so filter area will be incorrect in those cases. */
1061 t = dxt[0];
1062 dxt[0] = dxt[1];
1063 dxt[1] = -t;
1064 t = dyt[0];
1065 dyt[0] = dyt[1];
1066 dyt[1] = -t;
1067 }
1068
1069 /* side faces of unit-cube */
1070 minx = (minx > 0.25f) ? 0.25f : ((minx < 1e-5f) ? 1e-5f : minx);
1071 miny = (miny > 0.25f) ? 0.25f : ((miny < 1e-5f) ? 1e-5f : miny);
1072
1073 /* repeat and clip */
1074
1075 if (tex->extend == TEX_REPEAT) {
1077 extflag = TXC_EXTD;
1078 }
1079 else if (tex->flag & TEX_REPEAT_XMIR) {
1080 extflag = TXC_XMIR;
1081 }
1082 else if (tex->flag & TEX_REPEAT_YMIR) {
1083 extflag = TXC_YMIR;
1084 }
1085 else {
1086 extflag = TXC_REPT;
1087 }
1088 }
1089 else if (tex->extend == TEX_EXTEND) {
1090 extflag = TXC_EXTD;
1091 }
1092
1093 if (tex->extend == TEX_CHECKER) {
1094 int xs = int(floorf(fx)), ys = int(floorf(fy));
1095 /* both checkers available, no boundary exceptions, checkerdist will eat aliasing */
1096 if ((tex->flag & TEX_CHECKER_ODD) && (tex->flag & TEX_CHECKER_EVEN)) {
1097 fx -= xs;
1098 fy -= ys;
1099 }
1100 else if ((tex->flag & TEX_CHECKER_ODD) == 0 && (tex->flag & TEX_CHECKER_EVEN) == 0) {
1101 if (ima) {
1102 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1103 }
1104 return retval;
1105 }
1106 else {
1107 int xs1 = int(floorf(fx - minx));
1108 int ys1 = int(floorf(fy - miny));
1109 int xs2 = int(floorf(fx + minx));
1110 int ys2 = int(floorf(fy + miny));
1111 if ((xs1 != xs2) || (ys1 != ys2)) {
1112 if (tex->flag & TEX_CHECKER_ODD) {
1113 fx -= ((xs1 + ys) & 1) ? xs2 : xs1;
1114 fy -= ((ys1 + xs) & 1) ? ys2 : ys1;
1115 }
1116 if (tex->flag & TEX_CHECKER_EVEN) {
1117 fx -= ((xs1 + ys) & 1) ? xs1 : xs2;
1118 fy -= ((ys1 + xs) & 1) ? ys1 : ys2;
1119 }
1120 }
1121 else {
1122 if ((tex->flag & TEX_CHECKER_ODD) == 0 && ((xs + ys) & 1) == 0) {
1123 if (ima) {
1124 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1125 }
1126 return retval;
1127 }
1128 if ((tex->flag & TEX_CHECKER_EVEN) == 0 && (xs + ys) & 1) {
1129 if (ima) {
1130 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1131 }
1132 return retval;
1133 }
1134 fx -= xs;
1135 fy -= ys;
1136 }
1137 }
1138 /* scale around center, (0.5, 0.5) */
1139 if (tex->checkerdist < 1.0f) {
1140 const float omcd = 1.0f / (1.0f - tex->checkerdist);
1141 fx = (fx - 0.5f) * omcd + 0.5f;
1142 fy = (fy - 0.5f) * omcd + 0.5f;
1143 minx *= omcd;
1144 miny *= omcd;
1145 }
1146 }
1147
1148 if (tex->extend == TEX_CLIPCUBE) {
1149 if ((fx + minx) < 0.0f || (fy + miny) < 0.0f || (fx - minx) > 1.0f || (fy - miny) > 1.0f ||
1150 texvec[2] < -1.0f || texvec[2] > 1.0f)
1151 {
1152 if (ima) {
1153 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1154 }
1155 return retval;
1156 }
1157 }
1158 else if (ELEM(tex->extend, TEX_CLIP, TEX_CHECKER)) {
1159 if ((fx + minx) < 0.0f || (fy + miny) < 0.0f || (fx - minx) > 1.0f || (fy - miny) > 1.0f) {
1160 if (ima) {
1161 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1162 }
1163 return retval;
1164 }
1165 }
1166 else {
1167 if (tex->extend == TEX_EXTEND) {
1168 fx = (fx > 1.0f) ? 1.0f : ((fx < 0.0f) ? 0.0f : fx);
1169 fy = (fy > 1.0f) ? 1.0f : ((fy < 0.0f) ? 0.0f : fy);
1170 }
1171 else {
1172 fx -= floorf(fx);
1173 fy -= floorf(fy);
1174 }
1175 }
1176
1177 intpol = tex->imaflag & TEX_INTERPOL;
1178
1179 /* struct common data */
1180 copy_v2_v2(AFD.dxt, dxt);
1181 copy_v2_v2(AFD.dyt, dyt);
1182 AFD.intpol = intpol;
1183 AFD.extflag = extflag;
1184
1185 /* NOTE(@brecht): added stupid clamping here, large dx/dy can give very large
1186 * filter sizes which take ages to render, it may be better to do this
1187 * more intelligently later in the code .. probably it's not noticeable */
1188 if (AFD.dxt[0] * AFD.dxt[0] + AFD.dxt[1] * AFD.dxt[1] > 2.0f * 2.0f) {
1189 mul_v2_fl(AFD.dxt, 2.0f / len_v2(AFD.dxt));
1190 }
1191 if (AFD.dyt[0] * AFD.dyt[0] + AFD.dyt[1] * AFD.dyt[1] > 2.0f * 2.0f) {
1192 mul_v2_fl(AFD.dyt, 2.0f / len_v2(AFD.dyt));
1193 }
1194
1195 /* choice: */
1196 if (tex->imaflag & TEX_MIPMAP) {
1197 ImBuf *previbuf, *curibuf;
1198 float levf;
1199 int maxlev;
1200 ImBuf *mipmaps[IMB_MIPMAP_LEVELS + 1];
1201
1202 /* Modify ellipse minor axis if too eccentric, use for area sampling as well
1203 * scaling `dxt/dyt` as done in PBRT is not the same
1204 * (as in `ewa_eval()`, scale by `sqrt(ibuf->x)` to maximize precision). */
1205 const float ff = sqrtf(ibuf->x), q = ibuf->y / ff;
1206 const float Ux = dxt[0] * ff, Vx = dxt[1] * q, Uy = dyt[0] * ff, Vy = dyt[1] * q;
1207 const float A = Vx * Vx + Vy * Vy;
1208 const float B = -2.0f * (Ux * Vx + Uy * Vy);
1209 const float C = Ux * Ux + Uy * Uy;
1210 const float F = A * C - B * B * 0.25f;
1211 float a, b, th, ecc;
1212 BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
1213 if (tex->texfilter == TXF_FELINE) {
1214 float fProbes;
1215 a *= ff;
1216 b *= ff;
1217 a = max_ff(a, 1.0f);
1218 b = max_ff(b, 1.0f);
1219 fProbes = 2.0f * (a / b) - 1.0f;
1220 AFD.iProbes = round_fl_to_int(fProbes);
1221 AFD.iProbes = std::min(AFD.iProbes, tex->afmax);
1222 if (AFD.iProbes < fProbes) {
1223 b = 2.0f * a / float(AFD.iProbes + 1);
1224 }
1225 AFD.majrad = a / ff;
1226 AFD.minrad = b / ff;
1227 AFD.theta = th;
1228 AFD.dusc = 1.0f / ff;
1229 AFD.dvsc = ff / float(ibuf->y);
1230 }
1231 else { /* EWA & area */
1232 if (ecc > float(tex->afmax)) {
1233 b = a / float(tex->afmax);
1234 }
1235 b *= ff;
1236 }
1237 maxd = max_ff(b, 1e-8f);
1238 levf = float(M_LOG2E) * logf(maxd);
1239
1240 curmap = 0;
1241 maxlev = 1;
1242 mipmaps[0] = ibuf;
1243 while (curmap < IMB_MIPMAP_LEVELS) {
1244 mipmaps[curmap + 1] = ibuf->mipmap[curmap];
1245 if (ibuf->mipmap[curmap]) {
1246 maxlev++;
1247 }
1248 curmap++;
1249 }
1250
1251 /* mipmap level */
1252 if (levf < 0.0f) { /* original image only */
1253 previbuf = curibuf = mipmaps[0];
1254 levf = 0.0f;
1255 }
1256 else if (levf >= maxlev - 1) {
1257 previbuf = curibuf = mipmaps[maxlev - 1];
1258 levf = 0.0f;
1259 if (tex->texfilter == TXF_FELINE) {
1260 AFD.iProbes = 1;
1261 }
1262 }
1263 else {
1264 const int lev = isnan(levf) ? 0 : int(levf);
1265 curibuf = mipmaps[lev];
1266 previbuf = mipmaps[lev + 1];
1267 levf -= floorf(levf);
1268 }
1269
1270 /* filter functions take care of interpolation themselves, no need to modify dxt/dyt here */
1271 filterfunc(texres, curibuf, fx, fy, &AFD);
1272 if (previbuf != curibuf) { /* interpolate */
1273 filterfunc(&texr, previbuf, fx, fy, &AFD);
1274 texres->trgba[0] += levf * (texr.trgba[0] - texres->trgba[0]);
1275 texres->trgba[1] += levf * (texr.trgba[1] - texres->trgba[1]);
1276 texres->trgba[2] += levf * (texr.trgba[2] - texres->trgba[2]);
1277 texres->trgba[3] += levf * (texr.trgba[3] - texres->trgba[3]);
1278 }
1279
1280 if (tex->texfilter != TXF_EWA) {
1281 alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres);
1282 }
1283 }
1284 else { /* no mipmap */
1285 /* filter functions take care of interpolation themselves, no need to modify dxt/dyt here */
1286 if (tex->texfilter == TXF_FELINE) {
1287 const float ff = sqrtf(ibuf->x), q = ibuf->y / ff;
1288 const float Ux = dxt[0] * ff, Vx = dxt[1] * q, Uy = dyt[0] * ff, Vy = dyt[1] * q;
1289 const float A = Vx * Vx + Vy * Vy;
1290 const float B = -2.0f * (Ux * Vx + Uy * Vy);
1291 const float C = Ux * Ux + Uy * Uy;
1292 const float F = A * C - B * B * 0.25f;
1293 float a, b, th, ecc, fProbes;
1294 BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
1295 a *= ff;
1296 b *= ff;
1297 a = max_ff(a, 1.0f);
1298 b = max_ff(b, 1.0f);
1299 fProbes = 2.0f * (a / b) - 1.0f;
1300 /* no limit to number of Probes here */
1301 AFD.iProbes = round_fl_to_int(fProbes);
1302 if (AFD.iProbes < fProbes) {
1303 b = 2.0f * a / float(AFD.iProbes + 1);
1304 }
1305 AFD.majrad = a / ff;
1306 AFD.minrad = b / ff;
1307 AFD.theta = th;
1308 AFD.dusc = 1.0f / ff;
1309 AFD.dvsc = ff / float(ibuf->y);
1310 }
1311 filterfunc(texres, ibuf, fx, fy, &AFD);
1312 if (tex->texfilter != TXF_EWA) {
1313 alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres);
1314 }
1315 }
1316
1317 if (tex->imaflag & TEX_CALCALPHA) {
1318 texres->trgba[3] = texres->tin = texres->trgba[3] *
1319 max_fff(texres->trgba[0], texres->trgba[1], texres->trgba[2]);
1320 }
1321 else {
1322 texres->tin = texres->trgba[3];
1323 }
1324 if (tex->flag & TEX_NEGALPHA) {
1325 texres->trgba[3] = 1.0f - texres->trgba[3];
1326 }
1327
1328 /* de-pre-multiply, this is being pre-multiplied in shade_input_do_shade()
1329 * TXF: this currently does not (yet?) work properly, destroys edge AA in clip/checker mode,
1330 * so for now commented out also disabled in #imagewraposa()
1331 * to be able to compare results with blender's default texture filtering */
1332
1333 /* brecht: tried to fix this, see "TXF alpha" comments */
1334
1335 /* do not de-pre-multiply for generated alpha, it is already in straight */
1336 if (texres->trgba[3] != 1.0f && texres->trgba[3] > 1e-4f && !(tex->imaflag & TEX_CALCALPHA)) {
1337 fx = 1.0f / texres->trgba[3];
1338 texres->trgba[0] *= fx;
1339 texres->trgba[1] *= fx;
1340 texres->trgba[2] *= fx;
1341 }
1342
1343 if (ima) {
1344 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1345 }
1346
1347 BRICONTRGB;
1348
1349 return retval;
1350}
1351
1353 Image *ima,
1354 ImBuf *ibuf,
1355 const float texvec[3],
1356 const float DXT[2],
1357 const float DYT[2],
1358 TexResult *texres,
1359 ImagePool *pool,
1360 const bool skip_load_image)
1361{
1362 TexResult texr;
1363 float fx, fy, minx, maxx, miny, maxy, dx, dy, dxt[2], dyt[2];
1364 float maxd, pixsize;
1365 int curmap, retval, imaprepeat, imapextend;
1366
1367 /* TXF: since dxt/dyt might be modified here and since they might be needed after imagewraposa()
1368 * call, make a local copy here so that original vecs remain untouched. */
1369 copy_v2_v2(dxt, DXT);
1370 copy_v2_v2(dyt, DYT);
1371
1372 /* anisotropic filtering */
1373 if (tex->texfilter != TXF_BOX) {
1374 return imagewraposa_aniso(tex, ima, ibuf, texvec, dxt, dyt, texres, pool, skip_load_image);
1375 }
1376
1377 texres->tin = texres->trgba[3] = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = 0.0f;
1378
1379 retval = TEX_RGB;
1380
1381 /* quick tests */
1382 if (ibuf == nullptr && ima == nullptr) {
1383 return retval;
1384 }
1385 if (ima) {
1386
1387 /* hack for icon render */
1388 if (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) {
1389 return retval;
1390 }
1391
1392 ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);
1393
1394 ima->flag |= IMA_USED_FOR_RENDER;
1395 }
1396 if (ibuf == nullptr || (ibuf->byte_buffer.data == nullptr && ibuf->float_buffer.data == nullptr))
1397 {
1398 if (ima) {
1399 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1400 }
1401 return retval;
1402 }
1403
1404 /* mipmap test */
1405 image_mipmap_test(tex, ibuf);
1406
1407 if (ima) {
1408 if ((tex->imaflag & TEX_USEALPHA) && (ima->alpha_mode != IMA_ALPHA_IGNORE)) {
1409 if ((tex->imaflag & TEX_CALCALPHA) == 0) {
1410 texres->talpha = true;
1411 }
1412 }
1413 }
1414
1415 texr.talpha = texres->talpha;
1416
1417 if (tex->imaflag & TEX_IMAROT) {
1418 fy = texvec[0];
1419 fx = texvec[1];
1420 }
1421 else {
1422 fx = texvec[0];
1423 fy = texvec[1];
1424 }
1425
1426 /* pixel coordinates */
1427
1428 minx = min_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
1429 maxx = max_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
1430 miny = min_fff(dxt[1], dyt[1], dxt[1] + dyt[1]);
1431 maxy = max_fff(dxt[1], dyt[1], dxt[1] + dyt[1]);
1432
1433 /* tex_sharper has been removed */
1434 minx = (maxx - minx) / 2.0f;
1435 miny = (maxy - miny) / 2.0f;
1436
1437 if (tex->imaflag & TEX_FILTER_MIN) {
1438 /* Make sure the filtersize is minimal in pixels
1439 * (normal, ref map can have miniature pixel dx/dy). */
1440 float addval = (0.5f * tex->filtersize) / float(std::min(ibuf->x, ibuf->y));
1441
1442 if (addval > minx) {
1443 minx = addval;
1444 }
1445 if (addval > miny) {
1446 miny = addval;
1447 }
1448 }
1449 else if (tex->filtersize != 1.0f) {
1450 minx *= tex->filtersize;
1451 miny *= tex->filtersize;
1452
1453 dxt[0] *= tex->filtersize;
1454 dxt[1] *= tex->filtersize;
1455 dyt[0] *= tex->filtersize;
1456 dyt[1] *= tex->filtersize;
1457 }
1458
1459 if (tex->imaflag & TEX_IMAROT) {
1460 std::swap(minx, miny);
1461 }
1462
1463 if (minx > 0.25f) {
1464 minx = 0.25f;
1465 }
1466 else if (minx < 0.00001f) {
1467 minx = 0.00001f; /* side faces of unit-cube */
1468 }
1469 if (miny > 0.25f) {
1470 miny = 0.25f;
1471 }
1472 else if (miny < 0.00001f) {
1473 miny = 0.00001f;
1474 }
1475
1476 /* repeat and clip */
1477 imaprepeat = (tex->extend == TEX_REPEAT);
1478 imapextend = (tex->extend == TEX_EXTEND);
1479
1480 if (tex->extend == TEX_REPEAT) {
1482 imaprepeat = 0;
1483 imapextend = 1;
1484 }
1485 }
1486
1487 if (tex->extend == TEX_CHECKER) {
1488 int xs, ys, xs1, ys1, xs2, ys2, boundary;
1489
1490 xs = int(floor(fx));
1491 ys = int(floor(fy));
1492
1493 /* both checkers available, no boundary exceptions, checkerdist will eat aliasing */
1494 if ((tex->flag & TEX_CHECKER_ODD) && (tex->flag & TEX_CHECKER_EVEN)) {
1495 fx -= xs;
1496 fy -= ys;
1497 }
1498 else if ((tex->flag & TEX_CHECKER_ODD) == 0 && (tex->flag & TEX_CHECKER_EVEN) == 0) {
1499 if (ima) {
1500 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1501 }
1502 return retval;
1503 }
1504 else {
1505
1506 xs1 = int(floor(fx - minx));
1507 ys1 = int(floor(fy - miny));
1508 xs2 = int(floor(fx + minx));
1509 ys2 = int(floor(fy + miny));
1510 boundary = (xs1 != xs2) || (ys1 != ys2);
1511
1512 if (boundary == 0) {
1513 if ((tex->flag & TEX_CHECKER_ODD) == 0) {
1514 if ((xs + ys) & 1) {
1515 /* pass */
1516 }
1517 else {
1518 if (ima) {
1519 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1520 }
1521 return retval;
1522 }
1523 }
1524 if ((tex->flag & TEX_CHECKER_EVEN) == 0) {
1525 if ((xs + ys) & 1) {
1526 if (ima) {
1527 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1528 }
1529 return retval;
1530 }
1531 }
1532 fx -= xs;
1533 fy -= ys;
1534 }
1535 else {
1536 if (tex->flag & TEX_CHECKER_ODD) {
1537 if ((xs1 + ys) & 1) {
1538 fx -= xs2;
1539 }
1540 else {
1541 fx -= xs1;
1542 }
1543
1544 if ((ys1 + xs) & 1) {
1545 fy -= ys2;
1546 }
1547 else {
1548 fy -= ys1;
1549 }
1550 }
1551 if (tex->flag & TEX_CHECKER_EVEN) {
1552 if ((xs1 + ys) & 1) {
1553 fx -= xs1;
1554 }
1555 else {
1556 fx -= xs2;
1557 }
1558
1559 if ((ys1 + xs) & 1) {
1560 fy -= ys1;
1561 }
1562 else {
1563 fy -= ys2;
1564 }
1565 }
1566 }
1567 }
1568
1569 /* scale around center, (0.5, 0.5) */
1570 if (tex->checkerdist < 1.0f) {
1571 fx = (fx - 0.5f) / (1.0f - tex->checkerdist) + 0.5f;
1572 fy = (fy - 0.5f) / (1.0f - tex->checkerdist) + 0.5f;
1573 minx /= (1.0f - tex->checkerdist);
1574 miny /= (1.0f - tex->checkerdist);
1575 }
1576 }
1577
1578 if (tex->extend == TEX_CLIPCUBE) {
1579 if (fx + minx < 0.0f || fy + miny < 0.0f || fx - minx > 1.0f || fy - miny > 1.0f ||
1580 texvec[2] < -1.0f || texvec[2] > 1.0f)
1581 {
1582 if (ima) {
1583 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1584 }
1585 return retval;
1586 }
1587 }
1588 else if (ELEM(tex->extend, TEX_CLIP, TEX_CHECKER)) {
1589 if (fx + minx < 0.0f || fy + miny < 0.0f || fx - minx > 1.0f || fy - miny > 1.0f) {
1590 if (ima) {
1591 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1592 }
1593 return retval;
1594 }
1595 }
1596 else {
1597 if (imapextend) {
1598 if (fx > 1.0f) {
1599 fx = 1.0f;
1600 }
1601 else if (fx < 0.0f) {
1602 fx = 0.0f;
1603 }
1604 }
1605 else {
1606 if (fx > 1.0f) {
1607 fx -= int(fx);
1608 }
1609 else if (fx < 0.0f) {
1610 fx += 1 - int(fx);
1611 }
1612 }
1613
1614 if (imapextend) {
1615 if (fy > 1.0f) {
1616 fy = 1.0f;
1617 }
1618 else if (fy < 0.0f) {
1619 fy = 0.0f;
1620 }
1621 }
1622 else {
1623 if (fy > 1.0f) {
1624 fy -= int(fy);
1625 }
1626 else if (fy < 0.0f) {
1627 fy += 1 - int(fy);
1628 }
1629 }
1630 }
1631
1632 /* Choice: */
1633 if (tex->imaflag & TEX_MIPMAP) {
1634 ImBuf *previbuf, *curibuf;
1635
1636 dx = minx;
1637 dy = miny;
1638 maxd = max_ff(dx, dy);
1639 if (maxd > 0.5f) {
1640 maxd = 0.5f;
1641 }
1642
1643 pixsize = 1.0f / float(std::min(ibuf->x, ibuf->y));
1644
1645 curmap = 0;
1646 previbuf = curibuf = ibuf;
1647 while (curmap < IMB_MIPMAP_LEVELS && ibuf->mipmap[curmap]) {
1648 if (maxd < pixsize) {
1649 break;
1650 }
1651 previbuf = curibuf;
1652 curibuf = ibuf->mipmap[curmap];
1653 pixsize = 1.0f / float(std::min(curibuf->x, curibuf->y));
1654 curmap++;
1655 }
1656
1657 if (previbuf != curibuf || (tex->imaflag & TEX_INTERPOL)) {
1658 /* sample at least 1 pixel */
1659 if (minx < 0.5f / ibuf->x) {
1660 minx = 0.5f / ibuf->x;
1661 }
1662 if (miny < 0.5f / ibuf->y) {
1663 miny = 0.5f / ibuf->y;
1664 }
1665 }
1666
1667 maxx = fx + minx;
1668 minx = fx - minx;
1669 maxy = fy + miny;
1670 miny = fy - miny;
1671
1672 boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend);
1673
1674 if (previbuf != curibuf) { /* interpolate */
1675 boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend);
1676
1677 fx = 2.0f * (pixsize - maxd) / pixsize;
1678
1679 if (fx >= 1.0f) {
1680 texres->trgba[3] = texr.trgba[3];
1681 texres->trgba[2] = texr.trgba[2];
1682 texres->trgba[1] = texr.trgba[1];
1683 texres->trgba[0] = texr.trgba[0];
1684 }
1685 else {
1686 fy = 1.0f - fx;
1687 texres->trgba[2] = fy * texres->trgba[2] + fx * texr.trgba[2];
1688 texres->trgba[1] = fy * texres->trgba[1] + fx * texr.trgba[1];
1689 texres->trgba[0] = fy * texres->trgba[0] + fx * texr.trgba[0];
1690 texres->trgba[3] = fy * texres->trgba[3] + fx * texr.trgba[3];
1691 }
1692 }
1693 }
1694 else {
1695 const int intpol = tex->imaflag & TEX_INTERPOL;
1696 if (intpol) {
1697 /* sample 1 pixel minimum */
1698 if (minx < 0.5f / ibuf->x) {
1699 minx = 0.5f / ibuf->x;
1700 }
1701 if (miny < 0.5f / ibuf->y) {
1702 miny = 0.5f / ibuf->y;
1703 }
1704 }
1705
1706 boxsample(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend);
1707 }
1708
1709 if (tex->imaflag & TEX_CALCALPHA) {
1710 texres->trgba[3] = texres->tin = texres->trgba[3] *
1711 max_fff(texres->trgba[0], texres->trgba[1], texres->trgba[2]);
1712 }
1713 else {
1714 texres->tin = texres->trgba[3];
1715 }
1716
1717 if (tex->flag & TEX_NEGALPHA) {
1718 texres->trgba[3] = 1.0f - texres->trgba[3];
1719 }
1720
1721 /* de-pre-multiply, this is being pre-multiplied in shade_input_do_shade() */
1722 /* do not de-pre-multiply for generated alpha, it is already in straight */
1723 if (texres->trgba[3] != 1.0f && texres->trgba[3] > 1e-4f && !(tex->imaflag & TEX_CALCALPHA)) {
1724 mul_v3_fl(texres->trgba, 1.0f / texres->trgba[3]);
1725 }
1726
1727 if (ima) {
1728 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1729 }
1730
1731 BRICONTRGB;
1732
1733 return retval;
1734}
1735
1737 Image *ima, float fx, float fy, float dx, float dy, float result[4], ImagePool *pool)
1738{
1739 TexResult texres;
1740 ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, nullptr, pool);
1741
1742 if (UNLIKELY(ibuf == nullptr)) {
1743 zero_v4(result);
1744 return;
1745 }
1746
1747 texres.talpha = true; /* boxsample expects to be initialized */
1748 boxsample(ibuf, fx, fy, fx + dx, fy + dy, &texres, 0, 1);
1749 copy_v4_v4(result, texres.trgba);
1750
1751 ima->flag |= IMA_USED_FOR_RENDER;
1752
1753 BKE_image_pool_release_ibuf(ima, ibuf, pool);
1754}
1755
1756void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float result[4])
1757{
1758 TexResult texres = {0};
1759 afdata_t AFD;
1760
1761 AFD.dxt[0] = dx;
1762 AFD.dxt[1] = dx;
1763 AFD.dyt[0] = dy;
1764 AFD.dyt[1] = dy;
1765 // copy_v2_v2(AFD.dxt, dx);
1766 // copy_v2_v2(AFD.dyt, dy);
1767
1768 AFD.intpol = 1;
1769 AFD.extflag = TXC_EXTD;
1770
1771 ewa_eval(&texres, ibuf, fx, fy, &AFD);
1772
1773 copy_v4_v4(result, texres.trgba);
1774}
int BKE_image_get_tile_from_pos(Image *ima, const float uv[2], float r_uv[2], float r_ofs[2])
ImBuf * BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool)
void BKE_image_pool_release_ibuf(Image *ima, ImBuf *ibuf, ImagePool *pool)
bool BKE_image_has_loaded_ibuf(Image *image)
MINLINE float max_fff(float a, float b, float c)
MINLINE int round_fl_to_int(float a)
MINLINE float max_ff(float a, float b)
#define M_LOG2E
MINLINE float min_fff(float a, float b, float c)
#define EWA_MAXIDX
const float EWA_WTS[EWA_MAXIDX+1]
void BLI_ewa_filter(int width, int height, bool intpol, bool use_alpha, const float uv[2], const float du[2], const float dv[2], ewa_filter_read_pixel_cb read_pixel_cb, void *userdata, float result[4])
void BLI_ewa_imp2radangle(float A, float B, float C, float F, float *a, float *b, float *th, float *ecc)
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE void add_v4_v4(float r[4], const float a[4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v4(float r[4])
MINLINE void madd_v4_v4fl(float r[4], const float a[4], float f)
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:201
unsigned char uchar
void BLI_thread_unlock(int type)
Definition threads.cc:333
void BLI_thread_lock(int type)
Definition threads.cc:328
@ LOCK_IMAGE
Definition BLI_threads.h:67
#define CLAMP(a, b, c)
#define UNLIKELY(x)
#define ELEM(...)
@ IMA_SRC_TILED
@ IMA_USED_FOR_RENDER
@ IMA_ALPHA_IGNORE
@ TEX_RGB
@ TEX_REPEAT_YMIR
@ TEX_CHECKER_EVEN
@ TEX_NEGALPHA
@ TEX_REPEAT_XMIR
@ TEX_CHECKER_ODD
@ TXF_FELINE
@ TXF_BOX
@ TXF_AREA
@ TXF_EWA
@ TEX_USEALPHA
@ TEX_MIPMAP
@ TEX_CALCALPHA
@ TEX_INTERPOL
@ TEX_GAUSS_MIP
@ TEX_FILTER_MIN
@ TEX_IMAROT
@ TEX_CLIP
@ TEX_EXTEND
@ TEX_CHECKER
@ TEX_REPEAT
@ TEX_CLIPCUBE
void IMB_makemipmap(ImBuf *ibuf, int use_filter)
Definition filter.cc:490
void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
Definition filter.cc:454
Contains defines and structs used throughout the imbuf module.
#define IMB_MIPMAP_LEVELS
@ IB_MIPMAP_INVALID
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
local_group_size(16, 16) .push_constant(Type b
#define logf(x)
#define sinf(x)
#define cosf(x)
#define expf(x)
#define floorf(x)
#define sqrtf(x)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uint col
int count
ccl_device_inline float2 floor(const float2 a)
#define B
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
ImBuf * mipmap[IMB_MIPMAP_LEVELS]
short source
char alpha_mode
const afdata_t * AFD
float tin
Definition RE_texture.h:87
float trgba[4]
Definition RE_texture.h:88
short imaflag
float checkerdist
struct ImageUser iuser
short extend
float filtersize
float dyt[2]
float dxt[2]
float xmax
float xmin
float ymax
float ymin
#define BRICONTRGB
void image_sample(Image *ima, float fx, float fy, float dx, float dy, float result[4], ImagePool *pool)
void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float result[4])
static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres, ImagePool *pool, const bool skip_load_image)
static void feline_eval(TexResult *texr, ImBuf *ibuf, float fx, float fy, const afdata_t *AFD)
static float clipy_rctf(rctf *rf, float y1, float y2)
static float square_rctf(const rctf *rf)
int imagewrap(Tex *tex, Image *ima, const float texvec[3], TexResult *texres, ImagePool *pool, const bool skip_load_image)
@ TXC_YMIR
@ TXC_XMIR
@ TXC_REPT
@ TXC_EXTD
static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float maxy, TexResult *texres, const short imaprepeat, const short imapextend)
static int ibuf_get_color_clip_bilerp(float col[4], ImBuf *ibuf, float u, float v, int intpol, int extflag)
static float clipx_rctf(rctf *rf, float x1, float x2)
static void boxsampleclip(ImBuf *ibuf, const rctf *rf, TexResult *texres)
static void image_mipmap_test(Tex *tex, ImBuf *ibuf)
static void area_sample(TexResult *texr, ImBuf *ibuf, float fx, float fy, const afdata_t *AFD)
static void ibuf_get_color(float col[4], ImBuf *ibuf, int x, int y)
int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const float DXT[2], const float DYT[2], TexResult *texres, ImagePool *pool, const bool skip_load_image)
static void ewa_read_pixel_cb(void *userdata, int x, int y, float result[4])
static void clipx_rctf_swap(rctf *stack, short *count, float x1, float x2)
static void ewa_eval(TexResult *texr, ImBuf *ibuf, float fx, float fy, const afdata_t *AFD)
static void alpha_clip_aniso(const ImBuf *ibuf, float minx, float miny, float maxx, float maxy, int extflag, TexResult *texres)
static void clipy_rctf_swap(rctf *stack, short *count, float y1, float y2)
static int ibuf_get_color_clip(float col[4], ImBuf *ibuf, int x, int y, int extflag)