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
8
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];
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
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
#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