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