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