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