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