Blender  V2.93
image_gen.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include <math.h>
22 #include <stdlib.h>
23 
24 #include "BLI_math_base.h"
25 #include "BLI_math_color.h"
26 #include "BLI_math_vector.h"
27 
28 #include "BKE_image.h"
29 
30 #include "IMB_imbuf.h"
31 #include "IMB_imbuf_types.h"
32 
33 #include "BLF_api.h"
34 
35 typedef struct FillColorThreadData {
36  unsigned char *rect;
37  float *rect_float;
38  int width;
39  float color[4];
41 
43  unsigned char *rect, float *rect_float, int width, int height, const float color[4])
44 {
45  int x, y;
46 
47  /* blank image */
48  if (rect_float) {
49  for (y = 0; y < height; y++) {
50  for (x = 0; x < width; x++) {
51  copy_v4_v4(rect_float, color);
52  rect_float += 4;
53  }
54  }
55  }
56 
57  if (rect) {
58  unsigned char ccol[4];
59  rgba_float_to_uchar(ccol, color);
60  for (y = 0; y < height; y++) {
61  for (x = 0; x < width; x++) {
62  rect[0] = ccol[0];
63  rect[1] = ccol[1];
64  rect[2] = ccol[2];
65  rect[3] = ccol[3];
66  rect += 4;
67  }
68  }
69  }
70 }
71 
72 static void image_buf_fill_color_thread_do(void *data_v, int start_scanline, int num_scanlines)
73 {
75  size_t offset = ((size_t)start_scanline) * data->width * 4;
76  unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
77  float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
78  image_buf_fill_color_slice(rect, rect_float, data->width, num_scanlines, data->color);
79 }
80 
82  unsigned char *rect, float *rect_float, int width, int height, const float color[4])
83 {
84  if (((size_t)width) * height < 64 * 64) {
85  image_buf_fill_color_slice(rect, rect_float, width, height, color);
86  }
87  else {
89  data.rect = rect;
90  data.rect_float = rect_float;
91  data.width = width;
92  copy_v4_v4(data.color, color);
94  }
95 }
96 
98  unsigned char *rect, float *rect_float, int width, int height, int offset)
99 {
100  /* these two passes could be combined into one, but it's more readable and
101  * easy to tweak like this, speed isn't really that much of an issue in this situation... */
102 
103  int checkerwidth = 32, dark = 1;
104  int x, y;
105 
106  unsigned char *rect_orig = rect;
107  float *rect_float_orig = rect_float;
108 
109  float h = 0.0, hoffs = 0.0;
110  float hsv[3] = {0.0f, 0.9f, 0.9f};
111  float rgb[3];
112 
113  float dark_linear_color = 0.0f, bright_linear_color = 0.0f;
114  if (rect_float != NULL) {
115  dark_linear_color = srgb_to_linearrgb(0.25f);
116  bright_linear_color = srgb_to_linearrgb(0.58f);
117  }
118 
119  /* checkers */
120  for (y = offset; y < height + offset; y++) {
121  dark = powf(-1.0f, floorf(y / checkerwidth));
122 
123  for (x = 0; x < width; x++) {
124  if (x % checkerwidth == 0) {
125  dark = -dark;
126  }
127 
128  if (rect_float) {
129  if (dark > 0) {
130  rect_float[0] = rect_float[1] = rect_float[2] = dark_linear_color;
131  rect_float[3] = 1.0f;
132  }
133  else {
134  rect_float[0] = rect_float[1] = rect_float[2] = bright_linear_color;
135  rect_float[3] = 1.0f;
136  }
137  rect_float += 4;
138  }
139  else {
140  if (dark > 0) {
141  rect[0] = rect[1] = rect[2] = 64;
142  rect[3] = 255;
143  }
144  else {
145  rect[0] = rect[1] = rect[2] = 150;
146  rect[3] = 255;
147  }
148  rect += 4;
149  }
150  }
151  }
152 
153  rect = rect_orig;
154  rect_float = rect_float_orig;
155 
156  /* 2nd pass, colored + */
157  for (y = offset; y < height + offset; y++) {
158  hoffs = 0.125f * floorf(y / checkerwidth);
159 
160  for (x = 0; x < width; x++) {
161  h = 0.125f * floorf(x / checkerwidth);
162 
163  if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 4) &&
164  (abs((y % checkerwidth) - (checkerwidth / 2)) < 4)) {
165  if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 1) ||
166  (abs((y % checkerwidth) - (checkerwidth / 2)) < 1)) {
167  hsv[0] = fmodf(fabsf(h - hoffs), 1.0f);
168  hsv_to_rgb_v(hsv, rgb);
169 
170  if (rect) {
171  rect[0] = (char)(rgb[0] * 255.0f);
172  rect[1] = (char)(rgb[1] * 255.0f);
173  rect[2] = (char)(rgb[2] * 255.0f);
174  rect[3] = 255;
175  }
176 
177  if (rect_float) {
178  srgb_to_linearrgb_v3_v3(rect_float, rgb);
179  rect_float[3] = 1.0f;
180  }
181  }
182  }
183 
184  if (rect_float) {
185  rect_float += 4;
186  }
187  if (rect) {
188  rect += 4;
189  }
190  }
191  }
192 }
193 
194 typedef struct FillCheckerThreadData {
195  unsigned char *rect;
196  float *rect_float;
197  int width;
199 
200 static void image_buf_fill_checker_thread_do(void *data_v, int start_scanline, int num_scanlines)
201 {
203  size_t offset = ((size_t)start_scanline) * data->width * 4;
204  unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
205  float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
206  image_buf_fill_checker_slice(rect, rect_float, data->width, num_scanlines, start_scanline);
207 }
208 
209 void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height)
210 {
211  if (((size_t)width) * height < 64 * 64) {
212  image_buf_fill_checker_slice(rect, rect_float, width, height, 0);
213  }
214  else {
216  data.rect = rect;
217  data.rect_float = rect_float;
218  data.width = width;
220  }
221 }
222 
223 /* Utility functions for BKE_image_buf_fill_checker_color */
224 
225 #define BLEND_FLOAT(real, add) (real + add <= 1.0f) ? (real + add) : 1.0f
226 #define BLEND_CHAR(real, add) \
227  ((real + (char)(add * 255.0f)) <= 255) ? (real + (char)(add * 255.0f)) : 255
228 
230  unsigned char *rect, float *rect_float, int width, int height, int offset, int total_height)
231 {
232  int hue_step, y, x;
233  float hsv[3], rgb[3];
234 
235  hsv[1] = 1.0;
236 
237  hue_step = power_of_2_max_i(width / 8);
238  if (hue_step < 8) {
239  hue_step = 8;
240  }
241 
242  for (y = offset; y < height + offset; y++) {
243  /* Use a number lower than 1.0 else its too bright. */
244  hsv[2] = 0.1 + (y * (0.4 / total_height));
245 
246  for (x = 0; x < width; x++) {
247  hsv[0] = (float)((double)(x / hue_step) * 1.0 / width * hue_step);
248  hsv_to_rgb_v(hsv, rgb);
249 
250  if (rect) {
251  rect[0] = (char)(rgb[0] * 255.0f);
252  rect[1] = (char)(rgb[1] * 255.0f);
253  rect[2] = (char)(rgb[2] * 255.0f);
254  rect[3] = 255;
255 
256  rect += 4;
257  }
258 
259  if (rect_float) {
260  rect_float[0] = rgb[0];
261  rect_float[1] = rgb[1];
262  rect_float[2] = rgb[2];
263  rect_float[3] = 1.0f;
264 
265  rect_float += 4;
266  }
267  }
268  }
269 }
270 
271 static void checker_board_color_tint(unsigned char *rect,
272  float *rect_float,
273  int width,
274  int height,
275  int size,
276  float blend,
277  int offset)
278 {
279  int x, y;
280  float blend_half = blend * 0.5f;
281 
282  for (y = offset; y < height + offset; y++) {
283  for (x = 0; x < width; x++) {
284  if (((y / size) % 2 == 1 && (x / size) % 2 == 1) ||
285  ((y / size) % 2 == 0 && (x / size) % 2 == 0)) {
286  if (rect) {
287  rect[0] = (char)BLEND_CHAR(rect[0], blend);
288  rect[1] = (char)BLEND_CHAR(rect[1], blend);
289  rect[2] = (char)BLEND_CHAR(rect[2], blend);
290  rect[3] = 255;
291 
292  rect += 4;
293  }
294  if (rect_float) {
295  rect_float[0] = BLEND_FLOAT(rect_float[0], blend);
296  rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
297  rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
298  rect_float[3] = 1.0f;
299 
300  rect_float += 4;
301  }
302  }
303  else {
304  if (rect) {
305  rect[0] = (char)BLEND_CHAR(rect[0], blend_half);
306  rect[1] = (char)BLEND_CHAR(rect[1], blend_half);
307  rect[2] = (char)BLEND_CHAR(rect[2], blend_half);
308  rect[3] = 255;
309 
310  rect += 4;
311  }
312  if (rect_float) {
313  rect_float[0] = BLEND_FLOAT(rect_float[0], blend_half);
314  rect_float[1] = BLEND_FLOAT(rect_float[1], blend_half);
315  rect_float[2] = BLEND_FLOAT(rect_float[2], blend_half);
316  rect_float[3] = 1.0f;
317 
318  rect_float += 4;
319  }
320  }
321  }
322  }
323 }
324 
326  unsigned char *rect, float *rect_float, int width, int height, float blend, int offset)
327 {
328  int x, y;
329  for (y = offset; y < height + offset; y++) {
330  for (x = 0; x < width; x++) {
331  if (((y % 32) == 0) || ((x % 32) == 0) || x == 0) {
332  if (rect) {
333  rect[0] = BLEND_CHAR(rect[0], blend);
334  rect[1] = BLEND_CHAR(rect[1], blend);
335  rect[2] = BLEND_CHAR(rect[2], blend);
336  rect[3] = 255;
337 
338  rect += 4;
339  }
340  if (rect_float) {
341  rect_float[0] = BLEND_FLOAT(rect_float[0], blend);
342  rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
343  rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
344  rect_float[3] = 1.0f;
345 
346  rect_float += 4;
347  }
348  }
349  else {
350  if (rect_float) {
351  rect_float += 4;
352  }
353  if (rect) {
354  rect += 4;
355  }
356  }
357  }
358  }
359 }
360 
361 /* defined in image.c */
362 
363 static void checker_board_text(
364  unsigned char *rect, float *rect_float, int width, int height, int step, int outline)
365 {
366  int x, y;
367  int pen_x, pen_y;
368  char text[3] = {'A', '1', '\0'};
369  const int mono = blf_mono_font_render;
370 
371  BLF_size(mono, 54, 72); /* hard coded size! */
372 
373  /* OCIO_TODO: using NULL as display will assume using sRGB display
374  * this is correct since currently generated images are assumed to be in sRGB space,
375  * but this would probably needed to be fixed in some way
376  */
377  BLF_buffer(mono, rect_float, rect, width, height, 4, NULL);
378 
379  const float text_color[4] = {0.0, 0.0, 0.0, 1.0};
380  const float text_outline[4] = {1.0, 1.0, 1.0, 1.0};
381 
382  const char char_array[36] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
383 
384  int first_char_index = 0;
385  for (y = 0; y < height; y += step) {
386  text[0] = char_array[first_char_index];
387 
388  int second_char_index = 27;
389  for (x = 0; x < width; x += step) {
390  text[1] = char_array[second_char_index];
391 
392  /* hard coded offset */
393  pen_x = x + 33;
394  pen_y = y + 44;
395 
396  /* terribly crappy outline font! */
397  BLF_buffer_col(mono, text_outline);
398 
399  BLF_position(mono, pen_x - outline, pen_y, 0.0);
400  BLF_draw_buffer(mono, text, 2);
401  BLF_position(mono, pen_x + outline, pen_y, 0.0);
402  BLF_draw_buffer(mono, text, 2);
403  BLF_position(mono, pen_x, pen_y - outline, 0.0);
404  BLF_draw_buffer(mono, text, 2);
405  BLF_position(mono, pen_x, pen_y + outline, 0.0);
406  BLF_draw_buffer(mono, text, 2);
407 
408  BLF_position(mono, pen_x - outline, pen_y - outline, 0.0);
409  BLF_draw_buffer(mono, text, 2);
410  BLF_position(mono, pen_x + outline, pen_y + outline, 0.0);
411  BLF_draw_buffer(mono, text, 2);
412  BLF_position(mono, pen_x - outline, pen_y + outline, 0.0);
413  BLF_draw_buffer(mono, text, 2);
414  BLF_position(mono, pen_x + outline, pen_y - outline, 0.0);
415  BLF_draw_buffer(mono, text, 2);
416 
417  BLF_buffer_col(mono, text_color);
418  BLF_position(mono, pen_x, pen_y, 0.0);
419  BLF_draw_buffer(mono, text, 2);
420 
421  second_char_index = (second_char_index + 1) % ARRAY_SIZE(char_array);
422  }
423  first_char_index = (first_char_index + 1) % ARRAY_SIZE(char_array);
424  }
425 
426  /* cleanup the buffer. */
427  BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL);
428 }
429 
431  unsigned char *rect, float *rect_float, int width, int height, int offset, int total_height)
432 {
433  checker_board_color_fill(rect, rect_float, width, height, offset, total_height);
434  checker_board_color_tint(rect, rect_float, width, height, 1, 0.03f, offset);
435  checker_board_color_tint(rect, rect_float, width, height, 4, 0.05f, offset);
436  checker_board_color_tint(rect, rect_float, width, height, 32, 0.07f, offset);
437  checker_board_color_tint(rect, rect_float, width, height, 128, 0.15f, offset);
438  checker_board_grid_fill(rect, rect_float, width, height, 1.0f / 4.0f, offset);
439 }
440 
442  unsigned char *rect;
443  float *rect_float;
444  int width, height;
446 
447 static void checker_board_color_prepare_thread_do(void *data_v,
448  int start_scanline,
449  int num_scanlines)
450 {
452  size_t offset = ((size_t)data->width) * start_scanline * 4;
453  unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
454  float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
456  rect, rect_float, data->width, num_scanlines, start_scanline, data->height);
457 }
458 
459 void BKE_image_buf_fill_checker_color(unsigned char *rect,
460  float *rect_float,
461  int width,
462  int height)
463 {
464  if (((size_t)width) * height < 64 * 64) {
465  checker_board_color_prepare_slice(rect, rect_float, width, height, 0, height);
466  }
467  else {
469  data.rect = rect;
470  data.rect_float = rect_float;
471  data.width = width;
472  data.height = height;
474  }
475 
476  checker_board_text(rect, rect_float, width, height, 128, 2);
477 
478  if (rect_float != NULL) {
479  /* TODO(sergey): Currently it's easier to fill in form buffer and
480  * linearize it afterwards. This could be optimized with some smart
481  * trickery around blending factors and such.
482  */
484  rect_float,
485  4,
488  true,
489  width,
490  height,
491  width,
492  width);
493  }
494 }
typedef float(TangentPoint)[2]
void BLF_draw_buffer(int fontid, const char *str, size_t len) ATTR_NONNULL(2)
Definition: blf.c:913
int blf_mono_font_render
Definition: blf.c:71
void BLF_buffer_col(int fontid, const float rgba[4]) ATTR_NONNULL(2)
Definition: blf.c:871
void BLF_buffer(int fontid, float *fbuf, unsigned char *cbuf, int w, int h, int nch, struct ColorManagedDisplay *display)
Definition: blf.c:851
void BLF_size(int fontid, int size, int dpi)
Definition: blf.c:367
void BLF_position(int fontid, float x, float y, float z)
Definition: blf.c:312
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:68
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:427
float srgb_to_linearrgb(float c)
Definition: math_color.c:434
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 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
_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
void IMB_processor_apply_threaded_scanlines(int total_scanlines, ScanlineThreadFunc do_thread, void *custom_data)
Definition: imageprocess.c:424
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:558
Contains defines and structs used throughout the imbuf module.
#define IB_PROFILE_SRGB
#define IB_PROFILE_LINEAR_RGB
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
static void image_buf_fill_checker_thread_do(void *data_v, int start_scanline, int num_scanlines)
Definition: image_gen.c:200
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:229
static void image_buf_fill_checker_slice(unsigned char *rect, float *rect_float, int width, int height, int offset)
Definition: image_gen.c:97
static void image_buf_fill_color_thread_do(void *data_v, int start_scanline, int num_scanlines)
Definition: image_gen.c:72
#define BLEND_FLOAT(real, add)
Definition: image_gen.c:225
static void checker_board_grid_fill(unsigned char *rect, float *rect_float, int width, int height, float blend, int offset)
Definition: image_gen.c:325
static void checker_board_text(unsigned char *rect, float *rect_float, int width, int height, int step, int outline)
Definition: image_gen.c:363
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:459
void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height)
Definition: image_gen.c:209
#define BLEND_CHAR(real, add)
Definition: image_gen.c:226
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:430
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:42
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:271
void BKE_image_buf_fill_color(unsigned char *rect, float *rect_float, int width, int height, const float color[4])
Definition: image_gen.c:81
static void checker_board_color_prepare_thread_do(void *data_v, int start_scanline, int num_scanlines)
Definition: image_gen.c:447
#define powf(x, y)
#define fmodf(x, y)
#define floorf(x)
#define fabsf(x)
unsigned char * rect
Definition: image_gen.c:442
unsigned char * rect
Definition: image_gen.c:195
float * rect_float
Definition: image_gen.c:37
unsigned char * rect
Definition: image_gen.c:36
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
__forceinline const avxi abs(const avxi &a)
Definition: util_avxi.h:186