use 'bool' for BLI_/BKE_ functions.
[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_color.h"
31 #include "BLI_math_base.h"
32
33 #include "BKE_image.h"
34
35 #include "BLF_api.h"
36
37 void BKE_image_buf_fill_color(unsigned char *rect, float *rect_float, int width, int height, const float color[4])
38 {
39         int x, y;
40
41         /* blank image */
42         if (rect_float) {
43                 for (y = 0; y < height; y++) {
44                         for (x = 0; x < width; x++) {
45                                 copy_v4_v4(rect_float, color);
46                                 rect_float += 4;
47                         }
48                 }
49         }
50         
51         if (rect) {
52                 unsigned char ccol[4];
53
54                 rgba_float_to_uchar(ccol, color);
55
56                 for (y = 0; y < height; y++) {
57                         for (x = 0; x < width; x++) {
58                                 
59                                 rect[0] = ccol[0];
60                                 rect[1] = ccol[1];
61                                 rect[2] = ccol[2];
62                                 rect[3] = ccol[3];
63                                 rect += 4;
64                         }
65                 }
66         }
67 }
68
69
70 void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height)
71 {
72         /* these two passes could be combined into one, but it's more readable and 
73          * easy to tweak like this, speed isn't really that much of an issue in this situation... */
74  
75         int checkerwidth = 32, dark = 1;
76         int x, y;
77
78         unsigned char *rect_orig = rect;
79         float *rect_float_orig = rect_float;
80
81         
82         float h = 0.0, hoffs = 0.0;
83         float hsv[3] = {0.0f, 0.9f, 0.9f};
84         float rgb[3];
85
86         /* checkers */
87         for (y = 0; y < height; y++) {
88                 dark = powf(-1.0f, floorf(y / checkerwidth));
89                 
90                 for (x = 0; x < width; x++) {
91                         if (x % checkerwidth == 0) dark = -dark;
92                         
93                         if (rect_float) {
94                                 if (dark > 0) {
95                                         rect_float[0] = rect_float[1] = rect_float[2] = 0.25f;
96                                         rect_float[3] = 1.0f;
97                                 }
98                                 else {
99                                         rect_float[0] = rect_float[1] = rect_float[2] = 0.58f;
100                                         rect_float[3] = 1.0f;
101                                 }
102                                 rect_float += 4;
103                         }
104                         else {
105                                 if (dark > 0) {
106                                         rect[0] = rect[1] = rect[2] = 64;
107                                         rect[3] = 255;
108                                 }
109                                 else {
110                                         rect[0] = rect[1] = rect[2] = 150;
111                                         rect[3] = 255;
112                                 }
113                                 rect += 4;
114                         }
115                 }
116         }
117
118         rect = rect_orig;
119         rect_float = rect_float_orig;
120
121         /* 2nd pass, colored + */
122         for (y = 0; y < height; y++) {
123                 hoffs = 0.125f * floorf(y / checkerwidth);
124                 
125                 for (x = 0; x < width; x++) {
126                         h = 0.125f * floorf(x / checkerwidth);
127                         
128                         if ((fabs((x % checkerwidth) - (checkerwidth / 2)) < 4) &&
129                             (fabs((y % checkerwidth) - (checkerwidth / 2)) < 4))
130                         {
131                                 if ((fabs((x % checkerwidth) - (checkerwidth / 2)) < 1) ||
132                                     (fabs((y % checkerwidth) - (checkerwidth / 2)) < 1))
133                                 {
134                                         hsv[0] = fmodf(fabs(h - hoffs), 1.0f);
135                                         hsv_to_rgb_v(hsv, rgb);
136                                         
137                                         if (rect) {
138                                                 rect[0] = (char)(rgb[0] * 255.0f);
139                                                 rect[1] = (char)(rgb[1] * 255.0f);
140                                                 rect[2] = (char)(rgb[2] * 255.0f);
141                                                 rect[3] = 255;
142                                         }
143                                         
144                                         if (rect_float) {
145                                                 rect_float[0] = rgb[0];
146                                                 rect_float[1] = rgb[1];
147                                                 rect_float[2] = rgb[2];
148                                                 rect_float[3] = 1.0f;
149                                         }
150                                 }
151                         }
152
153                         if (rect_float) rect_float += 4;
154                         if (rect) rect += 4;
155                 }
156         }
157 }
158
159
160 /* Utility functions for BKE_image_buf_fill_checker_color */
161
162 #define BLEND_FLOAT(real, add)  (real + add <= 1.0f) ? (real + add) : 1.0f
163 #define BLEND_CHAR(real, add) ((real + (char)(add * 255.0f)) <= 255) ? (real + (char)(add * 255.0f)) : 255
164
165 static void checker_board_color_fill(unsigned char *rect, float *rect_float, int width, int height)
166 {
167         int hue_step, y, x;
168         float hsv[3], rgb[3];
169
170         hsv[1] = 1.0;
171
172         hue_step = power_of_2_max_i(width / 8);
173         if (hue_step < 8) hue_step = 8;
174
175         for (y = 0; y < height; y++) {
176
177                 hsv[2] = 0.1 + (y * (0.4 / height)); /* use a number lower then 1.0 else its too bright */
178                 for (x = 0; x < width; x++) {
179                         hsv[0] = (float)((double)(x / hue_step) * 1.0 / width * hue_step);
180                         hsv_to_rgb_v(hsv, rgb);
181
182                         if (rect) {
183                                 rect[0] = (char)(rgb[0] * 255.0f);
184                                 rect[1] = (char)(rgb[1] * 255.0f);
185                                 rect[2] = (char)(rgb[2] * 255.0f);
186                                 rect[3] = 255;
187                                 
188                                 rect += 4;
189                         }
190
191                         if (rect_float) {
192                                 rect_float[0] = rgb[0];
193                                 rect_float[1] = rgb[1];
194                                 rect_float[2] = rgb[2];
195                                 rect_float[3] = 1.0f;
196                                 
197                                 rect_float += 4;
198                         }
199                 }
200         }
201 }
202
203 static void checker_board_color_tint(unsigned char *rect, float *rect_float, int width, int height, int size, float blend)
204 {
205         int x, y;
206         float blend_half = blend * 0.5f;
207
208         for (y = 0; y < height; y++) {
209                 for (x = 0; x < width; x++) {
210                         if (((y / size) % 2 == 1 && (x / size) % 2 == 1) || ( (y / size) % 2 == 0 && (x / size) % 2 == 0)) {
211                                 if (rect) {
212                                         rect[0] = (char)BLEND_CHAR(rect[0], blend);
213                                         rect[1] = (char)BLEND_CHAR(rect[1], blend);
214                                         rect[2] = (char)BLEND_CHAR(rect[2], blend);
215                                         rect[3] = 255;
216                                 
217                                         rect += 4;
218                                 }
219                                 if (rect_float) {
220                                         rect_float[0] = BLEND_FLOAT(rect_float[0], blend);
221                                         rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
222                                         rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
223                                         rect_float[3] = 1.0f;
224                                 
225                                         rect_float += 4;
226                                 }
227                         }
228                         else {
229                                 if (rect) {
230                                         rect[0] = (char)BLEND_CHAR(rect[0], blend_half);
231                                         rect[1] = (char)BLEND_CHAR(rect[1], blend_half);
232                                         rect[2] = (char)BLEND_CHAR(rect[2], blend_half);
233                                         rect[3] = 255;
234                                 
235                                         rect += 4;
236                                 }
237                                 if (rect_float) {
238                                         rect_float[0] = BLEND_FLOAT(rect_float[0], blend_half);
239                                         rect_float[1] = BLEND_FLOAT(rect_float[1], blend_half);
240                                         rect_float[2] = BLEND_FLOAT(rect_float[2], blend_half);
241                                         rect_float[3] = 1.0f;
242                                 
243                                         rect_float += 4;
244                                 }
245                         }
246                         
247                 }
248         }
249 }
250
251 static void checker_board_grid_fill(unsigned char *rect, float *rect_float, int width, int height, float blend)
252 {
253         int x, y;
254         for (y = 0; y < height; y++) {
255                 for (x = 0; x < width; x++) {
256                         if (((y % 32) == 0) || ((x % 32) == 0) || x == 0) {
257                                 if (rect) {
258                                         rect[0] = BLEND_CHAR(rect[0], blend);
259                                         rect[1] = BLEND_CHAR(rect[1], blend);
260                                         rect[2] = BLEND_CHAR(rect[2], blend);
261                                         rect[3] = 255;
262
263                                         rect += 4;
264                                 }
265                                 if (rect_float) {
266                                         rect_float[0] = BLEND_FLOAT(rect_float[0], blend);
267                                         rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
268                                         rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
269                                         rect_float[3] = 1.0f;
270                                 
271                                         rect_float += 4;
272                                 }
273                         }
274                         else {
275                                 if (rect_float) rect_float += 4;
276                                 if (rect) rect += 4;
277                         }
278                 }
279         }
280 }
281
282 /* defined in image.c */
283
284 static void checker_board_text(unsigned char *rect, float *rect_float, int width, int height, int step, int outline)
285 {
286         int x, y;
287         int pen_x, pen_y;
288         char text[3] = {'A', '1', '\0'};
289         const int mono = blf_mono_font;
290
291         BLF_size(mono, 54, 72); /* hard coded size! */
292
293         /* OCIO_TODO: using NULL as display will assume using sRGB display
294          *            this is correct since currently generated images are assumed to be in sRGB space,
295          *            but this would probably needed to be fixed in some way
296          */
297         BLF_buffer(mono, rect_float, rect, width, height, 4, NULL);
298
299         for (y = 0; y < height; y += step) {
300                 text[1] = '1';
301
302                 for (x = 0; x < width; x += step) {
303                         /* hard coded offset */
304                         pen_x = x + 33;
305                         pen_y = y + 44;
306
307                         /* terribly crappy outline font! */
308                         BLF_buffer_col(mono, 1.0, 1.0, 1.0, 1.0);
309
310                         BLF_position(mono, pen_x - outline, pen_y, 0.0);
311                         BLF_draw_buffer(mono, text);
312                         BLF_position(mono, pen_x + outline, pen_y, 0.0);
313                         BLF_draw_buffer(mono, text);
314                         BLF_position(mono, pen_x, pen_y - outline, 0.0);
315                         BLF_draw_buffer(mono, text);
316                         BLF_position(mono, pen_x, pen_y + outline, 0.0);
317                         BLF_draw_buffer(mono, text);
318
319                         BLF_position(mono, pen_x - outline, pen_y - outline, 0.0);
320                         BLF_draw_buffer(mono, text);
321                         BLF_position(mono, pen_x + outline, pen_y + outline, 0.0);
322                         BLF_draw_buffer(mono, text);
323                         BLF_position(mono, pen_x - outline, pen_y + outline, 0.0);
324                         BLF_draw_buffer(mono, text);
325                         BLF_position(mono, pen_x + outline, pen_y - outline, 0.0);
326                         BLF_draw_buffer(mono, text);
327
328                         BLF_buffer_col(mono, 0.0, 0.0, 0.0, 1.0);
329                         BLF_position(mono, pen_x, pen_y, 0.0);
330                         BLF_draw_buffer(mono, text);
331
332                         text[1]++;
333                 }
334                 text[0]++;
335         }
336
337         /* cleanup the buffer. */
338         BLF_buffer(mono, NULL, NULL, 0, 0, 0, FALSE);
339 }
340
341 void BKE_image_buf_fill_checker_color(unsigned char *rect, float *rect_float, int width, int height)
342 {
343         checker_board_color_fill(rect, rect_float, width, height);
344         checker_board_color_tint(rect, rect_float, width, height, 1, 0.03f);
345         checker_board_color_tint(rect, rect_float, width, height, 4, 0.05f);
346         checker_board_color_tint(rect, rect_float, width, height, 32, 0.07f);
347         checker_board_color_tint(rect, rect_float, width, height, 128, 0.15f);
348         checker_board_grid_fill(rect, rect_float, width, height, 1.0f / 4.0f);
349
350         checker_board_text(rect, rect_float, width, height, 128, 2);
351 }