Orientation for 3D cursor
[blender.git] / source / blender / draw / intern / draw_cache.c
1 /*
2  * Copyright 2016, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Blender Institute
19  *
20  */
21
22 /** \file draw_cache.c
23  *  \ingroup draw
24  */
25
26
27 #include "DNA_scene_types.h"
28 #include "DNA_mesh_types.h"
29 #include "DNA_curve_types.h"
30 #include "DNA_object_types.h"
31 #include "DNA_particle_types.h"
32 #include "DNA_modifier_types.h"
33 #include "DNA_lattice_types.h"
34
35 #include "UI_resources.h"
36
37 #include "BLI_utildefines.h"
38 #include "BLI_math.h"
39
40 #include "GPU_batch.h"
41
42 #include "draw_cache.h"
43 #include "draw_cache_impl.h"
44
45 /* Batch's only (free'd as an array) */
46 static struct DRWShapeCache {
47         Gwn_Batch *drw_single_vertice;
48         Gwn_Batch *drw_cursor;
49         Gwn_Batch *drw_cursor_only_circle;
50         Gwn_Batch *drw_fullscreen_quad;
51         Gwn_Batch *drw_quad;
52         Gwn_Batch *drw_sphere;
53         Gwn_Batch *drw_screenspace_circle;
54         Gwn_Batch *drw_plain_axes;
55         Gwn_Batch *drw_single_arrow;
56         Gwn_Batch *drw_cube;
57         Gwn_Batch *drw_circle;
58         Gwn_Batch *drw_square;
59         Gwn_Batch *drw_line;
60         Gwn_Batch *drw_line_endpoints;
61         Gwn_Batch *drw_empty_sphere;
62         Gwn_Batch *drw_empty_cone;
63         Gwn_Batch *drw_arrows;
64         Gwn_Batch *drw_axis_names;
65         Gwn_Batch *drw_image_plane;
66         Gwn_Batch *drw_image_plane_wire;
67         Gwn_Batch *drw_field_wind;
68         Gwn_Batch *drw_field_force;
69         Gwn_Batch *drw_field_vortex;
70         Gwn_Batch *drw_field_tube_limit;
71         Gwn_Batch *drw_field_cone_limit;
72         Gwn_Batch *drw_lamp;
73         Gwn_Batch *drw_lamp_shadows;
74         Gwn_Batch *drw_lamp_sunrays;
75         Gwn_Batch *drw_lamp_area;
76         Gwn_Batch *drw_lamp_hemi;
77         Gwn_Batch *drw_lamp_spot;
78         Gwn_Batch *drw_lamp_spot_square;
79         Gwn_Batch *drw_speaker;
80         Gwn_Batch *drw_lightprobe_cube;
81         Gwn_Batch *drw_lightprobe_planar;
82         Gwn_Batch *drw_lightprobe_grid;
83         Gwn_Batch *drw_bone_octahedral;
84         Gwn_Batch *drw_bone_octahedral_wire;
85         Gwn_Batch *drw_bone_box;
86         Gwn_Batch *drw_bone_box_wire;
87         Gwn_Batch *drw_bone_wire_wire;
88         Gwn_Batch *drw_bone_envelope;
89         Gwn_Batch *drw_bone_envelope_outline;
90         Gwn_Batch *drw_bone_point;
91         Gwn_Batch *drw_bone_point_wire;
92         Gwn_Batch *drw_bone_stick;
93         Gwn_Batch *drw_bone_arrows;
94         Gwn_Batch *drw_camera;
95         Gwn_Batch *drw_camera_frame;
96         Gwn_Batch *drw_camera_tria;
97         Gwn_Batch *drw_camera_focus;
98         Gwn_Batch *drw_particle_cross;
99         Gwn_Batch *drw_particle_circle;
100         Gwn_Batch *drw_particle_axis;
101 } SHC = {NULL};
102
103 void DRW_shape_cache_free(void)
104 {
105         uint i = sizeof(SHC) / sizeof(Gwn_Batch *);
106         Gwn_Batch **batch = (Gwn_Batch **)&SHC;
107         while (i--) {
108                 GWN_BATCH_DISCARD_SAFE(*batch);
109                 batch++;
110         }
111 }
112
113
114 /* -------------------------------------------------------------------- */
115
116 /** \name Helper functions
117  * \{ */
118
119 static void add_fancy_edge(
120         Gwn_VertBuf *vbo, unsigned int pos_id, unsigned int n1_id, unsigned int n2_id,
121         unsigned int *v_idx, const float co1[3], const float co2[3],
122 const float n1[3], const float n2[3])
123 {
124         GWN_vertbuf_attr_set(vbo, n1_id, *v_idx, n1);
125         GWN_vertbuf_attr_set(vbo, n2_id, *v_idx, n2);
126         GWN_vertbuf_attr_set(vbo, pos_id, (*v_idx)++, co1);
127
128         GWN_vertbuf_attr_set(vbo, n1_id, *v_idx, n1);
129         GWN_vertbuf_attr_set(vbo, n2_id, *v_idx, n2);
130         GWN_vertbuf_attr_set(vbo, pos_id, (*v_idx)++, co2);
131 }
132
133 #if 0 /* UNUSED */
134 static void add_lat_lon_vert(
135         Gwn_VertBuf *vbo, unsigned int pos_id, unsigned int nor_id,
136         unsigned int *v_idx, const float rad, const float lat, const float lon)
137 {
138         float pos[3], nor[3];
139         nor[0] = sinf(lat) * cosf(lon);
140         nor[1] = cosf(lat);
141         nor[2] = sinf(lat) * sinf(lon);
142         mul_v3_v3fl(pos, nor, rad);
143
144         GWN_vertbuf_attr_set(vbo, nor_id, *v_idx, nor);
145         GWN_vertbuf_attr_set(vbo, pos_id, (*v_idx)++, pos);
146 }
147 #endif
148
149 static Gwn_VertBuf *fill_arrows_vbo(const float scale)
150 {
151         /* Position Only 3D format */
152         static Gwn_VertFormat format = { 0 };
153         static struct { uint pos; } attr_id;
154         if (format.attrib_ct == 0) {
155                 attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
156         }
157
158         /* Line */
159         Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
160         GWN_vertbuf_data_alloc(vbo, 6 * 3);
161
162         float v1[3] = {0.0, 0.0, 0.0};
163         float v2[3] = {0.0, 0.0, 0.0};
164         float vtmp1[3], vtmp2[3];
165
166         for (int axis = 0; axis < 3; axis++) {
167                 const int arrow_axis = (axis == 0) ? 1 : 0;
168
169                 v2[axis] = 1.0f;
170                 mul_v3_v3fl(vtmp1, v1, scale);
171                 mul_v3_v3fl(vtmp2, v2, scale);
172                 GWN_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 0, vtmp1);
173                 GWN_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 1, vtmp2);
174
175                 v1[axis] = 0.85f;
176                 v1[arrow_axis] = -0.08f;
177                 mul_v3_v3fl(vtmp1, v1, scale);
178                 mul_v3_v3fl(vtmp2, v2, scale);
179                 GWN_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 2, vtmp1);
180                 GWN_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 3, vtmp2);
181
182                 v1[arrow_axis] = 0.08f;
183                 mul_v3_v3fl(vtmp1, v1, scale);
184                 mul_v3_v3fl(vtmp2, v2, scale);
185                 GWN_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 4, vtmp1);
186                 GWN_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 5, vtmp2);
187
188                 /* reset v1 & v2 to zero */
189                 v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
190         }
191
192         return vbo;
193 }
194
195 static Gwn_VertBuf *sphere_wire_vbo(const float rad)
196 {
197 #define NSEGMENTS 32
198         /* Position Only 3D format */
199         static Gwn_VertFormat format = { 0 };
200         static struct { uint pos; } attr_id;
201         if (format.attrib_ct == 0) {
202                 attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
203         }
204
205         Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
206         GWN_vertbuf_data_alloc(vbo, NSEGMENTS * 2 * 3);
207
208         /* a single ring of vertices */
209         float p[NSEGMENTS][2];
210         for (int i = 0; i < NSEGMENTS; ++i) {
211                 float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
212                 p[i][0] = rad * cosf(angle);
213                 p[i][1] = rad * sinf(angle);
214         }
215
216         for (int axis = 0; axis < 3; ++axis) {
217                 for (int i = 0; i < NSEGMENTS; ++i) {
218                         for (int j = 0; j < 2; ++j) {
219                                 float cv[2], v[3];
220
221                                 cv[0] = p[(i + j) % NSEGMENTS][0];
222                                 cv[1] = p[(i + j) % NSEGMENTS][1];
223
224                                 if (axis == 0)
225                                         v[0] = cv[0], v[1] = cv[1], v[2] = 0.0f;
226                                 else if (axis == 1)
227                                         v[0] = cv[0], v[1] = 0.0f,  v[2] = cv[1];
228                                 else
229                                         v[0] = 0.0f,  v[1] = cv[0], v[2] = cv[1];
230
231                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + j + (NSEGMENTS * 2 * axis), v);
232                         }
233                 }
234         }
235
236         return vbo;
237 #undef NSEGMENTS
238 }
239
240 /* Quads */
241 /* Use this one for rendering fullscreen passes. For 3D objects use DRW_cache_quad_get(). */
242 Gwn_Batch *DRW_cache_fullscreen_quad_get(void)
243 {
244         if (!SHC.drw_fullscreen_quad) {
245                 /* Use a triangle instead of a real quad */
246                 /* https://www.slideshare.net/DevCentralAMD/vertex-shader-tricks-bill-bilodeau - slide 14 */
247                 float pos[3][2] = {{-1.0f, -1.0f}, { 3.0f, -1.0f}, {-1.0f,  3.0f}};
248                 float uvs[3][2] = {{ 0.0f,  0.0f}, { 2.0f,  0.0f}, { 0.0f,  2.0f}};
249
250                 /* Position Only 2D format */
251                 static Gwn_VertFormat format = { 0 };
252                 static struct { uint pos, uvs; } attr_id;
253                 if (format.attrib_ct == 0) {
254                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
255                         attr_id.uvs = GWN_vertformat_attr_add(&format, "uvs", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
256                 }
257
258                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
259                 GWN_vertbuf_data_alloc(vbo, 3);
260
261                 for (int i = 0; i < 3; ++i) {
262                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i, pos[i]);
263                         GWN_vertbuf_attr_set(vbo, attr_id.uvs, i, uvs[i]);
264                 }
265
266                 SHC.drw_fullscreen_quad = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO);
267         }
268         return SHC.drw_fullscreen_quad;
269 }
270
271 /* Just a regular quad with 4 vertices. */
272 Gwn_Batch *DRW_cache_quad_get(void)
273 {
274         if (!SHC.drw_quad) {
275                 float pos[4][2] = {{-1.0f, -1.0f}, { 1.0f, -1.0f}, {1.0f,  1.0f}, {-1.0f,  1.0f}};
276                 float uvs[4][2] = {{ 0.0f,  0.0f}, { 1.0f,  0.0f}, {1.0f,  1.0f}, { 0.0f,  1.0f}};
277
278                 /* Position Only 2D format */
279                 static Gwn_VertFormat format = { 0 };
280                 static struct { uint pos, uvs; } attr_id;
281                 if (format.attrib_ct == 0) {
282                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
283                         attr_id.uvs = GWN_vertformat_attr_add(&format, "uvs", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
284                 }
285
286                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
287                 GWN_vertbuf_data_alloc(vbo, 4);
288
289                 for (int i = 0; i < 4; ++i) {
290                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i, pos[i]);
291                         GWN_vertbuf_attr_set(vbo, attr_id.uvs, i, uvs[i]);
292                 }
293
294                 SHC.drw_quad = GWN_batch_create_ex(GWN_PRIM_TRI_FAN, vbo, NULL, GWN_BATCH_OWNS_VBO);
295         }
296         return SHC.drw_quad;
297 }
298
299 /* Sphere */
300 Gwn_Batch *DRW_cache_sphere_get(void)
301 {
302         if (!SHC.drw_sphere) {
303                 SHC.drw_sphere = gpu_batch_sphere(32, 24);
304         }
305         return SHC.drw_sphere;
306 }
307
308 /** \} */
309
310 /* -------------------------------------------------------------------- */
311
312 /** \name Common
313  * \{ */
314
315 Gwn_Batch *DRW_cache_cube_get(void)
316 {
317         if (!SHC.drw_cube) {
318                 const GLfloat verts[8][3] = {
319                         {-1.0f, -1.0f, -1.0f},
320                         {-1.0f, -1.0f,  1.0f},
321                         {-1.0f,  1.0f, -1.0f},
322                         {-1.0f,  1.0f,  1.0f},
323                         { 1.0f, -1.0f, -1.0f},
324                         { 1.0f, -1.0f,  1.0f},
325                         { 1.0f,  1.0f, -1.0f},
326                         { 1.0f,  1.0f,  1.0f}
327                 };
328
329                 const GLubyte indices[24] = {0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6};
330
331                 /* Position Only 3D format */
332                 static Gwn_VertFormat format = { 0 };
333                 static struct { uint pos; } attr_id;
334                 if (format.attrib_ct == 0) {
335                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
336                 }
337
338                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
339                 GWN_vertbuf_data_alloc(vbo, 24);
340
341                 for (int i = 0; i < 24; ++i) {
342                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i, verts[indices[i]]);
343                 }
344
345                 SHC.drw_cube = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
346         }
347         return SHC.drw_cube;
348 }
349
350 Gwn_Batch *DRW_cache_circle_get(void)
351 {
352 #define CIRCLE_RESOL 64
353         if (!SHC.drw_circle) {
354                 float v[3] = {0.0f, 0.0f, 0.0f};
355
356                 /* Position Only 3D format */
357                 static Gwn_VertFormat format = { 0 };
358                 static struct { uint pos; } attr_id;
359                 if (format.attrib_ct == 0) {
360                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
361                 }
362
363                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
364                 GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL);
365
366                 for (int a = 0; a < CIRCLE_RESOL; a++) {
367                         v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
368                         v[2] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
369                         v[1] = 0.0f;
370                         GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v);
371                 }
372
373                 SHC.drw_circle = GWN_batch_create_ex(GWN_PRIM_LINE_LOOP, vbo, NULL, GWN_BATCH_OWNS_VBO);
374         }
375         return SHC.drw_circle;
376 #undef CIRCLE_RESOL
377 }
378
379 Gwn_Batch *DRW_cache_square_get(void)
380 {
381         if (!SHC.drw_square) {
382                 float p[4][3] = {{ 1.0f, 0.0f,  1.0f},
383                                  { 1.0f, 0.0f, -1.0f},
384                                  {-1.0f, 0.0f, -1.0f},
385                                  {-1.0f, 0.0f,  1.0f}};
386
387                 /* Position Only 3D format */
388                 static Gwn_VertFormat format = { 0 };
389                 static struct { uint pos; } attr_id;
390                 if (format.attrib_ct == 0) {
391                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
392                 }
393
394                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
395                 GWN_vertbuf_data_alloc(vbo, 8);
396
397                 for (int i = 0; i < 4; i++) {
398                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 2,     p[i % 4]);
399                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + 1, p[(i + 1) % 4]);
400                 }
401
402                 SHC.drw_square = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
403         }
404         return SHC.drw_square;
405 }
406
407 Gwn_Batch *DRW_cache_single_line_get(void)
408 {
409         /* Z axis line */
410         if (!SHC.drw_line) {
411                 float v1[3] = {0.0f, 0.0f, 0.0f};
412                 float v2[3] = {0.0f, 0.0f, 1.0f};
413
414                 /* Position Only 3D format */
415                 static Gwn_VertFormat format = { 0 };
416                 static struct { uint pos; } attr_id;
417                 if (format.attrib_ct == 0) {
418                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
419                 }
420
421                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
422                 GWN_vertbuf_data_alloc(vbo, 2);
423
424                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
425                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 1, v2);
426
427                 SHC.drw_line = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
428         }
429         return SHC.drw_line;
430 }
431
432 Gwn_Batch *DRW_cache_single_line_endpoints_get(void)
433 {
434         /* Z axis line */
435         if (!SHC.drw_line_endpoints) {
436                 float v1[3] = {0.0f, 0.0f, 0.0f};
437                 float v2[3] = {0.0f, 0.0f, 1.0f};
438
439                 /* Position Only 3D format */
440                 static Gwn_VertFormat format = { 0 };
441                 static struct { uint pos; } attr_id;
442                 if (format.attrib_ct == 0) {
443                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
444                 }
445
446                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
447                 GWN_vertbuf_data_alloc(vbo, 2);
448
449                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
450                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 1, v2);
451
452                 SHC.drw_line_endpoints = GWN_batch_create_ex(GWN_PRIM_POINTS, vbo, NULL, GWN_BATCH_OWNS_VBO);
453         }
454         return SHC.drw_line_endpoints;
455 }
456
457 Gwn_Batch *DRW_cache_screenspace_circle_get(void)
458 {
459 #define CIRCLE_RESOL 32
460         if (!SHC.drw_screenspace_circle) {
461                 float v[3] = {0.0f, 0.0f, 0.0f};
462
463                 /* Position Only 3D format */
464                 static Gwn_VertFormat format = { 0 };
465                 static struct { uint pos; } attr_id;
466                 if (format.attrib_ct == 0) {
467                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
468                 }
469
470                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
471                 GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL + 1);
472
473                 for (int a = 0; a <= CIRCLE_RESOL; a++) {
474                         v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
475                         v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
476                         GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v);
477                 }
478
479                 SHC.drw_screenspace_circle = GWN_batch_create_ex(GWN_PRIM_LINE_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
480         }
481         return SHC.drw_screenspace_circle;
482 #undef CIRCLE_RESOL
483 }
484
485 /** \} */
486
487 /* -------------------------------------------------------------------- */
488
489 /** \name Common Object API
490  * \{ */
491
492 Gwn_Batch *DRW_cache_object_wire_outline_get(Object *ob)
493 {
494         switch (ob->type) {
495                 case OB_MESH:
496                         return DRW_cache_mesh_wire_outline_get(ob);
497
498                 /* TODO, should match 'DRW_cache_object_surface_get' */
499                 default:
500                         return NULL;
501         }
502 }
503
504 Gwn_Batch *DRW_cache_object_surface_get(Object *ob)
505 {
506         switch (ob->type) {
507                 case OB_MESH:
508                         return DRW_cache_mesh_surface_get(ob);
509                 case OB_CURVE:
510                         return DRW_cache_curve_surface_get(ob);
511                 case OB_SURF:
512                         return DRW_cache_surf_surface_get(ob);
513                 case OB_FONT:
514                         return DRW_cache_text_surface_get(ob);
515                 case OB_MBALL:
516                         return DRW_cache_mball_surface_get(ob);
517                 default:
518                         return NULL;
519         }
520 }
521
522 Gwn_Batch **DRW_cache_object_surface_material_get(
523         struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len,
524         char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count)
525 {
526         if (auto_layer_names != NULL) {
527                 *auto_layer_names = NULL;
528                 *auto_layer_is_srgb = NULL;
529                 *auto_layer_count = 0;
530         }
531
532         switch (ob->type) {
533                 case OB_MESH:
534                         return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len,
535                                                                  auto_layer_names, auto_layer_is_srgb, auto_layer_count);
536                 case OB_CURVE:
537                         return DRW_cache_curve_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
538                 case OB_SURF:
539                         return DRW_cache_surf_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
540                 case OB_FONT:
541                         return DRW_cache_text_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
542                 default:
543                         return NULL;
544         }
545 }
546
547 /** \} */
548
549
550 /* -------------------------------------------------------------------- */
551
552 /** \name Empties
553  * \{ */
554
555 Gwn_Batch *DRW_cache_plain_axes_get(void)
556 {
557         if (!SHC.drw_plain_axes) {
558                 int axis;
559                 float v1[3] = {0.0f, 0.0f, 0.0f};
560                 float v2[3] = {0.0f, 0.0f, 0.0f};
561
562                 /* Position Only 3D format */
563                 static Gwn_VertFormat format = { 0 };
564                 static struct { uint pos; } attr_id;
565                 if (format.attrib_ct == 0) {
566                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
567                 }
568
569                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
570                 GWN_vertbuf_data_alloc(vbo, 6);
571
572                 for (axis = 0; axis < 3; axis++) {
573                         v1[axis] = 1.0f;
574                         v2[axis] = -1.0f;
575
576                         GWN_vertbuf_attr_set(vbo, attr_id.pos, axis * 2, v1);
577                         GWN_vertbuf_attr_set(vbo, attr_id.pos, axis * 2 + 1, v2);
578
579                         /* reset v1 & v2 to zero for next axis */
580                         v1[axis] = v2[axis] = 0.0f;
581                 }
582
583                 SHC.drw_plain_axes = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
584         }
585         return SHC.drw_plain_axes;
586 }
587
588 Gwn_Batch *DRW_cache_single_arrow_get(void)
589 {
590         if (!SHC.drw_single_arrow) {
591                 float v1[3] = {0.0f, 0.0f, 1.0f}, v2[3], v3[3];
592
593                 /* Position Only 3D format */
594                 static Gwn_VertFormat format = { 0 };
595                 static struct { uint pos; } attr_id;
596                 if (format.attrib_ct == 0) {
597                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
598                 }
599
600                 /* Square Pyramid */
601                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
602                 GWN_vertbuf_data_alloc(vbo, 12);
603
604                 v2[0] = 0.035f; v2[1] = 0.035f;
605                 v3[0] = -0.035f; v3[1] = 0.035f;
606                 v2[2] = v3[2] = 0.75f;
607
608                 for (int sides = 0; sides < 4; sides++) {
609                         if (sides % 2 == 1) {
610                                 v2[0] = -v2[0];
611                                 v3[1] = -v3[1];
612                         }
613                         else {
614                                 v2[1] = -v2[1];
615                                 v3[0] = -v3[0];
616                         }
617
618                         GWN_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 0, v1);
619                         GWN_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 1, v2);
620                         GWN_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 2, v3);
621                 }
622
623                 SHC.drw_single_arrow = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO);
624         }
625         return SHC.drw_single_arrow;
626 }
627
628 Gwn_Batch *DRW_cache_empty_sphere_get(void)
629 {
630         if (!SHC.drw_empty_sphere) {
631                 Gwn_VertBuf *vbo = sphere_wire_vbo(1.0f);
632                 SHC.drw_empty_sphere = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
633         }
634         return SHC.drw_empty_sphere;
635 }
636
637 Gwn_Batch *DRW_cache_empty_cone_get(void)
638 {
639 #define NSEGMENTS 8
640         if (!SHC.drw_empty_cone) {
641                 /* a single ring of vertices */
642                 float p[NSEGMENTS][2];
643                 for (int i = 0; i < NSEGMENTS; ++i) {
644                         float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
645                         p[i][0] = cosf(angle);
646                         p[i][1] = sinf(angle);
647                 }
648
649                 /* Position Only 3D format */
650                 static Gwn_VertFormat format = { 0 };
651                 static struct { uint pos; } attr_id;
652                 if (format.attrib_ct == 0) {
653                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
654                 }
655
656                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
657                 GWN_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
658
659                 for (int i = 0; i < NSEGMENTS; ++i) {
660                         float cv[2], v[3];
661                         cv[0] = p[(i) % NSEGMENTS][0];
662                         cv[1] = p[(i) % NSEGMENTS][1];
663
664                         /* cone sides */
665                         v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1];
666                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4, v);
667                         v[0] = 0.0f, v[1] = 2.0f, v[2] = 0.0f;
668                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 1, v);
669
670                         /* end ring */
671                         v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1];
672                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 2, v);
673                         cv[0] = p[(i + 1) % NSEGMENTS][0];
674                         cv[1] = p[(i + 1) % NSEGMENTS][1];
675                         v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1];
676                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 3, v);
677                 }
678
679                 SHC.drw_empty_cone = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
680         }
681         return SHC.drw_empty_cone;
682 #undef NSEGMENTS
683 }
684
685 Gwn_Batch *DRW_cache_arrows_get(void)
686 {
687         if (!SHC.drw_arrows) {
688                 Gwn_VertBuf *vbo = fill_arrows_vbo(1.0f);
689
690                 SHC.drw_arrows = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
691         }
692         return SHC.drw_arrows;
693 }
694
695 Gwn_Batch *DRW_cache_axis_names_get(void)
696 {
697         if (!SHC.drw_axis_names) {
698                 const float size = 0.1f;
699                 float v1[3], v2[3];
700
701                 /* Position Only 3D format */
702                 static Gwn_VertFormat format = { 0 };
703                 static struct { uint pos; } attr_id;
704                 if (format.attrib_ct == 0) {
705                         /* Using 3rd component as axis indicator */
706                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
707                 }
708
709                 /* Line */
710                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
711                 GWN_vertbuf_data_alloc(vbo, 14);
712
713                 /* X */
714                 copy_v3_fl3(v1, -size,  size, 0.0f);
715                 copy_v3_fl3(v2,  size, -size, 0.0f);
716                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
717                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 1, v2);
718
719                 copy_v3_fl3(v1,  size,  size, 0.0f);
720                 copy_v3_fl3(v2, -size, -size, 0.0f);
721                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 2, v1);
722                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 3, v2);
723
724                 /* Y */
725                 copy_v3_fl3(v1, -size + 0.25f * size,  size, 1.0f);
726                 copy_v3_fl3(v2,  0.0f,  0.0f, 1.0f);
727                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 4, v1);
728                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 5, v2);
729
730                 copy_v3_fl3(v1,  size - 0.25f * size,  size, 1.0f);
731                 copy_v3_fl3(v2, -size + 0.25f * size, -size, 1.0f);
732                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 6, v1);
733                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 7, v2);
734
735                 /* Z */
736                 copy_v3_fl3(v1, -size,  size, 2.0f);
737                 copy_v3_fl3(v2,  size,  size, 2.0f);
738                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 8, v1);
739                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 9, v2);
740
741                 copy_v3_fl3(v1,  size,  size, 2.0f);
742                 copy_v3_fl3(v2, -size, -size, 2.0f);
743                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 10, v1);
744                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 11, v2);
745
746                 copy_v3_fl3(v1, -size, -size, 2.0f);
747                 copy_v3_fl3(v2,  size, -size, 2.0f);
748                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 12, v1);
749                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 13, v2);
750
751                 SHC.drw_axis_names = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
752         }
753         return SHC.drw_axis_names;
754 }
755
756 Gwn_Batch *DRW_cache_image_plane_get(void)
757 {
758         if (!SHC.drw_image_plane) {
759                 const float quad[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
760                 static Gwn_VertFormat format = { 0 };
761                 static struct { uint pos, texCoords; } attr_id;
762                 if (format.attrib_ct == 0) {
763                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
764                         attr_id.texCoords = GWN_vertformat_attr_add(&format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
765                 }
766                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
767                 GWN_vertbuf_data_alloc(vbo, 4);
768                 for (uint j = 0; j < 4; j++) {
769                         GWN_vertbuf_attr_set(vbo, attr_id.pos, j, quad[j]);
770                         GWN_vertbuf_attr_set(vbo, attr_id.texCoords, j, quad[j]);
771                 }
772                 SHC.drw_image_plane = GWN_batch_create_ex(GWN_PRIM_TRI_FAN, vbo, NULL, GWN_BATCH_OWNS_VBO);
773         }
774         return SHC.drw_image_plane;
775 }
776
777 Gwn_Batch *DRW_cache_image_plane_wire_get(void)
778 {
779         if (!SHC.drw_image_plane_wire) {
780                 const float quad[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
781                 static Gwn_VertFormat format = { 0 };
782                 static struct { uint pos; } attr_id;
783                 if (format.attrib_ct == 0) {
784                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
785                 }
786                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
787                 GWN_vertbuf_data_alloc(vbo, 4);
788                 for (uint j = 0; j < 4; j++) {
789                         GWN_vertbuf_attr_set(vbo, attr_id.pos, j, quad[j]);
790                 }
791                 SHC.drw_image_plane_wire = GWN_batch_create_ex(GWN_PRIM_LINE_LOOP, vbo, NULL, GWN_BATCH_OWNS_VBO);
792         }
793         return SHC.drw_image_plane_wire;
794 }
795
796 /* Force Field */
797 Gwn_Batch *DRW_cache_field_wind_get(void)
798 {
799 #define CIRCLE_RESOL 32
800         if (!SHC.drw_field_wind) {
801                 float v[3] = {0.0f, 0.0f, 0.0f};
802
803                 /* Position Only 3D format */
804                 static Gwn_VertFormat format = { 0 };
805                 static struct { uint pos; } attr_id;
806                 if (format.attrib_ct == 0) {
807                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
808                 }
809
810                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
811                 GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 4);
812
813                 for (int i = 0; i < 4; i++) {
814                         float z = 0.05f * (float)i;
815                         for (int a = 0; a < CIRCLE_RESOL; a++) {
816                                 v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
817                                 v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
818                                 v[2] = z;
819                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2, v);
820
821                                 v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
822                                 v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
823                                 v[2] = z;
824                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2 + 1, v);
825                         }
826                 }
827
828                 SHC.drw_field_wind = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
829         }
830         return SHC.drw_field_wind;
831 #undef CIRCLE_RESOL
832 }
833
834 Gwn_Batch *DRW_cache_field_force_get(void)
835 {
836 #define CIRCLE_RESOL 32
837         if (!SHC.drw_field_force) {
838                 float v[3] = {0.0f, 0.0f, 0.0f};
839
840                 /* Position Only 3D format */
841                 static Gwn_VertFormat format = { 0 };
842                 static struct { uint pos; } attr_id;
843                 if (format.attrib_ct == 0) {
844                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
845                 }
846
847                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
848                 GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 3);
849
850                 for (int i = 0; i < 3; i++) {
851                         float radius = 1.0f + 0.5f * (float)i;
852                         for (int a = 0; a < CIRCLE_RESOL; a++) {
853                                 v[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
854                                 v[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
855                                 v[2] = 0.0f;
856                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2, v);
857
858                                 v[0] = radius * sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
859                                 v[1] = radius * cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
860                                 v[2] = 0.0f;
861                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2 + 1, v);
862                         }
863                 }
864
865                 SHC.drw_field_force = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
866         }
867         return SHC.drw_field_force;
868 #undef CIRCLE_RESOL
869 }
870
871 Gwn_Batch *DRW_cache_field_vortex_get(void)
872 {
873 #define SPIRAL_RESOL 32
874         if (!SHC.drw_field_vortex) {
875                 float v[3] = {0.0f, 0.0f, 0.0f};
876                 unsigned int v_idx = 0;
877
878                 /* Position Only 3D format */
879                 static Gwn_VertFormat format = { 0 };
880                 static struct { uint pos; } attr_id;
881                 if (format.attrib_ct == 0) {
882                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
883                 }
884
885                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
886                 GWN_vertbuf_data_alloc(vbo, SPIRAL_RESOL * 2 + 1);
887
888                 for (int a = SPIRAL_RESOL; a > -1; a--) {
889                         v[0] = sinf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
890                         v[1] = cosf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
891
892                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
893                 }
894
895                 for (int a = 1; a <= SPIRAL_RESOL; a++) {
896                         v[0] = -sinf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
897                         v[1] = -cosf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
898
899                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
900                 }
901
902                 SHC.drw_field_vortex = GWN_batch_create_ex(GWN_PRIM_LINE_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
903         }
904         return SHC.drw_field_vortex;
905 #undef SPIRAL_RESOL
906 }
907
908 Gwn_Batch *DRW_cache_field_tube_limit_get(void)
909 {
910 #define CIRCLE_RESOL 32
911         if (!SHC.drw_field_tube_limit) {
912                 float v[3] = {0.0f, 0.0f, 0.0f};
913                 unsigned int v_idx = 0;
914
915                 /* Position Only 3D format */
916                 static Gwn_VertFormat format = { 0 };
917                 static struct { uint pos; } attr_id;
918                 if (format.attrib_ct == 0) {
919                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
920                 }
921
922                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
923                 GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 2 + 8);
924
925                 /* Caps */
926                 for (int i = 0; i < 2; i++) {
927                         float z = (float)i * 2.0f - 1.0f;
928                         for (int a = 0; a < CIRCLE_RESOL; a++) {
929                                 v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
930                                 v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
931                                 v[2] = z;
932                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
933
934                                 v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
935                                 v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
936                                 v[2] = z;
937                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
938                         }
939                 }
940                 /* Side Edges */
941                 for (int a = 0; a < 4; a++) {
942                         for (int i = 0; i < 2; i++) {
943                                 float z = (float)i * 2.0f - 1.0f;
944                                 v[0] = sinf((2.0f * M_PI * a) / 4.0f);
945                                 v[1] = cosf((2.0f * M_PI * a) / 4.0f);
946                                 v[2] = z;
947                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
948                         }
949                 }
950
951                 SHC.drw_field_tube_limit = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
952         }
953         return SHC.drw_field_tube_limit;
954 #undef CIRCLE_RESOL
955 }
956
957 Gwn_Batch *DRW_cache_field_cone_limit_get(void)
958 {
959 #define CIRCLE_RESOL 32
960         if (!SHC.drw_field_cone_limit) {
961                 float v[3] = {0.0f, 0.0f, 0.0f};
962                 unsigned int v_idx = 0;
963
964                 /* Position Only 3D format */
965                 static Gwn_VertFormat format = { 0 };
966                 static struct { uint pos; } attr_id;
967                 if (format.attrib_ct == 0) {
968                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
969                 }
970
971                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
972                 GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 2 + 8);
973
974                 /* Caps */
975                 for (int i = 0; i < 2; i++) {
976                         float z = (float)i * 2.0f - 1.0f;
977                         for (int a = 0; a < CIRCLE_RESOL; a++) {
978                                 v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
979                                 v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
980                                 v[2] = z;
981                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
982
983                                 v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
984                                 v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
985                                 v[2] = z;
986                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
987                         }
988                 }
989                 /* Side Edges */
990                 for (int a = 0; a < 4; a++) {
991                         for (int i = 0; i < 2; i++) {
992                                 float z = (float)i * 2.0f - 1.0f;
993                                 v[0] = z * sinf((2.0f * M_PI * a) / 4.0f);
994                                 v[1] = z * cosf((2.0f * M_PI * a) / 4.0f);
995                                 v[2] = z;
996                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
997                         }
998                 }
999
1000                 SHC.drw_field_cone_limit = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1001         }
1002         return SHC.drw_field_cone_limit;
1003 #undef CIRCLE_RESOL
1004 }
1005
1006 /** \} */
1007
1008 /* -------------------------------------------------------------------- */
1009
1010 /** \name Lamps
1011  * \{ */
1012
1013 Gwn_Batch *DRW_cache_lamp_get(void)
1014 {
1015 #define NSEGMENTS 8
1016         if (!SHC.drw_lamp) {
1017                 float v[2];
1018
1019                 /* Position Only 3D format */
1020                 static Gwn_VertFormat format = { 0 };
1021                 static struct { uint pos; } attr_id;
1022                 if (format.attrib_ct == 0) {
1023                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
1024                 }
1025
1026                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1027                 GWN_vertbuf_data_alloc(vbo, NSEGMENTS * 2);
1028
1029                 for (int a = 0; a < NSEGMENTS * 2; a += 2) {
1030                         v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
1031                         v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
1032                         GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v);
1033
1034                         v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
1035                         v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
1036                         GWN_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v);
1037                 }
1038
1039                 SHC.drw_lamp = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1040         }
1041         return SHC.drw_lamp;
1042 #undef NSEGMENTS
1043 }
1044
1045 Gwn_Batch *DRW_cache_lamp_shadows_get(void)
1046 {
1047 #define NSEGMENTS 10
1048         if (!SHC.drw_lamp_shadows) {
1049                 float v[2];
1050
1051                 /* Position Only 3D format */
1052                 static Gwn_VertFormat format = { 0 };
1053                 static struct { uint pos; } attr_id;
1054                 if (format.attrib_ct == 0) {
1055                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
1056                 }
1057
1058                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1059                 GWN_vertbuf_data_alloc(vbo, NSEGMENTS * 2);
1060
1061                 for (int a = 0; a < NSEGMENTS * 2; a += 2) {
1062                         v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
1063                         v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
1064                         GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v);
1065
1066                         v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
1067                         v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
1068                         GWN_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v);
1069                 }
1070
1071                 SHC.drw_lamp_shadows = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1072         }
1073         return SHC.drw_lamp_shadows;
1074 #undef NSEGMENTS
1075 }
1076
1077 Gwn_Batch *DRW_cache_lamp_sunrays_get(void)
1078 {
1079         if (!SHC.drw_lamp_sunrays) {
1080                 float v[2], v1[2], v2[2];
1081
1082                 /* Position Only 2D format */
1083                 static Gwn_VertFormat format = { 0 };
1084                 static struct { uint pos; } attr_id;
1085                 if (format.attrib_ct == 0) {
1086                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
1087                 }
1088
1089                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1090                 GWN_vertbuf_data_alloc(vbo, 32);
1091
1092                 for (int a = 0; a < 8; a++) {
1093                         v[0] = sinf((2.0f * M_PI * a) / 8.0f);
1094                         v[1] = cosf((2.0f * M_PI * a) / 8.0f);
1095
1096                         mul_v2_v2fl(v1, v, 1.6f);
1097                         mul_v2_v2fl(v2, v, 1.9f);
1098                         GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4, v1);
1099                         GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 1, v2);
1100
1101                         mul_v2_v2fl(v1, v, 2.2f);
1102                         mul_v2_v2fl(v2, v, 2.5f);
1103                         GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 2, v1);
1104                         GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 3, v2);
1105                 }
1106
1107                 SHC.drw_lamp_sunrays = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1108         }
1109         return SHC.drw_lamp_sunrays;
1110 }
1111
1112 Gwn_Batch *DRW_cache_lamp_area_get(void)
1113 {
1114         if (!SHC.drw_lamp_area) {
1115                 float v1[3] = {0.0f, 0.0f, 0.0f};
1116
1117                 /* Position Only 3D format */
1118                 static Gwn_VertFormat format = { 0 };
1119                 static struct { uint pos; } attr_id;
1120                 if (format.attrib_ct == 0) {
1121                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1122                 }
1123
1124                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1125                 GWN_vertbuf_data_alloc(vbo, 8);
1126
1127                 v1[0] = v1[1] = 0.5f;
1128                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
1129                 v1[0] = -0.5f;
1130                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 1, v1);
1131                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 2, v1);
1132                 v1[1] = -0.5f;
1133                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 3, v1);
1134                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 4, v1);
1135                 v1[0] = 0.5f;
1136                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 5, v1);
1137                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 6, v1);
1138                 v1[1] = 0.5f;
1139                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 7, v1);
1140
1141                 SHC.drw_lamp_area = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1142         }
1143         return SHC.drw_lamp_area;
1144 }
1145
1146 Gwn_Batch *DRW_cache_lamp_hemi_get(void)
1147 {
1148 #define CIRCLE_RESOL 32
1149         if (!SHC.drw_lamp_hemi) {
1150                 float v[3];
1151                 int vidx = 0;
1152
1153                 /* Position Only 3D format */
1154                 static Gwn_VertFormat format = { 0 };
1155                 static struct { uint pos; } attr_id;
1156                 if (format.attrib_ct == 0) {
1157                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1158                 }
1159
1160                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1161                 GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 2 - 6 * 2 * 2);
1162
1163                 /* XZ plane */
1164                 for (int a = 3; a < CIRCLE_RESOL / 2 - 3; a++) {
1165                         v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL) - M_PI / 2);
1166                         v[2] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL) - M_PI / 2) - 1.0f;
1167                         v[1] = 0.0f;
1168                         GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1169
1170                         v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL) - M_PI / 2);
1171                         v[2] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL) - M_PI / 2) - 1.0f;
1172                         v[1] = 0.0f;
1173                         GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1174                 }
1175
1176                 /* XY plane */
1177                 for (int a = 3; a < CIRCLE_RESOL / 2 - 3; a++) {
1178                         v[2] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)) - 1.0f;
1179                         v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1180                         v[0] = 0.0f;
1181                         GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1182
1183                         v[2] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL)) - 1.0f;
1184                         v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1185                         v[0] = 0.0f;
1186                         GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1187                 }
1188
1189                 /* YZ plane full circle */
1190                 /* lease v[2] as it is */
1191                 const float rad = cosf((2.0f * M_PI * 3) / ((float)CIRCLE_RESOL));
1192                 for (int a = 0; a < CIRCLE_RESOL; a++) {
1193                         v[1] = rad * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1194                         v[0] = rad * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1195                         GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1196
1197                         v[1] = rad * sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1198                         v[0] = rad * cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1199                         GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1200                 }
1201
1202
1203                 SHC.drw_lamp_hemi = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1204         }
1205         return SHC.drw_lamp_hemi;
1206 #undef CIRCLE_RESOL
1207 }
1208
1209
1210 Gwn_Batch *DRW_cache_lamp_spot_get(void)
1211 {
1212 #define NSEGMENTS 32
1213         if (!SHC.drw_lamp_spot) {
1214                 /* a single ring of vertices */
1215                 float p[NSEGMENTS][2];
1216                 float n[NSEGMENTS][3];
1217                 float neg[NSEGMENTS][3];
1218                 float half_angle = 2 * M_PI / ((float)NSEGMENTS * 2);
1219                 for (int i = 0; i < NSEGMENTS; ++i) {
1220                         float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
1221                         p[i][0] = cosf(angle);
1222                         p[i][1] = sinf(angle);
1223
1224                         n[i][0] = cosf(angle - half_angle);
1225                         n[i][1] = sinf(angle - half_angle);
1226                         n[i][2] = cosf(M_PI / 16.0f); /* slope of the cone */
1227                         normalize_v3(n[i]); /* necessary ? */
1228                         negate_v3_v3(neg[i], n[i]);
1229                 }
1230
1231                 /* Position Only 3D format */
1232                 static Gwn_VertFormat format = { 0 };
1233                 static struct { uint pos, n1, n2; } attr_id;
1234                 if (format.attrib_ct == 0) {
1235                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1236                         attr_id.n1 = GWN_vertformat_attr_add(&format, "N1", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1237                         attr_id.n2 = GWN_vertformat_attr_add(&format, "N2", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1238                 }
1239
1240                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1241                 GWN_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
1242
1243                 for (int i = 0; i < NSEGMENTS; ++i) {
1244                         float cv[2], v[3];
1245                         cv[0] = p[i % NSEGMENTS][0];
1246                         cv[1] = p[i % NSEGMENTS][1];
1247
1248                         /* cone sides */
1249                         v[0] = cv[0], v[1] = cv[1], v[2] = -1.0f;
1250                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4, v);
1251                         v[0] = 0.0f, v[1] = 0.0f, v[2] = 0.0f;
1252                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 1, v);
1253
1254                         GWN_vertbuf_attr_set(vbo, attr_id.n1, i * 4,     n[(i) % NSEGMENTS]);
1255                         GWN_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 1, n[(i) % NSEGMENTS]);
1256                         GWN_vertbuf_attr_set(vbo, attr_id.n2, i * 4,     n[(i + 1) % NSEGMENTS]);
1257                         GWN_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 1, n[(i + 1) % NSEGMENTS]);
1258
1259                         /* end ring */
1260                         v[0] = cv[0], v[1] = cv[1], v[2] = -1.0f;
1261                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 2, v);
1262                         cv[0] = p[(i + 1) % NSEGMENTS][0];
1263                         cv[1] = p[(i + 1) % NSEGMENTS][1];
1264                         v[0] = cv[0], v[1] = cv[1], v[2] = -1.0f;
1265                         GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 3, v);
1266
1267                         GWN_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 2, n[(i) % NSEGMENTS]);
1268                         GWN_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 3, n[(i) % NSEGMENTS]);
1269                         GWN_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 2, neg[(i) % NSEGMENTS]);
1270                         GWN_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 3, neg[(i) % NSEGMENTS]);
1271                 }
1272
1273                 SHC.drw_lamp_spot = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1274         }
1275         return SHC.drw_lamp_spot;
1276 #undef NSEGMENTS
1277 }
1278
1279 Gwn_Batch *DRW_cache_lamp_spot_square_get(void)
1280 {
1281         if (!SHC.drw_lamp_spot_square) {
1282                 float p[5][3] = {{ 0.0f,  0.0f,  0.0f},
1283                                  { 1.0f,  1.0f, -1.0f},
1284                                  { 1.0f, -1.0f, -1.0f},
1285                                  {-1.0f, -1.0f, -1.0f},
1286                                  {-1.0f,  1.0f, -1.0f}};
1287
1288                 unsigned int v_idx = 0;
1289
1290                 /* Position Only 3D format */
1291                 static Gwn_VertFormat format = { 0 };
1292                 static struct { uint pos; } attr_id;
1293                 if (format.attrib_ct == 0) {
1294                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1295                 }
1296
1297                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1298                 GWN_vertbuf_data_alloc(vbo, 16);
1299
1300                 /* piramid sides */
1301                 for (int i = 1; i <= 4; ++i) {
1302                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[0]);
1303                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[i]);
1304
1305                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[(i % 4) + 1]);
1306                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[((i + 1) % 4) + 1]);
1307                 }
1308
1309                 SHC.drw_lamp_spot_square = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1310         }
1311         return SHC.drw_lamp_spot_square;
1312 }
1313
1314 /** \} */
1315
1316 /* -------------------------------------------------------------------- */
1317
1318 /** \name Speaker
1319  * \{ */
1320
1321 Gwn_Batch *DRW_cache_speaker_get(void)
1322 {
1323         if (!SHC.drw_speaker) {
1324                 float v[3];
1325                 const int segments = 16;
1326                 int vidx = 0;
1327
1328                 /* Position Only 3D format */
1329                 static Gwn_VertFormat format = { 0 };
1330                 static struct { uint pos; } attr_id;
1331                 if (format.attrib_ct == 0) {
1332                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1333                 }
1334
1335                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1336                 GWN_vertbuf_data_alloc(vbo, 3 * segments * 2 + 4 * 4);
1337
1338                 for (int j = 0; j < 3; j++) {
1339                         float z = 0.25f * j - 0.125f;
1340                         float r = (j == 0 ? 0.5f : 0.25f);
1341
1342                         copy_v3_fl3(v, r, 0.0f, z);
1343                         GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1344                         for (int i = 1; i < segments; i++) {
1345                                 float x = cosf(2.f * (float)M_PI * i / segments) * r;
1346                                 float y = sinf(2.f * (float)M_PI * i / segments) * r;
1347                                 copy_v3_fl3(v, x, y, z);
1348                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1349                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1350                         }
1351                         copy_v3_fl3(v, r, 0.0f, z);
1352                         GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1353                 }
1354
1355                 for (int j = 0; j < 4; j++) {
1356                         float x = (((j + 1) % 2) * (j - 1)) * 0.5f;
1357                         float y = ((j % 2) * (j - 2)) * 0.5f;
1358                         for (int i = 0; i < 3; i++) {
1359                                 if (i == 1) {
1360                                         x *= 0.5f;
1361                                         y *= 0.5f;
1362                                 }
1363
1364                                 float z = 0.25f * i - 0.125f;
1365                                 copy_v3_fl3(v, x, y, z);
1366                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1367                                 if (i == 1) {
1368                                         GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1369                                 }
1370                         }
1371                 }
1372
1373                 SHC.drw_speaker = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1374         }
1375         return SHC.drw_speaker;
1376 }
1377
1378 /** \} */
1379
1380 /* -------------------------------------------------------------------- */
1381
1382 /** \name Probe
1383  * \{ */
1384
1385 Gwn_Batch *DRW_cache_lightprobe_cube_get(void)
1386 {
1387         if (!SHC.drw_lightprobe_cube) {
1388                 int v_idx = 0;
1389                 const float sin_pi_3 = 0.86602540378f;
1390                 const float cos_pi_3 = 0.5f;
1391                 float v[7][3] = {
1392                         {0.0f, 1.0f, 0.0f},
1393                         {sin_pi_3, cos_pi_3, 0.0f},
1394                         {sin_pi_3, -cos_pi_3, 0.0f},
1395                         {0.0f, -1.0f, 0.0f},
1396                         {-sin_pi_3, -cos_pi_3, 0.0f},
1397                         {-sin_pi_3, cos_pi_3, 0.0f},
1398                         {0.0f, 0.0f, 0.0f},
1399                 };
1400
1401                 /* Position Only 3D format */
1402                 static Gwn_VertFormat format = { 0 };
1403                 static struct { uint pos; } attr_id;
1404                 if (format.attrib_ct == 0) {
1405                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1406                 }
1407
1408                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1409                 GWN_vertbuf_data_alloc(vbo, (6 + 3) * 2);
1410
1411                 for (int i = 0; i < 6; ++i) {
1412                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
1413                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 6]);
1414                 }
1415
1416                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[1]);
1417                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
1418
1419                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[5]);
1420                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
1421
1422                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[3]);
1423                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
1424
1425                 SHC.drw_lightprobe_cube = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1426         }
1427         return SHC.drw_lightprobe_cube;
1428 }
1429
1430 Gwn_Batch *DRW_cache_lightprobe_grid_get(void)
1431 {
1432         if (!SHC.drw_lightprobe_grid) {
1433                 int v_idx = 0;
1434                 const float sin_pi_3 = 0.86602540378f;
1435                 const float cos_pi_3 = 0.5f;
1436                 const float v[7][3] = {
1437                         {0.0f, 1.0f, 0.0f},
1438                         {sin_pi_3, cos_pi_3, 0.0f},
1439                         {sin_pi_3, -cos_pi_3, 0.0f},
1440                         {0.0f, -1.0f, 0.0f},
1441                         {-sin_pi_3, -cos_pi_3, 0.0f},
1442                         {-sin_pi_3, cos_pi_3, 0.0f},
1443                         {0.0f, 0.0f, 0.0f},
1444                 };
1445
1446                 /* Position Only 3D format */
1447                 static Gwn_VertFormat format = { 0 };
1448                 static struct { uint pos; } attr_id;
1449                 if (format.attrib_ct == 0) {
1450                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1451                 }
1452
1453                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1454                 GWN_vertbuf_data_alloc(vbo, (6 * 2 + 3) * 2);
1455
1456                 for (int i = 0; i < 6; ++i) {
1457                         float tmp_v1[3], tmp_v2[3], tmp_tr[3];
1458                         copy_v3_v3(tmp_v1, v[i]);
1459                         copy_v3_v3(tmp_v2, v[(i + 1) % 6]);
1460                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v1);
1461                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v2);
1462
1463                         /* Internal wires. */
1464                         for (int j = 1; j < 2; ++j) {
1465                                 mul_v3_v3fl(tmp_tr, v[(i / 2) * 2 + 1], -0.5f * j);
1466                                 add_v3_v3v3(tmp_v1, v[i], tmp_tr);
1467                                 add_v3_v3v3(tmp_v2, v[(i + 1) % 6], tmp_tr);
1468                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v1);
1469                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v2);
1470                         }
1471                 }
1472
1473                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[1]);
1474                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
1475
1476                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[5]);
1477                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
1478
1479                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[3]);
1480                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
1481
1482                 SHC.drw_lightprobe_grid = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1483         }
1484         return SHC.drw_lightprobe_grid;
1485 }
1486
1487 Gwn_Batch *DRW_cache_lightprobe_planar_get(void)
1488 {
1489         if (!SHC.drw_lightprobe_planar) {
1490                 int v_idx = 0;
1491                 const float sin_pi_3 = 0.86602540378f;
1492                 float v[4][3] = {
1493                         {0.0f, 0.5f, 0.0f},
1494                         {sin_pi_3, 0.0f, 0.0f},
1495                         {0.0f, -0.5f, 0.0f},
1496                         {-sin_pi_3, 0.0f, 0.0f},
1497                 };
1498
1499                 /* Position Only 3D format */
1500                 static Gwn_VertFormat format = { 0 };
1501                 static struct { uint pos; } attr_id;
1502                 if (format.attrib_ct == 0) {
1503                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1504                 }
1505
1506                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1507                 GWN_vertbuf_data_alloc(vbo, 4 * 2);
1508
1509                 for (int i = 0; i < 4; ++i) {
1510                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
1511                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 4]);
1512                 }
1513
1514                 SHC.drw_lightprobe_planar = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1515         }
1516         return SHC.drw_lightprobe_planar;
1517 }
1518
1519 /** \} */
1520
1521 /* -------------------------------------------------------------------- */
1522
1523 /** \name Armature Bones
1524  * \{ */
1525
1526 static const float bone_octahedral_verts[6][3] = {
1527         { 0.0f, 0.0f,  0.0f},
1528         { 0.1f, 0.1f,  0.1f},
1529         { 0.1f, 0.1f, -0.1f},
1530         {-0.1f, 0.1f, -0.1f},
1531         {-0.1f, 0.1f,  0.1f},
1532         { 0.0f, 1.0f,  0.0f}
1533 };
1534
1535 static const float bone_octahedral_smooth_normals[6][3] = {
1536         { 0.0f, -1.0f,  0.0f},
1537 #if 0 /* creates problems for outlines when scaled */
1538         { 0.943608f * M_SQRT1_2, -0.331048f,  0.943608f * M_SQRT1_2},
1539         { 0.943608f * M_SQRT1_2, -0.331048f, -0.943608f * M_SQRT1_2},
1540         {-0.943608f * M_SQRT1_2, -0.331048f, -0.943608f * M_SQRT1_2},
1541         {-0.943608f * M_SQRT1_2, -0.331048f,  0.943608f * M_SQRT1_2},
1542 #else
1543         { M_SQRT1_2, 0.0f,  M_SQRT1_2},
1544         { M_SQRT1_2, 0.0f, -M_SQRT1_2},
1545         {-M_SQRT1_2, 0.0f, -M_SQRT1_2},
1546         {-M_SQRT1_2, 0.0f,  M_SQRT1_2},
1547 #endif
1548         { 0.0f,  1.0f,  0.0f}
1549 };
1550
1551 static const unsigned int bone_octahedral_wire[24] = {
1552         0, 1,  1, 5,  5, 3,  3, 0,
1553         0, 4,  4, 5,  5, 2,  2, 0,
1554         1, 2,  2, 3,  3, 4,  4, 1,
1555 };
1556
1557 /* aligned with bone_octahedral_wire
1558  * Contains adjacent normal index */
1559 static const unsigned int bone_octahedral_wire_adjacent_face[24] = {
1560         0, 3,  4, 7,  5, 6,  1, 2,
1561         2, 3,  6, 7,  4, 5,  0, 1,
1562         0, 4,  1, 5,  2, 6,  3, 7,
1563 };
1564
1565 static const unsigned int bone_octahedral_solid_tris[8][3] = {
1566         {2, 1, 0}, /* bottom */
1567         {3, 2, 0},
1568         {4, 3, 0},
1569         {1, 4, 0},
1570
1571         {5, 1, 2}, /* top */
1572         {5, 2, 3},
1573         {5, 3, 4},
1574         {5, 4, 1}
1575 };
1576
1577 /**
1578  * Store indices of generated verts from bone_octahedral_solid_tris to define adjacency infos.
1579  * Example: triangle {2, 1, 0} is adjacent to {3, 2, 0}, {1, 4, 0} and {5, 1, 2}.
1580  * {2, 1, 0} becomes {0, 1, 2}
1581  * {3, 2, 0} becomes {3, 4, 5}
1582  * {1, 4, 0} becomes {9, 10, 11}
1583  * {5, 1, 2} becomes {12, 13, 14}
1584  * According to opengl specification it becomes (starting from
1585  * the first vertex of the first face aka. vertex 2):
1586  * {0, 12, 1, 10, 2, 3}
1587  **/
1588 static const unsigned int bone_octahedral_solid_tris_adjacency[8][6] = {
1589         { 0, 12,  1, 10,  2,  3},
1590         { 3, 15,  4,  1,  5,  6},
1591         { 6, 18,  7,  4,  8,  9},
1592         { 9, 21, 10,  7, 11,  0},
1593
1594         {12, 22, 13,  2, 14, 17},
1595         {15, 13, 16,  5, 17, 20},
1596         {18, 16, 19,  8, 20, 23},
1597         {21, 19, 22, 11, 23, 14},
1598 };
1599
1600 /* aligned with bone_octahedral_solid_tris */
1601 static const float bone_octahedral_solid_normals[8][3] = {
1602         { M_SQRT1_2,   -M_SQRT1_2,    0.00000000f},
1603         {-0.00000000f, -M_SQRT1_2,   -M_SQRT1_2},
1604         {-M_SQRT1_2,   -M_SQRT1_2,    0.00000000f},
1605         { 0.00000000f, -M_SQRT1_2,    M_SQRT1_2},
1606         { 0.99388373f,  0.11043154f, -0.00000000f},
1607         { 0.00000000f,  0.11043154f, -0.99388373f},
1608         {-0.99388373f,  0.11043154f,  0.00000000f},
1609         { 0.00000000f,  0.11043154f,  0.99388373f}
1610 };
1611
1612 Gwn_Batch *DRW_cache_bone_octahedral_get(void)
1613 {
1614         if (!SHC.drw_bone_octahedral) {
1615                 unsigned int v_idx = 0;
1616
1617                 static Gwn_VertFormat format = { 0 };
1618                 static struct { uint pos, nor, snor; } attr_id;
1619                 if (format.attrib_ct == 0) {
1620                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1621                         attr_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1622                         attr_id.snor = GWN_vertformat_attr_add(&format, "snor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1623                 }
1624
1625                 /* Vertices */
1626                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1627                 GWN_vertbuf_data_alloc(vbo, 24);
1628
1629                 Gwn_IndexBufBuilder elb;
1630                 GWN_indexbuf_init_ex(&elb, GWN_PRIM_TRIS_ADJ, 6 * 8, 24, false);
1631
1632                 for (int i = 0; i < 8; i++) {
1633                         GWN_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_octahedral_solid_normals[i]);
1634                         GWN_vertbuf_attr_set(vbo, attr_id.snor, v_idx, bone_octahedral_smooth_normals[bone_octahedral_solid_tris[i][0]]);
1635                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_octahedral_verts[bone_octahedral_solid_tris[i][0]]);
1636                         GWN_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_octahedral_solid_normals[i]);
1637                         GWN_vertbuf_attr_set(vbo, attr_id.snor, v_idx, bone_octahedral_smooth_normals[bone_octahedral_solid_tris[i][1]]);
1638                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_octahedral_verts[bone_octahedral_solid_tris[i][1]]);
1639                         GWN_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_octahedral_solid_normals[i]);
1640                         GWN_vertbuf_attr_set(vbo, attr_id.snor, v_idx, bone_octahedral_smooth_normals[bone_octahedral_solid_tris[i][2]]);
1641                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_octahedral_verts[bone_octahedral_solid_tris[i][2]]);
1642                         for (int j = 0; j < 6; ++j) {
1643                                 GWN_indexbuf_add_generic_vert(&elb, bone_octahedral_solid_tris_adjacency[i][j]);
1644                         }
1645                 }
1646
1647                 SHC.drw_bone_octahedral = GWN_batch_create_ex(GWN_PRIM_TRIS_ADJ, vbo, GWN_indexbuf_build(&elb),
1648                                                               GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX);
1649         }
1650         return SHC.drw_bone_octahedral;
1651 }
1652
1653 Gwn_Batch *DRW_cache_bone_octahedral_wire_outline_get(void)
1654 {
1655         if (!SHC.drw_bone_octahedral_wire) {
1656                 unsigned int v_idx = 0;
1657
1658                 static Gwn_VertFormat format = { 0 };
1659                 static struct { uint pos, n1, n2; } attr_id;
1660                 if (format.attrib_ct == 0) {
1661                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1662                         attr_id.n1 = GWN_vertformat_attr_add(&format, "N1", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1663                         attr_id.n2 = GWN_vertformat_attr_add(&format, "N2", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1664                 }
1665
1666                 /* Vertices */
1667                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1668                 GWN_vertbuf_data_alloc(vbo, 12 * 2);
1669
1670                 for (int i = 0; i < 12; i++) {
1671                         const float *co1 = bone_octahedral_verts[bone_octahedral_wire[i * 2]];
1672                         const float *co2 = bone_octahedral_verts[bone_octahedral_wire[i * 2 + 1]];
1673                         const float *n1 = bone_octahedral_solid_normals[bone_octahedral_wire_adjacent_face[i * 2]];
1674                         const float *n2 = bone_octahedral_solid_normals[bone_octahedral_wire_adjacent_face[i * 2 + 1]];
1675                         add_fancy_edge(vbo, attr_id.pos, attr_id.n1, attr_id.n2, &v_idx, co1, co2, n1, n2);
1676                 }
1677
1678                 SHC.drw_bone_octahedral_wire = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1679         }
1680         return SHC.drw_bone_octahedral_wire;
1681 }
1682
1683
1684 /* XXX TODO move that 1 unit cube to more common/generic place? */
1685 static const float bone_box_verts[8][3] = {
1686         { 1.0f, 0.0f,  1.0f},
1687         { 1.0f, 0.0f, -1.0f},
1688         {-1.0f, 0.0f, -1.0f},
1689         {-1.0f, 0.0f,  1.0f},
1690         { 1.0f, 1.0f,  1.0f},
1691         { 1.0f, 1.0f, -1.0f},
1692         {-1.0f, 1.0f, -1.0f},
1693         {-1.0f, 1.0f,  1.0f}
1694 };
1695
1696 static const float bone_box_smooth_normals[8][3] = {
1697         { M_SQRT3, -M_SQRT3,  M_SQRT3},
1698         { M_SQRT3, -M_SQRT3, -M_SQRT3},
1699         {-M_SQRT3, -M_SQRT3, -M_SQRT3},
1700         {-M_SQRT3, -M_SQRT3,  M_SQRT3},
1701         { M_SQRT3,  M_SQRT3,  M_SQRT3},
1702         { M_SQRT3,  M_SQRT3, -M_SQRT3},
1703         {-M_SQRT3,  M_SQRT3, -M_SQRT3},
1704         {-M_SQRT3,  M_SQRT3,  M_SQRT3},
1705 };
1706
1707 static const unsigned int bone_box_wire[24] = {
1708         0, 1,  1, 2,  2, 3,  3, 0,
1709         4, 5,  5, 6,  6, 7,  7, 4,
1710         0, 4,  1, 5,  2, 6,  3, 7,
1711 };
1712
1713 /* aligned with bone_octahedral_wire
1714  * Contains adjacent normal index */
1715 static const unsigned int bone_box_wire_adjacent_face[24] = {
1716         0,  2,   0,  4,   1,  6,   1,  8,
1717         3, 10,   5, 10,   7, 11,   9, 11,
1718         3,  8,   2,  5,   4,  7,   6,  9,
1719 };
1720
1721 static const unsigned int bone_box_solid_tris[12][3] = {
1722         {0, 2, 1}, /* bottom */
1723         {0, 3, 2},
1724
1725         {0, 1, 5}, /* sides */
1726         {0, 5, 4},
1727
1728         {1, 2, 6},
1729         {1, 6, 5},
1730
1731         {2, 3, 7},
1732         {2, 7, 6},
1733
1734         {3, 0, 4},
1735         {3, 4, 7},
1736
1737         {4, 5, 6}, /* top */
1738         {4, 6, 7},
1739 };
1740
1741 /**
1742  * Store indices of generated verts from bone_box_solid_tris to define adjacency infos.
1743  * See bone_octahedral_solid_tris for more infos.
1744  **/
1745 static const unsigned int bone_box_solid_tris_adjacency[12][6] = {
1746         { 0,  5,  1, 14,  2,  8},
1747         { 3, 26,  4, 20,  5,  1},
1748
1749         { 6,  2,  7, 16,  8, 11},
1750         { 9,  7, 10, 32, 11, 24},
1751
1752         {12,  0, 13, 22, 14, 17},
1753         {15, 13, 16, 30, 17,  6},
1754
1755         {18,  3, 19, 28, 20, 23},
1756         {21, 19, 22, 33, 23, 12},
1757
1758         {24,  4, 25, 10, 26, 29},
1759         {27, 25, 28, 34, 29, 18},
1760
1761         {30,  9, 31, 15, 32, 35},
1762         {33, 31, 34, 21, 35, 27},
1763 };
1764
1765 /* aligned with bone_box_solid_tris */
1766 static const float bone_box_solid_normals[12][3] = {
1767         { 0.0f, -1.0f,  0.0f},
1768         { 0.0f, -1.0f,  0.0f},
1769
1770         { 1.0f,  0.0f,  0.0f},
1771         { 1.0f,  0.0f,  0.0f},
1772
1773         { 0.0f,  0.0f, -1.0f},
1774         { 0.0f,  0.0f, -1.0f},
1775
1776         {-1.0f,  0.0f,  0.0f},
1777         {-1.0f,  0.0f,  0.0f},
1778
1779         { 0.0f,  0.0f,  1.0f},
1780         { 0.0f,  0.0f,  1.0f},
1781
1782         { 0.0f,  1.0f,  0.0f},
1783         { 0.0f,  1.0f,  0.0f},
1784 };
1785
1786 Gwn_Batch *DRW_cache_bone_box_get(void)
1787 {
1788         if (!SHC.drw_bone_box) {
1789                 unsigned int v_idx = 0;
1790
1791                 static Gwn_VertFormat format = { 0 };
1792                 static struct { uint pos, nor, snor; } attr_id;
1793                 if (format.attrib_ct == 0) {
1794                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1795                         attr_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1796                         attr_id.snor = GWN_vertformat_attr_add(&format, "snor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1797                 }
1798
1799                 /* Vertices */
1800                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1801                 GWN_vertbuf_data_alloc(vbo, 36);
1802
1803                 Gwn_IndexBufBuilder elb;
1804                 GWN_indexbuf_init_ex(&elb, GWN_PRIM_TRIS_ADJ, 6 * 12, 36, false);
1805
1806                 for (int i = 0; i < 12; i++) {
1807                         for (int j = 0; j < 3; j++) {
1808                                 GWN_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_box_solid_normals[i]);
1809                                 GWN_vertbuf_attr_set(vbo, attr_id.snor, v_idx, bone_box_smooth_normals[bone_box_solid_tris[i][j]]);
1810                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_box_verts[bone_box_solid_tris[i][j]]);
1811                         }
1812                         for (int j = 0; j < 6; ++j) {
1813                                 GWN_indexbuf_add_generic_vert(&elb, bone_box_solid_tris_adjacency[i][j]);
1814                         }
1815                 }
1816
1817                 SHC.drw_bone_box = GWN_batch_create_ex(GWN_PRIM_TRIS_ADJ, vbo, GWN_indexbuf_build(&elb),
1818                                                        GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX);
1819         }
1820         return SHC.drw_bone_box;
1821 }
1822
1823 Gwn_Batch *DRW_cache_bone_box_wire_outline_get(void)
1824 {
1825         if (!SHC.drw_bone_box_wire) {
1826                 unsigned int v_idx = 0;
1827
1828                 static Gwn_VertFormat format = { 0 };
1829                 static struct { uint pos, n1, n2; } attr_id;
1830                 if (format.attrib_ct == 0) {
1831                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1832                         attr_id.n1 = GWN_vertformat_attr_add(&format, "N1", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1833                         attr_id.n2 = GWN_vertformat_attr_add(&format, "N2", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1834                 }
1835
1836                 /* Vertices */
1837                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1838                 GWN_vertbuf_data_alloc(vbo, 12 * 2);
1839
1840                 for (int i = 0; i < 12; i++) {
1841                         const float *co1 = bone_box_verts[bone_box_wire[i * 2]];
1842                         const float *co2 = bone_box_verts[bone_box_wire[i * 2 + 1]];
1843                         const float *n1 = bone_box_solid_normals[bone_box_wire_adjacent_face[i * 2]];
1844                         const float *n2 = bone_box_solid_normals[bone_box_wire_adjacent_face[i * 2 + 1]];
1845                         add_fancy_edge(vbo, attr_id.pos, attr_id.n1, attr_id.n2, &v_idx, co1, co2, n1, n2);
1846                 }
1847
1848                 SHC.drw_bone_box_wire = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1849         }
1850         return SHC.drw_bone_box_wire;
1851 }
1852
1853
1854 Gwn_Batch *DRW_cache_bone_wire_wire_outline_get(void)
1855 {
1856         if (!SHC.drw_bone_wire_wire) {
1857                 unsigned int v_idx = 0;
1858
1859                 static Gwn_VertFormat format = { 0 };
1860                 static struct { uint pos, n1, n2; } attr_id;
1861                 if (format.attrib_ct == 0) {
1862                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1863                         attr_id.n1 = GWN_vertformat_attr_add(&format, "N1", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1864                         attr_id.n2 = GWN_vertformat_attr_add(&format, "N2", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1865                 }
1866
1867                 /* Vertices */
1868                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1869                 GWN_vertbuf_data_alloc(vbo, 2);
1870
1871                 const float co1[3] = {0.0f, 0.0f, 0.0f};
1872                 const float co2[3] = {0.0f, 1.0f, 0.0f};
1873                 const float n[3] = {1.0f, 0.0f, 0.0f};
1874                 add_fancy_edge(vbo, attr_id.pos, attr_id.n1, attr_id.n2, &v_idx, co1, co2, n, n);
1875
1876                 SHC.drw_bone_wire_wire = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
1877         }
1878         return SHC.drw_bone_wire_wire;
1879 }
1880
1881 /* Helpers for envelope bone's solid sphere-with-hidden-equatorial-cylinder.
1882  * Note that here we only encode head/tail in forth component of the vector. */
1883 static void benv_lat_lon_to_co(const float lat, const float lon, float r_nor[3])
1884 {
1885         r_nor[0] = sinf(lat) * cosf(lon);
1886         r_nor[1] = sinf(lat) * sinf(lon);
1887         r_nor[2] = cosf(lat);
1888 }
1889
1890 Gwn_Batch *DRW_cache_bone_envelope_solid_get(void)
1891 {
1892         if (!SHC.drw_bone_envelope) {
1893                 const int lon_res = 24;
1894                 const int lat_res = 24;
1895                 const float lon_inc = 2.0f * M_PI / lon_res;
1896                 const float lat_inc = M_PI / lat_res;
1897                 unsigned int v_idx = 0;
1898
1899                 static Gwn_VertFormat format = { 0 };
1900                 static struct { uint pos; } attr_id;
1901                 if (format.attrib_ct == 0) {
1902                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
1903                 }
1904
1905                 /* Vertices */
1906                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1907                 GWN_vertbuf_data_alloc(vbo, ((lat_res + 1) * 2) * lon_res * 1);
1908
1909                 float lon = 0.0f;
1910                 for (int i = 0; i < lon_res; i++, lon += lon_inc) {
1911                         float lat = 0.0f;
1912                         float co1[3], co2[3];
1913
1914                         /* Note: the poles are duplicated on purpose, to restart the strip. */
1915
1916                         /* 1st sphere */
1917                         for (int j = 0; j < lat_res; j++, lat += lat_inc) {
1918                                 benv_lat_lon_to_co(lat, lon,           co1);
1919                                 benv_lat_lon_to_co(lat, lon + lon_inc, co2);
1920
1921                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co1);
1922                                 GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co2);
1923                         }
1924
1925                         /* Closing the loop */
1926                         benv_lat_lon_to_co(M_PI, lon,           co1);
1927                         benv_lat_lon_to_co(M_PI, lon + lon_inc, co2);
1928
1929                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co1);
1930                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co2);
1931                 }
1932
1933                 SHC.drw_bone_envelope = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
1934         }
1935         return SHC.drw_bone_envelope;
1936 }
1937
1938 Gwn_Batch *DRW_cache_bone_envelope_outline_get(void)
1939 {
1940         if (!SHC.drw_bone_envelope_outline) {
1941 #  define CIRCLE_RESOL 64
1942                 float v0[2], v1[2], v2[2];
1943                 const float radius = 1.0f;
1944
1945                 /* Position Only 2D format */
1946                 static Gwn_VertFormat format = { 0 };
1947                 static struct { uint pos0, pos1, pos2; } attr_id;
1948                 if (format.attrib_ct == 0) {
1949                         attr_id.pos0 = GWN_vertformat_attr_add(&format, "pos0", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
1950                         attr_id.pos1 = GWN_vertformat_attr_add(&format, "pos1", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
1951                         attr_id.pos2 = GWN_vertformat_attr_add(&format, "pos2", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
1952                 }
1953
1954                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
1955                 GWN_vertbuf_data_alloc(vbo, (CIRCLE_RESOL + 1) * 2);
1956
1957                 v0[0] = radius * sinf((2.0f * M_PI * -2) / ((float)CIRCLE_RESOL));
1958                 v0[1] = radius * cosf((2.0f * M_PI * -2) / ((float)CIRCLE_RESOL));
1959                 v1[0] = radius * sinf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
1960                 v1[1] = radius * cosf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
1961
1962                 /* Output 4 verts for each position. See shader for explanation. */
1963                 unsigned int v = 0;
1964                 for (int a = 0; a < CIRCLE_RESOL; a++) {
1965                         v2[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1966                         v2[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1967                         GWN_vertbuf_attr_set(vbo, attr_id.pos0, v  , v0);
1968                         GWN_vertbuf_attr_set(vbo, attr_id.pos1, v  , v1);
1969                         GWN_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
1970                         GWN_vertbuf_attr_set(vbo, attr_id.pos0, v  , v0);
1971                         GWN_vertbuf_attr_set(vbo, attr_id.pos1, v  , v1);
1972                         GWN_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
1973                         copy_v2_v2(v0, v1);
1974                         copy_v2_v2(v1, v2);
1975                 }
1976                 v2[0] = 0.0f;
1977                 v2[1] = radius;
1978                 GWN_vertbuf_attr_set(vbo, attr_id.pos0, v  , v0);
1979                 GWN_vertbuf_attr_set(vbo, attr_id.pos1, v  , v1);
1980                 GWN_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
1981                 GWN_vertbuf_attr_set(vbo, attr_id.pos0, v  , v0);
1982                 GWN_vertbuf_attr_set(vbo, attr_id.pos1, v  , v1);
1983                 GWN_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
1984
1985                 SHC.drw_bone_envelope_outline = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
1986 #  undef CIRCLE_RESOL
1987         }
1988         return SHC.drw_bone_envelope_outline;
1989 }
1990
1991 Gwn_Batch *DRW_cache_bone_point_get(void)
1992 {
1993         if (!SHC.drw_bone_point) {
1994 #if 0 /* old style geometry sphere */
1995                 const int lon_res = 16;
1996                 const int lat_res = 8;
1997                 const float rad = 0.05f;
1998                 const float lon_inc = 2 * M_PI / lon_res;
1999                 const float lat_inc = M_PI / lat_res;
2000                 unsigned int v_idx = 0;
2001
2002                 static Gwn_VertFormat format = { 0 };
2003                 static struct { uint pos, nor; } attr_id;
2004                 if (format.attrib_ct == 0) {
2005                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
2006                         attr_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
2007                 }
2008
2009                 /* Vertices */
2010                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
2011                 GWN_vertbuf_data_alloc(vbo, (lat_res - 1) * lon_res * 6);
2012
2013                 float lon = 0.0f;
2014                 for (int i = 0; i < lon_res; i++, lon += lon_inc) {
2015                         float lat = 0.0f;
2016                         for (int j = 0; j < lat_res; j++, lat += lat_inc) {
2017                                 if (j != lat_res - 1) { /* Pole */
2018                                         add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat + lat_inc, lon + lon_inc);
2019                                         add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat + lat_inc, lon);
2020                                         add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat,           lon);
2021                                 }
2022
2023                                 if (j != 0) { /* Pole */
2024                                         add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat,           lon + lon_inc);
2025                                         add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat + lat_inc, lon + lon_inc);
2026                                         add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat,           lon);
2027                                 }
2028                         }
2029                 }
2030
2031                 SHC.drw_bone_point = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO);
2032 #else
2033 #  define CIRCLE_RESOL 64
2034                 float v[2];
2035                 const float radius = 0.05f;
2036
2037                 /* Position Only 2D format */
2038                 static Gwn_VertFormat format = { 0 };
2039                 static struct { uint pos; } attr_id;
2040                 if (format.attrib_ct == 0) {
2041                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
2042                 }
2043
2044                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
2045                 GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL);
2046
2047                 for (int a = 0; a < CIRCLE_RESOL; a++) {
2048                         v[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2049                         v[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2050                         GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v);
2051                 }
2052
2053                 SHC.drw_bone_point = GWN_batch_create_ex(GWN_PRIM_TRI_FAN, vbo, NULL, GWN_BATCH_OWNS_VBO);
2054 #  undef CIRCLE_RESOL
2055 #endif
2056         }
2057         return SHC.drw_bone_point;
2058 }
2059
2060 Gwn_Batch *DRW_cache_bone_point_wire_outline_get(void)
2061 {
2062         if (!SHC.drw_bone_point_wire) {
2063 #if 0 /* old style geometry sphere */
2064                 Gwn_VertBuf *vbo = sphere_wire_vbo(0.05f);
2065                 SHC.drw_bone_point_wire = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
2066 #else
2067 #  define CIRCLE_RESOL 64
2068                 float v0[2], v1[2];
2069                 const float radius = 0.05f;
2070
2071                 /* Position Only 2D format */
2072                 static Gwn_VertFormat format = { 0 };
2073                 static struct { uint pos0, pos1; } attr_id;
2074                 if (format.attrib_ct == 0) {
2075                         attr_id.pos0 = GWN_vertformat_attr_add(&format, "pos0", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
2076                         attr_id.pos1 = GWN_vertformat_attr_add(&format, "pos1", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
2077                 }
2078
2079                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
2080                 GWN_vertbuf_data_alloc(vbo, (CIRCLE_RESOL + 1) * 2);
2081
2082                 v0[0] = radius * sinf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
2083                 v0[1] = radius * cosf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
2084
2085                 unsigned int v = 0;
2086                 for (int a = 0; a < CIRCLE_RESOL; a++) {
2087                         v1[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2088                         v1[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2089                         GWN_vertbuf_attr_set(vbo, attr_id.pos0, v  , v0);
2090                         GWN_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
2091                         GWN_vertbuf_attr_set(vbo, attr_id.pos0, v  , v0);
2092                         GWN_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
2093                         copy_v2_v2(v0, v1);
2094                 }
2095                 v1[0] = 0.0f;
2096                 v1[1] = radius;
2097                 GWN_vertbuf_attr_set(vbo, attr_id.pos0, v  , v0);
2098                 GWN_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
2099                 GWN_vertbuf_attr_set(vbo, attr_id.pos0, v  , v0);
2100                 GWN_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
2101
2102                 SHC.drw_bone_point_wire = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
2103 #  undef CIRCLE_RESOL
2104 #endif
2105         }
2106         return SHC.drw_bone_point_wire;
2107 }
2108
2109 /* keep in sync with armature_stick_vert.glsl */
2110 #define COL_WIRE (1 << 0)
2111 #define COL_HEAD (1 << 1)
2112 #define COL_TAIL (1 << 2)
2113 #define COL_BONE (1 << 3)
2114
2115 #define POS_HEAD (1 << 4)
2116 #define POS_TAIL (1 << 5)
2117 #define POS_BONE (1 << 6)
2118
2119 Gwn_Batch *DRW_cache_bone_stick_get(void)
2120 {
2121         if (!SHC.drw_bone_stick) {
2122 #define CIRCLE_RESOL 12
2123                 unsigned int v = 0;
2124                 unsigned int flag;
2125                 const float radius = 2.0f; /* head/tail radius */
2126                 float pos[2];
2127
2128                 /* Position Only 2D format */
2129                 static Gwn_VertFormat format = { 0 };
2130                 static struct { uint pos, flag; } attr_id;
2131                 if (format.attrib_ct == 0) {
2132                         attr_id.pos  = GWN_vertformat_attr_add(&format, "pos",  GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
2133                         attr_id.flag = GWN_vertformat_attr_add(&format, "flag", GWN_COMP_U32, 1, GWN_FETCH_INT);
2134                 }
2135
2136                 const unsigned int vcount = (CIRCLE_RESOL + 1) * 2 + 6;
2137
2138                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
2139                 GWN_vertbuf_data_alloc(vbo, vcount);
2140
2141                 Gwn_IndexBufBuilder elb;
2142                 GWN_indexbuf_init_ex(&elb, GWN_PRIM_TRI_FAN, (CIRCLE_RESOL + 2) * 2 + 6 + 2, vcount, true);
2143
2144                 /* head/tail points */
2145                 for (int i = 0; i < 2; ++i) {
2146                         /* center vertex */
2147                         copy_v2_fl(pos, 0.0f);
2148                         flag  = (i == 0) ? POS_HEAD : POS_TAIL;
2149                         flag |= (i == 0) ? COL_HEAD : COL_TAIL;
2150                         GWN_vertbuf_attr_set(vbo, attr_id.pos,  v, pos);
2151                         GWN_vertbuf_attr_set(vbo, attr_id.flag, v, &flag);
2152                         GWN_indexbuf_add_generic_vert(&elb, v++);
2153                         /* circle vertices */
2154                         flag |= COL_WIRE;
2155                         for (int a = 0; a < CIRCLE_RESOL; a++) {
2156                                 pos[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2157                                 pos[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2158                                 GWN_vertbuf_attr_set(vbo, attr_id.pos,  v, pos);
2159                                 GWN_vertbuf_attr_set(vbo, attr_id.flag, v, &flag);
2160                                 GWN_indexbuf_add_generic_vert(&elb, v++);
2161                         }
2162                         /* Close the circle */
2163                         GWN_indexbuf_add_generic_vert(&elb, v - CIRCLE_RESOL);
2164
2165                         GWN_indexbuf_add_primitive_restart(&elb);
2166                 }
2167
2168                 /* Bone rectangle */
2169                 pos[0] = 0.0f;
2170                 for (int i = 0; i < 6; ++i) {
2171                         pos[1] = (i == 0 || i == 3) ? 0.0f : ((i < 3) ? 1.0f : -1.0f);
2172                         flag   = ((i <  2 || i >  4) ? POS_HEAD : POS_TAIL) |
2173                                  ((i == 0 || i == 3) ? 0 : COL_WIRE) | COL_BONE | POS_BONE;
2174                         GWN_vertbuf_attr_set(vbo, attr_id.pos,  v, pos);
2175                         GWN_vertbuf_attr_set(vbo, attr_id.flag, v, &flag);
2176                         GWN_indexbuf_add_generic_vert(&elb, v++);
2177                 }
2178
2179                 SHC.drw_bone_stick = GWN_batch_create_ex(GWN_PRIM_TRI_FAN, vbo, GWN_indexbuf_build(&elb), GWN_BATCH_OWNS_VBO);
2180 #undef CIRCLE_RESOL
2181         }
2182         return SHC.drw_bone_stick;
2183 }
2184
2185 static void set_bone_axis_vert(
2186         Gwn_VertBuf *vbo, uint axis, uint pos, uint col,
2187         unsigned int *v, const float *a, const float *p, const float *c)
2188 {
2189         GWN_vertbuf_attr_set(vbo, axis, *v, a);
2190         GWN_vertbuf_attr_set(vbo, pos,  *v, p);
2191         GWN_vertbuf_attr_set(vbo, col,  *v, c);
2192         *v += 1;
2193 }
2194
2195 #define S_X 0.0215f
2196 #define S_Y 0.025f
2197 static float x_axis_name[4][2] = {
2198         { 0.9f * S_X,  1.0f * S_Y}, {-1.0f * S_X, -1.0f * S_Y},
2199         {-0.9f * S_X,  1.0f * S_Y}, { 1.0f * S_X, -1.0f * S_Y}
2200 };
2201 #define X_LEN (sizeof(x_axis_name) / (sizeof(float) * 2))
2202 #undef S_X
2203 #undef S_Y
2204
2205 #define S_X 0.0175f
2206 #define S_Y 0.025f
2207 static float y_axis_name[6][2] = {
2208         {-1.0f * S_X,  1.0f * S_Y}, { 0.0f * S_X, -0.1f * S_Y},
2209         { 1.0f * S_X,  1.0f * S_Y}, { 0.0f * S_X, -0.1f * S_Y},
2210         { 0.0f * S_X, -0.1f * S_Y}, { 0.0f * S_X, -1.0f * S_Y}
2211 };
2212 #define Y_LEN (sizeof(y_axis_name) / (sizeof(float) * 2))
2213 #undef S_X
2214 #undef S_Y
2215
2216 #define S_X 0.02f
2217 #define S_Y 0.025f
2218 static float z_axis_name[10][2] = {
2219         {-0.95f * S_X,  1.00f * S_Y}, { 0.95f * S_X,  1.00f * S_Y},
2220         { 0.95f * S_X,  1.00f * S_Y}, { 0.95f * S_X,  0.90f * S_Y},
2221         { 0.95f * S_X,  0.90f * S_Y}, {-1.00f * S_X, -0.90f * S_Y},
2222         {-1.00f * S_X, -0.90f * S_Y}, {-1.00f * S_X, -1.00f * S_Y},
2223         {-1.00f * S_X, -1.00f * S_Y}, { 1.00f * S_X, -1.00f * S_Y}
2224 };
2225 #define Z_LEN (sizeof(z_axis_name) / (sizeof(float) * 2))
2226 #undef S_X
2227 #undef S_Y
2228
2229 #define S_X 0.007f
2230 #define S_Y 0.007f
2231 static float axis_marker[8][2] = {
2232 #if 0 /* square */
2233         {-1.0f * S_X,  1.0f * S_Y}, { 1.0f * S_X,  1.0f * S_Y},
2234         { 1.0f * S_X,  1.0f * S_Y}, { 1.0f * S_X, -1.0f * S_Y},
2235         { 1.0f * S_X, -1.0f * S_Y}, {-1.0f * S_X, -1.0f * S_Y},
2236         {-1.0f * S_X, -1.0f * S_Y}, {-1.0f * S_X,  1.0f * S_Y}
2237 #else /* diamond */
2238         {-S_X,  0.f}, { 0.f,  S_Y},
2239         { 0.f,  S_Y}, { S_X,  0.f},
2240         { S_X,  0.f}, { 0.f, -S_Y},
2241         { 0.f, -S_Y}, {-S_X,  0.f}
2242 #endif
2243 };
2244 #define MARKER_LEN (sizeof(axis_marker) / (sizeof(float) * 2))
2245 #define MARKER_FILL_LAYER 6
2246 #undef S_X
2247 #undef S_Y
2248
2249 #define S_X 0.0007f
2250 #define S_Y 0.0007f
2251 #define O_X  0.001f
2252 #define O_Y -0.001f
2253 static float axis_name_shadow[8][2] = {
2254         {-S_X + O_X,  S_Y + O_Y}, { S_X + O_X,  S_Y + O_Y},
2255         { S_X + O_X,  S_Y + O_Y}, { S_X + O_X, -S_Y + O_Y},
2256         { S_X + O_X, -S_Y + O_Y}, {-S_X + O_X, -S_Y + O_Y},
2257         {-S_X + O_X, -S_Y + O_Y}, {-S_X + O_X,  S_Y + O_Y}
2258 };
2259 // #define SHADOW_RES (sizeof(axis_name_shadow) / (sizeof(float) * 2))
2260 #define SHADOW_RES 0
2261 #undef O_X
2262 #undef O_Y
2263 #undef S_X
2264 #undef S_Y
2265
2266 Gwn_Batch *DRW_cache_bone_arrows_get(void)
2267 {
2268         if (!SHC.drw_bone_arrows) {
2269                 /* Position Only 3D format */
2270                 static Gwn_VertFormat format = { 0 };
2271                 static struct { uint axis, pos, col; } attr_id;
2272                 if (format.attrib_ct == 0) {
2273                         attr_id.axis = GWN_vertformat_attr_add(&format, "axis", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
2274                         attr_id.pos = GWN_vertformat_attr_add(&format, "screenPos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
2275                         attr_id.col = GWN_vertformat_attr_add(&format, "colorAxis", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
2276                 }
2277
2278                 /* Line */
2279                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
2280                 GWN_vertbuf_data_alloc(vbo, (2 + MARKER_LEN * MARKER_FILL_LAYER) * 3 +
2281                                             (X_LEN + Y_LEN + Z_LEN) * (1 + SHADOW_RES));
2282
2283                 unsigned int v = 0;
2284
2285                 for (int axis = 0; axis < 3; axis++) {
2286                         float pos[2] = {0.0f, 0.0f};
2287                         float c[3] = {0.0f, 0.0f, 0.0f};
2288                         float a = 0.0f;
2289                         /* center to axis line */
2290                         set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, pos, c);
2291                         c[axis] = 0.5f;
2292                         a = axis + 0.25f;
2293                         set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, pos, c);
2294
2295                         /* Axis end marker */
2296                         for (int j = 1; j < MARKER_FILL_LAYER + 1; ++j) {
2297                                 for (int i = 0; i < MARKER_LEN; ++i) {
2298                                         float tmp[2];
2299                                         mul_v2_v2fl(tmp, axis_marker[i], j / (float)MARKER_FILL_LAYER);
2300                                         set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col,
2301                                                            &v, &a, tmp, c);
2302                                 }
2303                         }
2304
2305                         a = axis + 0.31f;
2306                         /* Axis name */
2307                         int axis_v_ct;
2308                         float (*axis_verts)[2];
2309                         if (axis == 0) {
2310                                 axis_verts = x_axis_name;
2311                                 axis_v_ct = X_LEN;
2312                         }
2313                         else if (axis == 1) {
2314                                 axis_verts = y_axis_name;
2315                                 axis_v_ct = Y_LEN;
2316                         }
2317                         else {
2318                                 axis_verts = z_axis_name;
2319                                 axis_v_ct = Z_LEN;
2320                         }
2321
2322                         /* Axis name shadows */
2323                         copy_v3_fl(c, 0.0f);
2324                         c[axis] = 0.3f;
2325                         for (int j = 0; j < SHADOW_RES; ++j) {
2326                                 for (int i = 0; i < axis_v_ct; ++i) {
2327                                         float tmp[2];
2328                                         add_v2_v2v2(tmp, axis_verts[i], axis_name_shadow[j]);
2329                                         set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col,
2330                                                            &v, &a, tmp, c);
2331                                 }
2332                         }
2333
2334                         /* Axis name */
2335                         copy_v3_fl(c, 0.1f);
2336                         c[axis] = 1.0f;
2337                         for (int i = 0; i < axis_v_ct; ++i) {
2338                                 set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col,
2339                                                    &v, &a, axis_verts[i], c);
2340                         }
2341                 }
2342
2343                 SHC.drw_bone_arrows = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
2344         }
2345         return SHC.drw_bone_arrows;
2346 }
2347
2348 /** \} */
2349
2350 /* -------------------------------------------------------------------- */
2351
2352 /** \name Camera
2353  * \{ */
2354
2355 /**
2356  * We could make these more generic functions.
2357  * although filling 1d lines is not common.
2358  *
2359  * \note Use x coordinate to identify the vertex the vertex shader take care to place it appropriately.
2360  */
2361
2362 static const float camera_coords_frame_bounds[5] = {
2363         0.0f, /* center point */
2364         1.0f, /* + X + Y */
2365         2.0f, /* + X - Y */
2366         3.0f, /* - X - Y */
2367         4.0f, /* - X + Y */
2368 };
2369
2370 static const float camera_coords_frame_tri[3] = {
2371         5.0f, /* tria + X */
2372         6.0f, /* tria - X */
2373         7.0f, /* tria + Y */
2374 };
2375
2376 /** Draw a loop of lines. */
2377 static void camera_fill_lines_loop_fl_v1(
2378         Gwn_VertBufRaw *pos_step,
2379         const float *coords, const uint coords_len)
2380 {
2381         for (uint i = 0, i_prev = coords_len - 1; i < coords_len; i_prev = i++) {
2382                 *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i_prev];
2383                 *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i];
2384         }
2385 }
2386
2387 /** Fan lines out from the first vertex. */
2388 static void camera_fill_lines_fan_fl_v1(
2389         Gwn_VertBufRaw *pos_step,
2390         const float *coords, const uint coords_len)
2391 {
2392         for (uint i = 1; i < coords_len; i++) {
2393                 *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[0];
2394                 *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i];
2395         }
2396 }
2397
2398 /** Simply fill the array. */
2399 static void camera_fill_array_fl_v1(
2400         Gwn_VertBufRaw *pos_step,
2401         const float *coords, const uint coords_len)
2402 {
2403         for (uint i = 0; i < coords_len; i++) {
2404                 *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i];
2405         }
2406 }
2407
2408
2409 Gwn_Batch *DRW_cache_camera_get(void)
2410 {
2411         if (!SHC.drw_camera) {
2412                 static Gwn_VertFormat format = { 0 };
2413                 static struct { uint pos; } attr_id;
2414                 if (format.attrib_ct == 0) {
2415                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
2416                 }
2417
2418                 /* Vertices */
2419                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
2420                 const int vbo_len_capacity = 22;
2421                 GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
2422                 Gwn_VertBufRaw pos_step;
2423                 GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
2424
2425                 /* camera cone (from center to frame) */
2426                 camera_fill_lines_fan_fl_v1(&pos_step, camera_coords_frame_bounds, ARRAY_SIZE(camera_coords_frame_bounds));
2427
2428                 /* camera frame (skip center) */
2429                 camera_fill_lines_loop_fl_v1(&pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1);
2430
2431                 /* camera triangle (above the frame) */
2432                 camera_fill_lines_loop_fl_v1(&pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri));
2433
2434                 BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step));
2435
2436                 SHC.drw_camera = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
2437         }
2438         return SHC.drw_camera;
2439 }
2440
2441 Gwn_Batch *DRW_cache_camera_frame_get(void)
2442 {
2443         if (!SHC.drw_camera_frame) {
2444
2445                 static Gwn_VertFormat format = { 0 };
2446                 static struct { uint pos; } attr_id;
2447                 if (format.attrib_ct == 0) {
2448                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
2449                 }
2450
2451                 /* Vertices */
2452                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
2453                 const int vbo_len_capacity = 8;
2454                 GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
2455                 Gwn_VertBufRaw pos_step;
2456                 GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
2457
2458                 /* camera frame (skip center) */
2459                 camera_fill_lines_loop_fl_v1(&pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1);
2460
2461                 BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step));
2462
2463                 SHC.drw_camera_frame = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
2464         }
2465         return SHC.drw_camera_frame;
2466 }
2467
2468 Gwn_Batch *DRW_cache_camera_tria_get(void)
2469 {
2470         if (!SHC.drw_camera_tria) {
2471                 static Gwn_VertFormat format = { 0 };
2472                 static struct { uint pos; } attr_id;
2473                 if (format.attrib_ct == 0) {
2474                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
2475                 }
2476
2477                 /* Vertices */
2478                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
2479                 const int vbo_len_capacity = 3;
2480                 GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
2481                 Gwn_VertBufRaw pos_step;
2482                 GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
2483
2484                 /* camera triangle (above the frame) */
2485                 camera_fill_array_fl_v1(&pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri));
2486
2487                 BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step));
2488
2489                 SHC.drw_camera_tria = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO);
2490         }
2491         return SHC.drw_camera_tria;
2492 }
2493
2494 /** \} */
2495
2496 /* -------------------------------------------------------------------- */
2497
2498 /** \name Object Mode Helpers
2499  * \{ */
2500
2501 /* Object Center */
2502 Gwn_Batch *DRW_cache_single_vert_get(void)
2503 {
2504         if (!SHC.drw_single_vertice) {
2505                 float v1[3] = {0.0f, 0.0f, 0.0f};
2506
2507                 /* Position Only 3D format */
2508                 static Gwn_VertFormat format = { 0 };
2509                 static struct { uint pos; } attr_id;
2510                 if (format.attrib_ct == 0) {
2511                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
2512                 }
2513
2514                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
2515                 GWN_vertbuf_data_alloc(vbo, 1);
2516
2517                 GWN_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
2518
2519                 SHC.drw_single_vertice = GWN_batch_create_ex(GWN_PRIM_POINTS, vbo, NULL, GWN_BATCH_OWNS_VBO);
2520         }
2521         return SHC.drw_single_vertice;
2522 }
2523
2524 /** \} */
2525
2526 /* -------------------------------------------------------------------- */
2527
2528 /** \name Meshes
2529  * \{ */
2530
2531 Gwn_Batch *DRW_cache_mesh_surface_overlay_get(Object *ob)
2532 {
2533         BLI_assert(ob->type == OB_MESH);
2534         Mesh *me = ob->data;
2535         return DRW_mesh_batch_cache_get_all_triangles(me);
2536 }
2537
2538 void DRW_cache_mesh_wire_overlay_get(
2539         Object *ob,
2540         Gwn_Batch **r_tris, Gwn_Batch **r_ledges, Gwn_Batch **r_lverts)
2541 {
2542         BLI_assert(ob->type == OB_MESH);
2543
2544         Mesh *me = ob->data;
2545
2546         *r_tris = DRW_mesh_batch_cache_get_overlay_triangles(me);
2547         *r_ledges = DRW_mesh_batch_cache_get_overlay_loose_edges(me);
2548         *r_lverts = DRW_mesh_batch_cache_get_overlay_loose_verts(me);
2549 }
2550
2551 void DRW_cache_mesh_normals_overlay_get(
2552         Object *ob,
2553         Gwn_Batch **r_tris, Gwn_Batch **r_ledges, Gwn_Batch **r_lverts)
2554 {
2555         BLI_assert(ob->type == OB_MESH);
2556
2557         Mesh *me = ob->data;
2558
2559         *r_tris = DRW_mesh_batch_cache_get_overlay_triangles_nor(me);
2560         *r_ledges = DRW_mesh_batch_cache_get_overlay_loose_edges_nor(me);
2561         *r_lverts = DRW_mesh_batch_cache_get_overlay_loose_verts(me);
2562 }
2563
2564 Gwn_Batch *DRW_cache_face_centers_get(Object *ob)
2565 {
2566         BLI_assert(ob->type == OB_MESH);
2567
2568         Mesh *me = ob->data;
2569
2570         return DRW_mesh_batch_cache_get_overlay_facedots(me);
2571 }
2572
2573 Gwn_Batch *DRW_cache_mesh_wire_outline_get(Object *ob)
2574 {
2575         BLI_assert(ob->type == OB_MESH);
2576
2577         Mesh *me = ob->data;
2578         return DRW_mesh_batch_cache_get_fancy_edges(me);
2579 }
2580
2581 Gwn_Batch *DRW_cache_mesh_surface_get(Object *ob)
2582 {
2583         BLI_assert(ob->type == OB_MESH);
2584
2585         Mesh *me = ob->data;
2586         return DRW_mesh_batch_cache_get_triangles_with_normals(me);
2587 }
2588
2589 Gwn_Batch *DRW_cache_mesh_surface_weights_get(Object *ob)
2590 {
2591         BLI_assert(ob->type == OB_MESH);
2592
2593         Mesh *me = ob->data;
2594         return DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(me, ob->actdef - 1);
2595 }
2596
2597 Gwn_Batch *DRW_cache_mesh_surface_vert_colors_get(Object *ob)
2598 {
2599         BLI_assert(ob->type == OB_MESH);
2600
2601         Mesh *me = ob->data;
2602         return DRW_mesh_batch_cache_get_triangles_with_normals_and_vert_colors(me);
2603 }
2604
2605 /* Return list of batches */
2606 Gwn_Batch **DRW_cache_mesh_surface_shaded_get(
2607         Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len,
2608         char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count)
2609 {
2610         BLI_assert(ob->type == OB_MESH);
2611
2612         Mesh *me = ob->data;
2613         return DRW_mesh_batch_cache_get_surface_shaded(me, gpumat_array, gpumat_array_len,
2614                                                        auto_layer_names, auto_layer_is_srgb, auto_layer_count);
2615 }
2616
2617 /* Return list of batches */
2618 Gwn_Batch **DRW_cache_mesh_surface_texpaint_get(Object *ob)
2619 {
2620         BLI_assert(ob->type == OB_MESH);
2621
2622         Mesh *me = ob->data;
2623         return DRW_mesh_batch_cache_get_surface_texpaint(me);
2624 }
2625
2626 Gwn_Batch *DRW_cache_mesh_surface_texpaint_single_get(Object *ob)
2627 {
2628         BLI_assert(ob->type == OB_MESH);
2629
2630         Mesh *me = ob->data;
2631         return DRW_mesh_batch_cache_get_surface_texpaint_single(me);
2632 }
2633
2634 Gwn_Batch *DRW_cache_mesh_surface_verts_get(Object *ob)
2635 {
2636         BLI_assert(ob->type == OB_MESH);
2637
2638         Mesh *me = ob->data;
2639         return DRW_mesh_batch_cache_get_points_with_normals(me);
2640 }
2641
2642 Gwn_Batch *DRW_cache_mesh_edges_get(Object *ob)
2643 {
2644         BLI_assert(ob->type == OB_MESH);
2645
2646         Mesh *me = ob->data;
2647         return DRW_mesh_batch_cache_get_all_edges(me);
2648 }
2649
2650 Gwn_Batch *DRW_cache_mesh_verts_get(Object *ob)
2651 {
2652         BLI_assert(ob->type == OB_MESH);
2653
2654         Mesh *me = ob->data;
2655         return DRW_mesh_batch_cache_get_all_verts(me);
2656 }
2657
2658 Gwn_Batch *DRW_cache_mesh_edges_paint_overlay_get(Object *ob, bool use_wire, bool use_sel)
2659 {
2660         BLI_assert(ob->type == OB_MESH);
2661
2662         Mesh *me = ob->data;
2663         return DRW_mesh_batch_cache_get_weight_overlay_edges(me, use_wire, use_sel);
2664 }
2665
2666 Gwn_Batch *DRW_cache_mesh_faces_weight_overlay_get(Object *ob)
2667 {
2668         BLI_assert(ob->type == OB_MESH);
2669
2670         Mesh *me = ob->data;
2671         return DRW_mesh_batch_cache_get_weight_overlay_faces(me);
2672 }
2673
2674 Gwn_Batch *DRW_cache_mesh_verts_weight_overlay_get(Object *ob)
2675 {
2676         BLI_assert(ob->type == OB_MESH);
2677
2678         Mesh *me = ob->data;
2679         return DRW_mesh_batch_cache_get_weight_overlay_verts(me);
2680 }
2681
2682 void DRW_cache_mesh_sculpt_coords_ensure(Object *ob)
2683 {
2684         BLI_assert(ob->type == OB_MESH);
2685
2686         Mesh *me = ob->data;
2687         DRW_mesh_cache_sculpt_coords_ensure(me);
2688 }
2689
2690 /** \} */
2691
2692 /* -------------------------------------------------------------------- */
2693
2694 /** \name Curve
2695  * \{ */
2696
2697 Gwn_Batch *DRW_cache_curve_edge_wire_get(Object *ob)
2698 {
2699         BLI_assert(ob->type == OB_CURVE);
2700
2701         struct Curve *cu = ob->data;
2702         return DRW_curve_batch_cache_get_wire_edge(cu, ob->curve_cache);
2703 }
2704
2705 Gwn_Batch *DRW_cache_curve_edge_normal_get(Object *ob, float normal_size)
2706 {
2707         BLI_assert(ob->type == OB_CURVE);
2708
2709         struct Curve *cu = ob->data;
2710         return DRW_curve_batch_cache_get_normal_edge(cu, ob->curve_cache, normal_size);
2711 }
2712
2713 Gwn_Batch *DRW_cache_curve_edge_overlay_get(Object *ob)
2714 {
2715         BLI_assert(ob->type == OB_CURVE);
2716
2717         struct Curve *cu = ob->data;
2718         return DRW_curve_batch_cache_get_overlay_edges(cu);
2719 }
2720
2721 Gwn_Batch *DRW_cache_curve_vert_overlay_get(Object *ob)
2722 {
2723         BLI_assert(ob->type == OB_CURVE);
2724
2725         struct Curve *cu = ob->data;
2726         return DRW_curve_batch_cache_get_overlay_verts(cu);
2727 }
2728
2729 Gwn_Batch *DRW_cache_curve_surface_get(Object *ob)
2730 {
2731         BLI_assert(ob->type == OB_CURVE);
2732
2733         struct Curve *cu = ob->data;
2734         return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache);
2735 }
2736
2737 /* Return list of batches */
2738 Gwn_Batch **DRW_cache_curve_surface_shaded_get(
2739         Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
2740 {
2741         BLI_assert(ob->type == OB_CURVE);
2742
2743         struct Curve *cu = ob->data;
2744         return DRW_curve_batch_cache_get_surface_shaded(cu, ob->curve_cache, gpumat_array, gpumat_array_len);
2745 }
2746
2747 /** \} */
2748
2749 /* -------------------------------------------------------------------- */
2750
2751 /** \name MetaBall
2752  * \{ */
2753
2754 Gwn_Batch *DRW_cache_mball_surface_get(Object *ob)
2755 {
2756         BLI_assert(ob->type == OB_MBALL);
2757         return DRW_metaball_batch_cache_get_triangles_with_normals(ob);
2758 }
2759
2760 /** \} */
2761
2762 /* -------------------------------------------------------------------- */
2763
2764 /** \name Font
2765  * \{ */
2766
2767 Gwn_Batch *DRW_cache_text_edge_wire_get(Object *ob)
2768 {
2769         BLI_assert(ob->type == OB_FONT);
2770
2771         struct Curve *cu = ob->data;
2772         return DRW_curve_batch_cache_get_wire_edge(cu, ob->curve_cache);
2773 }
2774
2775 Gwn_Batch *DRW_cache_text_surface_get(Object *ob)
2776 {
2777         BLI_assert(ob->type == OB_FONT);
2778         struct Curve *cu = ob->data;
2779         if (cu->editfont && (cu->flag & CU_FAST)) {
2780                 return NULL;
2781         }
2782         return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache);
2783 }
2784
2785 Gwn_Batch **DRW_cache_text_surface_shaded_get(
2786         Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
2787 {
2788         BLI_assert(ob->type == OB_FONT);
2789         struct Curve *cu = ob->data;
2790         if (cu->editfont && (cu->flag & CU_FAST)) {
2791                 return NULL;
2792         }
2793         return DRW_curve_batch_cache_get_surface_shaded(cu, ob->curve_cache, gpumat_array, gpumat_array_len);
2794 }
2795
2796 Gwn_Batch *DRW_cache_text_cursor_overlay_get(Object *ob)
2797 {
2798         BLI_assert(ob->type == OB_FONT);
2799         struct Curve *cu = ob->data;
2800         return DRW_curve_batch_cache_get_overlay_cursor(cu);
2801 }
2802
2803 Gwn_Batch *DRW_cache_text_select_overlay_get(Object *ob)
2804 {
2805         BLI_assert(ob->type == OB_FONT);
2806         struct Curve *cu = ob->data;
2807         return DRW_curve_batch_cache_get_overlay_select(cu);
2808 }
2809
2810 /** \} */
2811
2812 /* -------------------------------------------------------------------- */
2813
2814 /** \name Surface
2815  * \{ */
2816
2817 Gwn_Batch *DRW_cache_surf_surface_get(Object *ob)
2818 {
2819         BLI_assert(ob->type == OB_SURF);
2820
2821         struct Curve *cu = ob->data;
2822         return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache);
2823 }
2824
2825 /* Return list of batches */
2826 Gwn_Batch **DRW_cache_surf_surface_shaded_get(
2827         Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
2828 {
2829         BLI_assert(ob->type == OB_SURF);
2830
2831         struct Curve *cu = ob->data;
2832         return DRW_curve_batch_cache_get_surface_shaded(cu, ob->curve_cache, gpumat_array, gpumat_array_len);
2833 }
2834
2835 /** \} */
2836
2837 /* -------------------------------------------------------------------- */
2838
2839 /** \name Lattice
2840  * \{ */
2841
2842 Gwn_Batch *DRW_cache_lattice_verts_get(Object *ob)
2843 {
2844         BLI_assert(ob->type == OB_LATTICE);
2845
2846         struct Lattice *lt = ob->data;
2847         return DRW_lattice_batch_cache_get_all_verts(lt);
2848 }
2849
2850 Gwn_Batch *DRW_cache_lattice_wire_get(Object *ob, bool use_weight)
2851 {
2852         BLI_assert(ob->type == OB_LATTICE);
2853
2854         Lattice *lt = ob->data;
2855         int actdef = -1;
2856
2857         if (use_weight && ob->defbase.first && lt->editlatt->latt->dvert) {
2858                 actdef = ob->actdef - 1;
2859         }
2860
2861         return DRW_lattice_batch_cache_get_all_edges(lt, use_weight, actdef);
2862 }
2863
2864 Gwn_Batch *DRW_cache_lattice_vert_overlay_get(Object *ob)
2865 {
2866         BLI_assert(ob->type == OB_LATTICE);
2867
2868         struct Lattice *lt = ob->data;
2869         return DRW_lattice_batch_cache_get_overlay_verts(lt);
2870 }
2871
2872 /** \} */
2873
2874 /* -------------------------------------------------------------------- */
2875
2876 /** \name Particles
2877  * \{ */
2878
2879 Gwn_Batch *DRW_cache_particles_get_hair(ParticleSystem *psys, ModifierData *md)
2880 {
2881         return DRW_particles_batch_cache_get_hair(psys, md);
2882 }
2883
2884 Gwn_Batch *DRW_cache_particles_get_dots(Object *object, ParticleSystem *psys)
2885 {
2886         return DRW_particles_batch_cache_get_dots(object, psys);
2887 }
2888
2889 Gwn_Batch *DRW_cache_particles_get_prim(int type)
2890 {
2891         switch (type) {
2892                 case PART_DRAW_CROSS:
2893                         if (!SHC.drw_particle_cross) {
2894                                 static Gwn_VertFormat format = { 0 };
2895                                 static unsigned pos_id, axis_id;
2896
2897                                 if (format.attrib_ct == 0) {
2898                                         pos_id = GWN_vertformat_attr_add(&format, "inst_pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
2899                                         axis_id = GWN_vertformat_attr_add(&format, "axis", GWN_COMP_I32, 1, GWN_FETCH_INT);
2900                                 }
2901
2902                                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
2903                                 GWN_vertbuf_data_alloc(vbo, 6);
2904
2905                                 /* X axis */
2906                                 float co[3] = {-1.0f, 0.0f, 0.0f};
2907                                 int axis = -1;
2908                                 GWN_vertbuf_attr_set(vbo, pos_id, 0, co);
2909                                 GWN_vertbuf_attr_set(vbo, axis_id, 0, &axis);
2910
2911                                 co[0] = 1.0f;
2912                                 GWN_vertbuf_attr_set(vbo, pos_id, 1, co);
2913                                 GWN_vertbuf_attr_set(vbo, axis_id, 1, &axis);
2914
2915                                 /* Y axis */
2916                                 co[0] = 0.0f;
2917                                 co[1] = -1.0f;
2918                                 GWN_vertbuf_attr_set(vbo, pos_id, 2, co);
2919                                 GWN_vertbuf_attr_set(vbo, axis_id, 2, &axis);
2920
2921                                 co[1] = 1.0f;
2922                                 GWN_vertbuf_attr_set(vbo, pos_id, 3, co);
2923                                 GWN_vertbuf_attr_set(vbo, axis_id, 3, &axis);
2924
2925                                 /* Z axis */
2926                                 co[1] = 0.0f;
2927                                 co[2] = -1.0f;
2928                                 GWN_vertbuf_attr_set(vbo, pos_id, 4, co);
2929                                 GWN_vertbuf_attr_set(vbo, axis_id, 4, &axis);
2930
2931                                 co[2] = 1.0f;
2932                                 GWN_vertbuf_attr_set(vbo, pos_id, 5, co);
2933                                 GWN_vertbuf_attr_set(vbo, axis_id, 5, &axis);
2934
2935                                 SHC.drw_particle_cross = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
2936                         }
2937
2938                         return SHC.drw_particle_cross;
2939                 case PART_DRAW_AXIS:
2940                         if (!SHC.drw_particle_axis) {
2941                                 static Gwn_VertFormat format = { 0 };
2942                                 static unsigned pos_id, axis_id;
2943
2944                                 if (format.attrib_ct == 0) {
2945                                         pos_id = GWN_vertformat_attr_add(&format, "inst_pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
2946                                         axis_id = GWN_vertformat_attr_add(&format, "axis", GWN_COMP_I32, 1, GWN_FETCH_INT);
2947                                 }
2948
2949                                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
2950                                 GWN_vertbuf_data_alloc(vbo, 6);
2951
2952                                 /* X axis */
2953                                 float co[3] = {0.0f, 0.0f, 0.0f};
2954                                 int axis = 0;
2955                                 GWN_vertbuf_attr_set(vbo, pos_id, 0, co);
2956                                 GWN_vertbuf_attr_set(vbo, axis_id, 0, &axis);
2957
2958                                 co[0] = 1.0f;
2959                                 GWN_vertbuf_attr_set(vbo, pos_id, 1, co);
2960                                 GWN_vertbuf_attr_set(vbo, axis_id, 1, &axis);
2961
2962                                 /* Y axis */
2963                                 co[0] = 0.0f;
2964                                 axis = 1;
2965                                 GWN_vertbuf_attr_set(vbo, pos_id, 2, co);
2966                                 GWN_vertbuf_attr_set(vbo, axis_id, 2, &axis);
2967
2968                                 co[1] = 1.0f;
2969                                 GWN_vertbuf_attr_set(vbo, pos_id, 3, co);
2970                                 GWN_vertbuf_attr_set(vbo, axis_id, 3, &axis);
2971
2972                                 /* Z axis */
2973                                 co[1] = 0.0f;
2974                                 axis = 2;
2975                                 GWN_vertbuf_attr_set(vbo, pos_id, 4, co);
2976                                 GWN_vertbuf_attr_set(vbo, axis_id, 4, &axis);
2977
2978                                 co[2] = 1.0f;
2979                                 GWN_vertbuf_attr_set(vbo, pos_id, 5, co);
2980                                 GWN_vertbuf_attr_set(vbo, axis_id, 5, &axis);
2981
2982                                 SHC.drw_particle_axis = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
2983                         }
2984
2985                         return SHC.drw_particle_axis;
2986                 case PART_DRAW_CIRC:
2987 #define CIRCLE_RESOL 32
2988                         if (!SHC.drw_particle_circle) {
2989                                 float v[3] = {0.0f, 0.0f, 0.0f};
2990                                 int axis = -1;
2991
2992                                 static Gwn_VertFormat format = { 0 };
2993                                 static unsigned pos_id, axis_id;
2994
2995                                 if (format.attrib_ct == 0) {
2996                                         pos_id = GWN_vertformat_attr_add(&format, "inst_pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
2997                                         axis_id = GWN_vertformat_attr_add(&format, "axis", GWN_COMP_I32, 1, GWN_FETCH_INT);
2998                                 }
2999
3000                                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
3001                                 GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL);
3002
3003                                 for (int a = 0; a < CIRCLE_RESOL; a++) {
3004                                         v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
3005                                         v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
3006                                         v[2] = 0.0f;
3007                                         GWN_vertbuf_attr_set(vbo, pos_id, a, v);
3008                                         GWN_vertbuf_attr_set(vbo, axis_id, a, &axis);
3009                                 }
3010
3011                                 SHC.drw_particle_circle = GWN_batch_create_ex(GWN_PRIM_LINE_LOOP, vbo, NULL, GWN_BATCH_OWNS_VBO);
3012                         }
3013
3014                         return SHC.drw_particle_circle;
3015 #undef CIRCLE_RESOL
3016                 default:
3017                         BLI_assert(false);
3018                         break;
3019         }
3020
3021         return NULL;
3022 }
3023
3024 /* 3D cursor */
3025 Gwn_Batch *DRW_cache_cursor_get(bool crosshair_lines)
3026 {
3027         Gwn_Batch **drw_cursor = crosshair_lines ? &SHC.drw_cursor : &SHC.drw_cursor_only_circle;
3028
3029         if (*drw_cursor == NULL) {
3030                 const float f5 = 0.25f;
3031                 const float f10 = 0.5f;
3032                 const float f20 = 1.0f;
3033
3034                 const int segments = 16;
3035                 const int vert_ct = segments + 8;
3036                 const int index_ct = vert_ct + 5;
3037
3038                 unsigned char red[3] = {255, 0, 0};
3039                 unsigned char white[3] = {255, 255, 255};
3040
3041                 static Gwn_VertFormat format = { 0 };
3042                 static struct { uint pos, color; } attr_id;
3043                 if (format.attrib_ct == 0) {
3044                         attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
3045                         attr_id.color = GWN_vertformat_attr_add(&format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
3046                 }
3047
3048                 Gwn_IndexBufBuilder elb;
3049                 GWN_indexbuf_init_ex(&elb, GWN_PRIM_LINE_STRIP, index_ct, vert_ct, true);
3050
3051                 Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
3052                 GWN_vertbuf_data_alloc(vbo, vert_ct);
3053
3054                 int v = 0;
3055                 for (int i = 0; i < segments; ++i) {
3056                         float angle = (float)(2 * M_PI) * ((float)i / (float)segments);
3057                         float x = f10 * cosf(angle);
3058                         float y = f10 * sinf(angle);
3059
3060                         if (i % 2 == 0)
3061                                 GWN_vertbuf_attr_set(vbo, attr_id.color, v, red);
3062                         else
3063                                 GWN_vertbuf_attr_set(vbo, attr_id.color, v, white);
3064
3065                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){x, y});
3066                         GWN_indexbuf_add_generic_vert(&elb, v++);
3067                 }
3068                 GWN_indexbuf_add_generic_vert(&elb, 0);
3069
3070                 if (crosshair_lines) {
3071                         unsigned char crosshair_color[3];
3072                         UI_GetThemeColor3ubv(TH_VIEW_OVERLAY, crosshair_color);
3073
3074                         GWN_indexbuf_add_primitive_restart(&elb);
3075
3076                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){-f20, 0});
3077                         GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
3078                         GWN_indexbuf_add_generic_vert(&elb, v++);
3079                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){-f5, 0});
3080                         GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
3081                         GWN_indexbuf_add_generic_vert(&elb, v++);
3082
3083                         GWN_indexbuf_add_primitive_restart(&elb);
3084
3085                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){+f5, 0});
3086                         GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
3087                         GWN_indexbuf_add_generic_vert(&elb, v++);
3088                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){+f20, 0});
3089                         GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
3090                         GWN_indexbuf_add_generic_vert(&elb, v++);
3091
3092                         GWN_indexbuf_add_primitive_restart(&elb);
3093
3094                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){0, -f20});
3095                         GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
3096                         GWN_indexbuf_add_generic_vert(&elb, v++);
3097                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){0, -f5});
3098                         GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
3099                         GWN_indexbuf_add_generic_vert(&elb, v++);
3100
3101                         GWN_indexbuf_add_primitive_restart(&elb);
3102
3103                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){0, +f5});
3104                         GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
3105                         GWN_indexbuf_add_generic_vert(&elb, v++);
3106                         GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){0, +f20});
3107                         GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
3108                         GWN_indexbuf_add_generic_vert(&elb, v++);
3109                 }
3110
3111                 Gwn_IndexBuf *ibo = GWN_indexbuf_build(&elb);
3112
3113                 *drw_cursor = GWN_batch_create_ex(GWN_PRIM_LINE_STRIP, vbo, ibo, GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX);
3114         }
3115         return *drw_cursor;
3116 }