Blender V4.5
image_gen.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <cmath>
11#include <cstdlib>
12
13#include "BLI_math_base.h"
14#include "BLI_math_color.h"
15#include "BLI_math_vector.h"
16#include "BLI_task.hh"
17
18#include "BKE_image.hh"
19
20#include "IMB_imbuf.hh"
21#include "IMB_imbuf_types.hh"
22
23#include "BLF_api.hh"
24
26 uchar *rect_byte, float *rect_float, int width, int height, const float color[4])
27{
28 using namespace blender;
30 IndexRange(int64_t(width) * height), 64 * 1024, [&](const IndexRange i_range) {
31 if (rect_float != nullptr) {
32 float *dst = rect_float + i_range.first() * 4;
33 for ([[maybe_unused]] const int64_t i : i_range) {
34 copy_v4_v4(dst, color);
35 dst += 4;
36 }
37 }
38 if (rect_byte != nullptr) {
39 uchar ccol[4];
41 uchar *dst = rect_byte + i_range.first() * 4;
42 for ([[maybe_unused]] const int64_t i : i_range) {
43 dst[0] = ccol[0];
44 dst[1] = ccol[1];
45 dst[2] = ccol[2];
46 dst[3] = ccol[3];
47 dst += 4;
48 }
49 }
50 });
51}
52
54 uchar *rect, float *rect_float, int width, int height, int offset)
55{
56 /* these two passes could be combined into one, but it's more readable and
57 * easy to tweak like this, speed isn't really that much of an issue in this situation... */
58 const int checker_size = 32;
59 const int checker_size_half = checker_size / 2;
60
61 uchar *rect_orig = rect;
62 float *rect_float_orig = rect_float;
63
64 float hsv[3] = {0.0f, 0.9f, 0.9f};
65 float rgb[3];
66
67 float dark_linear_color = 0.0f, bright_linear_color = 0.0f;
68 if (rect_float != nullptr) {
69 dark_linear_color = srgb_to_linearrgb(0.25f);
70 bright_linear_color = srgb_to_linearrgb(0.58f);
71 }
72
73 /* checkers */
74 for (int y = offset; y < height + offset; y++) {
75 int dark = powf(-1.0f, floorf(y / checker_size));
76
77 for (int x = 0; x < width; x++) {
78 if (x % checker_size == 0) {
79 dark = -dark;
80 }
81
82 if (rect_float) {
83 if (dark > 0) {
84 rect_float[0] = rect_float[1] = rect_float[2] = dark_linear_color;
85 rect_float[3] = 1.0f;
86 }
87 else {
88 rect_float[0] = rect_float[1] = rect_float[2] = bright_linear_color;
89 rect_float[3] = 1.0f;
90 }
91 rect_float += 4;
92 }
93 else {
94 if (dark > 0) {
95 rect[0] = rect[1] = rect[2] = 64;
96 rect[3] = 255;
97 }
98 else {
99 rect[0] = rect[1] = rect[2] = 150;
100 rect[3] = 255;
101 }
102 rect += 4;
103 }
104 }
105 }
106
107 rect = rect_orig;
108 rect_float = rect_float_orig;
109
110 /* 2nd pass, colored `+`. */
111 for (int y = offset; y < height + offset; y++) {
112 float hoffs = 0.125f * floorf(y / checker_size);
113
114 for (int x = 0; x < width; x++) {
115 float h = 0.125f * floorf(x / checker_size);
116 int test_x, test_y;
117 /* Note that this `+` is not exactly centered since it's a 1px wide line being
118 * drawn inside an even sized square, keep as-is since solving requires either
119 * using odd sized checkers or double-width lines, see #112653. */
120 if (((test_x = abs((x % checker_size) - checker_size_half)) < 4) &&
121 ((test_y = abs((y % checker_size) - checker_size_half)) < 4) &&
122 ((test_x < 1) || (test_y < 1)))
123 {
124 hsv[0] = fmodf(fabsf(h - hoffs), 1.0f);
125 hsv_to_rgb_v(hsv, rgb);
126
127 if (rect) {
128 rect[0] = char(rgb[0] * 255.0f);
129 rect[1] = char(rgb[1] * 255.0f);
130 rect[2] = char(rgb[2] * 255.0f);
131 rect[3] = 255;
132 }
133
134 if (rect_float) {
135 srgb_to_linearrgb_v3_v3(rect_float, rgb);
136 rect_float[3] = 1.0f;
137 }
138 }
139
140 if (rect_float) {
141 rect_float += 4;
142 }
143 if (rect) {
144 rect += 4;
145 }
146 }
147 }
148}
149
150void BKE_image_buf_fill_checker(uchar *rect, float *rect_float, int width, int height)
151{
152 using namespace blender;
153 threading::parallel_for(IndexRange(height), 64, [&](const IndexRange y_range) {
154 int64_t offset = y_range.first() * width * 4;
155 uchar *dst_byte = (rect != nullptr) ? (rect + offset) : nullptr;
156 float *dst_float = (rect_float != nullptr) ? (rect_float + offset) : nullptr;
157 image_buf_fill_checker_slice(dst_byte, dst_float, width, y_range.size(), y_range.first());
158 });
159}
160
161/* Utility functions for BKE_image_buf_fill_checker_color */
162
163#define BLEND_FLOAT(real, add) (real + add <= 1.0f) ? (real + add) : 1.0f
164#define BLEND_CHAR(real, add) \
165 ((real + char(add * 255.0f)) <= 255) ? (real + char(add * 255.0f)) : 255
166
168 uchar *rect, float *rect_float, int width, int height, int offset, int total_height)
169{
170 int hue_step, y, x;
171 float hsv[3], rgb[3];
172
173 hsv[1] = 1.0;
174
175 hue_step = power_of_2_max_i(width / 8);
176 hue_step = std::max(hue_step, 8);
177
178 for (y = offset; y < height + offset; y++) {
179 /* Use a number lower than 1.0 else its too bright. */
180 hsv[2] = 0.1 + (y * (0.4 / total_height));
181
182 for (x = 0; x < width; x++) {
183 hsv[0] = float(double(x / hue_step) * 1.0 / width * hue_step);
184 hsv_to_rgb_v(hsv, rgb);
185
186 if (rect) {
187 rect[0] = char(rgb[0] * 255.0f);
188 rect[1] = char(rgb[1] * 255.0f);
189 rect[2] = char(rgb[2] * 255.0f);
190 rect[3] = 255;
191
192 rect += 4;
193 }
194
195 if (rect_float) {
196 rect_float[0] = rgb[0];
197 rect_float[1] = rgb[1];
198 rect_float[2] = rgb[2];
199 rect_float[3] = 1.0f;
200
201 rect_float += 4;
202 }
203 }
204 }
205}
206
208 uchar *rect, float *rect_float, int width, int height, int size, float blend, int offset)
209{
210 int x, y;
211 float blend_half = blend * 0.5f;
212
213 for (y = offset; y < height + offset; y++) {
214 for (x = 0; x < width; x++) {
215 if (((y / size) % 2 == 1 && (x / size) % 2 == 1) ||
216 ((y / size) % 2 == 0 && (x / size) % 2 == 0))
217 {
218 if (rect) {
219 rect[0] = char(BLEND_CHAR(rect[0], blend));
220 rect[1] = char(BLEND_CHAR(rect[1], blend));
221 rect[2] = char(BLEND_CHAR(rect[2], blend));
222 rect[3] = 255;
223
224 rect += 4;
225 }
226 if (rect_float) {
227 rect_float[0] = BLEND_FLOAT(rect_float[0], blend);
228 rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
229 rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
230 rect_float[3] = 1.0f;
231
232 rect_float += 4;
233 }
234 }
235 else {
236 if (rect) {
237 rect[0] = char(BLEND_CHAR(rect[0], blend_half));
238 rect[1] = char(BLEND_CHAR(rect[1], blend_half));
239 rect[2] = char(BLEND_CHAR(rect[2], blend_half));
240 rect[3] = 255;
241
242 rect += 4;
243 }
244 if (rect_float) {
245 rect_float[0] = BLEND_FLOAT(rect_float[0], blend_half);
246 rect_float[1] = BLEND_FLOAT(rect_float[1], blend_half);
247 rect_float[2] = BLEND_FLOAT(rect_float[2], blend_half);
248 rect_float[3] = 1.0f;
249
250 rect_float += 4;
251 }
252 }
253 }
254 }
255}
256
258 uchar *rect, float *rect_float, int width, int height, float blend, int offset)
259{
260 int x, y;
261 for (y = offset; y < height + offset; y++) {
262 for (x = 0; x < width; x++) {
263 if (((y % 32) == 0) || ((x % 32) == 0) || x == 0) {
264 if (rect) {
265 rect[0] = BLEND_CHAR(rect[0], blend);
266 rect[1] = BLEND_CHAR(rect[1], blend);
267 rect[2] = BLEND_CHAR(rect[2], blend);
268 rect[3] = 255;
269
270 rect += 4;
271 }
272 if (rect_float) {
273 rect_float[0] = BLEND_FLOAT(rect_float[0], blend);
274 rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
275 rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
276 rect_float[3] = 1.0f;
277
278 rect_float += 4;
279 }
280 }
281 else {
282 if (rect_float) {
283 rect_float += 4;
284 }
285 if (rect) {
286 rect += 4;
287 }
288 }
289 }
290 }
291}
292
293/* Defined in `image.cc`. */
294
296 uchar *rect, float *rect_float, int width, int height, int step, int outline)
297{
298 int x, y;
299 int pen_x, pen_y;
300 char text[3] = {'A', '1', '\0'};
301 const int mono = blf_mono_font_render;
302
303 BLF_size(mono, 54.0f); /* hard coded size! */
304
305 /* OCIO_TODO: using nullptr as display will assume using sRGB display
306 * this is correct since currently generated images are assumed to be in sRGB space,
307 * but this would probably needed to be fixed in some way
308 */
309 BLF_buffer(mono, rect_float, rect, width, height, nullptr);
310
311 const float text_color[4] = {0.0, 0.0, 0.0, 1.0};
312 const float text_outline[4] = {1.0, 1.0, 1.0, 1.0};
313
314 const char char_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
315 /* Subtract one because of null termination. */
316 const int char_num = sizeof(char_array) - 1;
317
318 int first_char_index = 0;
319 for (y = 0; y < height; y += step) {
320 text[0] = char_array[first_char_index];
321
322 int second_char_index = 27;
323 for (x = 0; x < width; x += step) {
324 text[1] = char_array[second_char_index];
325
326 /* hard coded offset */
327 pen_x = x + 33;
328 pen_y = y + 44;
329
330 /* terribly crappy outline font! */
331 BLF_buffer_col(mono, text_outline);
332
333 BLF_position(mono, pen_x - outline, pen_y, 0.0);
334 BLF_draw_buffer(mono, text, 2);
335 BLF_position(mono, pen_x + outline, pen_y, 0.0);
336 BLF_draw_buffer(mono, text, 2);
337 BLF_position(mono, pen_x, pen_y - outline, 0.0);
338 BLF_draw_buffer(mono, text, 2);
339 BLF_position(mono, pen_x, pen_y + outline, 0.0);
340 BLF_draw_buffer(mono, text, 2);
341
342 BLF_position(mono, pen_x - outline, pen_y - outline, 0.0);
343 BLF_draw_buffer(mono, text, 2);
344 BLF_position(mono, pen_x + outline, pen_y + outline, 0.0);
345 BLF_draw_buffer(mono, text, 2);
346 BLF_position(mono, pen_x - outline, pen_y + outline, 0.0);
347 BLF_draw_buffer(mono, text, 2);
348 BLF_position(mono, pen_x + outline, pen_y - outline, 0.0);
349 BLF_draw_buffer(mono, text, 2);
350
351 BLF_buffer_col(mono, text_color);
352 BLF_position(mono, pen_x, pen_y, 0.0);
353 BLF_draw_buffer(mono, text, 2);
354
355 second_char_index = (second_char_index + 1) % char_num;
356 }
357 first_char_index = (first_char_index + 1) % char_num;
358 }
359
360 /* cleanup the buffer. */
361 BLF_buffer(mono, nullptr, nullptr, 0, 0, nullptr);
362}
363
365 uchar *rect, float *rect_float, int width, int height, int offset, int total_height)
366{
367 checker_board_color_fill(rect, rect_float, width, height, offset, total_height);
368 checker_board_color_tint(rect, rect_float, width, height, 1, 0.03f, offset);
369 checker_board_color_tint(rect, rect_float, width, height, 4, 0.05f, offset);
370 checker_board_color_tint(rect, rect_float, width, height, 32, 0.07f, offset);
371 checker_board_color_tint(rect, rect_float, width, height, 128, 0.15f, offset);
372 checker_board_grid_fill(rect, rect_float, width, height, 1.0f / 4.0f, offset);
373}
374
375void BKE_image_buf_fill_checker_color(uchar *rect, float *rect_float, int width, int height)
376{
377 using namespace blender;
378 threading::parallel_for(IndexRange(height), 64, [&](const IndexRange y_range) {
379 int64_t offset = y_range.first() * width * 4;
380 uchar *dst_byte = (rect != nullptr) ? (rect + offset) : nullptr;
381 float *dst_float = (rect_float != nullptr) ? (rect_float + offset) : nullptr;
383 dst_byte, dst_float, width, y_range.size(), y_range.first(), height);
384 });
385
386 checker_board_text(rect, rect_float, width, height, 128, 2);
387
388 if (rect_float != nullptr) {
389 /* TODO(sergey): Currently it's easier to fill in form buffer and
390 * linearize it afterwards. This could be optimized with some smart
391 * trickery around blending factors and such.
392 */
394 rect_float,
395 4,
398 true,
399 width,
400 height,
401 width,
402 width);
403 }
404}
void BLF_size(int fontid, float size)
Definition blf.cc:440
void BLF_draw_buffer(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_NONNULL(2)
Definition blf.cc:1035
void BLF_buffer(int fontid, float *fbuf, unsigned char *cbuf, int w, int h, const ColorManagedDisplay *display)
Definition blf.cc:950
int blf_mono_font_render
Definition blf.cc:49
void BLF_buffer_col(int fontid, const float rgba[4]) ATTR_NONNULL(2)
Definition blf.cc:1010
void BLF_position(int fontid, float x, float y, float z)
Definition blf.cc:385
MINLINE int power_of_2_max_i(int n)
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition math_color.cc:57
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
float srgb_to_linearrgb(float c)
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
MINLINE void copy_v4_v4(float r[4], const float a[4])
unsigned char uchar
void IMB_buffer_float_from_float_threaded(float *rect_to, const float *rect_from, int channels_from, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
#define IB_PROFILE_SRGB
#define IB_PROFILE_LINEAR_RGB
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
constexpr int64_t first() const
constexpr int64_t size() const
#define powf(x, y)
#define fmodf(x, y)
#define floorf(x)
#define fabsf(x)
#define abs
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
void BKE_image_buf_fill_checker_color(uchar *rect, float *rect_float, int width, int height)
Definition image_gen.cc:375
static void checker_board_color_tint(uchar *rect, float *rect_float, int width, int height, int size, float blend, int offset)
Definition image_gen.cc:207
void BKE_image_buf_fill_color(uchar *rect_byte, float *rect_float, int width, int height, const float color[4])
Definition image_gen.cc:25
static void checker_board_color_prepare_slice(uchar *rect, float *rect_float, int width, int height, int offset, int total_height)
Definition image_gen.cc:364
#define BLEND_FLOAT(real, add)
Definition image_gen.cc:163
#define BLEND_CHAR(real, add)
Definition image_gen.cc:164
static void checker_board_text(uchar *rect, float *rect_float, int width, int height, int step, int outline)
Definition image_gen.cc:295
static void checker_board_color_fill(uchar *rect, float *rect_float, int width, int height, int offset, int total_height)
Definition image_gen.cc:167
static void image_buf_fill_checker_slice(uchar *rect, float *rect_float, int width, int height, int offset)
Definition image_gen.cc:53
void BKE_image_buf_fill_checker(uchar *rect, float *rect_float, int width, int height)
Definition image_gen.cc:150
static void checker_board_grid_fill(uchar *rect, float *rect_float, int width, int height, float blend, int offset)
Definition image_gen.cc:257
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
i
Definition text_draw.cc:230
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)