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