ac3acf5ac534007c7116f46080706afaa1a3b142
[blender.git] / source / blender / editors / interface / interface_draw.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  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/interface/interface_draw.c
27  *  \ingroup edinterface
28  */
29
30
31 #include <math.h>
32 #include <string.h>
33
34 #include "DNA_color_types.h"
35 #include "DNA_screen_types.h"
36 #include "DNA_movieclip_types.h"
37
38 #include "BLI_math.h"
39 #include "BLI_rect.h"
40 #include "BLI_string.h"
41 #include "BLI_utildefines.h"
42
43 #include "BKE_colorband.h"
44 #include "BKE_colortools.h"
45 #include "BKE_node.h"
46 #include "BKE_tracking.h"
47
48
49 #include "IMB_imbuf.h"
50 #include "IMB_imbuf_types.h"
51 #include "IMB_colormanagement.h"
52
53 #include "BIF_glutil.h"
54
55 #include "BLF_api.h"
56
57 #include "GPU_batch.h"
58 #include "GPU_batch_presets.h"
59 #include "GPU_immediate.h"
60 #include "GPU_immediate_util.h"
61 #include "GPU_matrix.h"
62 #include "GPU_state.h"
63
64 #include "UI_interface.h"
65
66 /* own include */
67 #include "interface_intern.h"
68
69
70 static int roundboxtype = UI_CNR_ALL;
71
72 void UI_draw_roundbox_corner_set(int type)
73 {
74         /* Not sure the roundbox function is the best place to change this
75          * if this is undone, it's not that big a deal, only makes curves edges
76          * square for the  */
77         roundboxtype = type;
78 }
79
80 #if 0 /* unused */
81 int UI_draw_roundbox_corner_get(void)
82 {
83         return roundboxtype;
84 }
85 #endif
86
87 void UI_draw_roundbox_3ubAlpha(bool filled, float minx, float miny, float maxx, float maxy, float rad, const unsigned char col[3], unsigned char alpha)
88 {
89         float colv[4];
90         colv[0] = ((float)col[0]) / 255;
91         colv[1] = ((float)col[1]) / 255;
92         colv[2] = ((float)col[2]) / 255;
93         colv[3] = ((float)alpha) / 255;
94         UI_draw_roundbox_4fv(filled, minx, miny, maxx, maxy, rad, colv);
95 }
96
97 void UI_draw_roundbox_3fvAlpha(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float col[3], float alpha)
98 {
99         float colv[4];
100         colv[0] = col[0];
101         colv[1] = col[1];
102         colv[2] = col[2];
103         colv[3] = alpha;
104         UI_draw_roundbox_4fv(filled, minx, miny, maxx, maxy, rad, colv);
105 }
106
107 void UI_draw_roundbox_aa(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float color[4])
108 {
109         uiWidgetBaseParameters widget_params = {
110                 .recti.xmin = minx, .recti.ymin = miny,
111                 .recti.xmax = maxx, .recti.ymax = maxy,
112                 .radi = rad,
113                 .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
114                 .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
115                 .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
116                 .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
117                 .color_inner1[0] = color[0], .color_inner2[0] = color[0],
118                 .color_inner1[1] = color[1], .color_inner2[1] = color[1],
119                 .color_inner1[2] = color[2], .color_inner2[2] = color[2],
120                 .color_inner1[3] = color[3], .color_inner2[3] = color[3],
121                 .alpha_discard = 1.0f,
122         };
123
124         GPU_blend(true);
125
126         if (filled) {
127                 /* plain antialiased filled box */
128                 widget_params.color_inner1[3] *= 0.125f;
129                 widget_params.color_inner2[3] *= 0.125f;
130
131                 /* WATCH: This is assuming the ModelViewProjectionMatrix is area pixel space.
132                  * If it has been scaled, then it's no longer valid. */
133                 GPUBatch *batch = ui_batch_roundbox_get(filled, true);
134                 GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
135                 GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
136                 GPU_batch_draw(batch);
137         }
138         else {
139                 /* plain antialiased unfilled box */
140                 GPU_line_smooth(true);
141
142                 GPUBatch *batch = ui_batch_roundbox_get(filled, false);
143                 GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
144                 GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
145                 GPU_batch_draw(batch);
146
147                 GPU_line_smooth(false);
148         }
149
150         GPU_blend(false);
151 }
152
153 void UI_draw_roundbox_4fv(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float col[4])
154 {
155 #if 0
156         float vec[7][2] = {
157                 {0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293},
158                 {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805},
159         };
160         int a;
161
162         GPUVertFormat *format = immVertexFormat();
163         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
164
165         /* mult */
166         for (a = 0; a < 7; a++) {
167                 mul_v2_fl(vec[a], rad);
168         }
169
170         uint vert_len = 0;
171         vert_len += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 9 : 1;
172         vert_len += (roundboxtype & UI_CNR_TOP_RIGHT) ? 9 : 1;
173         vert_len += (roundboxtype & UI_CNR_TOP_LEFT) ? 9 : 1;
174         vert_len += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 9 : 1;
175
176         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
177         immUniformColor4fv(col);
178
179         immBegin(filled ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_LOOP, vert_len);
180         /* start with corner right-bottom */
181         if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
182                 immVertex2f(pos, maxx - rad, miny);
183                 for (a = 0; a < 7; a++) {
184                         immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]);
185                 }
186                 immVertex2f(pos, maxx, miny + rad);
187         }
188         else {
189                 immVertex2f(pos, maxx, miny);
190         }
191
192         /* corner right-top */
193         if (roundboxtype & UI_CNR_TOP_RIGHT) {
194                 immVertex2f(pos, maxx, maxy - rad);
195                 for (a = 0; a < 7; a++) {
196                         immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]);
197                 }
198                 immVertex2f(pos, maxx - rad, maxy);
199         }
200         else {
201                 immVertex2f(pos, maxx, maxy);
202         }
203
204         /* corner left-top */
205         if (roundboxtype & UI_CNR_TOP_LEFT) {
206                 immVertex2f(pos, minx + rad, maxy);
207                 for (a = 0; a < 7; a++) {
208                         immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]);
209                 }
210                 immVertex2f(pos, minx, maxy - rad);
211         }
212         else {
213                 immVertex2f(pos, minx, maxy);
214         }
215
216         /* corner left-bottom */
217         if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
218                 immVertex2f(pos, minx, miny + rad);
219                 for (a = 0; a < 7; a++) {
220                         immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]);
221                 }
222                 immVertex2f(pos, minx + rad, miny);
223         }
224         else {
225                 immVertex2f(pos, minx, miny);
226         }
227
228         immEnd();
229         immUnbindProgram();
230 #endif
231
232         uiWidgetBaseParameters widget_params = {
233                 .recti.xmin = minx, .recti.ymin = miny,
234                 .recti.xmax = maxx, .recti.ymax = maxy,
235                 .radi = rad,
236                 .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
237                 .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
238                 .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
239                 .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
240                 .color_inner1[0] = col[0], .color_inner2[0] = col[0],
241                 .color_inner1[1] = col[1], .color_inner2[1] = col[1],
242                 .color_inner1[2] = col[2], .color_inner2[2] = col[2],
243                 .color_inner1[3] = col[3], .color_inner2[3] = col[3],
244                 .alpha_discard = 1.0f,
245         };
246
247         GPUBatch *batch = ui_batch_roundbox_get(filled, false);
248         GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
249         GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
250         GPU_batch_draw(batch);
251 }
252
253 #if 0
254 static void round_box_shade_col(unsigned attrib, const float col1[3], float const col2[3], const float fac)
255 {
256         float col[4] = {
257                 fac * col1[0] + (1.0f - fac) * col2[0],
258                 fac * col1[1] + (1.0f - fac) * col2[1],
259                 fac * col1[2] + (1.0f - fac) * col2[2],
260                 1.0f
261         };
262         immAttr4fv(attrib, col);
263 }
264 #endif
265
266 /* linear horizontal shade within button or in outline */
267 /* view2d scrollers use it */
268 void UI_draw_roundbox_shade_x(
269         bool filled, float minx, float miny, float maxx, float maxy,
270         float rad, float shadetop, float shadedown, const float col[4])
271 {
272 #if 0
273         float vec[7][2] = {
274                 {0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293},
275                 {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805},
276         };
277         const float div = maxy - miny;
278         const float idiv = 1.0f / div;
279         float coltop[3], coldown[3];
280         int vert_count = 0;
281         int a;
282
283         GPUVertFormat *format = immVertexFormat();
284         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
285         uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
286
287         immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
288
289         /* mult */
290         for (a = 0; a < 7; a++) {
291                 mul_v2_fl(vec[a], rad);
292         }
293
294         /* 'shade' defines strength of shading */
295         coltop[0]  = min_ff(1.0f, col[0] + shadetop);
296         coltop[1]  = min_ff(1.0f, col[1] + shadetop);
297         coltop[2]  = min_ff(1.0f, col[2] + shadetop);
298         coldown[0] = max_ff(0.0f, col[0] + shadedown);
299         coldown[1] = max_ff(0.0f, col[1] + shadedown);
300         coldown[2] = max_ff(0.0f, col[2] + shadedown);
301
302         vert_count += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 9 : 1;
303         vert_count += (roundboxtype & UI_CNR_TOP_RIGHT) ? 9 : 1;
304         vert_count += (roundboxtype & UI_CNR_TOP_LEFT) ? 9 : 1;
305         vert_count += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 9 : 1;
306
307         immBegin(filled ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_LOOP, vert_count);
308
309         /* start with corner right-bottom */
310         if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
311
312                 round_box_shade_col(color, coltop, coldown, 0.0);
313                 immVertex2f(pos, maxx - rad, miny);
314
315                 for (a = 0; a < 7; a++) {
316                         round_box_shade_col(color, coltop, coldown, vec[a][1] * idiv);
317                         immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]);
318                 }
319
320                 round_box_shade_col(color, coltop, coldown, rad * idiv);
321                 immVertex2f(pos, maxx, miny + rad);
322         }
323         else {
324                 round_box_shade_col(color, coltop, coldown, 0.0);
325                 immVertex2f(pos, maxx, miny);
326         }
327
328         /* corner right-top */
329         if (roundboxtype & UI_CNR_TOP_RIGHT) {
330
331                 round_box_shade_col(color, coltop, coldown, (div - rad) * idiv);
332                 immVertex2f(pos, maxx, maxy - rad);
333
334                 for (a = 0; a < 7; a++) {
335                         round_box_shade_col(color, coltop, coldown, (div - rad + vec[a][1]) * idiv);
336                         immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]);
337                 }
338                 round_box_shade_col(color, coltop, coldown, 1.0);
339                 immVertex2f(pos, maxx - rad, maxy);
340         }
341         else {
342                 round_box_shade_col(color, coltop, coldown, 1.0);
343                 immVertex2f(pos, maxx, maxy);
344         }
345
346         /* corner left-top */
347         if (roundboxtype & UI_CNR_TOP_LEFT) {
348
349                 round_box_shade_col(color, coltop, coldown, 1.0);
350                 immVertex2f(pos, minx + rad, maxy);
351
352                 for (a = 0; a < 7; a++) {
353                         round_box_shade_col(color, coltop, coldown, (div - vec[a][1]) * idiv);
354                         immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]);
355                 }
356
357                 round_box_shade_col(color, coltop, coldown, (div - rad) * idiv);
358                 immVertex2f(pos, minx, maxy - rad);
359         }
360         else {
361                 round_box_shade_col(color, coltop, coldown, 1.0);
362                 immVertex2f(pos, minx, maxy);
363         }
364
365         /* corner left-bottom */
366         if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
367
368                 round_box_shade_col(color, coltop, coldown, rad * idiv);
369                 immVertex2f(pos, minx, miny + rad);
370
371                 for (a = 0; a < 7; a++) {
372                         round_box_shade_col(color, coltop, coldown, (rad - vec[a][1]) * idiv);
373                         immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]);
374                 }
375
376                 round_box_shade_col(color, coltop, coldown, 0.0);
377                 immVertex2f(pos, minx + rad, miny);
378         }
379         else {
380                 round_box_shade_col(color, coltop, coldown, 0.0);
381                 immVertex2f(pos, minx, miny);
382         }
383
384         immEnd();
385         immUnbindProgram();
386 #endif
387
388         uiWidgetBaseParameters widget_params = {
389                 .recti.xmin = minx, .recti.ymin = miny,
390                 .recti.xmax = maxx, .recti.ymax = maxy,
391                 .radi = rad,
392                 .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
393                 .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
394                 .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
395                 .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
396                 .color_inner1[0] = min_ff(1.0f, col[0] + shadetop),
397                 .color_inner2[0] = max_ff(0.0f, col[0] + shadedown),
398                 .color_inner1[1] = min_ff(1.0f, col[1] + shadetop),
399                 .color_inner2[1] = max_ff(0.0f, col[1] + shadedown),
400                 .color_inner1[2] = min_ff(1.0f, col[2] + shadetop),
401                 .color_inner2[2] = max_ff(0.0f, col[2] + shadedown),
402                 .color_inner1[3] = 1.0f,
403                 .color_inner2[3] = 1.0f,
404                 .alpha_discard = 1.0f,
405         };
406
407         GPUBatch *batch = ui_batch_roundbox_get(filled, false);
408         GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
409         GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
410         GPU_batch_draw(batch);
411 }
412
413 #if 0 /* unused */
414 /* linear vertical shade within button or in outline */
415 /* view2d scrollers use it */
416 void UI_draw_roundbox_shade_y(
417         bool filled, float minx, float miny, float maxx, float maxy,
418         float rad, float shadeleft, float shaderight, const float col[4])
419 {
420         float vec[7][2] = {
421                 {0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293},
422                 {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805},
423         };
424         const float div = maxx - minx;
425         const float idiv = 1.0f / div;
426         float colLeft[3], colRight[3];
427         int vert_count = 0;
428         int a;
429
430         /* mult */
431         for (a = 0; a < 7; a++) {
432                 mul_v2_fl(vec[a], rad);
433         }
434
435         GPUVertFormat *format = immVertexFormat();
436         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
437         uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
438
439         immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
440
441         /* 'shade' defines strength of shading */
442         colLeft[0]  = min_ff(1.0f, col[0] + shadeleft);
443         colLeft[1]  = min_ff(1.0f, col[1] + shadeleft);
444         colLeft[2]  = min_ff(1.0f, col[2] + shadeleft);
445         colRight[0] = max_ff(0.0f, col[0] + shaderight);
446         colRight[1] = max_ff(0.0f, col[1] + shaderight);
447         colRight[2] = max_ff(0.0f, col[2] + shaderight);
448
449
450         vert_count += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 9 : 1;
451         vert_count += (roundboxtype & UI_CNR_TOP_RIGHT) ? 9 : 1;
452         vert_count += (roundboxtype & UI_CNR_TOP_LEFT) ? 9 : 1;
453         vert_count += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 9 : 1;
454
455         immBegin(filled ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_LOOP, vert_count);
456
457         /* start with corner right-bottom */
458         if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
459                 round_box_shade_col(color, colLeft, colRight, 0.0);
460                 immVertex2f(pos, maxx - rad, miny);
461
462                 for (a = 0; a < 7; a++) {
463                         round_box_shade_col(color, colLeft, colRight, vec[a][0] * idiv);
464                         immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]);
465                 }
466
467                 round_box_shade_col(color, colLeft, colRight, rad * idiv);
468                 immVertex2f(pos, maxx, miny + rad);
469         }
470         else {
471                 round_box_shade_col(color, colLeft, colRight, 0.0);
472                 immVertex2f(pos, maxx, miny);
473         }
474
475         /* corner right-top */
476         if (roundboxtype & UI_CNR_TOP_RIGHT) {
477                 round_box_shade_col(color, colLeft, colRight, 0.0);
478                 immVertex2f(pos, maxx, maxy - rad);
479
480                 for (a = 0; a < 7; a++) {
481
482                         round_box_shade_col(color, colLeft, colRight, (div - rad - vec[a][0]) * idiv);
483                         immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]);
484                 }
485                 round_box_shade_col(color, colLeft, colRight, (div - rad) * idiv);
486                 immVertex2f(pos, maxx - rad, maxy);
487         }
488         else {
489                 round_box_shade_col(color, colLeft, colRight, 0.0);
490                 immVertex2f(pos, maxx, maxy);
491         }
492
493         /* corner left-top */
494         if (roundboxtype & UI_CNR_TOP_LEFT) {
495                 round_box_shade_col(color, colLeft, colRight, (div - rad) * idiv);
496                 immVertex2f(pos, minx + rad, maxy);
497
498                 for (a = 0; a < 7; a++) {
499                         round_box_shade_col(color, colLeft, colRight, (div - rad + vec[a][0]) * idiv);
500                         immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]);
501                 }
502
503                 round_box_shade_col(color, colLeft, colRight, 1.0);
504                 immVertex2f(pos, minx, maxy - rad);
505         }
506         else {
507                 round_box_shade_col(color, colLeft, colRight, 1.0);
508                 immVertex2f(pos, minx, maxy);
509         }
510
511         /* corner left-bottom */
512         if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
513                 round_box_shade_col(color, colLeft, colRight, 1.0);
514                 immVertex2f(pos, minx, miny + rad);
515
516                 for (a = 0; a < 7; a++) {
517                         round_box_shade_col(color, colLeft, colRight, (vec[a][0]) * idiv);
518                         immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]);
519                 }
520
521                 round_box_shade_col(color, colLeft, colRight, 1.0);
522                 immVertex2f(pos, minx + rad, miny);
523         }
524         else {
525                 round_box_shade_col(color, colLeft, colRight, 1.0);
526                 immVertex2f(pos, minx, miny);
527         }
528
529         immEnd();
530         immUnbindProgram();
531 }
532 #endif /* unused */
533
534 void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4])
535 {
536         int ofs_y = 4 * U.pixelsize;
537
538         GPUVertFormat *format = immVertexFormat();
539         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
540
541         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
542         immUniformColor4fv(color);
543
544         immRecti(pos, pos_x, pos_y - ofs_y, pos_x + len, pos_y - ofs_y + (height * U.pixelsize));
545         immUnbindProgram();
546 }
547
548 /* ************** SPECIAL BUTTON DRAWING FUNCTIONS ************* */
549
550 /* based on UI_draw_roundbox_gl_mode, check on making a version which allows us to skip some sides */
551 void ui_draw_but_TAB_outline(const rcti *rect, float rad, unsigned char highlight[3], unsigned char highlight_fade[3])
552 {
553         GPUVertFormat *format = immVertexFormat();
554         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
555         uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
556         /* add a 1px offset, looks nicer */
557         const int minx = rect->xmin + U.pixelsize, maxx = rect->xmax - U.pixelsize;
558         const int miny = rect->ymin + U.pixelsize, maxy = rect->ymax - U.pixelsize;
559         int a;
560         float vec[4][2] = {
561                 {0.195, 0.02},
562                 {0.55, 0.169},
563                 {0.831, 0.45},
564                 {0.98, 0.805},
565         };
566
567
568         /* mult */
569         for (a = 0; a < 4; a++) {
570                 mul_v2_fl(vec[a], rad);
571         }
572
573         immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
574         immBeginAtMost(GPU_PRIM_LINE_STRIP, 25);
575
576         immAttr3ubv(col, highlight);
577
578         /* start with corner left-top */
579         if (roundboxtype & UI_CNR_TOP_LEFT) {
580                 immVertex2f(pos, minx, maxy - rad);
581                 for (a = 0; a < 4; a++) {
582                         immVertex2f(pos, minx + vec[a][1], maxy - rad + vec[a][0]);
583                 }
584                 immVertex2f(pos, minx + rad, maxy);
585         }
586         else {
587                 immVertex2f(pos, minx, maxy);
588         }
589
590         /* corner right-top */
591         if (roundboxtype & UI_CNR_TOP_RIGHT) {
592                 immVertex2f(pos, maxx - rad, maxy);
593                 for (a = 0; a < 4; a++) {
594                         immVertex2f(pos, maxx - rad + vec[a][0], maxy - vec[a][1]);
595                 }
596                 immVertex2f(pos, maxx, maxy - rad);
597         }
598         else {
599                 immVertex2f(pos, maxx, maxy);
600         }
601
602         immAttr3ubv(col, highlight_fade);
603
604         /* corner right-bottom */
605         if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
606                 immVertex2f(pos, maxx, miny + rad);
607                 for (a = 0; a < 4; a++) {
608                         immVertex2f(pos, maxx - vec[a][1], miny + rad - vec[a][0]);
609                 }
610                 immVertex2f(pos, maxx - rad, miny);
611         }
612         else {
613                 immVertex2f(pos, maxx, miny);
614         }
615
616         /* corner left-bottom */
617         if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
618                 immVertex2f(pos, minx + rad, miny);
619                 for (a = 0; a < 4; a++) {
620                         immVertex2f(pos, minx + rad - vec[a][0], miny + vec[a][1]);
621                 }
622                 immVertex2f(pos, minx, miny + rad);
623         }
624         else {
625                 immVertex2f(pos, minx, miny);
626         }
627
628         immAttr3ubv(col, highlight);
629
630         /* back to corner left-top */
631         immVertex2f(pos, minx, (roundboxtype & UI_CNR_TOP_LEFT) ? (maxy - rad) : maxy);
632
633         immEnd();
634         immUnbindProgram();
635 }
636
637 void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, const uiWidgetColors *UNUSED(wcol), const rcti *rect)
638 {
639 #ifdef WITH_HEADLESS
640         (void)rect;
641         (void)but;
642 #else
643         ImBuf *ibuf = (ImBuf *)but->poin;
644
645         if (!ibuf) return;
646
647         float facx = 1.0f;
648         float facy = 1.0f;
649
650         int w = BLI_rcti_size_x(rect);
651         int h = BLI_rcti_size_y(rect);
652
653         /* scissor doesn't seem to be doing the right thing...? */
654 #if 0
655         /* prevent drawing outside widget area */
656         int scissor[4];
657         GPU_scissor_get_i(scissor);
658         GPU_scissor(rect->xmin, rect->ymin, w, h);
659 #endif
660
661         GPU_blend(true);
662
663         if (w != ibuf->x || h != ibuf->y) {
664                 facx = (float)w / (float)ibuf->x;
665                 facy = (float)h / (float)ibuf->y;
666         }
667
668         IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
669         immDrawPixelsTex(
670                 &state, (float)rect->xmin, (float)rect->ymin, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, ibuf->rect,
671                 facx, facy, NULL);
672
673         GPU_blend(false);
674
675 #if 0
676         // restore scissortest
677         GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
678 #endif
679
680 #endif
681 }
682
683 /**
684  * Draw title and text safe areas.
685  *
686  * \Note This functionn is to be used with the 2D dashed shader enabled.
687  *
688  * \param pos: is a PRIM_FLOAT, 2, GPU_FETCH_FLOAT vertex attrib
689  * \param line_origin: is a PRIM_FLOAT, 2, GPU_FETCH_FLOAT vertex attrib
690  *
691  * The next 4 parameters are the offsets for the view, not the zones.
692  */
693 void UI_draw_safe_areas(
694         uint pos, float x1, float x2, float y1, float y2,
695         const float title_aspect[2], const float action_aspect[2])
696 {
697         const float size_x_half = (x2 - x1) * 0.5f;
698         const float size_y_half = (y2 - y1) * 0.5f;
699
700         const float *safe_areas[] = {title_aspect, action_aspect};
701         const int safe_len = ARRAY_SIZE(safe_areas);
702
703         for (int i = 0; i < safe_len; i++) {
704                 if (safe_areas[i][0] || safe_areas[i][1]) {
705                         float margin_x = safe_areas[i][0] * size_x_half;
706                         float margin_y = safe_areas[i][1] * size_y_half;
707
708                         float minx = x1 + margin_x;
709                         float miny = y1 + margin_y;
710                         float maxx = x2 - margin_x;
711                         float maxy = y2 - margin_y;
712
713                         imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
714                 }
715         }
716 }
717
718
719 static void draw_scope_end(const rctf *rect, GLint *scissor)
720 {
721         /* restore scissortest */
722         GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
723
724         GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
725
726         /* outline */
727         UI_draw_roundbox_corner_set(UI_CNR_ALL);
728         float color[4] = {0.0f, 0.0f, 0.0f, 0.5f};
729         UI_draw_roundbox_4fv(false, rect->xmin - 1, rect->ymin, rect->xmax + 1, rect->ymax + 1, 3.0f, color);
730 }
731
732 static void histogram_draw_one(
733         float r, float g, float b, float alpha,
734         float x, float y, float w, float h, const float *data, int res, const bool is_line,
735         unsigned int pos_attrib)
736 {
737         float color[4] = {r, g, b, alpha};
738
739         /* that can happen */
740         if (res == 0)
741                 return;
742
743         GPU_line_smooth(true);
744         glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
745
746         immUniformColor4fv(color);
747
748         if (is_line) {
749                 /* curve outline */
750                 GPU_line_width(1.5);
751
752                 immBegin(GPU_PRIM_LINE_STRIP, res);
753                 for (int i = 0; i < res; i++) {
754                         float x2 = x + i * (w / (float)res);
755                         immVertex2f(pos_attrib, x2, y + (data[i] * h));
756                 }
757                 immEnd();
758         }
759         else {
760                 /* under the curve */
761                 immBegin(GPU_PRIM_TRI_STRIP, res * 2);
762                 immVertex2f(pos_attrib, x, y);
763                 immVertex2f(pos_attrib, x, y + (data[0] * h));
764                 for (int i = 1; i < res; i++) {
765                         float x2 = x + i * (w / (float)res);
766                         immVertex2f(pos_attrib, x2, y + (data[i] * h));
767                         immVertex2f(pos_attrib, x2, y);
768                 }
769                 immEnd();
770
771                 /* curve outline */
772                 immUniformColor4f(0.0f, 0.0f, 0.0f, 0.25f);
773
774                 GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
775                 immBegin(GPU_PRIM_LINE_STRIP, res);
776                 for (int i = 0; i < res; i++) {
777                         float x2 = x + i * (w / (float)res);
778                         immVertex2f(pos_attrib, x2, y + (data[i] * h));
779                 }
780                 immEnd();
781         }
782
783         GPU_line_smooth(false);
784 }
785
786 #define HISTOGRAM_TOT_GRID_LINES 4
787
788 void ui_draw_but_HISTOGRAM(ARegion *UNUSED(ar), uiBut *but, const uiWidgetColors *UNUSED(wcol), const rcti *recti)
789 {
790         Histogram *hist = (Histogram *)but->poin;
791         int res = hist->x_resolution;
792         const bool is_line = (hist->flag & HISTO_FLAG_LINE) != 0;
793
794         rctf rect = {
795                 .xmin = (float)recti->xmin + 1,
796                 .xmax = (float)recti->xmax - 1,
797                 .ymin = (float)recti->ymin + 1,
798                 .ymax = (float)recti->ymax - 1
799         };
800
801         float w = BLI_rctf_size_x(&rect);
802         float h = BLI_rctf_size_y(&rect) * hist->ymax;
803
804         GPU_blend(true);
805         GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
806
807         float color[4];
808         UI_GetThemeColor4fv(TH_PREVIEW_BACK, color);
809         UI_draw_roundbox_corner_set(UI_CNR_ALL);
810         UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
811
812         /* need scissor test, histogram can draw outside of boundary */
813         int scissor[4];
814         GPU_scissor_get_i(scissor);
815         GPU_scissor(
816                 (rect.xmin - 1),
817                 (rect.ymin - 1),
818                 (rect.xmax + 1) - (rect.xmin - 1),
819                 (rect.ymax + 1) - (rect.ymin - 1));
820
821         GPUVertFormat *format = immVertexFormat();
822         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
823
824         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
825
826         immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f);
827         /* draw grid lines here */
828         for (int i = 1; i <= HISTOGRAM_TOT_GRID_LINES; i++) {
829                 const float fac = (float)i / (float)HISTOGRAM_TOT_GRID_LINES;
830
831                 /* so we can tell the 1.0 color point */
832                 if (i == HISTOGRAM_TOT_GRID_LINES) {
833                         immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
834                 }
835
836                 immBegin(GPU_PRIM_LINES, 4);
837
838                 immVertex2f(pos, rect.xmin, rect.ymin + fac * h);
839                 immVertex2f(pos, rect.xmax, rect.ymin + fac * h);
840
841                 immVertex2f(pos, rect.xmin + fac * w, rect.ymin);
842                 immVertex2f(pos, rect.xmin + fac * w, rect.ymax);
843
844                 immEnd();
845         }
846
847         if (hist->mode == HISTO_MODE_LUMA) {
848                 histogram_draw_one(1.0, 1.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_luma, res, is_line, pos);
849         }
850         else if (hist->mode == HISTO_MODE_ALPHA) {
851                 histogram_draw_one(1.0, 1.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_a, res, is_line, pos);
852         }
853         else {
854                 if (hist->mode == HISTO_MODE_RGB || hist->mode == HISTO_MODE_R)
855                         histogram_draw_one(1.0, 0.0, 0.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_r, res, is_line, pos);
856                 if (hist->mode == HISTO_MODE_RGB || hist->mode == HISTO_MODE_G)
857                         histogram_draw_one(0.0, 1.0, 0.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_g, res, is_line, pos);
858                 if (hist->mode == HISTO_MODE_RGB || hist->mode == HISTO_MODE_B)
859                         histogram_draw_one(0.0, 0.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_b, res, is_line, pos);
860         }
861
862         immUnbindProgram();
863
864         /* outline */
865         draw_scope_end(&rect, scissor);
866 }
867
868 #undef HISTOGRAM_TOT_GRID_LINES
869
870 static void waveform_draw_one(float *waveform, int nbr, const float col[3])
871 {
872         GPUVertFormat format = {0};
873         uint pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
874
875         GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
876         GPU_vertbuf_data_alloc(vbo, nbr);
877
878         GPU_vertbuf_attr_fill(vbo, pos_id, waveform);
879
880         /* TODO store the GPUBatch inside the scope */
881         GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
882         GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR);
883         GPU_batch_uniform_4f(batch, "color", col[0], col[1], col[2], 1.0f);
884         GPU_batch_draw(batch);
885
886         GPU_batch_discard(batch);
887 }
888
889 void ui_draw_but_WAVEFORM(ARegion *UNUSED(ar), uiBut *but, const uiWidgetColors *UNUSED(wcol), const rcti *recti)
890 {
891         Scopes *scopes = (Scopes *)but->poin;
892         int scissor[4];
893         float colors[3][3];
894         float colorsycc[3][3] = {{1, 0, 1}, {1, 1, 0}, {0, 1, 1}};
895         float colors_alpha[3][3], colorsycc_alpha[3][3]; /* colors  pre multiplied by alpha for speed up */
896         float min, max;
897
898         if (scopes == NULL) return;
899
900         rctf rect = {
901                 .xmin = (float)recti->xmin + 1,
902                 .xmax = (float)recti->xmax - 1,
903                 .ymin = (float)recti->ymin + 1,
904                 .ymax = (float)recti->ymax - 1
905         };
906
907         if (scopes->wavefrm_yfac < 0.5f)
908                 scopes->wavefrm_yfac = 0.98f;
909         float w = BLI_rctf_size_x(&rect) - 7;
910         float h = BLI_rctf_size_y(&rect) * scopes->wavefrm_yfac;
911         float yofs = rect.ymin + (BLI_rctf_size_y(&rect) - h) * 0.5f;
912         float w3 = w / 3.0f;
913
914         /* log scale for alpha */
915         float alpha = scopes->wavefrm_alpha * scopes->wavefrm_alpha;
916
917         unit_m3(colors);
918
919         for (int c = 0; c < 3; c++) {
920                 for (int i = 0; i < 3; i++) {
921                         colors_alpha[c][i] = colors[c][i] * alpha;
922                         colorsycc_alpha[c][i] = colorsycc[c][i] * alpha;
923                 }
924         }
925
926         /* Flush text cache before changing scissors. */
927         BLF_batch_draw_flush();
928
929         GPU_blend(true);
930         GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
931
932         float color[4];
933         UI_GetThemeColor4fv(TH_PREVIEW_BACK, color);
934         UI_draw_roundbox_corner_set(UI_CNR_ALL);
935         UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
936
937         /* need scissor test, waveform can draw outside of boundary */
938         GPU_scissor_get_i(scissor);
939         GPU_scissor(
940                 (rect.xmin - 1),
941                 (rect.ymin - 1),
942                 (rect.xmax + 1) - (rect.xmin - 1),
943                 (rect.ymax + 1) - (rect.ymin - 1));
944
945         /* draw scale numbers first before binding any shader */
946         for (int i = 0; i < 6; i++) {
947                 char str[4];
948                 BLI_snprintf(str, sizeof(str), "%-3d", i * 20);
949                 str[3] = '\0';
950                 BLF_color4f(BLF_default(), 1.0f, 1.0f, 1.0f, 0.08f);
951                 BLF_draw_default(rect.xmin + 1, yofs - 5 + (i * 0.2f) * h, 0, str, sizeof(str) - 1);
952         }
953
954         /* Flush text cache before drawing things on top. */
955         BLF_batch_draw_flush();
956
957         GPU_blend(true);
958         GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
959
960         GPUVertFormat *format = immVertexFormat();
961         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
962
963         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
964
965         immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f);
966
967         /* draw grid lines here */
968         immBegin(GPU_PRIM_LINES, 12);
969
970         for (int i = 0; i < 6; i++) {
971                 immVertex2f(pos, rect.xmin + 22, yofs + (i * 0.2f) * h);
972                 immVertex2f(pos, rect.xmax + 1, yofs + (i * 0.2f) * h);
973         }
974
975         immEnd();
976
977         /* 3 vertical separation */
978         if (scopes->wavefrm_mode != SCOPES_WAVEFRM_LUMA) {
979                 immBegin(GPU_PRIM_LINES, 4);
980
981                 for (int i = 1; i < 3; i++) {
982                         immVertex2f(pos, rect.xmin + i * w3, rect.ymin);
983                         immVertex2f(pos, rect.xmin + i * w3, rect.ymax);
984                 }
985
986                 immEnd();
987         }
988
989         /* separate min max zone on the right */
990         immBegin(GPU_PRIM_LINES, 2);
991         immVertex2f(pos, rect.xmin + w, rect.ymin);
992         immVertex2f(pos, rect.xmin + w, rect.ymax);
993         immEnd();
994
995         /* 16-235-240 level in case of ITU-R BT601/709 */
996         immUniformColor4f(1.0f, 0.4f, 0.0f, 0.2f);
997         if (ELEM(scopes->wavefrm_mode, SCOPES_WAVEFRM_YCC_601, SCOPES_WAVEFRM_YCC_709)) {
998                 immBegin(GPU_PRIM_LINES, 8);
999
1000                 immVertex2f(pos, rect.xmin + 22, yofs + h * 16.0f / 255.0f);
1001                 immVertex2f(pos, rect.xmax + 1, yofs + h * 16.0f / 255.0f);
1002
1003                 immVertex2f(pos, rect.xmin + 22, yofs + h * 235.0f / 255.0f);
1004                 immVertex2f(pos, rect.xmin + w3, yofs + h * 235.0f / 255.0f);
1005
1006                 immVertex2f(pos, rect.xmin + 3 * w3, yofs + h * 235.0f / 255.0f);
1007                 immVertex2f(pos, rect.xmax + 1, yofs + h * 235.0f / 255.0f);
1008
1009                 immVertex2f(pos, rect.xmin + w3, yofs + h * 240.0f / 255.0f);
1010                 immVertex2f(pos, rect.xmax + 1, yofs + h * 240.0f / 255.0f);
1011
1012                 immEnd();
1013         }
1014         /* 7.5 IRE black point level for NTSC */
1015         if (scopes->wavefrm_mode == SCOPES_WAVEFRM_LUMA) {
1016                 immBegin(GPU_PRIM_LINES, 2);
1017                 immVertex2f(pos, rect.xmin, yofs + h * 0.075f);
1018                 immVertex2f(pos, rect.xmax + 1, yofs + h * 0.075f);
1019                 immEnd();
1020         }
1021
1022         if (scopes->ok && scopes->waveform_1 != NULL) {
1023                 glBlendFunc(GL_ONE, GL_ONE);
1024                 GPU_point_size(1.0);
1025
1026                 /* LUMA (1 channel) */
1027                 if (scopes->wavefrm_mode == SCOPES_WAVEFRM_LUMA) {
1028                         float col[3] = {alpha, alpha, alpha};
1029
1030                         GPU_matrix_push();
1031                         GPU_matrix_translate_2f(rect.xmin, yofs);
1032                         GPU_matrix_scale_2f(w, h);
1033
1034                         waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, col);
1035
1036                         GPU_matrix_pop();
1037
1038                         /* min max */
1039                         immUniformColor3f(0.5f, 0.5f, 0.5f);
1040                         min = yofs + scopes->minmax[0][0] * h;
1041                         max = yofs + scopes->minmax[0][1] * h;
1042                         CLAMP(min, rect.ymin, rect.ymax);
1043                         CLAMP(max, rect.ymin, rect.ymax);
1044
1045                         immBegin(GPU_PRIM_LINES, 2);
1046                         immVertex2f(pos, rect.xmax - 3, min);
1047                         immVertex2f(pos, rect.xmax - 3, max);
1048                         immEnd();
1049                 }
1050                 /* RGB (3 channel) */
1051                 else if (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB) {
1052                         GPU_matrix_push();
1053                         GPU_matrix_translate_2f(rect.xmin, yofs);
1054                         GPU_matrix_scale_2f(w, h);
1055
1056                         waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, colors_alpha[0]);
1057                         waveform_draw_one(scopes->waveform_2, scopes->waveform_tot, colors_alpha[1]);
1058                         waveform_draw_one(scopes->waveform_3, scopes->waveform_tot, colors_alpha[2]);
1059
1060                         GPU_matrix_pop();
1061                 }
1062                 /* PARADE / YCC (3 channels) */
1063                 else if (ELEM(scopes->wavefrm_mode,
1064                               SCOPES_WAVEFRM_RGB_PARADE,
1065                               SCOPES_WAVEFRM_YCC_601,
1066                               SCOPES_WAVEFRM_YCC_709,
1067                               SCOPES_WAVEFRM_YCC_JPEG
1068                               ))
1069                 {
1070                         int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB_PARADE);
1071
1072                         GPU_matrix_push();
1073                         GPU_matrix_translate_2f(rect.xmin, yofs);
1074                         GPU_matrix_scale_2f(w3, h);
1075
1076                         waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, (rgb) ? colors_alpha[0] : colorsycc_alpha[0]);
1077
1078                         GPU_matrix_translate_2f(1.0f, 0.0f);
1079                         waveform_draw_one(scopes->waveform_2, scopes->waveform_tot, (rgb) ? colors_alpha[1] : colorsycc_alpha[1]);
1080
1081                         GPU_matrix_translate_2f(1.0f, 0.0f);
1082                         waveform_draw_one(scopes->waveform_3, scopes->waveform_tot, (rgb) ? colors_alpha[2] : colorsycc_alpha[2]);
1083
1084                         GPU_matrix_pop();
1085                 }
1086
1087                 /* min max */
1088                 if (scopes->wavefrm_mode != SCOPES_WAVEFRM_LUMA ) {
1089                         for (int c = 0; c < 3; c++) {
1090                                 if (ELEM(scopes->wavefrm_mode, SCOPES_WAVEFRM_RGB_PARADE, SCOPES_WAVEFRM_RGB))
1091                                         immUniformColor3f(colors[c][0] * 0.75f, colors[c][1] * 0.75f, colors[c][2] * 0.75f);
1092                                 else
1093                                         immUniformColor3f(colorsycc[c][0] * 0.75f, colorsycc[c][1] * 0.75f, colorsycc[c][2] * 0.75f);
1094                                 min = yofs + scopes->minmax[c][0] * h;
1095                                 max = yofs + scopes->minmax[c][1] * h;
1096                                 CLAMP(min, rect.ymin, rect.ymax);
1097                                 CLAMP(max, rect.ymin, rect.ymax);
1098
1099                                 immBegin(GPU_PRIM_LINES, 2);
1100                                 immVertex2f(pos, rect.xmin + w + 2 + c * 2, min);
1101                                 immVertex2f(pos, rect.xmin + w + 2 + c * 2, max);
1102                                 immEnd();
1103                         }
1104                 }
1105         }
1106
1107         immUnbindProgram();
1108
1109         /* outline */
1110         draw_scope_end(&rect, scissor);
1111
1112         GPU_blend(false);
1113 }
1114
1115 static float polar_to_x(float center, float diam, float ampli, float angle)
1116 {
1117         return center + diam * ampli * cosf(angle);
1118 }
1119
1120 static float polar_to_y(float center, float diam, float ampli, float angle)
1121 {
1122         return center + diam * ampli * sinf(angle);
1123 }
1124
1125 static void vectorscope_draw_target(unsigned int pos, float centerx, float centery, float diam, const float colf[3])
1126 {
1127         float y, u, v;
1128         float tangle = 0.0f, tampli;
1129         float dangle, dampli, dangle2, dampli2;
1130
1131         rgb_to_yuv(colf[0], colf[1], colf[2], &y, &u, &v, BLI_YUV_ITU_BT709);
1132         if (u > 0 && v >= 0) tangle = atanf(v / u);
1133         else if (u > 0 && v < 0) tangle = atanf(v / u) + 2.0f * (float)M_PI;
1134         else if (u < 0) tangle = atanf(v / u) + (float)M_PI;
1135         else if (u == 0 && v > 0.0f) tangle = M_PI_2;
1136         else if (u == 0 && v < 0.0f) tangle = -M_PI_2;
1137         tampli = sqrtf(u * u + v * v);
1138
1139         /* small target vary by 2.5 degree and 2.5 IRE unit */
1140         immUniformColor4f(1.0f, 1.0f, 1.0f, 0.12f);
1141         dangle = DEG2RADF(2.5f);
1142         dampli = 2.5f / 200.0f;
1143         immBegin(GPU_PRIM_LINE_LOOP, 4);
1144         immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle + dangle), polar_to_y(centery, diam, tampli + dampli, tangle + dangle));
1145         immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle + dangle), polar_to_y(centery, diam, tampli - dampli, tangle + dangle));
1146         immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle - dangle), polar_to_y(centery, diam, tampli - dampli, tangle - dangle));
1147         immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle - dangle), polar_to_y(centery, diam, tampli + dampli, tangle - dangle));
1148         immEnd();
1149         /* big target vary by 10 degree and 20% amplitude */
1150         immUniformColor4f(1.0f, 1.0f, 1.0f, 0.12f);
1151         dangle = DEG2RADF(10.0f);
1152         dampli = 0.2f * tampli;
1153         dangle2 = DEG2RADF(5.0f);
1154         dampli2 = 0.5f * dampli;
1155         immBegin(GPU_PRIM_LINE_STRIP, 3);
1156         immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli - dampli2, tangle + dangle), polar_to_y(centery, diam, tampli + dampli - dampli2, tangle + dangle));
1157         immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle + dangle), polar_to_y(centery, diam, tampli + dampli, tangle + dangle));
1158         immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle + dangle - dangle2), polar_to_y(centery, diam, tampli + dampli, tangle + dangle - dangle2));
1159         immEnd();
1160         immBegin(GPU_PRIM_LINE_STRIP, 3);
1161         immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli + dampli2, tangle + dangle), polar_to_y(centery, diam, tampli - dampli + dampli2, tangle + dangle));
1162         immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle + dangle), polar_to_y(centery, diam, tampli - dampli, tangle + dangle));
1163         immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle + dangle - dangle2), polar_to_y(centery, diam, tampli - dampli, tangle + dangle - dangle2));
1164         immEnd();
1165         immBegin(GPU_PRIM_LINE_STRIP, 3);
1166         immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli + dampli2, tangle - dangle), polar_to_y(centery, diam, tampli - dampli + dampli2, tangle - dangle));
1167         immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle - dangle), polar_to_y(centery, diam, tampli - dampli, tangle - dangle));
1168         immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle - dangle + dangle2), polar_to_y(centery, diam, tampli - dampli, tangle - dangle + dangle2));
1169         immEnd();
1170         immBegin(GPU_PRIM_LINE_STRIP, 3);
1171         immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli - dampli2, tangle - dangle), polar_to_y(centery, diam, tampli + dampli - dampli2, tangle - dangle));
1172         immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle - dangle), polar_to_y(centery, diam, tampli + dampli, tangle - dangle));
1173         immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle - dangle + dangle2), polar_to_y(centery, diam, tampli + dampli, tangle - dangle + dangle2));
1174         immEnd();
1175 }
1176
1177 void ui_draw_but_VECTORSCOPE(ARegion *UNUSED(ar), uiBut *but, const uiWidgetColors *UNUSED(wcol), const rcti *recti)
1178 {
1179         const float skin_rad = DEG2RADF(123.0f); /* angle in radians of the skin tone line */
1180         Scopes *scopes = (Scopes *)but->poin;
1181
1182         const float colors[6][3] = {
1183             {0.75, 0.0, 0.0},  {0.75, 0.75, 0.0}, {0.0, 0.75, 0.0},
1184             {0.0, 0.75, 0.75}, {0.0, 0.0, 0.75},  {0.75, 0.0, 0.75}};
1185
1186         rctf rect = {
1187                 .xmin = (float)recti->xmin + 1,
1188                 .xmax = (float)recti->xmax - 1,
1189                 .ymin = (float)recti->ymin + 1,
1190                 .ymax = (float)recti->ymax - 1
1191         };
1192
1193         float w = BLI_rctf_size_x(&rect);
1194         float h = BLI_rctf_size_y(&rect);
1195         float centerx = rect.xmin + w * 0.5f;
1196         float centery = rect.ymin + h * 0.5f;
1197         float diam = (w < h) ? w : h;
1198
1199         float alpha = scopes->vecscope_alpha * scopes->vecscope_alpha * scopes->vecscope_alpha;
1200
1201         GPU_blend(true);
1202         GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1203
1204         float color[4];
1205         UI_GetThemeColor4fv(TH_PREVIEW_BACK, color);
1206         UI_draw_roundbox_corner_set(UI_CNR_ALL);
1207         UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
1208
1209         /* need scissor test, hvectorscope can draw outside of boundary */
1210         int scissor[4];
1211         GPU_scissor_get_i(scissor);
1212         GPU_scissor(
1213                 (rect.xmin - 1),
1214                 (rect.ymin - 1),
1215                 (rect.xmax + 1) - (rect.xmin - 1),
1216                 (rect.ymax + 1) - (rect.ymin - 1));
1217
1218         GPUVertFormat *format = immVertexFormat();
1219         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1220
1221         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1222
1223         immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f);
1224         /* draw grid elements */
1225         /* cross */
1226         immBegin(GPU_PRIM_LINES, 4);
1227
1228         immVertex2f(pos, centerx - (diam * 0.5f) - 5, centery);
1229         immVertex2f(pos, centerx + (diam * 0.5f) + 5, centery);
1230
1231         immVertex2f(pos, centerx, centery - (diam * 0.5f) - 5);
1232         immVertex2f(pos, centerx, centery + (diam * 0.5f) + 5);
1233
1234         immEnd();
1235
1236         /* circles */
1237         for (int j = 0; j < 5; j++) {
1238                 const int increment = 15;
1239                 immBegin(GPU_PRIM_LINE_LOOP, (int)(360 / increment));
1240                 for (int i = 0; i <= 360 - increment; i += increment) {
1241                         const float a = DEG2RADF((float)i);
1242                         const float r = (j + 1) * 0.1f;
1243                         immVertex2f(pos, polar_to_x(centerx, diam, r, a), polar_to_y(centery, diam, r, a));
1244                 }
1245                 immEnd();
1246         }
1247         /* skin tone line */
1248         immUniformColor4f(1.0f, 0.4f, 0.0f, 0.2f);
1249
1250         immBegin(GPU_PRIM_LINES, 2);
1251         immVertex2f(pos, polar_to_x(centerx, diam, 0.5f, skin_rad), polar_to_y(centery, diam, 0.5f, skin_rad));
1252         immVertex2f(pos, polar_to_x(centerx, diam, 0.1f, skin_rad), polar_to_y(centery, diam, 0.1f, skin_rad));
1253         immEnd();
1254
1255         /* saturation points */
1256         for (int i = 0; i < 6; i++)
1257                 vectorscope_draw_target(pos, centerx, centery, diam, colors[i]);
1258
1259         if (scopes->ok && scopes->vecscope != NULL) {
1260                 /* pixel point cloud */
1261                 float col[3] = {alpha, alpha, alpha};
1262
1263                 glBlendFunc(GL_ONE, GL_ONE);
1264                 GPU_point_size(1.0);
1265
1266                 GPU_matrix_push();
1267                 GPU_matrix_translate_2f(centerx, centery);
1268                 GPU_matrix_scale_1f(diam);
1269
1270                 waveform_draw_one(scopes->vecscope, scopes->waveform_tot, col);
1271
1272                 GPU_matrix_pop();
1273         }
1274
1275         immUnbindProgram();
1276
1277         /* outline */
1278         draw_scope_end(&rect, scissor);
1279
1280         GPU_blend(false);
1281 }
1282
1283 static void ui_draw_colorband_handle_tri_hlight(unsigned int pos, float x1, float y1, float halfwidth, float height)
1284 {
1285         GPU_line_smooth(true);
1286
1287         immBegin(GPU_PRIM_LINE_STRIP, 3);
1288         immVertex2f(pos, x1 + halfwidth, y1);
1289         immVertex2f(pos, x1, y1 + height);
1290         immVertex2f(pos, x1 - halfwidth, y1);
1291         immEnd();
1292
1293         GPU_line_smooth(false);
1294 }
1295
1296 static void ui_draw_colorband_handle_tri(unsigned int pos, float x1, float y1, float halfwidth, float height, bool fill)
1297 {
1298         glEnable(fill ? GL_POLYGON_SMOOTH : GL_LINE_SMOOTH);
1299
1300         immBegin(fill ? GPU_PRIM_TRIS : GPU_PRIM_LINE_LOOP, 3);
1301         immVertex2f(pos, x1 + halfwidth, y1);
1302         immVertex2f(pos, x1, y1 + height);
1303         immVertex2f(pos, x1 - halfwidth, y1);
1304         immEnd();
1305
1306         glDisable(fill ? GL_POLYGON_SMOOTH : GL_LINE_SMOOTH);
1307 }
1308
1309 static void ui_draw_colorband_handle_box(unsigned int pos, float x1, float y1, float x2, float y2, bool fill)
1310 {
1311         immBegin(fill ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_LOOP, 4);
1312         immVertex2f(pos, x1, y1);
1313         immVertex2f(pos, x1, y2);
1314         immVertex2f(pos, x2, y2);
1315         immVertex2f(pos, x2, y1);
1316         immEnd();
1317 }
1318
1319 static void ui_draw_colorband_handle(
1320         uint shdr_pos, const rcti *rect, float x,
1321         const float rgb[3], struct ColorManagedDisplay *display,
1322         bool active)
1323 {
1324         const float sizey = BLI_rcti_size_y(rect);
1325         const float min_width = 3.0f;
1326         float colf[3] = {UNPACK3(rgb)};
1327
1328         float half_width = floorf(sizey / 3.5f);
1329         float height = half_width * 1.4f;
1330
1331         float y1 = rect->ymin + (sizey * 0.16f);
1332         float y2 = rect->ymax;
1333
1334         /* align to pixels */
1335         x  = floorf(x  + 0.5f);
1336         y1 = floorf(y1 + 0.5f);
1337
1338         if (active || half_width < min_width) {
1339                 immUnbindProgram();
1340
1341                 immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
1342
1343                 float viewport_size[4];
1344                 GPU_viewport_size_get_f(viewport_size);
1345                 immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
1346
1347                 immUniform1i("colors_len", 2);  /* "advanced" mode */
1348                 immUniformArray4fv("colors", (float *)(float[][4]){{0.8f, 0.8f, 0.8f, 1.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}, 2);
1349                 immUniform1f("dash_width", active ? 4.0f : 2.0f);
1350
1351                 immBegin(GPU_PRIM_LINES, 2);
1352                 immVertex2f(shdr_pos, x, y1);
1353                 immVertex2f(shdr_pos, x, y2);
1354                 immEnd();
1355
1356                 immUnbindProgram();
1357
1358                 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1359
1360                 /* hide handles when zoomed out too far */
1361                 if (half_width < min_width) {
1362                         return;
1363                 }
1364         }
1365
1366         /* shift handle down */
1367         y1 -= half_width;
1368
1369         immUniformColor3ub(0, 0, 0);
1370         ui_draw_colorband_handle_box(shdr_pos, x - half_width, y1 - 1, x + half_width, y1 + height, false);
1371
1372         /* draw all triangles blended */
1373         GPU_blend(true);
1374
1375         ui_draw_colorband_handle_tri(shdr_pos, x, y1 + height, half_width, half_width, true);
1376
1377         if (active)
1378                 immUniformColor3ub(196, 196, 196);
1379         else
1380                 immUniformColor3ub(96, 96, 96);
1381         ui_draw_colorband_handle_tri(shdr_pos, x, y1 + height, half_width, half_width, true);
1382
1383         if (active)
1384                 immUniformColor3ub(255, 255, 255);
1385         else
1386                 immUniformColor3ub(128, 128, 128);
1387         ui_draw_colorband_handle_tri_hlight(shdr_pos, x, y1 + height - 1, (half_width - 1), (half_width - 1));
1388
1389         immUniformColor3ub(0, 0, 0);
1390         ui_draw_colorband_handle_tri_hlight(shdr_pos, x, y1 + height, half_width, half_width);
1391
1392         GPU_blend(false);
1393
1394         immUniformColor3ub(128, 128, 128);
1395         ui_draw_colorband_handle_box(shdr_pos, x - (half_width - 1), y1, x + (half_width - 1), y1 + height, true);
1396
1397         if (display) {
1398                 IMB_colormanagement_scene_linear_to_display_v3(colf, display);
1399         }
1400
1401         immUniformColor3fv(colf);
1402         ui_draw_colorband_handle_box(shdr_pos, x - (half_width - 2), y1 + 1, x + (half_width - 2), y1 + height - 2, true);
1403 }
1404
1405 void ui_draw_but_COLORBAND(uiBut *but, const uiWidgetColors *UNUSED(wcol), const rcti *rect)
1406 {
1407         struct ColorManagedDisplay *display = ui_block_cm_display_get(but->block);
1408         uint pos_id, col_id;
1409
1410         ColorBand *coba = (ColorBand *)(but->editcoba ? but->editcoba : but->poin);
1411         if (coba == NULL) return;
1412
1413         float x1 = rect->xmin;
1414         float sizex = rect->xmax - x1;
1415         float sizey = BLI_rcti_size_y(rect);
1416         float sizey_solid = sizey * 0.25f;
1417         float y1 = rect->ymin;
1418
1419         GPUVertFormat *format = immVertexFormat();
1420         pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1421         immBindBuiltinProgram(GPU_SHADER_2D_CHECKER);
1422
1423         /* Drawing the checkerboard. */
1424         immUniform4f("color1", UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_DARK / 255.0f, 1.0f);
1425         immUniform4f("color2", UI_ALPHA_CHECKER_LIGHT / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 1.0f);
1426         immUniform1i("size", 8);
1427         immRectf(pos_id, x1, y1, x1 + sizex, rect->ymax);
1428         immUnbindProgram();
1429
1430         /* New format */
1431         format = immVertexFormat();
1432         pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1433         col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1434         immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
1435
1436         /* layer: color ramp */
1437         GPU_blend(true);
1438
1439         CBData *cbd = coba->data;
1440
1441         float v1[2], v2[2];
1442         float colf[4] = {0, 0, 0, 0}; /* initialize in case the colorband isn't valid */
1443
1444         v1[1] = y1 + sizey_solid;
1445         v2[1] = rect->ymax;
1446
1447         immBegin(GPU_PRIM_TRI_STRIP, (sizex + 1) * 2);
1448         for (int a = 0; a <= sizex; a++) {
1449                 float pos = ((float)a) / sizex;
1450                 BKE_colorband_evaluate(coba, pos, colf);
1451                 if (display)
1452                         IMB_colormanagement_scene_linear_to_display_v3(colf, display);
1453
1454                 v1[0] = v2[0] = x1 + a;
1455
1456                 immAttr4fv(col_id, colf);
1457                 immVertex2fv(pos_id, v1);
1458                 immVertex2fv(pos_id, v2);
1459         }
1460         immEnd();
1461
1462         /* layer: color ramp without alpha for reference when manipulating ramp properties */
1463         v1[1] = y1;
1464         v2[1] = y1 + sizey_solid;
1465
1466         immBegin(GPU_PRIM_TRI_STRIP, (sizex + 1) * 2);
1467         for (int a = 0; a <= sizex; a++) {
1468                 float pos = ((float)a) / sizex;
1469                 BKE_colorband_evaluate(coba, pos, colf);
1470                 if (display)
1471                         IMB_colormanagement_scene_linear_to_display_v3(colf, display);
1472
1473                 v1[0] = v2[0] = x1 + a;
1474
1475                 immAttr4f(col_id, colf[0], colf[1], colf[2], 1.0f);
1476                 immVertex2fv(pos_id, v1);
1477                 immVertex2fv(pos_id, v2);
1478         }
1479         immEnd();
1480
1481         immUnbindProgram();
1482
1483         GPU_blend(false);
1484
1485         /* New format */
1486         format = immVertexFormat();
1487         pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1488         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1489
1490         /* layer: box outline */
1491         immUniformColor4f(0.0f, 0.0f, 0.0f, 1.0f);
1492         imm_draw_box_wire_2d(pos_id, x1, y1, x1 + sizex, rect->ymax);
1493
1494         /* layer: box outline */
1495         GPU_blend(true);
1496         immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
1497
1498         immBegin(GPU_PRIM_LINES, 2);
1499         immVertex2f(pos_id, x1, y1);
1500         immVertex2f(pos_id, x1 + sizex, y1);
1501         immEnd();
1502
1503         immUniformColor4f(1.0f, 1.0f, 1.0f, 0.25f);
1504
1505         immBegin(GPU_PRIM_LINES, 2);
1506         immVertex2f(pos_id, x1, y1 - 1);
1507         immVertex2f(pos_id, x1 + sizex, y1 - 1);
1508         immEnd();
1509
1510         GPU_blend(false);
1511
1512         /* layer: draw handles */
1513         for (int a = 0; a < coba->tot; a++, cbd++) {
1514                 if (a != coba->cur) {
1515                         float pos = x1 + cbd->pos * (sizex - 1) + 1;
1516                         ui_draw_colorband_handle(pos_id, rect, pos, &cbd->r, display, false);
1517                 }
1518         }
1519
1520         /* layer: active handle */
1521         if (coba->tot != 0) {
1522                 cbd = &coba->data[coba->cur];
1523                 float pos = x1 + cbd->pos * (sizex - 1) + 1;
1524                 ui_draw_colorband_handle(pos_id, rect, pos, &cbd->r, display, true);
1525         }
1526
1527         immUnbindProgram();
1528 }
1529
1530 void ui_draw_but_UNITVEC(uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
1531 {
1532         /* sphere color */
1533         float diffuse[3] = {1.0f, 1.0f, 1.0f};
1534         float light[3];
1535         float size;
1536
1537         /* backdrop */
1538         UI_draw_roundbox_corner_set(UI_CNR_ALL);
1539         UI_draw_roundbox_3ubAlpha(true, rect->xmin, rect->ymin, rect->xmax, rect->ymax, 5.0f, (unsigned char *)wcol->inner, 255);
1540
1541         glCullFace(GL_BACK);
1542         glEnable(GL_CULL_FACE);
1543
1544         /* setup lights */
1545         ui_but_v3_get(but, light);
1546
1547         /* transform to button */
1548         GPU_matrix_push();
1549
1550         if (BLI_rcti_size_x(rect) < BLI_rcti_size_y(rect))
1551                 size = 0.5f * BLI_rcti_size_x(rect);
1552         else
1553                 size = 0.5f * BLI_rcti_size_y(rect);
1554
1555         GPU_matrix_translate_2f(rect->xmin + 0.5f * BLI_rcti_size_x(rect), rect->ymin + 0.5f * BLI_rcti_size_y(rect));
1556         GPU_matrix_scale_1f(size);
1557
1558         GPUBatch *sphere = GPU_batch_preset_sphere(2);
1559         GPU_batch_program_set_builtin(sphere, GPU_SHADER_SIMPLE_LIGHTING);
1560         GPU_batch_uniform_4f(sphere, "color", diffuse[0], diffuse[1], diffuse[2], 1.0f);
1561         GPU_batch_uniform_3fv(sphere, "light", light);
1562         GPU_batch_draw(sphere);
1563
1564         /* restore */
1565         glDisable(GL_CULL_FACE);
1566
1567         /* AA circle */
1568         GPUVertFormat *format = immVertexFormat();
1569         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1570         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1571         immUniformColor3ubv((unsigned char *)wcol->inner);
1572
1573         GPU_blend(true);
1574         GPU_line_smooth(true);
1575         imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, 1.0f, 32);
1576         GPU_blend(false);
1577         GPU_line_smooth(false);
1578
1579         /* matrix after circle */
1580         GPU_matrix_pop();
1581
1582         immUnbindProgram();
1583 }
1584
1585 static void ui_draw_but_curve_grid(unsigned int pos, const rcti *rect, float zoomx, float zoomy, float offsx, float offsy, float step)
1586 {
1587         float dx = step * zoomx;
1588         float fx = rect->xmin + zoomx * (-offsx);
1589         if (fx > rect->xmin) fx -= dx * (floorf(fx - rect->xmin));
1590
1591         float dy = step * zoomy;
1592         float fy = rect->ymin + zoomy * (-offsy);
1593         if (fy > rect->ymin) fy -= dy * (floorf(fy - rect->ymin));
1594
1595         float line_count = (
1596                 floorf((rect->xmax - fx) / dx) + 1.0f +
1597                 floorf((rect->ymax - fy) / dy) + 1.0f);
1598
1599         immBegin(GPU_PRIM_LINES, (int)line_count * 2);
1600         while (fx < rect->xmax) {
1601                 immVertex2f(pos, fx, rect->ymin);
1602                 immVertex2f(pos, fx, rect->ymax);
1603                 fx += dx;
1604         }
1605         while (fy < rect->ymax) {
1606                 immVertex2f(pos, rect->xmin, fy);
1607                 immVertex2f(pos, rect->xmax, fy);
1608                 fy += dy;
1609         }
1610         immEnd();
1611
1612 }
1613
1614 static void gl_shaded_color(unsigned char *col, int shade)
1615 {
1616         immUniformColor3ub(
1617                 col[0] - shade > 0 ? col[0] - shade : 0,
1618                 col[1] - shade > 0 ? col[1] - shade : 0,
1619                 col[2] - shade > 0 ? col[2] - shade : 0);
1620 }
1621
1622 void ui_draw_but_CURVE(ARegion *ar, uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
1623 {
1624         CurveMapping *cumap;
1625
1626         if (but->editcumap) {
1627                 cumap = but->editcumap;
1628         }
1629         else {
1630                 cumap = (CurveMapping *)but->poin;
1631         }
1632
1633         CurveMap *cuma = &cumap->cm[cumap->cur];
1634
1635         /* need scissor test, curve can draw outside of boundary */
1636         int scissor[4];
1637         GPU_scissor_get_i(scissor);
1638         rcti scissor_new = {
1639                 .xmin = rect->xmin,
1640                 .ymin = rect->ymin,
1641                 .xmax = rect->xmax,
1642                 .ymax = rect->ymax
1643         };
1644         rcti scissor_region = {0, ar->winx, 0, ar->winy};
1645         BLI_rcti_isect(&scissor_new, &scissor_region, &scissor_new);
1646         GPU_scissor(
1647                 scissor_new.xmin,
1648                 scissor_new.ymin,
1649                 BLI_rcti_size_x(&scissor_new),
1650                 BLI_rcti_size_y(&scissor_new));
1651
1652         /* calculate offset and zoom */
1653         float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / BLI_rctf_size_x(&cumap->curr);
1654         float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&cumap->curr);
1655         float offsx = cumap->curr.xmin - (1.0f / zoomx);
1656         float offsy = cumap->curr.ymin - (1.0f / zoomy);
1657
1658         /* Do this first to not mess imm context */
1659         if (but->a1 == UI_GRAD_H) {
1660                 /* magic trigger for curve backgrounds */
1661                 float col[3] = {0.0f, 0.0f, 0.0f}; /* dummy arg */
1662
1663                 rcti grid = {
1664                         .xmin = rect->xmin + zoomx * (-offsx),
1665                         .xmax = grid.xmin + zoomx,
1666                         .ymin = rect->ymin + zoomy * (-offsy),
1667                         .ymax = grid.ymin + zoomy
1668                 };
1669
1670                 ui_draw_gradient(&grid, col, UI_GRAD_H, 1.0f);
1671         }
1672
1673         GPU_line_width(1.0f);
1674
1675         GPUVertFormat *format = immVertexFormat();
1676         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1677         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1678
1679         /* backdrop */
1680         if (but->a1 == UI_GRAD_H) {
1681                 /* grid, hsv uses different grid */
1682                 GPU_blend(true);
1683                 GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1684                 immUniformColor4ub(0, 0, 0, 48);
1685                 ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.1666666f);
1686                 GPU_blend(false);
1687         }
1688         else {
1689                 if (cumap->flag & CUMA_DO_CLIP) {
1690                         gl_shaded_color((unsigned char *)wcol->inner, -20);
1691                         immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1692                         immUniformColor3ubv((unsigned char *)wcol->inner);
1693                         immRectf(pos,
1694                                  rect->xmin + zoomx * (cumap->clipr.xmin - offsx),
1695                                  rect->ymin + zoomy * (cumap->clipr.ymin - offsy),
1696                                  rect->xmin + zoomx * (cumap->clipr.xmax - offsx),
1697                                  rect->ymin + zoomy * (cumap->clipr.ymax - offsy));
1698                 }
1699                 else {
1700                         immUniformColor3ubv((unsigned char *)wcol->inner);
1701                         immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1702                 }
1703
1704                 /* grid, every 0.25 step */
1705                 gl_shaded_color((unsigned char *)wcol->inner, -16);
1706                 ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.25f);
1707                 /* grid, every 1.0 step */
1708                 gl_shaded_color((unsigned char *)wcol->inner, -24);
1709                 ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 1.0f);
1710                 /* axes */
1711                 gl_shaded_color((unsigned char *)wcol->inner, -50);
1712                 immBegin(GPU_PRIM_LINES, 4);
1713                 immVertex2f(pos, rect->xmin, rect->ymin + zoomy * (-offsy));
1714                 immVertex2f(pos, rect->xmax, rect->ymin + zoomy * (-offsy));
1715                 immVertex2f(pos, rect->xmin + zoomx * (-offsx), rect->ymin);
1716                 immVertex2f(pos, rect->xmin + zoomx * (-offsx), rect->ymax);
1717                 immEnd();
1718         }
1719
1720         /* cfra option */
1721         /* XXX 2.48 */
1722 #if 0
1723         if (cumap->flag & CUMA_DRAW_CFRA) {
1724                 immUniformColor3ub(0x60, 0xc0, 0x40);
1725                 immBegin(GPU_PRIM_LINES, 2);
1726                 immVertex2f(pos, rect->xmin + zoomx * (cumap->sample[0] - offsx), rect->ymin);
1727                 immVertex2f(pos, rect->xmin + zoomx * (cumap->sample[0] - offsx), rect->ymax);
1728                 immEnd();
1729         }
1730 #endif
1731         /* sample option */
1732
1733         if (cumap->flag & CUMA_DRAW_SAMPLE) {
1734                 immBegin(GPU_PRIM_LINES, 2); /* will draw one of the following 3 lines */
1735                 if (but->a1 == UI_GRAD_H) {
1736                         float tsample[3];
1737                         float hsv[3];
1738                         linearrgb_to_srgb_v3_v3(tsample, cumap->sample);
1739                         rgb_to_hsv_v(tsample, hsv);
1740                         immUniformColor3ub(240, 240, 240);
1741
1742                         immVertex2f(pos, rect->xmin + zoomx * (hsv[0] - offsx), rect->ymin);
1743                         immVertex2f(pos, rect->xmin + zoomx * (hsv[0] - offsx), rect->ymax);
1744                 }
1745                 else if (cumap->cur == 3) {
1746                         float lum = IMB_colormanagement_get_luminance(cumap->sample);
1747                         immUniformColor3ub(240, 240, 240);
1748
1749                         immVertex2f(pos, rect->xmin + zoomx * (lum - offsx), rect->ymin);
1750                         immVertex2f(pos, rect->xmin + zoomx * (lum - offsx), rect->ymax);
1751                 }
1752                 else {
1753                         if (cumap->cur == 0)
1754                                 immUniformColor3ub(240, 100, 100);
1755                         else if (cumap->cur == 1)
1756                                 immUniformColor3ub(100, 240, 100);
1757                         else
1758                                 immUniformColor3ub(100, 100, 240);
1759
1760                         immVertex2f(pos, rect->xmin + zoomx * (cumap->sample[cumap->cur] - offsx), rect->ymin);
1761                         immVertex2f(pos, rect->xmin + zoomx * (cumap->sample[cumap->cur] - offsx), rect->ymax);
1762                 }
1763                 immEnd();
1764         }
1765         immUnbindProgram();
1766
1767
1768
1769         if (cuma->table == NULL)
1770                 curvemapping_changed(cumap, false);
1771
1772         CurveMapPoint *cmp = cuma->table;
1773         rctf line_range;
1774
1775         /* First curve point. */
1776         if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
1777                 line_range.xmin = rect->xmin;
1778                 line_range.ymin = rect->ymin + zoomy * (cmp[0].y - offsy);
1779         }
1780         else {
1781                 line_range.xmin = rect->xmin + zoomx * (cmp[0].x - offsx + cuma->ext_in[0]);
1782                 line_range.ymin = rect->ymin + zoomy * (cmp[0].y - offsy + cuma->ext_in[1]);
1783         }
1784         /* Last curve point. */
1785         if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
1786                 line_range.xmax = rect->xmax;
1787                 line_range.ymax = rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy);
1788         }
1789         else {
1790                 line_range.xmax = rect->xmin + zoomx * (cmp[CM_TABLE].x - offsx - cuma->ext_out[0]);
1791                 line_range.ymax = rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy - cuma->ext_out[1]);
1792         }
1793
1794         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1795         GPU_blend(true);
1796
1797         /* Curve filled. */
1798         immUniformColor3ubvAlpha((unsigned char *)wcol->item, 128);
1799         GPU_polygon_smooth(true);
1800         immBegin(GPU_PRIM_TRI_STRIP, (CM_TABLE * 2 + 2) + 4);
1801         immVertex2f(pos, line_range.xmin, rect->ymin);
1802         immVertex2f(pos, line_range.xmin, line_range.ymin);
1803         for (int a = 0; a <= CM_TABLE; a++) {
1804                 float fx = rect->xmin + zoomx * (cmp[a].x - offsx);
1805                 float fy = rect->ymin + zoomy * (cmp[a].y - offsy);
1806                 immVertex2f(pos, fx, rect->ymin);
1807                 immVertex2f(pos, fx, fy);
1808         }
1809         immVertex2f(pos, line_range.xmax, rect->ymin);
1810         immVertex2f(pos, line_range.xmax, rect->ymax);
1811         immEnd();
1812         GPU_polygon_smooth(false);
1813
1814         /* Curve line. */
1815         GPU_line_width(1.0f);
1816         immUniformColor3ubvAlpha((unsigned char *)wcol->item, 255);
1817         GPU_line_smooth(true);
1818         immBegin(GPU_PRIM_LINE_STRIP, (CM_TABLE + 1) + 2);
1819         immVertex2f(pos, line_range.xmin, line_range.ymin);
1820         for (int a = 0; a <= CM_TABLE; a++) {
1821                 float fx = rect->xmin + zoomx * (cmp[a].x - offsx);
1822                 float fy = rect->ymin + zoomy * (cmp[a].y - offsy);
1823                 immVertex2f(pos, fx, fy);
1824         }
1825         immVertex2f(pos, line_range.xmax, line_range.ymax);
1826         immEnd();
1827
1828         /* Reset state for fill & line. */
1829         GPU_line_smooth(false);
1830         GPU_blend(false);
1831         immUnbindProgram();
1832
1833         /* The points, use aspect to make them visible on edges. */
1834         format = immVertexFormat();
1835         pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1836         uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1837         immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
1838
1839         cmp = cuma->curve;
1840         GPU_point_size(max_ff(1.0f, min_ff(UI_DPI_FAC / but->block->aspect * 4.0f, 4.0f)));
1841         immBegin(GPU_PRIM_POINTS, cuma->totpoint);
1842         for (int a = 0; a < cuma->totpoint; a++) {
1843                 float color[4];
1844                 if (cmp[a].flag & CUMA_SELECT)
1845                         UI_GetThemeColor4fv(TH_TEXT_HI, color);
1846                 else
1847                         UI_GetThemeColor4fv(TH_TEXT, color);
1848                 float fx = rect->xmin + zoomx * (cmp[a].x - offsx);
1849                 float fy = rect->ymin + zoomy * (cmp[a].y - offsy);
1850                 immAttr4fv(col, color);
1851                 immVertex2f(pos, fx, fy);
1852         }
1853         immEnd();
1854         immUnbindProgram();
1855
1856         /* restore scissortest */
1857         GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
1858
1859         /* outline */
1860         format = immVertexFormat();
1861         pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1862         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1863
1864         immUniformColor3ubv((unsigned char *)wcol->outline);
1865         imm_draw_box_wire_2d(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1866
1867         immUnbindProgram();
1868 }
1869
1870 void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(ar), uiBut *but, const uiWidgetColors *UNUSED(wcol), const rcti *recti)
1871 {
1872         bool ok = false;
1873         MovieClipScopes *scopes = (MovieClipScopes *)but->poin;
1874
1875         rctf rect = {
1876                 .xmin = (float)recti->xmin + 1,
1877                 .xmax = (float)recti->xmax - 1,
1878                 .ymin = (float)recti->ymin + 1,
1879                 .ymax = (float)recti->ymax - 1
1880         };
1881
1882         int width  = BLI_rctf_size_x(&rect) + 1;
1883         int height = BLI_rctf_size_y(&rect);
1884
1885         GPU_blend(true);
1886         GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1887
1888         /* need scissor test, preview image can draw outside of boundary */
1889         int scissor[4];
1890         GPU_scissor_get_i(scissor);
1891         GPU_scissor(
1892                 (rect.xmin - 1),
1893                 (rect.ymin - 1),
1894                 (rect.xmax + 1) - (rect.xmin - 1),
1895                 (rect.ymax + 1) - (rect.ymin - 1));
1896
1897         if (scopes->track_disabled) {
1898                 float color[4] = {0.7f, 0.3f, 0.3f, 0.3f};
1899                 UI_draw_roundbox_corner_set(UI_CNR_ALL);
1900                 UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
1901
1902                 ok = true;
1903         }
1904         else if ((scopes->track_search) &&
1905                  ((!scopes->track_preview) ||
1906                   (scopes->track_preview->x != width || scopes->track_preview->y != height)))
1907         {
1908                 if (scopes->track_preview)
1909                         IMB_freeImBuf(scopes->track_preview);
1910
1911                 ImBuf *tmpibuf = BKE_tracking_sample_pattern(
1912                         scopes->frame_width, scopes->frame_height,
1913                         scopes->track_search, scopes->track,
1914                         &scopes->undist_marker, true, scopes->use_track_mask,
1915                         width, height, scopes->track_pos);
1916                 if (tmpibuf) {
1917                         if (tmpibuf->rect_float)
1918                                 IMB_rect_from_float(tmpibuf);
1919
1920                         if (tmpibuf->rect)
1921                                 scopes->track_preview = tmpibuf;
1922                         else
1923                                 IMB_freeImBuf(tmpibuf);
1924                 }
1925         }
1926
1927         if (!ok && scopes->track_preview) {
1928                 GPU_matrix_push();
1929
1930                 /* draw content of pattern area */
1931                 GPU_scissor(rect.xmin, rect.ymin, scissor[2], scissor[3]);
1932
1933                 if (width > 0 && height > 0) {
1934                         ImBuf *drawibuf = scopes->track_preview;
1935                         float col_sel[4], col_outline[4];
1936
1937                         if (scopes->use_track_mask) {
1938                                 float color[4] = {0.0f, 0.0f, 0.0f, 0.3f};
1939                                 UI_draw_roundbox_corner_set(UI_CNR_ALL);
1940                                 UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
1941                         }
1942
1943                         IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
1944                         immDrawPixelsTex(&state, rect.xmin, rect.ymin + 1, drawibuf->x, drawibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, drawibuf->rect, 1.0f, 1.0f, NULL);
1945
1946                         /* draw cross for pixel position */
1947                         GPU_matrix_translate_2f(rect.xmin + scopes->track_pos[0], rect.ymin + scopes->track_pos[1]);
1948                         GPU_scissor(
1949                                 rect.xmin,
1950                                 rect.ymin,
1951                                 BLI_rctf_size_x(&rect),
1952                                 BLI_rctf_size_y(&rect));
1953
1954                         GPUVertFormat *format = immVertexFormat();
1955                         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1956                         uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1957                         immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
1958
1959                         UI_GetThemeColor4fv(TH_SEL_MARKER, col_sel);
1960                         UI_GetThemeColor4fv(TH_MARKER_OUTLINE, col_outline);
1961
1962                         /* Do stipple cross with geometry */
1963                         immBegin(GPU_PRIM_LINES, 7 * 2 * 2);
1964                         float pos_sel[8] = {-10.0f, -7.0f, -4.0f, -1.0f, 2.0f, 5.0f, 8.0f, 11.0f};
1965                         for (int axe = 0; axe < 2; ++axe) {
1966                                 for (int i = 0; i < 7; ++i) {
1967                                         float x1 = pos_sel[i] * (1 - axe);
1968                                         float y1 = pos_sel[i] * axe;
1969                                         float x2 = pos_sel[i + 1] * (1 - axe);
1970                                         float y2 = pos_sel[i + 1] * axe;
1971
1972                                         if (i % 2 == 1)
1973                                                 immAttr4fv(col, col_sel);
1974                                         else
1975                                                 immAttr4fv(col, col_outline);
1976
1977                                         immVertex2f(pos, x1, y1);
1978                                         immVertex2f(pos, x2, y2);
1979                                 }
1980                         }
1981                         immEnd();
1982
1983                         immUnbindProgram();
1984                 }
1985
1986                 GPU_matrix_pop();
1987
1988                 ok = true;
1989         }
1990
1991         if (!ok) {
1992                 float color[4] = {0.0f, 0.0f, 0.0f, 0.3f};
1993                 UI_draw_roundbox_corner_set(UI_CNR_ALL);
1994                 UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
1995         }
1996
1997         /* outline */
1998         draw_scope_end(&rect, scissor);
1999
2000         GPU_blend(false);
2001 }
2002
2003 void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, const uiWidgetColors *UNUSED(wcol), const rcti *recti)
2004 {
2005         static const float size = 5.0f;
2006
2007         /* 16 values of sin function */
2008         const float si[16] = {
2009             0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f,
2010             0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f,
2011             -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f,
2012             -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f
2013         };
2014         /* 16 values of cos function */
2015         const float co[16] = {
2016             1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f,
2017             -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f,
2018             -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f,
2019             0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f,
2020         };
2021
2022         int scissor[4];
2023
2024         /* need scissor test, can draw outside of boundary */
2025         GPU_scissor_get_i(scissor);
2026
2027         rcti scissor_new = {
2028                 .xmin = recti->xmin,
2029                 .ymin = recti->ymin,
2030                 .xmax = recti->xmax,
2031                 .ymax = recti->ymax
2032         };
2033
2034         rcti scissor_region = {0, ar->winx, 0, ar->winy};
2035
2036         BLI_rcti_isect(&scissor_new, &scissor_region, &scissor_new);
2037         GPU_scissor(
2038                 scissor_new.xmin,
2039                 scissor_new.ymin,
2040                 BLI_rcti_size_x(&scissor_new),
2041                 BLI_rcti_size_y(&scissor_new));
2042
2043         float x = 0.5f * (recti->xmin + recti->xmax);
2044         float y = 0.5f * (recti->ymin + recti->ymax);
2045
2046         GPUVertFormat *format = immVertexFormat();
2047         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2048         immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
2049         immUniformColor4ubv(but->col);
2050
2051         GPU_blend(true);
2052         immBegin(GPU_PRIM_TRI_FAN, 16);
2053         for (int a = 0; a < 16; a++)
2054                 immVertex2f(pos, x + size * si[a], y + size * co[a]);
2055         immEnd();
2056
2057         immUniformColor4ub(0, 0, 0, 150);
2058         GPU_line_width(1);
2059         GPU_line_smooth(true);
2060         immBegin(GPU_PRIM_LINE_LOOP, 16);
2061         for (int a = 0; a < 16; a++)
2062                 immVertex2f(pos, x + size * si[a], y + size * co[a]);
2063         immEnd();
2064         GPU_line_smooth(false);
2065         GPU_blend(false);
2066
2067         immUnbindProgram();
2068
2069         /* restore scissortest */
2070         GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
2071 }
2072
2073 /* ****************************************************** */
2074
2075 /* TODO: high quality UI drop shadows using GLSL shader and single draw call
2076  * would replace / modify the following 3 functions  - merwin
2077  */
2078
2079 static void ui_shadowbox(unsigned pos, unsigned color, float minx, float miny, float maxx, float maxy, float shadsize, unsigned char alpha)
2080 {
2081         /**
2082          * <pre>
2083          *          v1-_
2084          *          |   -_v2
2085          *          |     |
2086          *          |     |
2087          *          |     |
2088          * v7_______v3____v4
2089          * \        |     /
2090          *  \       |   _v5
2091          *  v8______v6_-
2092          * </pre>
2093          */
2094         const float v1[2] = {maxx,                   maxy - 0.3f * shadsize};
2095         const float v2[2] = {maxx + shadsize,        maxy - 0.75f * shadsize};
2096         const float v3[2] = {maxx,                   miny};
2097         const float v4[2] = {maxx + shadsize,        miny};
2098
2099         const float v5[2] = {maxx + 0.7f * shadsize, miny - 0.7f * shadsize};
2100
2101         const float v6[2] = {maxx,                   miny - shadsize};
2102         const float v7[2] = {minx + 0.3f * shadsize, miny};
2103         const float v8[2] = {minx + 0.5f * shadsize, miny - shadsize};
2104
2105         /* right quad */
2106         immAttr4ub(color, 0, 0, 0, alpha);
2107         immVertex2fv(pos, v3);
2108         immVertex2fv(pos, v1);
2109         immAttr4ub(color, 0, 0, 0, 0);
2110         immVertex2fv(pos, v2);
2111
2112         immVertex2fv(pos, v2);
2113         immVertex2fv(pos, v4);
2114         immAttr4ub(color, 0, 0, 0, alpha);
2115         immVertex2fv(pos, v3);
2116
2117         /* corner shape */
2118         /* immAttr4ub(color, 0, 0, 0, alpha); */  /* Not needed, done above in previous tri */
2119         immVertex2fv(pos, v3);
2120         immAttr4ub(color, 0, 0, 0, 0);
2121         immVertex2fv(pos, v4);
2122         immVertex2fv(pos, v5);
2123
2124         immVertex2fv(pos, v5);
2125         immVertex2fv(pos, v6);
2126         immAttr4ub(color, 0, 0, 0, alpha);
2127         immVertex2fv(pos, v3);
2128
2129         /* bottom quad */
2130         /* immAttr4ub(color, 0, 0, 0, alpha); */  /* Not needed, done above in previous tri */
2131         immVertex2fv(pos, v3);
2132         immAttr4ub(color, 0, 0, 0, 0);
2133         immVertex2fv(pos, v6);
2134         immVertex2fv(pos, v8);
2135
2136         immVertex2fv(pos, v8);
2137         immAttr4ub(color, 0, 0, 0, alpha);
2138         immVertex2fv(pos, v7);
2139         immVertex2fv(pos, v3);
2140 }
2141
2142 void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy)
2143 {
2144         GPU_blend(true);
2145
2146         GPUVertFormat *format = immVertexFormat();
2147         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2148         uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
2149
2150         immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
2151
2152         immBegin(GPU_PRIM_TRIS, 54);
2153
2154         /* accumulated outline boxes to make shade not linear, is more pleasant */
2155         ui_shadowbox(pos, color, minx, miny, maxx, maxy, 11.0, (20 * alpha) >> 8);
2156         ui_shadowbox(pos, color, minx, miny, maxx, maxy, 7.0, (40 * alpha) >> 8);
2157         ui_shadowbox(pos, color, minx, miny, maxx, maxy, 5.0, (80 * alpha) >> 8);
2158
2159         immEnd();
2160
2161         immUnbindProgram();
2162
2163         GPU_blend(false);
2164 }
2165
2166
2167 void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int UNUSED(select))
2168 {
2169         float rad;
2170
2171         if (radius > (BLI_rctf_size_y(rct) - 10.0f) * 0.5f)
2172                 rad = (BLI_rctf_size_y(rct) - 10.0f) * 0.5f;
2173         else
2174                 rad = radius;
2175
2176         int a, i = 12;
2177 #if 0
2178         if (select) {
2179                 a = i * aspect; /* same as below */
2180         }
2181         else
2182 #endif
2183         {
2184                 a = i * aspect;
2185         }
2186
2187         GPU_blend(true);
2188         const float dalpha = alpha * 2.0f / 255.0f;
2189         float calpha = dalpha;
2190         float visibility = 1.0f;
2191         for (; i--;) {
2192                 /* alpha ranges from 2 to 20 or so */
2193 #if 0 /* Old Method (pre 2.8) */
2194                 float color[4] = {0.0f, 0.0f, 0.0f, calpha};
2195                 UI_draw_roundbox_4fv(true, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax - 10.0f + a, rad + a, color);
2196 #endif
2197                 /* Compute final visibility to match old method result. */
2198                 /* TODO we could just find a better fit function inside the shader instead of this. */
2199                 visibility = visibility * (1.0f - calpha);
2200                 calpha += dalpha;
2201         }
2202
2203         uiWidgetBaseParameters widget_params = {
2204                 .recti.xmin = rct->xmin, .recti.ymin = rct->ymin,
2205                 .recti.xmax = rct->xmax, .recti.ymax = rct->ymax - 10.0f,
2206                 .rect.xmin = rct->xmin - a, .rect.ymin = rct->ymin - a,
2207                 .rect.xmax = rct->xmax + a, .rect.ymax = rct->ymax - 10.0f + a,
2208                 .radi = rad,
2209                 .rad = rad + a,
2210                 .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
2211                 .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
2212                 .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
2213                 .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
2214                 .alpha_discard = 1.0f,
2215         };
2216
2217         GPUBatch *batch = ui_batch_roundbox_shadow_get();
2218         GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_SHADOW);
2219         GPU_batch_uniform_4fv_array(batch, "parameters", 4, (float *)&widget_params);
2220         GPU_batch_uniform_1f(batch, "alpha", 1.0f - visibility);
2221         GPU_batch_draw(batch);
2222
2223         /* outline emphasis */
2224         GPU_line_smooth(true);
2225         float color[4] = {0.0f, 0.0f, 0.0f, 0.4f};
2226         UI_draw_roundbox_4fv(false, rct->xmin - 0.5f, rct->ymin - 0.5f, rct->xmax + 0.5f, rct->ymax + 0.5f, radius + 0.5f, color);
2227         GPU_line_smooth(false);
2228
2229         GPU_blend(false);
2230 }