Blender  V3.3
image_gen.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <math.h>
8 #include <stdlib.h>
9 
10 #include "BLI_math_base.h"
11 #include "BLI_math_color.h"
12 #include "BLI_math_vector.h"
13 
14 #include "BKE_image.h"
15 
16 #include "IMB_imbuf.h"
17 #include "IMB_imbuf_types.h"
18 
19 #include "BLF_api.h"
20 
21 typedef struct FillColorThreadData {
22  unsigned char *rect;
23  float *rect_float;
24  int width;
25  float color[4];
27 
29  unsigned char *rect, float *rect_float, int width, int height, const float color[4])
30 {
31  int x, y;
32 
33  /* blank image */
34  if (rect_float) {
35  for (y = 0; y < height; y++) {
36  for (x = 0; x < width; x++) {
37  copy_v4_v4(rect_float, color);
38  rect_float += 4;
39  }
40  }
41  }
42 
43  if (rect) {
44  unsigned char ccol[4];
46  for (y = 0; y < height; y++) {
47  for (x = 0; x < width; x++) {
48  rect[0] = ccol[0];
49  rect[1] = ccol[1];
50  rect[2] = ccol[2];
51  rect[3] = ccol[3];
52  rect += 4;
53  }
54  }
55  }
56 }
57 
58 static void image_buf_fill_color_thread_do(void *data_v, int scanline)
59 {
61  const int num_scanlines = 1;
62  size_t offset = ((size_t)scanline) * data->width * 4;
63  unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
64  float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
65  image_buf_fill_color_slice(rect, rect_float, data->width, num_scanlines, data->color);
66 }
67 
69  unsigned char *rect, float *rect_float, int width, int height, const float color[4])
70 {
71  if (((size_t)width) * height < 64 * 64) {
72  image_buf_fill_color_slice(rect, rect_float, width, height, color);
73  }
74  else {
76  data.rect = rect;
77  data.rect_float = rect_float;
78  data.width = width;
79  copy_v4_v4(data.color, color);
81  }
82 }
83 
85  unsigned char *rect, float *rect_float, int width, int height, int offset)
86 {
87  /* these two passes could be combined into one, but it's more readable and
88  * easy to tweak like this, speed isn't really that much of an issue in this situation... */
89 
90  int checkerwidth = 32;
91  int x, y;
92 
93  unsigned char *rect_orig = rect;
94  float *rect_float_orig = rect_float;
95 
96  float hsv[3] = {0.0f, 0.9f, 0.9f};
97  float rgb[3];
98 
99  float dark_linear_color = 0.0f, bright_linear_color = 0.0f;
100  if (rect_float != NULL) {
101  dark_linear_color = srgb_to_linearrgb(0.25f);
102  bright_linear_color = srgb_to_linearrgb(0.58f);
103  }
104 
105  /* checkers */
106  for (y = offset; y < height + offset; y++) {
107  int dark = powf(-1.0f, floorf(y / checkerwidth));
108 
109  for (x = 0; x < width; x++) {
110  if (x % checkerwidth == 0) {
111  dark = -dark;
112  }
113 
114  if (rect_float) {
115  if (dark > 0) {
116  rect_float[0] = rect_float[1] = rect_float[2] = dark_linear_color;
117  rect_float[3] = 1.0f;
118  }
119  else {
120  rect_float[0] = rect_float[1] = rect_float[2] = bright_linear_color;
121  rect_float[3] = 1.0f;
122  }
123  rect_float += 4;
124  }
125  else {
126  if (dark > 0) {
127  rect[0] = rect[1] = rect[2] = 64;
128  rect[3] = 255;
129  }
130  else {
131  rect[0] = rect[1] = rect[2] = 150;
132  rect[3] = 255;
133  }
134  rect += 4;
135  }
136  }
137  }
138 
139  rect = rect_orig;
140  rect_float = rect_float_orig;
141 
142  /* 2nd pass, colored + */
143  for (y = offset; y < height + offset; y++) {
144  float hoffs = 0.125f * floorf(y / checkerwidth);
145 
146  for (x = 0; x < width; x++) {
147  float h = 0.125f * floorf(x / checkerwidth);
148 
149  if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 4) &&
150  (abs((y % checkerwidth) - (checkerwidth / 2)) < 4)) {
151  if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 1) ||
152  (abs((y % checkerwidth) - (checkerwidth / 2)) < 1)) {
153  hsv[0] = fmodf(fabsf(h - hoffs), 1.0f);
154  hsv_to_rgb_v(hsv, rgb);
155 
156  if (rect) {
157  rect[0] = (char)(rgb[0] * 255.0f);
158  rect[1] = (char)(rgb[1] * 255.0f);
159  rect[2] = (char)(rgb[2] * 255.0f);
160  rect[3] = 255;
161  }
162 
163  if (rect_float) {
164  srgb_to_linearrgb_v3_v3(rect_float, rgb);
165  rect_float[3] = 1.0f;
166  }
167  }
168  }
169 
170  if (rect_float) {
171  rect_float += 4;
172  }
173  if (rect) {
174  rect += 4;
175  }
176  }
177  }
178 }
179 
180 typedef struct FillCheckerThreadData {
181  unsigned char *rect;
182  float *rect_float;
183  int width;
185 
186 static void image_buf_fill_checker_thread_do(void *data_v, int scanline)
187 {
189  size_t offset = ((size_t)scanline) * data->width * 4;
190  const int num_scanlines = 1;
191  unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
192  float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
193  image_buf_fill_checker_slice(rect, rect_float, data->width, num_scanlines, scanline);
194 }
195 
196 void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height)
197 {
198  if (((size_t)width) * height < 64 * 64) {
199  image_buf_fill_checker_slice(rect, rect_float, width, height, 0);
200  }
201  else {
203  data.rect = rect;
204  data.rect_float = rect_float;
205  data.width = width;
207  }
208 }
209 
210 /* Utility functions for BKE_image_buf_fill_checker_color */
211 
212 #define BLEND_FLOAT(real, add) (real + add <= 1.0f) ? (real + add) : 1.0f
213 #define BLEND_CHAR(real, add) \
214  ((real + (char)(add * 255.0f)) <= 255) ? (real + (char)(add * 255.0f)) : 255
215 
217  unsigned char *rect, float *rect_float, int width, int height, int offset, int total_height)
218 {
219  int hue_step, y, x;
220  float hsv[3], rgb[3];
221 
222  hsv[1] = 1.0;
223 
224  hue_step = power_of_2_max_i(width / 8);
225  if (hue_step < 8) {
226  hue_step = 8;
227  }
228 
229  for (y = offset; y < height + offset; y++) {
230  /* Use a number lower than 1.0 else its too bright. */
231  hsv[2] = 0.1 + (y * (0.4 / total_height));
232 
233  for (x = 0; x < width; x++) {
234  hsv[0] = (float)((double)(x / hue_step) * 1.0 / width * hue_step);
235  hsv_to_rgb_v(hsv, rgb);
236 
237  if (rect) {
238  rect[0] = (char)(rgb[0] * 255.0f);
239  rect[1] = (char)(rgb[1] * 255.0f);
240  rect[2] = (char)(rgb[2] * 255.0f);
241  rect[3] = 255;
242 
243  rect += 4;
244  }
245 
246  if (rect_float) {
247  rect_float[0] = rgb[0];
248  rect_float[1] = rgb[1];
249  rect_float[2] = rgb[2];
250  rect_float[3] = 1.0f;
251 
252  rect_float += 4;
253  }
254  }
255  }
256 }
257 
258 static void checker_board_color_tint(unsigned char *rect,
259  float *rect_float,
260  int width,
261  int height,
262  int size,
263  float blend,
264  int offset)
265 {
266  int x, y;
267  float blend_half = blend * 0.5f;
268 
269  for (y = offset; y < height + offset; y++) {
270  for (x = 0; x < width; x++) {
271  if (((y / size) % 2 == 1 && (x / size) % 2 == 1) ||
272  ((y / size) % 2 == 0 && (x / size) % 2 == 0)) {
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  unsigned char *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.c */
349 
350 static void checker_board_text(
351  unsigned char *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, 72); /* hard coded size! */
359 
360  /* OCIO_TODO: using NULL 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, 4, NULL);
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[36] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
370 
371  int first_char_index = 0;
372  for (y = 0; y < height; y += step) {
373  text[0] = char_array[first_char_index];
374 
375  int second_char_index = 27;
376  for (x = 0; x < width; x += step) {
377  text[1] = char_array[second_char_index];
378 
379  /* hard coded offset */
380  pen_x = x + 33;
381  pen_y = y + 44;
382 
383  /* terribly crappy outline font! */
384  BLF_buffer_col(mono, text_outline);
385 
386  BLF_position(mono, pen_x - outline, pen_y, 0.0);
387  BLF_draw_buffer(mono, text, 2);
388  BLF_position(mono, pen_x + outline, pen_y, 0.0);
389  BLF_draw_buffer(mono, text, 2);
390  BLF_position(mono, pen_x, pen_y - outline, 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 
395  BLF_position(mono, pen_x - outline, pen_y - outline, 0.0);
396  BLF_draw_buffer(mono, text, 2);
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 
404  BLF_buffer_col(mono, text_color);
405  BLF_position(mono, pen_x, pen_y, 0.0);
406  BLF_draw_buffer(mono, text, 2);
407 
408  second_char_index = (second_char_index + 1) % ARRAY_SIZE(char_array);
409  }
410  first_char_index = (first_char_index + 1) % ARRAY_SIZE(char_array);
411  }
412 
413  /* cleanup the buffer. */
414  BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL);
415 }
416 
418  unsigned char *rect, float *rect_float, int width, int height, int offset, int total_height)
419 {
420  checker_board_color_fill(rect, rect_float, width, height, offset, total_height);
421  checker_board_color_tint(rect, rect_float, width, height, 1, 0.03f, offset);
422  checker_board_color_tint(rect, rect_float, width, height, 4, 0.05f, offset);
423  checker_board_color_tint(rect, rect_float, width, height, 32, 0.07f, offset);
424  checker_board_color_tint(rect, rect_float, width, height, 128, 0.15f, offset);
425  checker_board_grid_fill(rect, rect_float, width, height, 1.0f / 4.0f, offset);
426 }
427 
429  unsigned char *rect;
430  float *rect_float;
431  int width, height;
433 
434 static void checker_board_color_prepare_thread_do(void *data_v, int scanline)
435 {
437  const int num_scanlines = 1;
438  size_t offset = ((size_t)data->width) * scanline * 4;
439  unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
440  float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
442  rect, rect_float, data->width, num_scanlines, scanline, data->height);
443 }
444 
445 void BKE_image_buf_fill_checker_color(unsigned char *rect,
446  float *rect_float,
447  int width,
448  int height)
449 {
450  if (((size_t)width) * height < 64 * 64) {
451  checker_board_color_prepare_slice(rect, rect_float, width, height, 0, height);
452  }
453  else {
455  data.rect = rect;
456  data.rect_float = rect_float;
457  data.width = width;
458  data.height = height;
460  }
461 
462  checker_board_text(rect, rect_float, width, height, 128, 2);
463 
464  if (rect_float != NULL) {
465  /* TODO(sergey): Currently it's easier to fill in form buffer and
466  * linearize it afterwards. This could be optimized with some smart
467  * trickery around blending factors and such.
468  */
470  rect_float,
471  4,
474  true,
475  width,
476  height,
477  width,
478  width);
479  }
480 }
typedef float(TangentPoint)[2]
void BLF_draw_buffer(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2)
Definition: blf.c:881
int blf_mono_font_render
Definition: blf.c:49
void BLF_buffer_col(int fontid, const float rgba[4]) ATTR_NONNULL(2)
Definition: blf.c:836
void BLF_buffer(int fontid, float *fbuf, unsigned char *cbuf, int w, int h, int nch, struct ColorManagedDisplay *display)
Definition: blf.c:816
void BLF_size(int fontid, float size, int dpi)
Definition: blf.c:363
void BLF_position(int fontid, float x, float y, float z)
Definition: blf.c:308
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.c:49
MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
Definition: math_color.c:396
float srgb_to_linearrgb(float c)
Definition: math_color.c:403
MINLINE void copy_v4_v4(float r[4], const float a[4])
#define ARRAY_SIZE(arr)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
void IMB_processor_apply_threaded_scanlines(int total_scanlines, ScanlineThreadFunc do_thread, void *custom_data)
Definition: imageprocess.c:415
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.c:536
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 Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input 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 a color
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
#define powf(x, y)
Definition: cuda/compat.h:103
static void image_buf_fill_color_thread_do(void *data_v, int scanline)
Definition: image_gen.c:58
static void image_buf_fill_checker_thread_do(void *data_v, int scanline)
Definition: image_gen.c:186
static void checker_board_color_fill(unsigned char *rect, float *rect_float, int width, int height, int offset, int total_height)
Definition: image_gen.c:216
static void image_buf_fill_checker_slice(unsigned char *rect, float *rect_float, int width, int height, int offset)
Definition: image_gen.c:84
#define BLEND_FLOAT(real, add)
Definition: image_gen.c:212
static void checker_board_grid_fill(unsigned char *rect, float *rect_float, int width, int height, float blend, int offset)
Definition: image_gen.c:312
static void checker_board_text(unsigned char *rect, float *rect_float, int width, int height, int step, int outline)
Definition: image_gen.c:350
struct FillCheckerThreadData FillCheckerThreadData
struct FillCheckerColorThreadData FillCheckerColorThreadData
struct FillColorThreadData FillColorThreadData
void BKE_image_buf_fill_checker_color(unsigned char *rect, float *rect_float, int width, int height)
Definition: image_gen.c:445
static void checker_board_color_prepare_thread_do(void *data_v, int scanline)
Definition: image_gen.c:434
void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height)
Definition: image_gen.c:196
#define BLEND_CHAR(real, add)
Definition: image_gen.c:213
static void checker_board_color_prepare_slice(unsigned char *rect, float *rect_float, int width, int height, int offset, int total_height)
Definition: image_gen.c:417
static void image_buf_fill_color_slice(unsigned char *rect, float *rect_float, int width, int height, const float color[4])
Definition: image_gen.c:28
static void checker_board_color_tint(unsigned char *rect, float *rect_float, int width, int height, int size, float blend, int offset)
Definition: image_gen.c:258
void BKE_image_buf_fill_color(unsigned char *rect, float *rect_float, int width, int height, const float color[4])
Definition: image_gen.c:68
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
#define fmodf(x, y)
Definition: metal/compat.h:230
#define floorf(x)
Definition: metal/compat.h:224
#define fabsf(x)
Definition: metal/compat.h:219
T abs(const T &a)
static const pxr::TfToken rgb("rgb", pxr::TfToken::Immortal)
unsigned char * rect
Definition: image_gen.c:429
unsigned char * rect
Definition: image_gen.c:181
float * rect_float
Definition: image_gen.c:23
unsigned char * rect
Definition: image_gen.c:22
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)