Blender V4.3
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
9#include <cmath>
10#include <cstdlib>
11
12#include "BLI_math_base.h"
13#include "BLI_math_color.h"
14#include "BLI_math_vector.h"
15
16#include "BKE_image.hh"
17
18#include "IMB_imbuf.hh"
19#include "IMB_imbuf_types.hh"
20
21#include "BLF_api.hh"
22
25 float *rect_float;
26 int width;
27 float color[4];
28};
29
31 uchar *rect, float *rect_float, int width, int height, const float color[4])
32{
33 int x, y;
34
35 /* blank image */
36 if (rect_float) {
37 for (y = 0; y < height; y++) {
38 for (x = 0; x < width; x++) {
39 copy_v4_v4(rect_float, color);
40 rect_float += 4;
41 }
42 }
43 }
44
45 if (rect) {
46 uchar ccol[4];
47 rgba_float_to_uchar(ccol, color);
48 for (y = 0; y < height; y++) {
49 for (x = 0; x < width; x++) {
50 rect[0] = ccol[0];
51 rect[1] = ccol[1];
52 rect[2] = ccol[2];
53 rect[3] = ccol[3];
54 rect += 4;
55 }
56 }
57 }
58}
59
60static void image_buf_fill_color_thread_do(void *data_v, int scanline)
61{
63 const int num_scanlines = 1;
64 size_t offset = size_t(scanline) * data->width * 4;
65 uchar *rect = (data->rect != nullptr) ? (data->rect + offset) : nullptr;
66 float *rect_float = (data->rect_float != nullptr) ? (data->rect_float + offset) : nullptr;
67 image_buf_fill_color_slice(rect, rect_float, data->width, num_scanlines, data->color);
68}
69
71 uchar *rect, float *rect_float, int width, int height, const float color[4])
72{
73 if (size_t(width) * height < 64 * 64) {
74 image_buf_fill_color_slice(rect, rect_float, width, height, color);
75 }
76 else {
78 data.rect = rect;
79 data.rect_float = rect_float;
80 data.width = width;
81 copy_v4_v4(data.color, color);
83 }
84}
85
87 uchar *rect, float *rect_float, int width, int height, int offset)
88{
89 /* these two passes could be combined into one, but it's more readable and
90 * easy to tweak like this, speed isn't really that much of an issue in this situation... */
91
92 int checkerwidth = 32;
93 int x, y;
94
95 uchar *rect_orig = rect;
96 float *rect_float_orig = rect_float;
97
98 float hsv[3] = {0.0f, 0.9f, 0.9f};
99 float rgb[3];
100
101 float dark_linear_color = 0.0f, bright_linear_color = 0.0f;
102 if (rect_float != nullptr) {
103 dark_linear_color = srgb_to_linearrgb(0.25f);
104 bright_linear_color = srgb_to_linearrgb(0.58f);
105 }
106
107 /* checkers */
108 for (y = offset; y < height + offset; y++) {
109 int dark = powf(-1.0f, floorf(y / checkerwidth));
110
111 for (x = 0; x < width; x++) {
112 if (x % checkerwidth == 0) {
113 dark = -dark;
114 }
115
116 if (rect_float) {
117 if (dark > 0) {
118 rect_float[0] = rect_float[1] = rect_float[2] = dark_linear_color;
119 rect_float[3] = 1.0f;
120 }
121 else {
122 rect_float[0] = rect_float[1] = rect_float[2] = bright_linear_color;
123 rect_float[3] = 1.0f;
124 }
125 rect_float += 4;
126 }
127 else {
128 if (dark > 0) {
129 rect[0] = rect[1] = rect[2] = 64;
130 rect[3] = 255;
131 }
132 else {
133 rect[0] = rect[1] = rect[2] = 150;
134 rect[3] = 255;
135 }
136 rect += 4;
137 }
138 }
139 }
140
141 rect = rect_orig;
142 rect_float = rect_float_orig;
143
144 /* 2nd pass, colored `+`. */
145 for (y = offset; y < height + offset; y++) {
146 float hoffs = 0.125f * floorf(y / checkerwidth);
147
148 for (x = 0; x < width; x++) {
149 float h = 0.125f * floorf(x / checkerwidth);
150
151 if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 4) &&
152 (abs((y % checkerwidth) - (checkerwidth / 2)) < 4))
153 {
154 if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 1) ||
155 (abs((y % checkerwidth) - (checkerwidth / 2)) < 1))
156 {
157 hsv[0] = fmodf(fabsf(h - hoffs), 1.0f);
158 hsv_to_rgb_v(hsv, rgb);
159
160 if (rect) {
161 rect[0] = char(rgb[0] * 255.0f);
162 rect[1] = char(rgb[1] * 255.0f);
163 rect[2] = char(rgb[2] * 255.0f);
164 rect[3] = 255;
165 }
166
167 if (rect_float) {
168 srgb_to_linearrgb_v3_v3(rect_float, rgb);
169 rect_float[3] = 1.0f;
170 }
171 }
172 }
173
174 if (rect_float) {
175 rect_float += 4;
176 }
177 if (rect) {
178 rect += 4;
179 }
180 }
181 }
182}
183
189
190static void image_buf_fill_checker_thread_do(void *data_v, int scanline)
191{
193 size_t offset = size_t(scanline) * data->width * 4;
194 const int num_scanlines = 1;
195 uchar *rect = (data->rect != nullptr) ? (data->rect + offset) : nullptr;
196 float *rect_float = (data->rect_float != nullptr) ? (data->rect_float + offset) : nullptr;
197 image_buf_fill_checker_slice(rect, rect_float, data->width, num_scanlines, scanline);
198}
199
200void BKE_image_buf_fill_checker(uchar *rect, float *rect_float, int width, int height)
201{
202 if (size_t(width) * height < 64 * 64) {
203 image_buf_fill_checker_slice(rect, rect_float, width, height, 0);
204 }
205 else {
207 data.rect = rect;
208 data.rect_float = rect_float;
209 data.width = width;
211 }
212}
213
214/* Utility functions for BKE_image_buf_fill_checker_color */
215
216#define BLEND_FLOAT(real, add) (real + add <= 1.0f) ? (real + add) : 1.0f
217#define BLEND_CHAR(real, add) \
218 ((real + char(add * 255.0f)) <= 255) ? (real + char(add * 255.0f)) : 255
219
221 uchar *rect, float *rect_float, int width, int height, int offset, int total_height)
222{
223 int hue_step, y, x;
224 float hsv[3], rgb[3];
225
226 hsv[1] = 1.0;
227
228 hue_step = power_of_2_max_i(width / 8);
229 if (hue_step < 8) {
230 hue_step = 8;
231 }
232
233 for (y = offset; y < height + offset; y++) {
234 /* Use a number lower than 1.0 else its too bright. */
235 hsv[2] = 0.1 + (y * (0.4 / total_height));
236
237 for (x = 0; x < width; x++) {
238 hsv[0] = float(double(x / hue_step) * 1.0 / width * hue_step);
239 hsv_to_rgb_v(hsv, rgb);
240
241 if (rect) {
242 rect[0] = char(rgb[0] * 255.0f);
243 rect[1] = char(rgb[1] * 255.0f);
244 rect[2] = char(rgb[2] * 255.0f);
245 rect[3] = 255;
246
247 rect += 4;
248 }
249
250 if (rect_float) {
251 rect_float[0] = rgb[0];
252 rect_float[1] = rgb[1];
253 rect_float[2] = rgb[2];
254 rect_float[3] = 1.0f;
255
256 rect_float += 4;
257 }
258 }
259 }
260}
261
263 uchar *rect, float *rect_float, int width, int height, int size, float blend, int offset)
264{
265 int x, y;
266 float blend_half = blend * 0.5f;
267
268 for (y = offset; y < height + offset; y++) {
269 for (x = 0; x < width; x++) {
270 if (((y / size) % 2 == 1 && (x / size) % 2 == 1) ||
271 ((y / size) % 2 == 0 && (x / size) % 2 == 0))
272 {
273 if (rect) {
274 rect[0] = char(BLEND_CHAR(rect[0], blend));
275 rect[1] = char(BLEND_CHAR(rect[1], blend));
276 rect[2] = char(BLEND_CHAR(rect[2], blend));
277 rect[3] = 255;
278
279 rect += 4;
280 }
281 if (rect_float) {
282 rect_float[0] = BLEND_FLOAT(rect_float[0], blend);
283 rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
284 rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
285 rect_float[3] = 1.0f;
286
287 rect_float += 4;
288 }
289 }
290 else {
291 if (rect) {
292 rect[0] = char(BLEND_CHAR(rect[0], blend_half));
293 rect[1] = char(BLEND_CHAR(rect[1], blend_half));
294 rect[2] = char(BLEND_CHAR(rect[2], blend_half));
295 rect[3] = 255;
296
297 rect += 4;
298 }
299 if (rect_float) {
300 rect_float[0] = BLEND_FLOAT(rect_float[0], blend_half);
301 rect_float[1] = BLEND_FLOAT(rect_float[1], blend_half);
302 rect_float[2] = BLEND_FLOAT(rect_float[2], blend_half);
303 rect_float[3] = 1.0f;
304
305 rect_float += 4;
306 }
307 }
308 }
309 }
310}
311
313 uchar *rect, float *rect_float, int width, int height, float blend, int offset)
314{
315 int x, y;
316 for (y = offset; y < height + offset; y++) {
317 for (x = 0; x < width; x++) {
318 if (((y % 32) == 0) || ((x % 32) == 0) || x == 0) {
319 if (rect) {
320 rect[0] = BLEND_CHAR(rect[0], blend);
321 rect[1] = BLEND_CHAR(rect[1], blend);
322 rect[2] = BLEND_CHAR(rect[2], blend);
323 rect[3] = 255;
324
325 rect += 4;
326 }
327 if (rect_float) {
328 rect_float[0] = BLEND_FLOAT(rect_float[0], blend);
329 rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
330 rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
331 rect_float[3] = 1.0f;
332
333 rect_float += 4;
334 }
335 }
336 else {
337 if (rect_float) {
338 rect_float += 4;
339 }
340 if (rect) {
341 rect += 4;
342 }
343 }
344 }
345 }
346}
347
348/* Defined in `image.cc`. */
349
351 uchar *rect, float *rect_float, int width, int height, int step, int outline)
352{
353 int x, y;
354 int pen_x, pen_y;
355 char text[3] = {'A', '1', '\0'};
356 const int mono = blf_mono_font_render;
357
358 BLF_size(mono, 54.0f); /* hard coded size! */
359
360 /* OCIO_TODO: using nullptr as display will assume using sRGB display
361 * this is correct since currently generated images are assumed to be in sRGB space,
362 * but this would probably needed to be fixed in some way
363 */
364 BLF_buffer(mono, rect_float, rect, width, height, nullptr);
365
366 const float text_color[4] = {0.0, 0.0, 0.0, 1.0};
367 const float text_outline[4] = {1.0, 1.0, 1.0, 1.0};
368
369 const char char_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
370 /* Subtract one because of null termination. */
371 const int char_num = sizeof(char_array) - 1;
372
373 int first_char_index = 0;
374 for (y = 0; y < height; y += step) {
375 text[0] = char_array[first_char_index];
376
377 int second_char_index = 27;
378 for (x = 0; x < width; x += step) {
379 text[1] = char_array[second_char_index];
380
381 /* hard coded offset */
382 pen_x = x + 33;
383 pen_y = y + 44;
384
385 /* terribly crappy outline font! */
386 BLF_buffer_col(mono, text_outline);
387
388 BLF_position(mono, pen_x - outline, pen_y, 0.0);
389 BLF_draw_buffer(mono, text, 2);
390 BLF_position(mono, pen_x + outline, pen_y, 0.0);
391 BLF_draw_buffer(mono, text, 2);
392 BLF_position(mono, pen_x, pen_y - outline, 0.0);
393 BLF_draw_buffer(mono, text, 2);
394 BLF_position(mono, pen_x, pen_y + outline, 0.0);
395 BLF_draw_buffer(mono, text, 2);
396
397 BLF_position(mono, pen_x - outline, pen_y - outline, 0.0);
398 BLF_draw_buffer(mono, text, 2);
399 BLF_position(mono, pen_x + outline, pen_y + outline, 0.0);
400 BLF_draw_buffer(mono, text, 2);
401 BLF_position(mono, pen_x - outline, pen_y + outline, 0.0);
402 BLF_draw_buffer(mono, text, 2);
403 BLF_position(mono, pen_x + outline, pen_y - outline, 0.0);
404 BLF_draw_buffer(mono, text, 2);
405
406 BLF_buffer_col(mono, text_color);
407 BLF_position(mono, pen_x, pen_y, 0.0);
408 BLF_draw_buffer(mono, text, 2);
409
410 second_char_index = (second_char_index + 1) % char_num;
411 }
412 first_char_index = (first_char_index + 1) % char_num;
413 }
414
415 /* cleanup the buffer. */
416 BLF_buffer(mono, nullptr, nullptr, 0, 0, nullptr);
417}
418
420 uchar *rect, float *rect_float, int width, int height, int offset, int total_height)
421{
422 checker_board_color_fill(rect, rect_float, width, height, offset, total_height);
423 checker_board_color_tint(rect, rect_float, width, height, 1, 0.03f, offset);
424 checker_board_color_tint(rect, rect_float, width, height, 4, 0.05f, offset);
425 checker_board_color_tint(rect, rect_float, width, height, 32, 0.07f, offset);
426 checker_board_color_tint(rect, rect_float, width, height, 128, 0.15f, offset);
427 checker_board_grid_fill(rect, rect_float, width, height, 1.0f / 4.0f, offset);
428}
429
435
436static void checker_board_color_prepare_thread_do(void *data_v, int scanline)
437{
439 const int num_scanlines = 1;
440 size_t offset = size_t(data->width) * scanline * 4;
441 uchar *rect = (data->rect != nullptr) ? (data->rect + offset) : nullptr;
442 float *rect_float = (data->rect_float != nullptr) ? (data->rect_float + offset) : nullptr;
444 rect, rect_float, data->width, num_scanlines, scanline, data->height);
445}
446
447void BKE_image_buf_fill_checker_color(uchar *rect, float *rect_float, int width, int height)
448{
449 if (size_t(width) * height < 64 * 64) {
450 checker_board_color_prepare_slice(rect, rect_float, width, height, 0, height);
451 }
452 else {
454 data.rect = rect;
455 data.rect_float = rect_float;
456 data.width = width;
457 data.height = height;
459 }
460
461 checker_board_text(rect, rect_float, width, height, 128, 2);
462
463 if (rect_float != nullptr) {
464 /* TODO(sergey): Currently it's easier to fill in form buffer and
465 * linearize it afterwards. This could be optimized with some smart
466 * trickery around blending factors and such.
467 */
469 rect_float,
470 4,
473 true,
474 width,
475 height,
476 width,
477 width);
478 }
479}
void BLF_size(int fontid, float size)
Definition blf.cc:426
void BLF_draw_buffer(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_NONNULL(2)
Definition blf.cc:962
int blf_mono_font_render
Definition blf.cc:52
void BLF_buffer_col(int fontid, const float rgba[4]) ATTR_NONNULL(2)
Definition blf.cc:937
void BLF_buffer(int fontid, float *fbuf, unsigned char *cbuf, int w, int h, ColorManagedDisplay *display)
Definition blf.cc:924
void BLF_position(int fontid, float x, float y, float z)
Definition blf.cc:371
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_processor_apply_threaded_scanlines(int total_scanlines, ScanlineThreadFunc do_thread, void *custom_data)
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)
Definition divers.cc:534
Contains defines and structs used throughout the imbuf module.
#define IB_PROFILE_SRGB
#define IB_PROFILE_LINEAR_RGB
#define powf(x, y)
#define fmodf(x, y)
#define floorf(x)
#define fabsf(x)
draw_view in_light_buf[] float
void BKE_image_buf_fill_checker_color(uchar *rect, float *rect_float, int width, int height)
Definition image_gen.cc:447
static void image_buf_fill_color_thread_do(void *data_v, int scanline)
Definition image_gen.cc:60
static void image_buf_fill_checker_thread_do(void *data_v, int scanline)
Definition image_gen.cc:190
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:262
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:419
#define BLEND_FLOAT(real, add)
Definition image_gen.cc:216
static void checker_board_color_prepare_thread_do(void *data_v, int scanline)
Definition image_gen.cc:436
#define BLEND_CHAR(real, add)
Definition image_gen.cc:217
static void checker_board_text(uchar *rect, float *rect_float, int width, int height, int step, int outline)
Definition image_gen.cc:350
static void checker_board_color_fill(uchar *rect, float *rect_float, int width, int height, int offset, int total_height)
Definition image_gen.cc:220
static void image_buf_fill_checker_slice(uchar *rect, float *rect_float, int width, int height, int offset)
Definition image_gen.cc:86
static void image_buf_fill_color_slice(uchar *rect, float *rect_float, int width, int height, const float color[4])
Definition image_gen.cc:30
void BKE_image_buf_fill_checker(uchar *rect, float *rect_float, int width, int height)
Definition image_gen.cc:200
void BKE_image_buf_fill_color(uchar *rect, float *rect_float, int width, int height, const float color[4])
Definition image_gen.cc:70
static void checker_board_grid_fill(uchar *rect, float *rect_float, int width, int height, float blend, int offset)
Definition image_gen.cc:312
ccl_device_inline int abs(int x)
Definition util/math.h:120