6b6a79bfb6061d18f6ce41e737f14ab52869656a
[blender.git] / source / blender / draw / intern / draw_cache.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file
18  * \ingroup draw
19  */
20
21 #include "DNA_scene_types.h"
22 #include "DNA_mesh_types.h"
23 #include "DNA_meta_types.h"
24 #include "DNA_curve_types.h"
25 #include "DNA_object_types.h"
26 #include "DNA_particle_types.h"
27 #include "DNA_modifier_types.h"
28 #include "DNA_lattice_types.h"
29
30 #include "UI_resources.h"
31
32 #include "BLI_utildefines.h"
33 #include "BLI_math.h"
34
35 #include "BKE_object.h"
36 #include "BKE_paint.h"
37
38 #include "GPU_batch.h"
39 #include "GPU_batch_utils.h"
40
41 #include "MEM_guardedalloc.h"
42
43 #include "draw_cache.h"
44 #include "draw_cache_impl.h"
45 #include "draw_manager.h"
46
47 /* Batch's only (free'd as an array) */
48 static struct DRWShapeCache {
49   GPUBatch *drw_single_vertice;
50   GPUBatch *drw_cursor;
51   GPUBatch *drw_cursor_only_circle;
52   GPUBatch *drw_fullscreen_quad;
53   GPUBatch *drw_fullscreen_quad_texcoord;
54   GPUBatch *drw_quad;
55   GPUBatch *drw_quad_wires;
56   GPUBatch *drw_grid;
57   GPUBatch *drw_sphere;
58   GPUBatch *drw_screenspace_circle;
59   GPUBatch *drw_plain_axes;
60   GPUBatch *drw_single_arrow;
61   GPUBatch *drw_cube;
62   GPUBatch *drw_circle;
63   GPUBatch *drw_square;
64   GPUBatch *drw_line;
65   GPUBatch *drw_line_endpoints;
66   GPUBatch *drw_empty_cube;
67   GPUBatch *drw_empty_sphere;
68   GPUBatch *drw_empty_cylinder;
69   GPUBatch *drw_empty_capsule_body;
70   GPUBatch *drw_empty_capsule_cap;
71   GPUBatch *drw_empty_cone;
72   GPUBatch *drw_arrows;
73   GPUBatch *drw_axis_names;
74   GPUBatch *drw_image_plane;
75   GPUBatch *drw_image_plane_wire;
76   GPUBatch *drw_field_wind;
77   GPUBatch *drw_field_force;
78   GPUBatch *drw_field_vortex;
79   GPUBatch *drw_field_tube_limit;
80   GPUBatch *drw_field_cone_limit;
81   GPUBatch *drw_light;
82   GPUBatch *drw_light_shadows;
83   GPUBatch *drw_light_sunrays;
84   GPUBatch *drw_light_area_square;
85   GPUBatch *drw_light_area_disk;
86   GPUBatch *drw_light_hemi;
87   GPUBatch *drw_light_spot;
88   GPUBatch *drw_light_spot_volume;
89   GPUBatch *drw_light_spot_square;
90   GPUBatch *drw_light_spot_square_volume;
91   GPUBatch *drw_speaker;
92   GPUBatch *drw_lightprobe_cube;
93   GPUBatch *drw_lightprobe_planar;
94   GPUBatch *drw_lightprobe_grid;
95   GPUBatch *drw_bone_octahedral;
96   GPUBatch *drw_bone_octahedral_wire;
97   GPUBatch *drw_bone_box;
98   GPUBatch *drw_bone_box_wire;
99   GPUBatch *drw_bone_wire_wire;
100   GPUBatch *drw_bone_envelope;
101   GPUBatch *drw_bone_envelope_outline;
102   GPUBatch *drw_bone_point;
103   GPUBatch *drw_bone_point_wire;
104   GPUBatch *drw_bone_stick;
105   GPUBatch *drw_bone_arrows;
106   GPUBatch *drw_bone_dof_sphere;
107   GPUBatch *drw_bone_dof_lines;
108   GPUBatch *drw_camera;
109   GPUBatch *drw_camera_frame;
110   GPUBatch *drw_camera_tria;
111   GPUBatch *drw_camera_focus;
112   GPUBatch *drw_particle_cross;
113   GPUBatch *drw_particle_circle;
114   GPUBatch *drw_particle_axis;
115   GPUBatch *drw_gpencil_axes;
116 } SHC = {NULL};
117
118 void DRW_shape_cache_free(void)
119 {
120   uint i = sizeof(SHC) / sizeof(GPUBatch *);
121   GPUBatch **batch = (GPUBatch **)&SHC;
122   while (i--) {
123     GPU_BATCH_DISCARD_SAFE(*batch);
124     batch++;
125   }
126 }
127
128 void DRW_shape_cache_reset(void)
129 {
130   uint i = sizeof(SHC) / sizeof(GPUBatch *);
131   GPUBatch **batch = (GPUBatch **)&SHC;
132   while (i--) {
133     if (*batch) {
134       GPU_batch_vao_cache_clear(*batch);
135     }
136     batch++;
137   }
138 }
139
140 /* -------------------------------------------------------------------- */
141 /** \name Helper functions
142  * \{ */
143
144 static void UNUSED_FUNCTION(add_fancy_edge)(GPUVertBuf *vbo,
145                                             uint pos_id,
146                                             uint n1_id,
147                                             uint n2_id,
148                                             uint *v_idx,
149                                             const float co1[3],
150                                             const float co2[3],
151                                             const float n1[3],
152                                             const float n2[3])
153 {
154   GPU_vertbuf_attr_set(vbo, n1_id, *v_idx, n1);
155   GPU_vertbuf_attr_set(vbo, n2_id, *v_idx, n2);
156   GPU_vertbuf_attr_set(vbo, pos_id, (*v_idx)++, co1);
157
158   GPU_vertbuf_attr_set(vbo, n1_id, *v_idx, n1);
159   GPU_vertbuf_attr_set(vbo, n2_id, *v_idx, n2);
160   GPU_vertbuf_attr_set(vbo, pos_id, (*v_idx)++, co2);
161 }
162
163 #if 0  /* UNUSED */
164 static void add_lat_lon_vert(GPUVertBuf *vbo,
165                              uint pos_id,
166                              uint nor_id,
167                              uint *v_idx,
168                              const float rad,
169                              const float lat,
170                              const float lon)
171 {
172   float pos[3], nor[3];
173   nor[0] = sinf(lat) * cosf(lon);
174   nor[1] = cosf(lat);
175   nor[2] = sinf(lat) * sinf(lon);
176   mul_v3_v3fl(pos, nor, rad);
177
178   GPU_vertbuf_attr_set(vbo, nor_id, *v_idx, nor);
179   GPU_vertbuf_attr_set(vbo, pos_id, (*v_idx)++, pos);
180 }
181
182 static GPUVertBuf *fill_arrows_vbo(const float scale)
183 {
184   /* Position Only 3D format */
185   static GPUVertFormat format = {0};
186   static struct {
187     uint pos;
188   } attr_id;
189   if (format.attr_len == 0) {
190     attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
191   }
192
193   /* Line */
194   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
195   GPU_vertbuf_data_alloc(vbo, 6 * 3);
196
197   float v1[3] = {0.0, 0.0, 0.0};
198   float v2[3] = {0.0, 0.0, 0.0};
199   float vtmp1[3], vtmp2[3];
200
201   for (int axis = 0; axis < 3; axis++) {
202     const int arrow_axis = (axis == 0) ? 1 : 0;
203
204     v2[axis] = 1.0f;
205     mul_v3_v3fl(vtmp1, v1, scale);
206     mul_v3_v3fl(vtmp2, v2, scale);
207     GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 0, vtmp1);
208     GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 1, vtmp2);
209
210     v1[axis] = 0.85f;
211     v1[arrow_axis] = -0.08f;
212     mul_v3_v3fl(vtmp1, v1, scale);
213     mul_v3_v3fl(vtmp2, v2, scale);
214     GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 2, vtmp1);
215     GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 3, vtmp2);
216
217     v1[arrow_axis] = 0.08f;
218     mul_v3_v3fl(vtmp1, v1, scale);
219     mul_v3_v3fl(vtmp2, v2, scale);
220     GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 4, vtmp1);
221     GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 5, vtmp2);
222
223     /* reset v1 & v2 to zero */
224     v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
225   }
226
227   return vbo;
228 }
229 #endif /* UNUSED */
230
231 static GPUVertBuf *sphere_wire_vbo(const float rad)
232 {
233 #define NSEGMENTS 32
234   /* Position Only 3D format */
235   static GPUVertFormat format = {0};
236   static struct {
237     uint pos;
238   } attr_id;
239   if (format.attr_len == 0) {
240     attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
241   }
242
243   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
244   GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 2 * 3);
245
246   /* a single ring of vertices */
247   float p[NSEGMENTS][2];
248   for (int i = 0; i < NSEGMENTS; ++i) {
249     float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
250     p[i][0] = rad * cosf(angle);
251     p[i][1] = rad * sinf(angle);
252   }
253
254   for (int axis = 0; axis < 3; ++axis) {
255     for (int i = 0; i < NSEGMENTS; ++i) {
256       for (int j = 0; j < 2; ++j) {
257         float cv[2], v[3];
258
259         cv[0] = p[(i + j) % NSEGMENTS][0];
260         cv[1] = p[(i + j) % NSEGMENTS][1];
261
262         if (axis == 0) {
263           ARRAY_SET_ITEMS(v, cv[0], cv[1], 0.0f);
264         }
265         else if (axis == 1) {
266           ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]);
267         }
268         else {
269           ARRAY_SET_ITEMS(v, 0.0f, cv[0], cv[1]);
270         }
271         GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + j + (NSEGMENTS * 2 * axis), v);
272       }
273     }
274   }
275
276   return vbo;
277 #undef NSEGMENTS
278 }
279
280 /* Quads */
281 /* Use this one for rendering fullscreen passes. For 3D objects use DRW_cache_quad_get(). */
282 GPUBatch *DRW_cache_fullscreen_quad_get(void)
283 {
284   if (!SHC.drw_fullscreen_quad) {
285     /* Use a triangle instead of a real quad */
286     /* https://www.slideshare.net/DevCentralAMD/vertex-shader-tricks-bill-bilodeau - slide 14 */
287     float pos[3][2] = {{-1.0f, -1.0f}, {3.0f, -1.0f}, {-1.0f, 3.0f}};
288     float uvs[3][2] = {{0.0f, 0.0f}, {2.0f, 0.0f}, {0.0f, 2.0f}};
289
290     /* Position Only 2D format */
291     static GPUVertFormat format = {0};
292     static struct {
293       uint pos, uvs;
294     } attr_id;
295     if (format.attr_len == 0) {
296       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
297       attr_id.uvs = GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
298       GPU_vertformat_alias_add(&format, "texCoord");
299     }
300
301     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
302     GPU_vertbuf_data_alloc(vbo, 3);
303
304     for (int i = 0; i < 3; ++i) {
305       GPU_vertbuf_attr_set(vbo, attr_id.pos, i, pos[i]);
306       GPU_vertbuf_attr_set(vbo, attr_id.uvs, i, uvs[i]);
307     }
308
309     SHC.drw_fullscreen_quad = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
310   }
311   return SHC.drw_fullscreen_quad;
312 }
313
314 /* Just a regular quad with 4 vertices. */
315 GPUBatch *DRW_cache_quad_get(void)
316 {
317   if (!SHC.drw_quad) {
318     float pos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {1.0f, 1.0f}, {-1.0f, 1.0f}};
319     float uvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}};
320
321     /* Position Only 2D format */
322     static GPUVertFormat format = {0};
323     static struct {
324       uint pos, uvs;
325     } attr_id;
326     if (format.attr_len == 0) {
327       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
328       attr_id.uvs = GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
329     }
330
331     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
332     GPU_vertbuf_data_alloc(vbo, 4);
333
334     for (int i = 0; i < 4; ++i) {
335       GPU_vertbuf_attr_set(vbo, attr_id.pos, i, pos[i]);
336       GPU_vertbuf_attr_set(vbo, attr_id.uvs, i, uvs[i]);
337     }
338
339     SHC.drw_quad = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
340   }
341   return SHC.drw_quad;
342 }
343
344 /* Just a regular quad with 4 vertices - wires. */
345 GPUBatch *DRW_cache_quad_wires_get(void)
346 {
347   if (!SHC.drw_quad_wires) {
348     float pos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {1.0f, 1.0f}, {-1.0f, 1.0f}};
349
350     /* Position Only 2D format */
351     static GPUVertFormat format = {0};
352     static struct {
353       uint pos;
354     } attr_id;
355     if (format.attr_len == 0) {
356       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
357     }
358
359     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
360     GPU_vertbuf_data_alloc(vbo, 8);
361
362     for (int i = 0; i < 4; i++) {
363       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2, pos[i % 4]);
364       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + 1, pos[(i + 1) % 4]);
365     }
366
367     SHC.drw_quad_wires = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
368   }
369   return SHC.drw_quad_wires;
370 }
371
372 /* Grid */
373 GPUBatch *DRW_cache_grid_get(void)
374 {
375   if (!SHC.drw_grid) {
376     /* Position Only 2D format */
377     static GPUVertFormat format = {0};
378     static struct {
379       uint pos;
380     } attr_id;
381     if (format.attr_len == 0) {
382       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
383     }
384
385     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
386     GPU_vertbuf_data_alloc(vbo, 8 * 8 * 2 * 3);
387
388     uint v_idx = 0;
389     for (int i = 0; i < 8; ++i) {
390       for (int j = 0; j < 8; ++j) {
391         float pos0[2] = {(float)i / 8.0f, (float)j / 8.0f};
392         float pos1[2] = {(float)(i + 1) / 8.0f, (float)j / 8.0f};
393         float pos2[2] = {(float)i / 8.0f, (float)(j + 1) / 8.0f};
394         float pos3[2] = {(float)(i + 1) / 8.0f, (float)(j + 1) / 8.0f};
395
396         madd_v2_v2v2fl(pos0, (float[2]){-1.0f, -1.0f}, pos0, 2.0f);
397         madd_v2_v2v2fl(pos1, (float[2]){-1.0f, -1.0f}, pos1, 2.0f);
398         madd_v2_v2v2fl(pos2, (float[2]){-1.0f, -1.0f}, pos2, 2.0f);
399         madd_v2_v2v2fl(pos3, (float[2]){-1.0f, -1.0f}, pos3, 2.0f);
400
401         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, pos0);
402         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, pos1);
403         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, pos2);
404
405         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, pos2);
406         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, pos1);
407         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, pos3);
408       }
409     }
410
411     SHC.drw_grid = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
412   }
413   return SHC.drw_grid;
414 }
415
416 /* Sphere */
417 GPUBatch *DRW_cache_sphere_get(void)
418 {
419   if (!SHC.drw_sphere) {
420     SHC.drw_sphere = gpu_batch_sphere(32, 24);
421   }
422   return SHC.drw_sphere;
423 }
424
425 /** \} */
426
427 /* -------------------------------------------------------------------- */
428 /** \name Common
429  * \{ */
430
431 GPUBatch *DRW_cache_cube_get(void)
432 {
433   if (!SHC.drw_cube) {
434     const GLfloat verts[8][3] = {
435         {-1.0f, -1.0f, -1.0f},
436         {-1.0f, -1.0f, 1.0f},
437         {-1.0f, 1.0f, -1.0f},
438         {-1.0f, 1.0f, 1.0f},
439         {1.0f, -1.0f, -1.0f},
440         {1.0f, -1.0f, 1.0f},
441         {1.0f, 1.0f, -1.0f},
442         {1.0f, 1.0f, 1.0f},
443     };
444
445     const uint indices[36] = {
446         0, 1, 2, 1, 3, 2, 0, 4, 1, 4, 5, 1, 6, 5, 4, 6, 7, 5,
447         2, 7, 6, 2, 3, 7, 3, 1, 7, 1, 5, 7, 0, 2, 4, 2, 6, 4,
448     };
449
450     /* Position Only 3D format */
451     static GPUVertFormat format = {0};
452     static struct {
453       uint pos;
454     } attr_id;
455     if (format.attr_len == 0) {
456       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
457     }
458
459     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
460     GPU_vertbuf_data_alloc(vbo, 36);
461
462     for (int i = 0; i < 36; ++i) {
463       GPU_vertbuf_attr_set(vbo, attr_id.pos, i, verts[indices[i]]);
464     }
465
466     SHC.drw_cube = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
467   }
468   return SHC.drw_cube;
469 }
470
471 GPUBatch *DRW_cache_empty_cube_get(void)
472 {
473   if (!SHC.drw_empty_cube) {
474     const GLfloat verts[8][3] = {
475         {-1.0f, -1.0f, -1.0f},
476         {-1.0f, -1.0f, 1.0f},
477         {-1.0f, 1.0f, -1.0f},
478         {-1.0f, 1.0f, 1.0f},
479         {1.0f, -1.0f, -1.0f},
480         {1.0f, -1.0f, 1.0f},
481         {1.0f, 1.0f, -1.0f},
482         {1.0f, 1.0f, 1.0f},
483     };
484
485     const GLubyte indices[24] = {
486         0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6,
487     };
488
489     /* Position Only 3D format */
490     static GPUVertFormat format = {0};
491     static struct {
492       uint pos;
493     } attr_id;
494     if (format.attr_len == 0) {
495       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
496     }
497
498     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
499     GPU_vertbuf_data_alloc(vbo, 24);
500
501     for (int i = 0; i < 24; ++i) {
502       GPU_vertbuf_attr_set(vbo, attr_id.pos, i, verts[indices[i]]);
503     }
504
505     SHC.drw_empty_cube = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
506   }
507   return SHC.drw_empty_cube;
508 }
509
510 GPUBatch *DRW_cache_circle_get(void)
511 {
512 #define CIRCLE_RESOL 64
513   if (!SHC.drw_circle) {
514     float v[3] = {0.0f, 0.0f, 0.0f};
515
516     /* Position Only 3D format */
517     static GPUVertFormat format = {0};
518     static struct {
519       uint pos;
520     } attr_id;
521     if (format.attr_len == 0) {
522       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
523     }
524
525     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
526     GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL);
527
528     for (int a = 0; a < CIRCLE_RESOL; a++) {
529       v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
530       v[2] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
531       v[1] = 0.0f;
532       GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
533     }
534
535     SHC.drw_circle = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO);
536   }
537   return SHC.drw_circle;
538 #undef CIRCLE_RESOL
539 }
540
541 GPUBatch *DRW_cache_square_get(void)
542 {
543   if (!SHC.drw_square) {
544     float p[4][3] = {
545         {1.0f, 0.0f, 1.0f}, {1.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 1.0f}};
546
547     /* Position Only 3D format */
548     static GPUVertFormat format = {0};
549     static struct {
550       uint pos;
551     } attr_id;
552     if (format.attr_len == 0) {
553       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
554     }
555
556     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
557     GPU_vertbuf_data_alloc(vbo, 8);
558
559     for (int i = 0; i < 4; i++) {
560       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2, p[i % 4]);
561       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + 1, p[(i + 1) % 4]);
562     }
563
564     SHC.drw_square = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
565   }
566   return SHC.drw_square;
567 }
568
569 GPUBatch *DRW_cache_single_line_get(void)
570 {
571   /* Z axis line */
572   if (!SHC.drw_line) {
573     float v1[3] = {0.0f, 0.0f, 0.0f};
574     float v2[3] = {0.0f, 0.0f, 1.0f};
575
576     /* Position Only 3D format */
577     static GPUVertFormat format = {0};
578     static struct {
579       uint pos;
580     } attr_id;
581     if (format.attr_len == 0) {
582       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
583     }
584
585     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
586     GPU_vertbuf_data_alloc(vbo, 2);
587
588     GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
589     GPU_vertbuf_attr_set(vbo, attr_id.pos, 1, v2);
590
591     SHC.drw_line = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
592   }
593   return SHC.drw_line;
594 }
595
596 GPUBatch *DRW_cache_single_line_endpoints_get(void)
597 {
598   /* Z axis line */
599   if (!SHC.drw_line_endpoints) {
600     float v1[3] = {0.0f, 0.0f, 0.0f};
601     float v2[3] = {0.0f, 0.0f, 1.0f};
602
603     /* Position Only 3D format */
604     static GPUVertFormat format = {0};
605     static struct {
606       uint pos;
607     } attr_id;
608     if (format.attr_len == 0) {
609       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
610     }
611
612     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
613     GPU_vertbuf_data_alloc(vbo, 2);
614
615     GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
616     GPU_vertbuf_attr_set(vbo, attr_id.pos, 1, v2);
617
618     SHC.drw_line_endpoints = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
619   }
620   return SHC.drw_line_endpoints;
621 }
622
623 GPUBatch *DRW_cache_screenspace_circle_get(void)
624 {
625 #define CIRCLE_RESOL 32
626   if (!SHC.drw_screenspace_circle) {
627     float v[3] = {0.0f, 0.0f, 0.0f};
628
629     /* Position Only 3D format */
630     static GPUVertFormat format = {0};
631     static struct {
632       uint pos;
633     } attr_id;
634     if (format.attr_len == 0) {
635       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
636     }
637
638     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
639     GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL + 1);
640
641     for (int a = 0; a <= CIRCLE_RESOL; a++) {
642       v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
643       v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
644       GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
645     }
646
647     SHC.drw_screenspace_circle = GPU_batch_create_ex(
648         GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
649   }
650   return SHC.drw_screenspace_circle;
651 #undef CIRCLE_RESOL
652 }
653
654 /* Grease Pencil object */
655 GPUBatch *DRW_cache_gpencil_axes_get(void)
656 {
657   if (!SHC.drw_gpencil_axes) {
658     int axis;
659     float v1[3] = {0.0f, 0.0f, 0.0f};
660     float v2[3] = {0.0f, 0.0f, 0.0f};
661
662     /* cube data */
663     const GLfloat verts[8][3] = {
664         {-0.25f, -0.25f, -0.25f},
665         {-0.25f, -0.25f, 0.25f},
666         {-0.25f, 0.25f, -0.25f},
667         {-0.25f, 0.25f, 0.25f},
668         {0.25f, -0.25f, -0.25f},
669         {0.25f, -0.25f, 0.25f},
670         {0.25f, 0.25f, -0.25f},
671         {0.25f, 0.25f, 0.25f},
672     };
673
674     const GLubyte indices[24] = {
675         0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6,
676     };
677
678     /* Position Only 3D format */
679     static GPUVertFormat format = {0};
680     static uint pos_id;
681     if (format.attr_len == 0) {
682       pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
683     }
684
685     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
686
687     /* alloc 30 elements for cube and 3 axis */
688     GPU_vertbuf_data_alloc(vbo, ARRAY_SIZE(indices) + 6);
689
690     /* draw axis */
691     for (axis = 0; axis < 3; axis++) {
692       v1[axis] = 1.0f;
693       v2[axis] = -1.0f;
694
695       GPU_vertbuf_attr_set(vbo, pos_id, axis * 2, v1);
696       GPU_vertbuf_attr_set(vbo, pos_id, axis * 2 + 1, v2);
697
698       /* reset v1 & v2 to zero for next axis */
699       v1[axis] = v2[axis] = 0.0f;
700     }
701
702     /* draw cube */
703     for (int i = 0; i < 24; ++i) {
704       GPU_vertbuf_attr_set(vbo, pos_id, i + 6, verts[indices[i]]);
705     }
706
707     SHC.drw_gpencil_axes = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
708   }
709   return SHC.drw_gpencil_axes;
710 }
711
712 /* -------------------------------------------------------------------- */
713 /** \name Common Object API
714  * \{ */
715
716 GPUBatch *DRW_cache_object_all_edges_get(Object *ob)
717 {
718   switch (ob->type) {
719     case OB_MESH:
720       return DRW_cache_mesh_all_edges_get(ob);
721
722     /* TODO, should match 'DRW_cache_object_surface_get' */
723     default:
724       return NULL;
725   }
726 }
727
728 GPUBatch *DRW_cache_object_edge_detection_get(Object *ob, bool *r_is_manifold)
729 {
730   switch (ob->type) {
731     case OB_MESH:
732       return DRW_cache_mesh_edge_detection_get(ob, r_is_manifold);
733     case OB_CURVE:
734       return DRW_cache_curve_edge_detection_get(ob, r_is_manifold);
735     case OB_SURF:
736       return DRW_cache_surf_edge_detection_get(ob, r_is_manifold);
737     case OB_FONT:
738       return DRW_cache_text_edge_detection_get(ob, r_is_manifold);
739     case OB_MBALL:
740       return DRW_cache_mball_edge_detection_get(ob, r_is_manifold);
741     default:
742       return NULL;
743   }
744 }
745
746 GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob)
747 {
748   switch (ob->type) {
749     case OB_MESH:
750       return DRW_cache_mesh_face_wireframe_get(ob);
751     case OB_CURVE:
752       return DRW_cache_curve_face_wireframe_get(ob);
753     case OB_SURF:
754       return DRW_cache_surf_face_wireframe_get(ob);
755     case OB_FONT:
756       return DRW_cache_text_face_wireframe_get(ob);
757     case OB_MBALL:
758       return DRW_cache_mball_face_wireframe_get(ob);
759     default:
760       return NULL;
761   }
762 }
763
764 GPUBatch *DRW_cache_object_loose_edges_get(struct Object *ob)
765 {
766   switch (ob->type) {
767     case OB_MESH:
768       return DRW_cache_mesh_loose_edges_get(ob);
769     case OB_CURVE:
770       return DRW_cache_curve_loose_edges_get(ob);
771     case OB_SURF:
772       return DRW_cache_surf_loose_edges_get(ob);
773     case OB_FONT:
774       return DRW_cache_text_loose_edges_get(ob);
775     case OB_MBALL:
776       /* Cannot have any loose edge */
777     default:
778       return NULL;
779   }
780 }
781
782 GPUBatch *DRW_cache_object_surface_get(Object *ob)
783 {
784   switch (ob->type) {
785     case OB_MESH:
786       return DRW_cache_mesh_surface_get(ob);
787     case OB_CURVE:
788       return DRW_cache_curve_surface_get(ob);
789     case OB_SURF:
790       return DRW_cache_surf_surface_get(ob);
791     case OB_FONT:
792       return DRW_cache_text_surface_get(ob);
793     case OB_MBALL:
794       return DRW_cache_mball_surface_get(ob);
795     default:
796       return NULL;
797   }
798 }
799
800 GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
801                                                  struct GPUMaterial **gpumat_array,
802                                                  uint gpumat_array_len,
803                                                  char **auto_layer_names,
804                                                  int **auto_layer_is_srgb,
805                                                  int *auto_layer_count)
806 {
807   if (auto_layer_names != NULL) {
808     *auto_layer_names = NULL;
809     *auto_layer_is_srgb = NULL;
810     *auto_layer_count = 0;
811   }
812
813   switch (ob->type) {
814     case OB_MESH:
815       return DRW_cache_mesh_surface_shaded_get(ob,
816                                                gpumat_array,
817                                                gpumat_array_len,
818                                                auto_layer_names,
819                                                auto_layer_is_srgb,
820                                                auto_layer_count);
821     case OB_CURVE:
822       return DRW_cache_curve_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
823     case OB_SURF:
824       return DRW_cache_surf_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
825     case OB_FONT:
826       return DRW_cache_text_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
827     case OB_MBALL:
828       return DRW_cache_mball_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
829     default:
830       return NULL;
831   }
832 }
833
834 /** \} */
835
836 /* -------------------------------------------------------------------- */
837 /** \name Empties
838  * \{ */
839
840 GPUBatch *DRW_cache_plain_axes_get(void)
841 {
842   if (!SHC.drw_plain_axes) {
843     int axis;
844     float v1[3] = {0.0f, 0.0f, 0.0f};
845     float v2[3] = {0.0f, 0.0f, 0.0f};
846
847     /* Position Only 3D format */
848     static GPUVertFormat format = {0};
849     static struct {
850       uint pos;
851     } attr_id;
852     if (format.attr_len == 0) {
853       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
854     }
855
856     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
857     GPU_vertbuf_data_alloc(vbo, 6);
858
859     for (axis = 0; axis < 3; axis++) {
860       v1[axis] = 1.0f;
861       v2[axis] = -1.0f;
862
863       GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 2, v1);
864       GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 2 + 1, v2);
865
866       /* reset v1 & v2 to zero for next axis */
867       v1[axis] = v2[axis] = 0.0f;
868     }
869
870     SHC.drw_plain_axes = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
871   }
872   return SHC.drw_plain_axes;
873 }
874
875 GPUBatch *DRW_cache_single_arrow_get(void)
876 {
877   if (!SHC.drw_single_arrow) {
878     float v1[3] = {0.0f, 0.0f, 1.0f}, v2[3], v3[3];
879
880     /* Position Only 3D format */
881     static GPUVertFormat format = {0};
882     static struct {
883       uint pos;
884     } attr_id;
885     if (format.attr_len == 0) {
886       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
887     }
888
889     /* Square Pyramid */
890     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
891     GPU_vertbuf_data_alloc(vbo, 12);
892
893     v2[0] = 0.035f;
894     v2[1] = 0.035f;
895     v3[0] = -0.035f;
896     v3[1] = 0.035f;
897     v2[2] = v3[2] = 0.75f;
898
899     for (int sides = 0; sides < 4; sides++) {
900       if (sides % 2 == 1) {
901         v2[0] = -v2[0];
902         v3[1] = -v3[1];
903       }
904       else {
905         v2[1] = -v2[1];
906         v3[0] = -v3[0];
907       }
908
909       GPU_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 0, v1);
910       GPU_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 1, v2);
911       GPU_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 2, v3);
912     }
913
914     SHC.drw_single_arrow = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
915   }
916   return SHC.drw_single_arrow;
917 }
918
919 GPUBatch *DRW_cache_empty_sphere_get(void)
920 {
921   if (!SHC.drw_empty_sphere) {
922     GPUVertBuf *vbo = sphere_wire_vbo(1.0f);
923     SHC.drw_empty_sphere = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
924   }
925   return SHC.drw_empty_sphere;
926 }
927
928 GPUBatch *DRW_cache_empty_cone_get(void)
929 {
930 #define NSEGMENTS 8
931   if (!SHC.drw_empty_cone) {
932     /* a single ring of vertices */
933     float p[NSEGMENTS][2];
934     for (int i = 0; i < NSEGMENTS; ++i) {
935       float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
936       p[i][0] = cosf(angle);
937       p[i][1] = sinf(angle);
938     }
939
940     /* Position Only 3D format */
941     static GPUVertFormat format = {0};
942     static struct {
943       uint pos;
944     } attr_id;
945     if (format.attr_len == 0) {
946       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
947     }
948
949     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
950     GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
951
952     for (int i = 0; i < NSEGMENTS; ++i) {
953       float cv[2], v[3];
954       cv[0] = p[(i) % NSEGMENTS][0];
955       cv[1] = p[(i) % NSEGMENTS][1];
956
957       /* cone sides */
958       ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]);
959       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4, v);
960       ARRAY_SET_ITEMS(v, 0.0f, 2.0f, 0.0f);
961       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 1, v);
962
963       /* end ring */
964       ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]);
965       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 2, v);
966       cv[0] = p[(i + 1) % NSEGMENTS][0];
967       cv[1] = p[(i + 1) % NSEGMENTS][1];
968       ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]);
969       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 3, v);
970     }
971
972     SHC.drw_empty_cone = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
973   }
974   return SHC.drw_empty_cone;
975 #undef NSEGMENTS
976 }
977
978 GPUBatch *DRW_cache_empty_cylinder_get(void)
979 {
980 #define NSEGMENTS 12
981   if (!SHC.drw_empty_cylinder) {
982     /* a single ring of vertices */
983     float p[NSEGMENTS][2];
984     for (int i = 0; i < NSEGMENTS; ++i) {
985       float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
986       p[i][0] = cosf(angle);
987       p[i][1] = sinf(angle);
988     }
989
990     /* Position Only 3D format */
991     static GPUVertFormat format = {0};
992     static struct {
993       uint pos;
994     } attr_id;
995     if (format.attr_len == 0) {
996       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
997     }
998
999     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1000     GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 6);
1001
1002     for (int i = 0; i < NSEGMENTS; ++i) {
1003       float cv[2], pv[2], v[3];
1004       cv[0] = p[(i) % NSEGMENTS][0];
1005       cv[1] = p[(i) % NSEGMENTS][1];
1006       pv[0] = p[(i + 1) % NSEGMENTS][0];
1007       pv[1] = p[(i + 1) % NSEGMENTS][1];
1008
1009       /* cylinder sides */
1010       copy_v3_fl3(v, cv[0], cv[1], -1.0f);
1011       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6, v);
1012       copy_v3_fl3(v, cv[0], cv[1], 1.0f);
1013       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 1, v);
1014
1015       /* top ring */
1016       copy_v3_fl3(v, cv[0], cv[1], 1.0f);
1017       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 2, v);
1018       copy_v3_fl3(v, pv[0], pv[1], 1.0f);
1019       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 3, v);
1020
1021       /* bottom ring */
1022       copy_v3_fl3(v, cv[0], cv[1], -1.0f);
1023       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 4, v);
1024       copy_v3_fl3(v, pv[0], pv[1], -1.0f);
1025       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 5, v);
1026     }
1027
1028     SHC.drw_empty_cylinder = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1029   }
1030   return SHC.drw_empty_cylinder;
1031 #undef NSEGMENTS
1032 }
1033
1034 GPUBatch *DRW_cache_empty_capsule_body_get(void)
1035 {
1036   if (!SHC.drw_empty_capsule_body) {
1037     const float pos[8][3] = {
1038         {1.0f, 0.0f, 1.0f},
1039         {1.0f, 0.0f, 0.0f},
1040         {0.0f, 1.0f, 1.0f},
1041         {0.0f, 1.0f, 0.0f},
1042         {-1.0f, 0.0f, 1.0f},
1043         {-1.0f, 0.0f, 0.0f},
1044         {0.0f, -1.0f, 1.0f},
1045         {0.0f, -1.0f, 0.0f},
1046     };
1047
1048     /* Position Only 3D format */
1049     static GPUVertFormat format = {0};
1050     static struct {
1051       uint pos;
1052     } attr_id;
1053     if (format.attr_len == 0) {
1054       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1055     }
1056
1057     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1058     GPU_vertbuf_data_alloc(vbo, 8);
1059     GPU_vertbuf_attr_fill(vbo, attr_id.pos, pos);
1060
1061     SHC.drw_empty_capsule_body = GPU_batch_create_ex(
1062         GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1063   }
1064   return SHC.drw_empty_capsule_body;
1065 }
1066
1067 GPUBatch *DRW_cache_empty_capsule_cap_get(void)
1068 {
1069 #define NSEGMENTS 24 /* Must be multiple of 2. */
1070   if (!SHC.drw_empty_capsule_cap) {
1071     /* a single ring of vertices */
1072     float p[NSEGMENTS][2];
1073     for (int i = 0; i < NSEGMENTS; ++i) {
1074       float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
1075       p[i][0] = cosf(angle);
1076       p[i][1] = sinf(angle);
1077     }
1078
1079     /* Position Only 3D format */
1080     static GPUVertFormat format = {0};
1081     static struct {
1082       uint pos;
1083     } attr_id;
1084     if (format.attr_len == 0) {
1085       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1086     }
1087
1088     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1089     GPU_vertbuf_data_alloc(vbo, (NSEGMENTS * 2) * 2);
1090
1091     /* Base circle */
1092     int vidx = 0;
1093     for (int i = 0; i < NSEGMENTS; ++i) {
1094       float v[3] = {0.0f, 0.0f, 0.0f};
1095       copy_v2_v2(v, p[(i) % NSEGMENTS]);
1096       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1097       copy_v2_v2(v, p[(i + 1) % NSEGMENTS]);
1098       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1099     }
1100
1101     for (int i = 0; i < NSEGMENTS / 2; ++i) {
1102       float v[3] = {0.0f, 0.0f, 0.0f};
1103       int ci = i % NSEGMENTS;
1104       int pi = (i + 1) % NSEGMENTS;
1105       /* Y half circle */
1106       copy_v3_fl3(v, p[ci][0], 0.0f, p[ci][1]);
1107       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1108       copy_v3_fl3(v, p[pi][0], 0.0f, p[pi][1]);
1109       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1110       /* X half circle */
1111       copy_v3_fl3(v, 0.0f, p[ci][0], p[ci][1]);
1112       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1113       copy_v3_fl3(v, 0.0f, p[pi][0], p[pi][1]);
1114       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1115     }
1116
1117     SHC.drw_empty_capsule_cap = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1118   }
1119   return SHC.drw_empty_capsule_cap;
1120 #undef NSEGMENTS
1121 }
1122
1123 GPUBatch *DRW_cache_image_plane_get(void)
1124 {
1125   if (!SHC.drw_image_plane) {
1126     const float quad[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
1127     static GPUVertFormat format = {0};
1128     static struct {
1129       uint pos, texCoords;
1130     } attr_id;
1131     if (format.attr_len == 0) {
1132       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1133       attr_id.texCoords = GPU_vertformat_attr_add(
1134           &format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1135     }
1136     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1137     GPU_vertbuf_data_alloc(vbo, 4);
1138     for (uint j = 0; j < 4; j++) {
1139       GPU_vertbuf_attr_set(vbo, attr_id.pos, j, quad[j]);
1140       GPU_vertbuf_attr_set(vbo, attr_id.texCoords, j, quad[j]);
1141     }
1142     SHC.drw_image_plane = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
1143   }
1144   return SHC.drw_image_plane;
1145 }
1146
1147 GPUBatch *DRW_cache_image_plane_wire_get(void)
1148 {
1149   if (!SHC.drw_image_plane_wire) {
1150     const float quad[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
1151     static GPUVertFormat format = {0};
1152     static struct {
1153       uint pos;
1154     } attr_id;
1155     if (format.attr_len == 0) {
1156       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1157     }
1158     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1159     GPU_vertbuf_data_alloc(vbo, 4);
1160     for (uint j = 0; j < 4; j++) {
1161       GPU_vertbuf_attr_set(vbo, attr_id.pos, j, quad[j]);
1162     }
1163     SHC.drw_image_plane_wire = GPU_batch_create_ex(
1164         GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO);
1165   }
1166   return SHC.drw_image_plane_wire;
1167 }
1168
1169 /* Force Field */
1170 GPUBatch *DRW_cache_field_wind_get(void)
1171 {
1172 #define CIRCLE_RESOL 32
1173   if (!SHC.drw_field_wind) {
1174     float v[3] = {0.0f, 0.0f, 0.0f};
1175
1176     /* Position Only 3D format */
1177     static GPUVertFormat format = {0};
1178     static struct {
1179       uint pos;
1180     } attr_id;
1181     if (format.attr_len == 0) {
1182       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1183     }
1184
1185     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1186     GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 4);
1187
1188     for (int i = 0; i < 4; i++) {
1189       float z = 0.05f * (float)i;
1190       for (int a = 0; a < CIRCLE_RESOL; a++) {
1191         v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1192         v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1193         v[2] = z;
1194         GPU_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2, v);
1195
1196         v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1197         v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1198         v[2] = z;
1199         GPU_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2 + 1, v);
1200       }
1201     }
1202
1203     SHC.drw_field_wind = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1204   }
1205   return SHC.drw_field_wind;
1206 #undef CIRCLE_RESOL
1207 }
1208
1209 GPUBatch *DRW_cache_field_force_get(void)
1210 {
1211 #define CIRCLE_RESOL 32
1212   if (!SHC.drw_field_force) {
1213     float v[3] = {0.0f, 0.0f, 0.0f};
1214
1215     /* Position Only 3D format */
1216     static GPUVertFormat format = {0};
1217     static struct {
1218       uint pos;
1219     } attr_id;
1220     if (format.attr_len == 0) {
1221       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1222     }
1223
1224     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1225     GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 3);
1226
1227     for (int i = 0; i < 3; i++) {
1228       float radius = 1.0f + 0.5f * (float)i;
1229       for (int a = 0; a < CIRCLE_RESOL; a++) {
1230         v[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1231         v[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1232         v[2] = 0.0f;
1233         GPU_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2, v);
1234
1235         v[0] = radius * sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1236         v[1] = radius * cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1237         v[2] = 0.0f;
1238         GPU_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2 + 1, v);
1239       }
1240     }
1241
1242     SHC.drw_field_force = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1243   }
1244   return SHC.drw_field_force;
1245 #undef CIRCLE_RESOL
1246 }
1247
1248 GPUBatch *DRW_cache_field_vortex_get(void)
1249 {
1250 #define SPIRAL_RESOL 32
1251   if (!SHC.drw_field_vortex) {
1252     float v[3] = {0.0f, 0.0f, 0.0f};
1253     uint v_idx = 0;
1254
1255     /* Position Only 3D format */
1256     static GPUVertFormat format = {0};
1257     static struct {
1258       uint pos;
1259     } attr_id;
1260     if (format.attr_len == 0) {
1261       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1262     }
1263
1264     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1265     GPU_vertbuf_data_alloc(vbo, SPIRAL_RESOL * 2 + 1);
1266
1267     for (int a = SPIRAL_RESOL; a > -1; a--) {
1268       v[0] = sinf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
1269       v[1] = cosf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
1270
1271       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
1272     }
1273
1274     for (int a = 1; a <= SPIRAL_RESOL; a++) {
1275       v[0] = -sinf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
1276       v[1] = -cosf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
1277
1278       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
1279     }
1280
1281     SHC.drw_field_vortex = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
1282   }
1283   return SHC.drw_field_vortex;
1284 #undef SPIRAL_RESOL
1285 }
1286
1287 GPUBatch *DRW_cache_field_tube_limit_get(void)
1288 {
1289 #define CIRCLE_RESOL 32
1290   if (!SHC.drw_field_tube_limit) {
1291     float v[3] = {0.0f, 0.0f, 0.0f};
1292     uint v_idx = 0;
1293
1294     /* Position Only 3D format */
1295     static GPUVertFormat format = {0};
1296     static struct {
1297       uint pos;
1298     } attr_id;
1299     if (format.attr_len == 0) {
1300       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1301     }
1302
1303     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1304     GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 2 + 8);
1305
1306     /* Caps */
1307     for (int i = 0; i < 2; i++) {
1308       float z = (float)i * 2.0f - 1.0f;
1309       for (int a = 0; a < CIRCLE_RESOL; a++) {
1310         v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1311         v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1312         v[2] = z;
1313         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
1314
1315         v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1316         v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1317         v[2] = z;
1318         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
1319       }
1320     }
1321     /* Side Edges */
1322     for (int a = 0; a < 4; a++) {
1323       for (int i = 0; i < 2; i++) {
1324         float z = (float)i * 2.0f - 1.0f;
1325         v[0] = sinf((2.0f * M_PI * a) / 4.0f);
1326         v[1] = cosf((2.0f * M_PI * a) / 4.0f);
1327         v[2] = z;
1328         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
1329       }
1330     }
1331
1332     SHC.drw_field_tube_limit = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1333   }
1334   return SHC.drw_field_tube_limit;
1335 #undef CIRCLE_RESOL
1336 }
1337
1338 GPUBatch *DRW_cache_field_cone_limit_get(void)
1339 {
1340 #define CIRCLE_RESOL 32
1341   if (!SHC.drw_field_cone_limit) {
1342     float v[3] = {0.0f, 0.0f, 0.0f};
1343     uint v_idx = 0;
1344
1345     /* Position Only 3D format */
1346     static GPUVertFormat format = {0};
1347     static struct {
1348       uint pos;
1349     } attr_id;
1350     if (format.attr_len == 0) {
1351       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1352     }
1353
1354     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1355     GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 2 + 8);
1356
1357     /* Caps */
1358     for (int i = 0; i < 2; i++) {
1359       float z = (float)i * 2.0f - 1.0f;
1360       for (int a = 0; a < CIRCLE_RESOL; a++) {
1361         v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1362         v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1363         v[2] = z;
1364         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
1365
1366         v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1367         v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1368         v[2] = z;
1369         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
1370       }
1371     }
1372     /* Side Edges */
1373     for (int a = 0; a < 4; a++) {
1374       for (int i = 0; i < 2; i++) {
1375         float z = (float)i * 2.0f - 1.0f;
1376         v[0] = z * sinf((2.0f * M_PI * a) / 4.0f);
1377         v[1] = z * cosf((2.0f * M_PI * a) / 4.0f);
1378         v[2] = z;
1379         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
1380       }
1381     }
1382
1383     SHC.drw_field_cone_limit = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1384   }
1385   return SHC.drw_field_cone_limit;
1386 #undef CIRCLE_RESOL
1387 }
1388
1389 /** \} */
1390
1391 /* -------------------------------------------------------------------- */
1392 /** \name Lights
1393  * \{ */
1394
1395 GPUBatch *DRW_cache_light_get(void)
1396 {
1397 #define NSEGMENTS 8
1398   if (!SHC.drw_light) {
1399     float v[2];
1400
1401     /* Position Only 3D format */
1402     static GPUVertFormat format = {0};
1403     static struct {
1404       uint pos;
1405     } attr_id;
1406     if (format.attr_len == 0) {
1407       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1408     }
1409
1410     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1411     GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 2);
1412
1413     for (int a = 0; a < NSEGMENTS * 2; a += 2) {
1414       v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
1415       v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
1416       GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
1417
1418       v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
1419       v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
1420       GPU_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v);
1421     }
1422
1423     SHC.drw_light = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1424   }
1425   return SHC.drw_light;
1426 #undef NSEGMENTS
1427 }
1428
1429 GPUBatch *DRW_cache_light_shadows_get(void)
1430 {
1431 #define NSEGMENTS 10
1432   if (!SHC.drw_light_shadows) {
1433     float v[2];
1434
1435     /* Position Only 3D format */
1436     static GPUVertFormat format = {0};
1437     static struct {
1438       uint pos;
1439     } attr_id;
1440     if (format.attr_len == 0) {
1441       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1442     }
1443
1444     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1445     GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 2);
1446
1447     for (int a = 0; a < NSEGMENTS * 2; a += 2) {
1448       v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
1449       v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
1450       GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
1451
1452       v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
1453       v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
1454       GPU_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v);
1455     }
1456
1457     SHC.drw_light_shadows = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1458   }
1459   return SHC.drw_light_shadows;
1460 #undef NSEGMENTS
1461 }
1462
1463 GPUBatch *DRW_cache_light_sunrays_get(void)
1464 {
1465   if (!SHC.drw_light_sunrays) {
1466     float v[2], v1[2], v2[2];
1467
1468     /* Position Only 2D format */
1469     static GPUVertFormat format = {0};
1470     static struct {
1471       uint pos;
1472     } attr_id;
1473     if (format.attr_len == 0) {
1474       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1475     }
1476
1477     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1478     GPU_vertbuf_data_alloc(vbo, 32);
1479
1480     for (int a = 0; a < 8; a++) {
1481       v[0] = sinf((2.0f * M_PI * a) / 8.0f);
1482       v[1] = cosf((2.0f * M_PI * a) / 8.0f);
1483
1484       mul_v2_v2fl(v1, v, 1.6f);
1485       mul_v2_v2fl(v2, v, 1.9f);
1486       GPU_vertbuf_attr_set(vbo, attr_id.pos, a * 4, v1);
1487       GPU_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 1, v2);
1488
1489       mul_v2_v2fl(v1, v, 2.2f);
1490       mul_v2_v2fl(v2, v, 2.5f);
1491       GPU_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 2, v1);
1492       GPU_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 3, v2);
1493     }
1494
1495     SHC.drw_light_sunrays = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1496   }
1497   return SHC.drw_light_sunrays;
1498 }
1499
1500 GPUBatch *DRW_cache_light_area_square_get(void)
1501 {
1502   if (!SHC.drw_light_area_square) {
1503     float v1[3] = {0.0f, 0.0f, 0.0f};
1504
1505     /* Position Only 3D format */
1506     static GPUVertFormat format = {0};
1507     static struct {
1508       uint pos;
1509     } attr_id;
1510     if (format.attr_len == 0) {
1511       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1512     }
1513
1514     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1515     GPU_vertbuf_data_alloc(vbo, 8);
1516
1517     v1[0] = v1[1] = 0.5f;
1518     GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
1519     v1[0] = -0.5f;
1520     GPU_vertbuf_attr_set(vbo, attr_id.pos, 1, v1);
1521     GPU_vertbuf_attr_set(vbo, attr_id.pos, 2, v1);
1522     v1[1] = -0.5f;
1523     GPU_vertbuf_attr_set(vbo, attr_id.pos, 3, v1);
1524     GPU_vertbuf_attr_set(vbo, attr_id.pos, 4, v1);
1525     v1[0] = 0.5f;
1526     GPU_vertbuf_attr_set(vbo, attr_id.pos, 5, v1);
1527     GPU_vertbuf_attr_set(vbo, attr_id.pos, 6, v1);
1528     v1[1] = 0.5f;
1529     GPU_vertbuf_attr_set(vbo, attr_id.pos, 7, v1);
1530
1531     SHC.drw_light_area_square = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1532   }
1533   return SHC.drw_light_area_square;
1534 }
1535
1536 GPUBatch *DRW_cache_light_area_disk_get(void)
1537 {
1538 #define NSEGMENTS 32
1539   if (!SHC.drw_light_area_disk) {
1540     /* Position Only 3D format */
1541     static GPUVertFormat format = {0};
1542     static struct {
1543       uint pos;
1544     } attr_id;
1545     if (format.attr_len == 0) {
1546       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1547     }
1548
1549     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1550     GPU_vertbuf_data_alloc(vbo, 2 * NSEGMENTS);
1551
1552     float v[3] = {0.0f, 0.5f, 0.0f};
1553     GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v);
1554     for (int a = 1; a < NSEGMENTS; a++) {
1555       v[0] = 0.5f * sinf(2.0f * (float)M_PI * a / NSEGMENTS);
1556       v[1] = 0.5f * cosf(2.0f * (float)M_PI * a / NSEGMENTS);
1557       GPU_vertbuf_attr_set(vbo, attr_id.pos, 2 * a - 1, v);
1558       GPU_vertbuf_attr_set(vbo, attr_id.pos, 2 * a, v);
1559     }
1560     copy_v3_fl3(v, 0.0f, 0.5f, 0.0f);
1561     GPU_vertbuf_attr_set(vbo, attr_id.pos, (2 * NSEGMENTS) - 1, v);
1562
1563     SHC.drw_light_area_disk = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1564   }
1565   return SHC.drw_light_area_disk;
1566 #undef NSEGMENTS
1567 }
1568
1569 GPUBatch *DRW_cache_light_hemi_get(void)
1570 {
1571 #define CIRCLE_RESOL 32
1572   if (!SHC.drw_light_hemi) {
1573     float v[3];
1574     int vidx = 0;
1575
1576     /* Position Only 3D format */
1577     static GPUVertFormat format = {0};
1578     static struct {
1579       uint pos;
1580     } attr_id;
1581     if (format.attr_len == 0) {
1582       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1583     }
1584
1585     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1586     GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 2 - 6 * 2 * 2);
1587
1588     /* XZ plane */
1589     for (int a = 3; a < CIRCLE_RESOL / 2 - 3; a++) {
1590       v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL) - M_PI / 2);
1591       v[2] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL) - M_PI / 2) - 1.0f;
1592       v[1] = 0.0f;
1593       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1594
1595       v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL) - M_PI / 2);
1596       v[2] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL) - M_PI / 2) - 1.0f;
1597       v[1] = 0.0f;
1598       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1599     }
1600
1601     /* XY plane */
1602     for (int a = 3; a < CIRCLE_RESOL / 2 - 3; a++) {
1603       v[2] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)) - 1.0f;
1604       v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1605       v[0] = 0.0f;
1606       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1607
1608       v[2] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL)) - 1.0f;
1609       v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1610       v[0] = 0.0f;
1611       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1612     }
1613
1614     /* YZ plane full circle */
1615     /* lease v[2] as it is */
1616     const float rad = cosf((2.0f * M_PI * 3) / ((float)CIRCLE_RESOL));
1617     for (int a = 0; a < CIRCLE_RESOL; a++) {
1618       v[1] = rad * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1619       v[0] = rad * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
1620       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1621
1622       v[1] = rad * sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1623       v[0] = rad * cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
1624       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1625     }
1626
1627     SHC.drw_light_hemi = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1628   }
1629   return SHC.drw_light_hemi;
1630 #undef CIRCLE_RESOL
1631 }
1632
1633 GPUBatch *DRW_cache_light_spot_get(void)
1634 {
1635 #define NSEGMENTS 32
1636   if (!SHC.drw_light_spot) {
1637     /* a single ring of vertices */
1638     float p[NSEGMENTS][2];
1639     float n[NSEGMENTS][3];
1640     float neg[NSEGMENTS][3];
1641     float half_angle = 2 * M_PI / ((float)NSEGMENTS * 2);
1642     for (int i = 0; i < NSEGMENTS; ++i) {
1643       float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
1644       p[i][0] = cosf(angle);
1645       p[i][1] = sinf(angle);
1646
1647       n[i][0] = cosf(angle - half_angle);
1648       n[i][1] = sinf(angle - half_angle);
1649       n[i][2] = cosf(M_PI / 16.0f); /* slope of the cone */
1650       normalize_v3(n[i]);           /* necessary ? */
1651       negate_v3_v3(neg[i], n[i]);
1652     }
1653
1654     static GPUVertFormat format = {0};
1655     static struct {
1656       uint pos, n1, n2;
1657     } attr_id;
1658     if (format.attr_len == 0) {
1659       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1660       attr_id.n1 = GPU_vertformat_attr_add(&format, "N1", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1661       attr_id.n2 = GPU_vertformat_attr_add(&format, "N2", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1662     }
1663
1664     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1665     GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
1666
1667     for (int i = 0; i < NSEGMENTS; ++i) {
1668       float cv[2], v[3];
1669       cv[0] = p[i % NSEGMENTS][0];
1670       cv[1] = p[i % NSEGMENTS][1];
1671
1672       /* cone sides */
1673       ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
1674       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4, v);
1675       ARRAY_SET_ITEMS(v, 0.0f, 0.0f, 0.0f);
1676       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 1, v);
1677
1678       GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4, n[(i) % NSEGMENTS]);
1679       GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 1, n[(i) % NSEGMENTS]);
1680       GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4, n[(i + 1) % NSEGMENTS]);
1681       GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 1, n[(i + 1) % NSEGMENTS]);
1682
1683       /* end ring */
1684       ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
1685       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 2, v);
1686       cv[0] = p[(i + 1) % NSEGMENTS][0];
1687       cv[1] = p[(i + 1) % NSEGMENTS][1];
1688       ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
1689       GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 3, v);
1690
1691       GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 2, n[(i) % NSEGMENTS]);
1692       GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 3, n[(i) % NSEGMENTS]);
1693       GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 2, neg[(i) % NSEGMENTS]);
1694       GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 3, neg[(i) % NSEGMENTS]);
1695     }
1696
1697     SHC.drw_light_spot = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1698   }
1699   return SHC.drw_light_spot;
1700 #undef NSEGMENTS
1701 }
1702
1703 GPUBatch *DRW_cache_light_spot_volume_get(void)
1704 {
1705 #define NSEGMENTS 32
1706   if (!SHC.drw_light_spot_volume) {
1707     /* a single ring of vertices */
1708     float p[NSEGMENTS][2];
1709     for (int i = 0; i < NSEGMENTS; ++i) {
1710       float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
1711       p[i][0] = cosf(angle);
1712       p[i][1] = sinf(angle);
1713     }
1714
1715     static GPUVertFormat format = {0};
1716     static struct {
1717       uint pos;
1718     } attr_id;
1719     if (format.attr_len == 0) {
1720       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1721     }
1722
1723     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1724     GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 3);
1725
1726     uint v_idx = 0;
1727     for (int i = 0; i < NSEGMENTS; ++i) {
1728       float cv[2], v[3];
1729
1730       ARRAY_SET_ITEMS(v, 0.0f, 0.0f, 0.0f);
1731       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
1732
1733       cv[0] = p[i % NSEGMENTS][0];
1734       cv[1] = p[i % NSEGMENTS][1];
1735       ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
1736       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
1737
1738       cv[0] = p[(i + 1) % NSEGMENTS][0];
1739       cv[1] = p[(i + 1) % NSEGMENTS][1];
1740       ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
1741       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
1742     }
1743
1744     SHC.drw_light_spot_volume = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
1745   }
1746   return SHC.drw_light_spot_volume;
1747 #undef NSEGMENTS
1748 }
1749
1750 GPUBatch *DRW_cache_light_spot_square_get(void)
1751 {
1752   if (!SHC.drw_light_spot_square) {
1753     float p[5][3] = {
1754         {0.0f, 0.0f, 0.0f},
1755         {1.0f, 1.0f, -1.0f},
1756         {1.0f, -1.0f, -1.0f},
1757         {-1.0f, -1.0f, -1.0f},
1758         {-1.0f, 1.0f, -1.0f},
1759     };
1760
1761     uint v_idx = 0;
1762
1763     /* Position Only 3D format */
1764     static GPUVertFormat format = {0};
1765     static struct {
1766       uint pos;
1767     } attr_id;
1768     if (format.attr_len == 0) {
1769       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1770     }
1771
1772     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1773     GPU_vertbuf_data_alloc(vbo, 16);
1774
1775     /* piramid sides */
1776     for (int i = 1; i <= 4; ++i) {
1777       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[0]);
1778       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[i]);
1779
1780       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[(i % 4) + 1]);
1781       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[((i + 1) % 4) + 1]);
1782     }
1783
1784     SHC.drw_light_spot_square = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1785   }
1786   return SHC.drw_light_spot_square;
1787 }
1788
1789 GPUBatch *DRW_cache_light_spot_square_volume_get(void)
1790 {
1791   if (!SHC.drw_light_spot_square_volume) {
1792     float p[5][3] = {
1793         {0.0f, 0.0f, 0.0f},
1794         {1.0f, 1.0f, -1.0f},
1795         {1.0f, -1.0f, -1.0f},
1796         {-1.0f, -1.0f, -1.0f},
1797         {-1.0f, 1.0f, -1.0f},
1798     };
1799
1800     uint v_idx = 0;
1801
1802     /* Position Only 3D format */
1803     static GPUVertFormat format = {0};
1804     static struct {
1805       uint pos;
1806     } attr_id;
1807     if (format.attr_len == 0) {
1808       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1809     }
1810
1811     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1812     GPU_vertbuf_data_alloc(vbo, 12);
1813
1814     /* piramid sides */
1815     for (int i = 1; i <= 4; ++i) {
1816       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[0]);
1817       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[((i + 1) % 4) + 1]);
1818       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[(i % 4) + 1]);
1819     }
1820
1821     SHC.drw_light_spot_square_volume = GPU_batch_create_ex(
1822         GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
1823   }
1824   return SHC.drw_light_spot_square_volume;
1825 }
1826
1827 /** \} */
1828
1829 /* -------------------------------------------------------------------- */
1830 /** \name Speaker
1831  * \{ */
1832
1833 GPUBatch *DRW_cache_speaker_get(void)
1834 {
1835   if (!SHC.drw_speaker) {
1836     float v[3];
1837     const int segments = 16;
1838     int vidx = 0;
1839
1840     /* Position Only 3D format */
1841     static GPUVertFormat format = {0};
1842     static struct {
1843       uint pos;
1844     } attr_id;
1845     if (format.attr_len == 0) {
1846       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1847     }
1848
1849     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1850     GPU_vertbuf_data_alloc(vbo, 3 * segments * 2 + 4 * 4);
1851
1852     for (int j = 0; j < 3; j++) {
1853       float z = 0.25f * j - 0.125f;
1854       float r = (j == 0 ? 0.5f : 0.25f);
1855
1856       copy_v3_fl3(v, r, 0.0f, z);
1857       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1858       for (int i = 1; i < segments; i++) {
1859         float x = cosf(2.f * (float)M_PI * i / segments) * r;
1860         float y = sinf(2.f * (float)M_PI * i / segments) * r;
1861         copy_v3_fl3(v, x, y, z);
1862         GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1863         GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1864       }
1865       copy_v3_fl3(v, r, 0.0f, z);
1866       GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1867     }
1868
1869     for (int j = 0; j < 4; j++) {
1870       float x = (((j + 1) % 2) * (j - 1)) * 0.5f;
1871       float y = ((j % 2) * (j - 2)) * 0.5f;
1872       for (int i = 0; i < 3; i++) {
1873         if (i == 1) {
1874           x *= 0.5f;
1875           y *= 0.5f;
1876         }
1877
1878         float z = 0.25f * i - 0.125f;
1879         copy_v3_fl3(v, x, y, z);
1880         GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1881         if (i == 1) {
1882           GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
1883         }
1884       }
1885     }
1886
1887     SHC.drw_speaker = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1888   }
1889   return SHC.drw_speaker;
1890 }
1891
1892 /** \} */
1893
1894 /* -------------------------------------------------------------------- */
1895 /** \name Probe
1896  * \{ */
1897
1898 GPUBatch *DRW_cache_lightprobe_cube_get(void)
1899 {
1900   if (!SHC.drw_lightprobe_cube) {
1901     int v_idx = 0;
1902     const float sin_pi_3 = 0.86602540378f;
1903     const float cos_pi_3 = 0.5f;
1904     float v[7][3] = {
1905         {0.0f, 1.0f, 0.0f},
1906         {sin_pi_3, cos_pi_3, 0.0f},
1907         {sin_pi_3, -cos_pi_3, 0.0f},
1908         {0.0f, -1.0f, 0.0f},
1909         {-sin_pi_3, -cos_pi_3, 0.0f},
1910         {-sin_pi_3, cos_pi_3, 0.0f},
1911         {0.0f, 0.0f, 0.0f},
1912     };
1913
1914     /* Position Only 3D format */
1915     static GPUVertFormat format = {0};
1916     static struct {
1917       uint pos;
1918     } attr_id;
1919     if (format.attr_len == 0) {
1920       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1921     }
1922
1923     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1924     GPU_vertbuf_data_alloc(vbo, (6 + 3) * 2);
1925
1926     for (int i = 0; i < 6; ++i) {
1927       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
1928       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 6]);
1929     }
1930
1931     GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[1]);
1932     GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
1933
1934     GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[5]);
1935     GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
1936
1937     GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[3]);
1938     GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
1939
1940     SHC.drw_lightprobe_cube = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1941   }
1942   return SHC.drw_lightprobe_cube;
1943 }
1944
1945 GPUBatch *DRW_cache_lightprobe_grid_get(void)
1946 {
1947   if (!SHC.drw_lightprobe_grid) {
1948     int v_idx = 0;
1949     const float sin_pi_3 = 0.86602540378f;
1950     const float cos_pi_3 = 0.5f;
1951     const float v[7][3] = {
1952         {0.0f, 1.0f, 0.0f},
1953         {sin_pi_3, cos_pi_3, 0.0f},
1954         {sin_pi_3, -cos_pi_3, 0.0f},
1955         {0.0f, -1.0f, 0.0f},
1956         {-sin_pi_3, -cos_pi_3, 0.0f},
1957         {-sin_pi_3, cos_pi_3, 0.0f},
1958         {0.0f, 0.0f, 0.0f},
1959     };
1960
1961     /* Position Only 3D format */
1962     static GPUVertFormat format = {0};
1963     static struct {
1964       uint pos;
1965     } attr_id;
1966     if (format.attr_len == 0) {
1967       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1968     }
1969
1970     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1971     GPU_vertbuf_data_alloc(vbo, (6 * 2 + 3) * 2);
1972
1973     for (int i = 0; i < 6; ++i) {
1974       float tmp_v1[3], tmp_v2[3], tmp_tr[3];
1975       copy_v3_v3(tmp_v1, v[i]);
1976       copy_v3_v3(tmp_v2, v[(i + 1) % 6]);
1977       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v1);
1978       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v2);
1979
1980       /* Internal wires. */
1981       for (int j = 1; j < 2; ++j) {
1982         mul_v3_v3fl(tmp_tr, v[(i / 2) * 2 + 1], -0.5f * j);
1983         add_v3_v3v3(tmp_v1, v[i], tmp_tr);
1984         add_v3_v3v3(tmp_v2, v[(i + 1) % 6], tmp_tr);
1985         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v1);
1986         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v2);
1987       }
1988     }
1989
1990     GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[1]);
1991     GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
1992
1993     GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[5]);
1994     GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
1995
1996     GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[3]);
1997     GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
1998
1999     SHC.drw_lightprobe_grid = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
2000   }
2001   return SHC.drw_lightprobe_grid;
2002 }
2003
2004 GPUBatch *DRW_cache_lightprobe_planar_get(void)
2005 {
2006   if (!SHC.drw_lightprobe_planar) {
2007     int v_idx = 0;
2008     const float sin_pi_3 = 0.86602540378f;
2009     float v[4][3] = {
2010         {0.0f, 0.5f, 0.0f},
2011         {sin_pi_3, 0.0f, 0.0f},
2012         {0.0f, -0.5f, 0.0f},
2013         {-sin_pi_3, 0.0f, 0.0f},
2014     };
2015
2016     /* Position Only 3D format */
2017     static GPUVertFormat format = {0};
2018     static struct {
2019       uint pos;
2020     } attr_id;
2021     if (format.attr_len == 0) {
2022       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
2023     }
2024
2025     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
2026     GPU_vertbuf_data_alloc(vbo, 4 * 2);
2027
2028     for (int i = 0; i < 4; ++i) {
2029       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
2030       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 4]);
2031     }
2032
2033     SHC.drw_lightprobe_planar = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
2034   }
2035   return SHC.drw_lightprobe_planar;
2036 }
2037
2038 /** \} */
2039
2040 /* -------------------------------------------------------------------- */
2041 /** \name Armature Bones
2042  * \{ */
2043
2044 static const float bone_octahedral_verts[6][3] = {
2045     {0.0f, 0.0f, 0.0f},
2046     {0.1f, 0.1f, 0.1f},
2047     {0.1f, 0.1f, -0.1f},
2048     {-0.1f, 0.1f, -0.1f},
2049     {-0.1f, 0.1f, 0.1f},
2050     {0.0f, 1.0f, 0.0f},
2051 };
2052
2053 static const float bone_octahedral_smooth_normals[6][3] = {
2054     {0.0f, -1.0f, 0.0f},
2055 #if 0 /* creates problems for outlines when scaled */
2056     {0.943608f * M_SQRT1_2, -0.331048f, 0.943608f * M_SQRT1_2},
2057     {0.943608f * M_SQRT1_2, -0.331048f, -0.943608f * M_SQRT1_2},
2058     {-0.943608f * M_SQRT1_2, -0.331048f, -0.943608f * M_SQRT1_2},
2059     {-0.943608f * M_SQRT1_2, -0.331048f, 0.943608f * M_SQRT1_2},
2060 #else
2061     {M_SQRT1_2, 0.0f, M_SQRT1_2},
2062     {M_SQRT1_2, 0.0f, -M_SQRT1_2},
2063     {-M_SQRT1_2, 0.0f, -M_SQRT1_2},
2064     {-M_SQRT1_2, 0.0f, M_SQRT1_2},
2065 #endif
2066     {0.0f, 1.0f, 0.0f},
2067 };
2068
2069 #if 0 /* UNUSED */
2070
2071 static const uint bone_octahedral_wire[24] = {
2072     0, 1, 1, 5, 5, 3, 3, 0, 0, 4, 4, 5, 5, 2, 2, 0, 1, 2, 2, 3, 3, 4, 4, 1,
2073 };
2074
2075 /* aligned with bone_octahedral_wire
2076  * Contains adjacent normal index */
2077 static const uint bone_octahedral_wire_adjacent_face[24] = {
2078     0, 3, 4, 7, 5, 6, 1, 2, 2, 3, 6, 7, 4, 5, 0, 1, 0, 4, 1, 5, 2, 6, 3, 7,
2079 };
2080 #endif
2081
2082 static const uint bone_octahedral_solid_tris[8][3] = {
2083     {2, 1, 0}, /* bottom */
2084     {3, 2, 0},
2085     {4, 3, 0},
2086     {1, 4, 0},
2087
2088     {5, 1, 2}, /* top */
2089     {5, 2, 3},
2090     {5, 3, 4},
2091     {5, 4, 1},
2092 };
2093
2094 /**
2095  * Store indices of generated verts from bone_octahedral_solid_tris to define adjacency infos.
2096  * Example: triangle {2, 1, 0} is adjacent to {3, 2, 0}, {1, 4, 0} and {5, 1, 2}.
2097  * {2, 1, 0} becomes {0, 1, 2}
2098  * {3, 2, 0} becomes {3, 4, 5}
2099  * {1, 4, 0} becomes {9, 10, 11}
2100  * {5, 1, 2} becomes {12, 13, 14}
2101  * According to opengl specification it becomes (starting from
2102  * the first vertex of the first face aka. vertex 2):
2103  * {0, 12, 1, 10, 2, 3}
2104  */
2105 static const uint bone_octahedral_wire_lines_adjacency[12][4] = {
2106     {0, 1, 2, 6},
2107     {0, 12, 1, 6},
2108     {0, 3, 12, 6},
2109     {0, 2, 3, 6},
2110     {1, 6, 2, 3},
2111     {1, 12, 6, 3},
2112     {1, 0, 12, 3},
2113     {1, 2, 0, 3},
2114     {2, 0, 1, 12},
2115     {2, 3, 0, 12},
2116     {2, 6, 3, 12},
2117     {2, 1, 6, 12},
2118 };
2119
2120 #if 0 /* UNUSED */
2121 static const uint bone_octahedral_solid_tris_adjacency[8][6] = {
2122     {0, 12, 1, 10, 2, 3},
2123     {3, 15, 4, 1, 5, 6},
2124     {6, 18, 7, 4, 8, 9},
2125     {9, 21, 10, 7, 11, 0},
2126
2127     {12, 22, 13, 2, 14, 17},
2128     {15, 13, 16, 5, 17, 20},
2129     {18, 16, 19, 8, 20, 23},
2130     {21, 19, 22, 11, 23, 14},
2131 };
2132 #endif
2133
2134 /* aligned with bone_octahedral_solid_tris */
2135 static const float bone_octahedral_solid_normals[8][3] = {
2136     {M_SQRT1_2, -M_SQRT1_2, 0.00000000f},
2137     {-0.00000000f, -M_SQRT1_2, -M_SQRT1_2},
2138     {-M_SQRT1_2, -M_SQRT1_2, 0.00000000f},
2139     {0.00000000f, -M_SQRT1_2, M_SQRT1_2},
2140     {0.99388373f, 0.11043154f, -0.00000000f},
2141     {0.00000000f, 0.11043154f, -0.99388373f},
2142     {-0.99388373f, 0.11043154f, 0.00000000f},
2143     {0.00000000f, 0.11043154f, 0.99388373f},
2144 };
2145
2146 GPUBatch *DRW_cache_bone_octahedral_get(void)
2147 {
2148   if (!SHC.drw_bone_octahedral) {
2149     uint v_idx = 0;
2150
2151     static GPUVertFormat format = {0};
2152     static struct {
2153       uint pos, nor, snor;
2154     } attr_id;
2155     if (format.attr_len == 0) {
2156       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
2157       attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
2158       attr_id.snor = GPU_vertformat_attr_add(&format, "snor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
2159     }
2160
2161     /* Vertices */
2162     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
2163     GPU_vertbuf_data_alloc(vbo, 24);
2164
2165     for (int i = 0; i < 8; i++) {
2166       for (int j = 0; j < 3; ++j) {
2167         GPU_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_octahedral_solid_normals[i]);
2168         GPU_vertbuf_attr_set(vbo,
2169                              attr_id.snor,
2170                              v_idx,
2171                              bone_octahedral_smooth_normals[bone_octahedral_solid_tris[i][j]]);
2172         GPU_vertbuf_attr_set(
2173             vbo, attr_id.pos, v_idx++, bone_octahedral_verts[bone_octahedral_solid_tris[i][j]]);
2174       }
2175     }
2176
2177     SHC.drw_bone_octahedral = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
2178   }
2179   return SHC.drw_bone_octahedral;
2180 }
2181
2182 GPUBatch *DRW_cache_bone_octahedral_wire_get(void)
2183 {
2184   if (!SHC.drw_bone_octahedral_wire) {
2185     GPUIndexBufBuilder elb;
2186     GPU_indexbuf_init(&elb, GPU_PRIM_LINES_ADJ, 12, 24);
2187
2188     for (int i = 0; i < 12; i++) {
2189       GPU_indexbuf_add_line_adj_verts(&elb,
2190                                       bone_octahedral_wire_lines_adjacency[i][0],
2191                                       bone_octahedral_wire_lines_adjacency[i][1],
2192                                       bone_octahedral_wire_lines_adjacency[i][2],
2193                                       bone_octahedral_wire_lines_adjacency[i][3]);
2194     }
2195
2196     /* HACK Reuse vertex buffer. */
2197     GPUBatch *pos_nor_batch = DRW_cache_bone_octahedral_get();
2198
2199     SHC.drw_bone_octahedral_wire = GPU_batch_create_ex(GPU_PRIM_LINES_ADJ,
2200                                                        pos_nor_batch->verts[0],
2201                                                        GPU_indexbuf_build(&elb),
2202                                                        GPU_BATCH_OWNS_INDEX);
2203   }
2204   return SHC.drw_bone_octahedral_wire;
2205 }
2206
2207 /* XXX TODO move that 1 unit cube to more common/generic place? */
2208 static const float bone_box_verts[8][3] = {
2209     {1.0f, 0.0f, 1.0f},
2210     {1.0f, 0.0f, -1.0f},
2211     {-1.0f, 0.0f, -1.0f},
2212     {-1.0f, 0.0f, 1.0f},
2213     {1.0f, 1.0f, 1.0f},
2214     {1.0f, 1.0f, -1.0f},
2215     {-1.0f, 1.0f, -1.0f},
2216     {-1.0f, 1.0f, 1.0f},
2217 };
2218
2219 static const float bone_box_smooth_normals[8][3] = {
2220     {M_SQRT3, -M_SQRT3, M_SQRT3},
2221     {M_SQRT3, -M_SQRT3, -M_SQRT3},
2222     {-M_SQRT3, -M_SQRT3, -M_SQRT3},
2223     {-M_SQRT3, -M_SQRT3, M_SQRT3},
2224     {M_SQRT3, M_SQRT3, M_SQRT3},
2225     {M_SQRT3, M_SQRT3, -M_SQRT3},
2226     {-M_SQRT3, M_SQRT3, -M_SQRT3},
2227     {-M_SQRT3, M_SQRT3, M_SQRT3},
2228 };
2229
2230 #if 0 /* UNUSED */
2231 static const uint bone_box_wire[24] = {
2232     0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7,
2233 };
2234
2235 /* aligned with bone_octahedral_wire
2236  * Contains adjacent normal index */
2237 static const uint bone_box_wire_adjacent_face[24] = {
2238     0, 2, 0, 4, 1, 6, 1, 8, 3, 10, 5, 10, 7, 11, 9, 11, 3, 8, 2, 5, 4, 7, 6, 9,
2239 };
2240 #endif
2241
2242 static const uint bone_box_solid_tris[12][3] = {
2243     {0, 2, 1}, /* bottom */
2244     {0, 3, 2},
2245
2246     {0, 1, 5}, /* sides */
2247     {0, 5, 4},
2248
2249     {1, 2, 6},
2250     {1, 6, 5},
2251
2252     {2, 3, 7},
2253     {2, 7, 6},
2254
2255     {3, 0, 4},
2256     {3, 4, 7},
2257
2258     {4, 5, 6}, /* top */
2259     {4, 6, 7},
2260 };
2261
2262 /**
2263  * Store indices of generated verts from bone_box_solid_tris to define adjacency infos.
2264  * See bone_octahedral_solid_tris for more infos.
2265  */
2266 static const uint bone_box_wire_lines_adjacency[12][4] = {
2267     {4, 2, 0, 11},
2268     {0, 1, 2, 8},
2269     {2, 4, 1, 14},
2270     {1, 0, 4, 20}, /* bottom */
2271     {0, 8, 11, 14},
2272     {2, 14, 8, 20},
2273     {1, 20, 14, 11},
2274     {4, 11, 20, 8}, /* top */
2275     {20, 0, 11, 2},
2276     {11, 2, 8, 1},
2277     {8, 1, 14, 4},
2278     {14, 4, 20, 0}, /* sides */
2279 };
2280
2281 #if 0 /* UNUSED */
2282 static const uint bone_box_solid_tris_adjacency[12][6] = {
2283     {0, 5, 1, 14, 2, 8},
2284     {3, 26, 4, 20, 5, 1},
2285
2286     {6, 2, 7, 16, 8, 11},
2287     {9, 7, 10, 32, 11, 24},
2288
2289     {12, 0, 13, 22, 14, 17},
2290     {15, 13, 16, 30, 17, 6},
2291
2292     {18, 3, 19, 28, 20, 23},
2293     {21, 19, 22, 33, 23, 12},
2294
2295     {24, 4, 25, 10, 26, 29},
2296     {27, 25, 28, 34, 29, 18},
2297
2298     {30, 9, 31, 15, 32, 35},
2299     {33, 31, 34, 21, 35, 27},
2300 };
2301 #endif
2302
2303 /* aligned with bone_box_solid_tris */
2304 static const float bone_box_solid_normals[12][3] = {
2305     {0.0f, -1.0f, 0.0f},
2306     {0.0f, -1.0f, 0.0f},
2307
2308     {1.0f, 0.0f, 0.0f},
2309     {1.0f, 0.0f, 0.0f},
2310
2311     {0.0f, 0.0f, -1.0f},
2312     {0.0f, 0.0f, -1.0f},
2313
2314     {-1.0f, 0.0f, 0.0f},
2315     {-1.0f, 0.0f, 0.0f},
2316
2317     {0.0f, 0.0f, 1.0f},
2318     {0.0f, 0.0f, 1.0f},
2319
2320     {0.0f, 1.0f, 0.0f},
2321     {0.0f, 1.0f, 0.0f},
2322 };
2323
2324 GPUBatch *DRW_cache_bone_box_get(void)
2325 {
2326   if (!SHC.drw_bone_box) {
2327     uint v_idx = 0;
2328
2329     static GPUVertFormat format = {0};
2330     static struct {
2331       uint pos, nor, snor;
2332     } attr_id;
2333     if (format.attr_len == 0) {
2334       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
2335       attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
2336       attr_id.snor = GPU_vertformat_attr_add(&format, "snor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
2337     }
2338
2339     /* Vertices */
2340     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
2341     GPU_vertbuf_data_alloc(vbo, 36);
2342
2343     for (int i = 0; i < 12; i++) {
2344       for (int j = 0; j < 3; j++) {
2345         GPU_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_box_solid_normals[i]);
2346         GPU_vertbuf_attr_set(
2347             vbo, attr_id.snor, v_idx, bone_box_smooth_normals[bone_box_solid_tris[i][j]]);
2348         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_box_verts[bone_box_solid_tris[i][j]]);
2349       }
2350     }
2351
2352     SHC.drw_bone_box = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
2353   }
2354   return SHC.drw_bone_box;
2355 }
2356
2357 GPUBatch *DRW_cache_bone_box_wire_get(void)
2358 {
2359   if (!SHC.drw_bone_box_wire) {
2360     GPUIndexBufBuilder elb;
2361     GPU_indexbuf_init(&elb, GPU_PRIM_LINES_ADJ, 12, 36);
2362
2363     for (int i = 0; i < 12; i++) {
2364       GPU_indexbuf_add_line_adj_verts(&elb,
2365                                       bone_box_wire_lines_adjacency[i][0],
2366                                       bone_box_wire_lines_adjacency[i][1],
2367                                       bone_box_wire_lines_adjacency[i][2],
2368                                       bone_box_wire_lines_adjacency[i][3]);
2369     }
2370
2371     /* HACK Reuse vertex buffer. */
2372     GPUBatch *pos_nor_batch = DRW_cache_bone_box_get();
2373
2374     SHC.drw_bone_box_wire = GPU_batch_create_ex(GPU_PRIM_LINES_ADJ,
2375                                                 pos_nor_batch->verts[0],
2376                                                 GPU_indexbuf_build(&elb),
2377                                                 GPU_BATCH_OWNS_INDEX);
2378   }
2379   return SHC.drw_bone_box_wire;
2380 }
2381
2382 /* Helpers for envelope bone's solid sphere-with-hidden-equatorial-cylinder.
2383  * Note that here we only encode head/tail in forth component of the vector. */
2384 static void benv_lat_lon_to_co(const float lat, const float lon, float r_nor[3])
2385 {
2386   r_nor[0] = sinf(lat) * cosf(lon);
2387   r_nor[1] = sinf(lat) * sinf(lon);
2388   r_nor[2] = cosf(lat);
2389 }
2390
2391 GPUBatch *DRW_cache_bone_envelope_solid_get(void)
2392 {
2393   if (!SHC.drw_bone_envelope) {
2394     const int lon_res = 24;
2395     const int lat_res = 24;
2396     const float lon_inc = 2.0f * M_PI / lon_res;
2397     const float lat_inc = M_PI / lat_res;
2398     uint v_idx = 0;
2399
2400     static GPUVertFormat format = {0};
2401     static struct {
2402       uint pos;
2403     } attr_id;
2404     if (format.attr_len == 0) {
2405       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
2406     }
2407
2408     /* Vertices */
2409     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
2410     GPU_vertbuf_data_alloc(vbo, ((lat_res + 1) * 2) * lon_res * 1);
2411
2412     float lon = 0.0f;
2413     for (int i = 0; i < lon_res; i++, lon += lon_inc) {
2414       float lat = 0.0f;
2415       float co1[3], co2[3];
2416
2417       /* Note: the poles are duplicated on purpose, to restart the strip. */
2418
2419       /* 1st sphere */
2420       for (int j = 0; j < lat_res; j++, lat += lat_inc) {
2421         benv_lat_lon_to_co(lat, lon, co1);
2422         benv_lat_lon_to_co(lat, lon + lon_inc, co2);
2423
2424         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co1);
2425         GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co2);
2426       }
2427
2428       /* Closing the loop */
2429       benv_lat_lon_to_co(M_PI, lon, co1);
2430       benv_lat_lon_to_co(M_PI, lon + lon_inc, co2);
2431
2432       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co1);
2433       GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co2);
2434     }
2435
2436     SHC.drw_bone_envelope = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
2437   }
2438   return SHC.drw_bone_envelope;
2439 }
2440
2441 GPUBatch *DRW_cache_bone_envelope_outline_get(void)
2442 {
2443   if (!SHC.drw_bone_envelope_outline) {
2444 #define CIRCLE_RESOL 64
2445     float v0[2], v1[2], v2[2];
2446     const float radius = 1.0f;
2447
2448     /* Position Only 2D format */
2449     static GPUVertFormat format = {0};
2450     static struct {
2451       uint pos0, pos1, pos2;
2452     } attr_id;
2453     if (format.attr_len == 0) {
2454       attr_id.pos0 = GPU_vertformat_attr_add(&format, "pos0", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2455       attr_id.pos1 = GPU_vertformat_attr_add(&format, "pos1", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2456       attr_id.pos2 = GPU_vertformat_attr_add(&format, "pos2", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2457     }
2458
2459     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
2460     GPU_vertbuf_data_alloc(vbo, (CIRCLE_RESOL + 1) * 2);
2461
2462     v0[0] = radius * sinf((2.0f * M_PI * -2) / ((float)CIRCLE_RESOL));
2463     v0[1] = radius * cosf((2.0f * M_PI * -2) / ((float)CIRCLE_RESOL));
2464     v1[0] = radius * sinf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
2465     v1[1] = radius * cosf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
2466
2467     /* Output 4 verts for each position. See shader for explanation. */
2468     uint v = 0;
2469     for (int a = 0; a < CIRCLE_RESOL; a++) {
2470       v2[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2471       v2[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2472       GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
2473       GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
2474       GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
2475       GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
2476       GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
2477       GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
2478       copy_v2_v2(v0, v1);
2479       copy_v2_v2(v1, v2);
2480     }
2481     v2[0] = 0.0f;
2482     v2[1] = radius;
2483     GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
2484     GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
2485     GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
2486     GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
2487     GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
2488     GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
2489
2490     SHC.drw_bone_envelope_outline = GPU_batch_create_ex(
2491         GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
2492 #undef CIRCLE_RESOL
2493   }
2494   return SHC.drw_bone_envelope_outline;
2495 }
2496
2497 GPUBatch *DRW_cache_bone_point_get(void)
2498 {
2499   if (!SHC.drw_bone_point) {
2500 #if 0 /* old style geometry sphere */
2501     const int lon_res = 16;
2502     const int lat_res = 8;
2503     const float rad = 0.05f;
2504     const float lon_inc = 2 * M_PI / lon_res;
2505     const float lat_inc = M_PI / lat_res;
2506     uint v_idx = 0;
2507
2508     static GPUVertFormat format = {0};
2509     static struct {
2510       uint pos, nor;
2511     } attr_id;
2512     if (format.attr_len == 0) {
2513       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
2514       attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
2515     }
2516
2517     /* Vertices */
2518     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
2519     GPU_vertbuf_data_alloc(vbo, (lat_res - 1) * lon_res * 6);
2520
2521     float lon = 0.0f;
2522     for (int i = 0; i < lon_res; i++, lon += lon_inc) {
2523       float lat = 0.0f;
2524       for (int j = 0; j < lat_res; j++, lat += lat_inc) {
2525         if (j != lat_res - 1) { /* Pole */
2526           add_lat_lon_vert(
2527               vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat + lat_inc, lon + lon_inc);
2528           add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat + lat_inc, lon);
2529           add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat, lon);
2530         }
2531
2532         if (j != 0) { /* Pole */
2533           add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat, lon + lon_inc);
2534           add_lat_lon_vert(
2535               vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat + lat_inc, lon + lon_inc);
2536           add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat, lon);
2537         }
2538       }
2539     }
2540
2541     SHC.drw_bone_point = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
2542 #else
2543 #  define CIRCLE_RESOL 64
2544     float v[2];
2545     const float radius = 0.05f;
2546
2547     /* Position Only 2D format */
2548     static GPUVertFormat format = {0};
2549     static struct {
2550       uint pos;
2551     } attr_id;
2552     if (format.attr_len == 0) {
2553       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2554     }
2555
2556     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
2557     GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL);
2558
2559     for (int a = 0; a < CIRCLE_RESOL; a++) {
2560       v[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2561       v[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2562       GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
2563     }
2564
2565     SHC.drw_bone_point = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
2566 #  undef CIRCLE_RESOL
2567 #endif
2568   }
2569   return SHC.drw_bone_point;
2570 }
2571
2572 GPUBatch *DRW_cache_bone_point_wire_outline_get(void)
2573 {
2574   if (!SHC.drw_bone_point_wire) {
2575 #if 0 /* old style geometry sphere */
2576     GPUVertBuf *vbo = sphere_wire_vbo(0.05f);
2577     SHC.drw_bone_point_wire = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
2578 #else
2579 #  define CIRCLE_RESOL 64
2580     float v0[2], v1[2];
2581     const float radius = 0.05f;
2582
2583     /* Position Only 2D format */
2584     static GPUVertFormat format = {0};
2585     static struct {
2586       uint pos0, pos1;
2587     } attr_id;
2588     if (format.attr_len == 0) {
2589       attr_id.pos0 = GPU_vertformat_attr_add(&format, "pos0", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2590       attr_id.pos1 = GPU_vertformat_attr_add(&format, "pos1", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2591     }
2592
2593     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
2594     GPU_vertbuf_data_alloc(vbo, (CIRCLE_RESOL + 1) * 2);
2595
2596     v0[0] = radius * sinf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
2597     v0[1] = radius * cosf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
2598
2599     uint v = 0;
2600     for (int a = 0; a < CIRCLE_RESOL; a++) {
2601       v1[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2602       v1[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2603       GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
2604       GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
2605       GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
2606       GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
2607       copy_v2_v2(v0, v1);
2608     }
2609     v1[0] = 0.0f;
2610     v1[1] = radius;
2611     GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
2612     GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
2613     GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
2614     GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
2615
2616     SHC.drw_bone_point_wire = GPU_batch_create_ex(
2617         GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
2618 #  undef CIRCLE_RESOL
2619 #endif
2620   }
2621   return SHC.drw_bone_point_wire;
2622 }
2623
2624 /* keep in sync with armature_stick_vert.glsl */
2625 #define COL_WIRE (1 << 0)
2626 #define COL_HEAD (1 << 1)
2627 #define COL_TAIL (1 << 2)
2628 #define COL_BONE (1 << 3)
2629
2630 #define POS_HEAD (1 << 4)
2631 #define POS_TAIL (1 << 5)
2632 #define POS_BONE (1 << 6)
2633
2634 GPUBatch *DRW_cache_bone_stick_get(void)
2635 {
2636   if (!SHC.drw_bone_stick) {
2637 #define CIRCLE_RESOL 12
2638     uint v = 0;
2639     uint flag;
2640     const float radius = 2.0f; /* head/tail radius */
2641     float pos[2];
2642
2643     /* Position Only 2D format */
2644     static GPUVertFormat format = {0};
2645     static struct {
2646       uint pos, flag;
2647     } attr_id;
2648     if (format.attr_len == 0) {
2649       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2650       attr_id.flag = GPU_vertformat_attr_add(&format, "flag", GPU_COMP_U32, 1, GPU_FETCH_INT);
2651     }
2652
2653     const uint vcount = (CIRCLE_RESOL + 1) * 2 + 6;
2654
2655     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
2656     GPU_vertbuf_data_alloc(vbo, vcount);
2657
2658     GPUIndexBufBuilder elb;
2659     GPU_indexbuf_init_ex(&elb, GPU_PRIM_TRI_FAN, (CIRCLE_RESOL + 2) * 2 + 6 + 2, vcount, true);
2660
2661     /* head/tail points */
2662     for (int i = 0; i < 2; ++i) {
2663       /* center vertex */
2664       copy_v2_fl(pos, 0.0f);
2665       flag = (i == 0) ? POS_HEAD : POS_TAIL;
2666       flag |= (i == 0) ? COL_HEAD : COL_TAIL;
2667       GPU_vertbuf_attr_set(vbo, attr_id.pos, v, pos);
2668       GPU_vertbuf_attr_set(vbo, attr_id.flag, v, &flag);
2669       GPU_indexbuf_add_generic_vert(&elb, v++);
2670       /* circle vertices */
2671       flag |= COL_WIRE;
2672       for (int a = 0; a < CIRCLE_RESOL; a++) {
2673         pos[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2674         pos[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
2675         GPU_vertbuf_attr_set(vbo, attr_id.pos, v, pos);
2676         GPU_vertbuf_attr_set(vbo, attr_id.flag, v, &flag);
2677         GPU_indexbuf_add_generic_vert(&elb, v++);
2678       }
2679       /* Close the circle */
2680       GPU_indexbuf_add_generic_vert(&elb, v - CIRCLE_RESOL);
2681
2682       GPU_indexbuf_add_primitive_restart(&elb);
2683     }
2684
2685     /* Bone rectangle */
2686     pos[0] = 0.0f;
2687     for (int i = 0; i < 6; ++i) {
2688       pos[1] = (i == 0 || i == 3) ? 0.0f : ((i < 3) ? 1.0f : -1.0f);
2689       flag = ((i < 2 || i > 4) ? POS_HEAD : POS_TAIL) | ((i == 0 || i == 3) ? 0 : COL_WIRE) |
2690              COL_BONE | POS_BONE;
2691       GPU_vertbuf_attr_set(vbo, attr_id.pos, v, pos);
2692       GPU_vertbuf_attr_set(vbo, attr_id.flag, v, &flag);
2693       GPU_indexbuf_add_generic_vert(&elb, v++);
2694     }
2695
2696     SHC.drw_bone_stick = GPU_batch_create_ex(GPU_PRIM_TRI_FAN,
2697                                              vbo,
2698                                              GPU_indexbuf_build(&elb),
2699                                              GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
2700 #undef CIRCLE_RESOL
2701   }
2702   return SHC.drw_bone_stick;
2703 }
2704
2705 static void set_bone_axis_vert(GPUVertBuf *vbo,
2706                                uint axis,
2707                                uint pos,
2708                                uint col,
2709                                uint *v,
2710                                const float *a,
2711                                const float *p,
2712                                const float *c)
2713 {
2714   GPU_vertbuf_attr_set(vbo, axis, *v, a);
2715   GPU_vertbuf_attr_set(vbo, pos, *v, p);
2716   GPU_vertbuf_attr_set(vbo, col, *v, c);
2717   *v += 1;
2718 }
2719
2720 #define S_X 0.0215f
2721 #define S_Y 0.025f
2722 static float x_axis_name[4][2] = {
2723     {0.9f * S_X, 1.0f * S_Y},
2724     {-1.0f * S_X, -1.0f * S_Y},
2725     {-0.9f * S_X, 1.0f * S_Y},
2726     {1.0f * S_X, -1.0f * S_Y},
2727 };
2728 #define X_LEN (sizeof(x_axis_name) / (sizeof(float) * 2))
2729 #undef S_X
2730 #undef S_Y
2731
2732 #define S_X 0.0175f
2733 #define S_Y 0.025f
2734 static float y_axis_name[6][2] = {
2735     {-1.0f * S_X, 1.0f * S_Y},
2736     {0.0f * S_X, -0.1f * S_Y},
2737     {1.0f * S_X, 1.0f * S_Y},
2738     {0.0f * S_X, -0.1f * S_Y},
2739     {0.0f * S_X, -0.1f * S_Y},
2740     {0.0f * S_X, -1.0f * S_Y},
2741 };
2742 #define Y_LEN (sizeof(y_axis_name) / (sizeof(float) * 2))
2743 #undef S_X
2744 #undef S_Y
2745
2746 #define S_X 0.02f
2747 #define S_Y 0.025f
2748 static float z_axis_name[10][2] = {
2749     {-0.95f * S_X, 1.00f * S_Y},
2750     {0.95f * S_X, 1.00f * S_Y},
2751     {0.95f * S_X, 1.00f * S_Y},
2752     {0.95f * S_X, 0.90f * S_Y},
2753     {0.95f * S_X, 0.90f * S_Y},
2754     {-1.00f * S_X, -0.90f * S_Y},
2755     {-1.00f * S_X, -0.90f * S_Y},
2756     {-1.00f * S_X, -1.00f * S_Y},
2757     {-1.00f * S_X, -1.00f * S_Y},
2758     {1.00f * S_X, -1.00f * S_Y},
2759 };
2760 #define Z_LEN (sizeof(z_axis_name) / (sizeof(float) * 2))
2761 #undef S_X
2762 #undef S_Y
2763
2764 #define S_X 0.007f
2765 #define S_Y 0.007f
2766 static float axis_marker[8][2] = {
2767 #if 0 /* square */
2768     {-1.0f * S_X, 1.0f * S_Y},
2769     {1.0f * S_X, 1.0f * S_Y},
2770     {1.0f * S_X, 1.0f * S_Y},
2771     {1.0f * S_X, -1.0f * S_Y},
2772     {1.0f * S_X, -1.0f * S_Y},
2773     {-1.0f * S_X, -1.0f * S_Y},
2774     {-1.0f * S_X, -1.0f * S_Y},
2775     {-1.0f * S_X, 1.0f * S_Y}
2776 #else /* diamond */
2777     {-S_X, 0.f},
2778     {0.f, S_Y},
2779     {0.f, S_Y},
2780     {S_X, 0.f},
2781     {S_X, 0.f},
2782     {0.f, -S_Y},
2783     {0.f, -S_Y},
2784     {-S_X, 0.f}
2785 #endif
2786 };
2787 #define MARKER_LEN (sizeof(axis_marker) / (sizeof(float) * 2))
2788 #define MARKER_FILL_LAYER 6
2789 #undef S_X
2790 #undef S_Y
2791
2792 #define S_X 0.0007f
2793 #define S_Y 0.0007f
2794 #define O_X 0.001f
2795 #define O_Y -0.001f
2796 static float axis_name_shadow[8][2] = {
2797     {-S_X + O_X, S_Y + O_Y},
2798     {S_X + O_X, S_Y + O_Y},
2799     {S_X + O_X, S_Y + O_Y},
2800     {S_X + O_X, -S_Y + O_Y},
2801     {S_X + O_X, -S_Y + O_Y},
2802     {-S_X + O_X, -S_Y + O_Y},
2803     {-S_X + O_X, -S_Y + O_Y},
2804     {-S_X + O_X, S_Y + O_Y},
2805 };
2806 // #define SHADOW_RES (sizeof(axis_name_shadow) / (sizeof(float) * 2))
2807 #define SHADOW_RES 0
2808 #undef O_X
2809 #undef O_Y
2810 #undef S_X
2811 #undef S_Y
2812
2813 GPUBatch *DRW_cache_bone_arrows_get(void)
2814 {
2815   if (!SHC.drw_bone_arrows) {
2816     /* Position Only 3D format */
2817     static GPUVertFormat format = {0};
2818     static struct {
2819       uint axis, pos, col;
2820     } attr_id;
2821     if (format.attr_len == 0) {
2822       attr_id.axis = GPU_vertformat_attr_add(&format, "axis", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
2823       attr_id.pos = GPU_vertformat_attr_add(
2824           &format, "screenPos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2825       attr_id.col = GPU_vertformat_attr_add(
2826           &format, "colorAxis", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
2827     }
2828
2829     /* Line */
2830     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
2831     GPU_vertbuf_data_alloc(vbo,
2832                            (2 + MARKER_LEN * MARKER_FILL_LAYER) * 3 +
2833                                (X_LEN + Y_LEN + Z_LEN) * (1 + SHADOW_RES));
2834
2835     uint v = 0;
2836
2837     for (int axis = 0; axis < 3; axis++) {
2838       float pos[2] = {0.0f, 0.0f};
2839       float c[3] = {0.0f, 0.0f, 0.0f};
2840       float a = 0.0f;
2841       /* center to axis line */
2842       set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, pos, c);
2843       c[axis] = 0.5f;
2844       a = axis + 0.25f;
2845       set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, pos, c);
2846
2847       /* Axis end marker */
2848       for (int j = 1; j < MARKER_FILL_LAYER + 1; ++j) {
2849         for (int i = 0; i < MARKER_LEN; ++i) {
2850           float tmp[2];
2851           mul_v2_v2fl(tmp, axis_marker[i], j / (float)MARKER_FILL_LAYER);
2852           set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, tmp, c);
2853         }
2854       }
2855
2856       a = axis + 0.31f;
2857       /* Axis name */
2858       int axis_v_len;
2859       float(*axis_verts)[2];
2860       if (axis == 0) {
2861         axis_verts = x_axis_name;
2862         axis_v_len = X_LEN;
2863       }
2864       else if (axis == 1) {
2865         axis_verts = y_axis_name;
2866         axis_v_len = Y_LEN;
2867       }
2868       else {
2869         axis_verts = z_axis_name;
2870         axis_v_len = Z_LEN;
2871       }
2872
2873       /* Axis name shadows */
2874       copy_v3_fl(c, 0.0f);
2875       c[axis] = 0.3f;
2876       for (int j = 0; j < SHADOW_RES; ++j) {
2877         for (int i = 0; i < axis_v_len; ++i) {
2878           float tmp[2];
2879           add_v2_v2v2(tmp, axis_verts[i], axis_name_shadow[j]);
2880           set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, tmp, c);
2881         }
2882       }
2883
2884       /* Axis name */
2885       copy_v3_fl(c, 0.1f);
2886       c[axis] = 1.0f;
2887       for (int i = 0; i < axis_v_len; ++i) {
2888         set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, axis_verts[i], c);
2889       }
2890     }
2891
2892     SHC.drw_bone_arrows = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
2893   }
2894   return SHC.drw_bone_arrows;
2895 }
2896
2897 static const float staticSine[16] = {
2898     0.0f,
2899     0.104528463268f,
2900     0.207911690818f,
2901     0.309016994375f,
2902     0.406736643076f,
2903     0.5f,
2904     0.587785252292f,
2905     0.669130606359f,
2906     0.743144825477f,
2907     0.809016994375f,
2908     0.866025403784f,
2909     0.913545457643f,
2910     0.951056516295f,
2911     0.978147600734f,
2912     0.994521895368f,
2913     1.0f,
2914 };
2915
2916 #define set_vert(a, b, quarter) \
2917   { \
2918     copy_v2_fl2(pos, (quarter % 2 == 0) ? -(a) : (a), (quarter < 2) ? -(b) : (b)); \
2919     GPU_vertbuf_attr_set(vbo, attr_id.pos, v++, pos); \
2920   } \
2921   ((void)0)
2922
2923 GPUBatch *DRW_cache_bone_dof_sphere_get(void)
2924 {
2925   if (!SHC.drw_bone_dof_sphere) {
2926     int i, j, q, n = ARRAY_SIZE(staticSine);
2927     float x, z, px, pz, pos[2];
2928
2929     /* Position Only 3D format */
2930     static GPUVertFormat format = {0};
2931     static struct {
2932       uint pos;
2933     } attr_id;
2934     if (format.attr_len == 0) {
2935       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2936     }
2937
2938     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
2939     GPU_vertbuf_data_alloc(vbo, n * n * 6 * 4);
2940
2941     uint v = 0;
2942     for (q = 0; q < 4; ++q) {
2943       pz = 0.0f;
2944       for (i = 1; i < n; ++i) {
2945         z = staticSine[i];
2946         px = 0.0f;
2947         for (j = 1; j <= (n - i); ++j) {
2948           x = staticSine[j];
2949           if (j == n - i) {
2950             set_vert(px, z, q);
2951             set_vert(px, pz, q);
2952             set_vert(x, pz, q);
2953           }
2954           else {
2955             set_vert(x, z, q);
2956             set_vert(x, pz, q);
2957             set_vert(px, z, q);
2958
2959             set_vert(x, pz, q);
2960             set_vert(px, pz, q);
2961             set_vert(px, z, q);
2962           }
2963           px = x;
2964         }
2965         pz = z;
2966       }
2967     }
2968     /* TODO alloc right count from the begining. */
2969     GPU_vertbuf_data_resize(vbo, v);
2970
2971     SHC.drw_bone_dof_sphere = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
2972   }
2973   return SHC.drw_bone_dof_sphere;
2974 }
2975
2976 GPUBatch *DRW_cache_bone_dof_lines_get(void)
2977 {
2978   if (!SHC.drw_bone_dof_lines) {
2979     int i, n = ARRAY_SIZE(staticSine);
2980     float pos[2];
2981
2982     /* Position Only 3D format */
2983     static GPUVertFormat format = {0};
2984     static struct {
2985       uint pos;
2986     } attr_id;
2987     if (format.attr_len == 0) {
2988       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2989     }
2990
2991     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
2992     GPU_vertbuf_data_alloc(vbo, n * 4);
2993
2994     uint v = 0;
2995     for (i = 0; i < n * 4; i++) {
2996       float a = (1.0f - (i / (float)(n * 4))) * 2.0f * M_PI;
2997       float x = cosf(a);
2998       float y = sinf(a);
2999       set_vert(x, y, 0);
3000     }
3001
3002     SHC.drw_bone_dof_lines = GPU_batch_create_ex(
3003         GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO);
3004   }
3005   return SHC.drw_bone_dof_lines;
3006 }
3007
3008 #undef set_vert
3009
3010 /** \} */
3011
3012 /* -------------------------------------------------------------------- */
3013 /** \name Camera
3014  * \{ */
3015
3016 /**
3017  * We could make these more generic functions.
3018  * although filling 1d lines is not common.
3019  *
3020  * \note Use x coordinate to identify the vertex the vertex shader take care to place it appropriately.
3021  */
3022
3023 static const float camera_coords_frame_bounds[5] = {
3024     0.0f, /* center point */
3025     1.0f, /* + X + Y */
3026     2.0f, /* + X - Y */
3027     3.0f, /* - X - Y */
3028     4.0f, /* - X + Y */
3029 };
3030
3031 static const float camera_coords_frame_tri[3] = {
3032     5.0f, /* tria + X */
3033     6.0f, /* tria - X */
3034     7.0f, /* tria + Y */
3035 };
3036
3037 /** Draw a loop of lines. */
3038 static void camera_fill_lines_loop_fl_v1(GPUVertBufRaw *pos_step,
3039                                          const float *coords,
3040                                          const uint coords_len)
3041 {
3042   for (uint i = 0, i_prev = coords_len - 1; i < coords_len; i_prev = i++) {
3043     *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[i_prev];
3044     *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[i];
3045   }
3046 }
3047
3048 /** Fan lines out from the first vertex. */
3049 static void camera_fill_lines_fan_fl_v1(GPUVertBufRaw *pos_step,
3050                                         const float *coords,
3051                                         const uint coords_len)
3052 {
3053   for (uint i = 1; i < coords_len; i++) {
3054     *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[0];
3055     *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[i];
3056   }
3057 }
3058
3059 /** Simply fill the array. */
3060 static void camera_fill_array_fl_v1(GPUVertBufRaw *pos_step,
3061                                     const float *coords,
3062                                     const uint coords_len)
3063 {
3064   for (uint i = 0; i < coords_len; i++) {
3065     *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[i];
3066   }
3067 }
3068
3069 GPUBatch *DRW_cache_camera_get(void)
3070 {
3071   if (!SHC.drw_camera) {
3072     static GPUVertFormat format = {0};
3073     static struct {
3074       uint pos;
3075     } attr_id;
3076     if (format.attr_len == 0) {
3077       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
3078     }
3079
3080     /* Vertices */
3081     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
3082     const int vbo_len_capacity = 22;
3083     GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
3084     GPUVertBufRaw pos_step;
3085     GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
3086
3087     /* camera cone (from center to frame) */
3088     camera_fill_lines_fan_fl_v1(
3089         &pos_step, camera_coords_frame_bounds, ARRAY_SIZE(camera_coords_frame_bounds));
3090
3091     /* camera frame (skip center) */
3092     camera_fill_lines_loop_fl_v1(
3093         &pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1);
3094
3095     /* camera triangle (above the frame) */
3096     camera_fill_lines_loop_fl_v1(
3097         &pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri));
3098
3099     BLI_assert(vbo_len_capacity == GPU_vertbuf_raw_used(&pos_step));
3100
3101     SHC.drw_camera = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
3102   }
3103   return SHC.drw_camera;
3104 }
3105
3106 GPUBatch *DRW_cache_camera_frame_get(void)
3107 {
3108   if (!SHC.drw_camera_frame) {
3109
3110     static GPUVertFormat format = {0};
3111     static struct {
3112       uint pos;
3113     } attr_id;
3114     if (format.attr_len == 0) {
3115       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
3116     }
3117
3118     /* Vertices */
3119     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
3120     const int vbo_len_capacity = 8;
3121     GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
3122     GPUVertBufRaw pos_step;
3123     GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
3124
3125     /* camera frame (skip center) */
3126     camera_fill_lines_loop_fl_v1(
3127         &pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1);
3128
3129     BLI_assert(vbo_len_capacity == GPU_vertbuf_raw_used(&pos_step));
3130
3131     SHC.drw_camera_frame = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
3132   }
3133   return SHC.drw_camera_frame;
3134 }
3135
3136 GPUBatch *DRW_cache_camera_tria_get(void)
3137 {
3138   if (!SHC.drw_camera_tria) {
3139     static GPUVertFormat format = {0};
3140     static struct {
3141       uint pos;
3142     } attr_id;
3143     if (format.attr_len == 0) {
3144       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
3145     }
3146
3147     /* Vertices */
3148     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
3149     const int vbo_len_capacity = 3;
3150     GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
3151     GPUVertBufRaw pos_step;
3152     GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
3153
3154     /* camera triangle (above the frame) */
3155     camera_fill_array_fl_v1(
3156         &pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri));
3157
3158     BLI_assert(vbo_len_capacity == GPU_vertbuf_raw_used(&pos_step));
3159
3160     SHC.drw_camera_tria = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
3161   }
3162   return SHC.drw_camera_tria;
3163 }
3164
3165 /** \} */
3166
3167 /* -------------------------------------------------------------------- */
3168 /** \name Object Mode Helpers
3169  * \{ */
3170
3171 /* Object Center */
3172 GPUBatch *DRW_cache_single_vert_get(void)
3173 {
3174   if (!SHC.drw_single_vertice) {
3175     float v1[3] = {0.0f, 0.0f, 0.0f};
3176
3177     /* Position Only 3D format */
3178     static GPUVertFormat format = {0};
3179     static struct {
3180       uint pos;
3181     } attr_id;
3182     if (format.attr_len == 0) {
3183       attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
3184     }
3185
3186     GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
3187     GPU_vertbuf_data_alloc(vbo, 1);
3188
3189     GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
3190
3191     SHC.drw_single_vertice = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
3192   }
3193   return SHC.drw_single_vertice;
3194 }
3195
3196 /** \} */
3197
3198 /* -------------------------------------------------------------------- */
3199 /** \name Meshes
3200  * \{ */
3201
3202 GPUBatch *DRW_cache_mesh_all_verts_get(Object *ob)
3203 {
3204   BLI_assert(ob->type == OB_MESH);
3205   return DRW_mesh_batch_cache_get_all_verts(ob->data);
3206 }
3207
3208 GPUBatch *DRW_cache_mesh_all_edges_get(Object *ob)
3209 {
3210   BLI_assert(ob->type == OB_MESH);
3211   return DRW_mesh_batch_cache_get_all_edges(ob->data);
3212 }
3213
3214 GPUBatch *DRW_cache_mesh_loose_edges_get(Object *ob)
3215 {
3216   BLI_assert(ob->type == OB_MESH);
3217   return DRW_mesh_batch_cache_get_loose_edges(ob->data);
3218 }
3219
3220 GPUBatch *DRW_cache_mesh_edge_detection_get(Object *ob, bool *r_is_manifold)
3221 {
3222   BLI_assert(ob->type == OB_MESH);
3223   return DRW_mesh_batch_cache_get_edge_detection(ob->data, r_is_manifold);
3224 }
3225
3226 GPUBatch *DRW_cache_mesh_surface_get(Object *ob)
3227 {
3228   BLI_assert(ob->type == OB_MESH);
3229   return DRW_mesh_batch_cache_get_surface(ob->data);
3230 }
3231
3232 GPUBatch *DRW_cache_mesh_surface_edges_get(Object *ob)
3233 {
3234   BLI_assert(ob->type == OB_MESH);
3235   return DRW_mesh_batch_cache_get_surface_edges(ob->data);
3236 }
3237
3238 /* Return list of batches with length equal to max(1, totcol). */
3239 GPUBatch **DRW_cache_mesh_surface_shaded_get(Object *ob,
3240                                              struct GPUMaterial **gpumat_array,
3241                                              uint gpumat_array_len,
3242                                              char **auto_layer_names,
3243                                              int **auto_layer_is_srgb,
3244                                              int *auto_layer_count)
3245 {
3246   BLI_assert(ob->type == OB_MESH);
3247   return DRW_mesh_batch_cache_get_surface_shaded(ob->data,
3248                                                  gpumat_array,
3249                                                  gpumat_array_len,
3250                                                  auto_layer_names,
3251                                                  auto_layer_is_srgb,
3252                                                  auto_layer_count);
3253 }
3254
3255 /* Return list of batches with length equal to max(1, totcol). */
3256 GPUBatch **DRW_cache_mesh_surface_texpaint_get(Object *ob)
3257 {
3258   BLI_assert(ob->type == OB_MESH);
3259   return DRW_mesh_batch_cache_get_surface_texpaint(ob->data);
3260 }
3261
3262 GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(Object *ob)
3263 {
3264   BLI_assert(ob->type == OB_MESH);
3265   return DRW_mesh_batch_cache_get_surface_texpaint_single(ob->data);
3266 }
3267
3268 GPUBatch *DRW_cache_mesh_surface_vertpaint_get(Object *ob)
3269 {
3270   BLI_assert(ob->type == OB_MESH);
3271   return DRW_mesh_batch_cache_get_surface_vertpaint(ob->data);
3272 }
3273
3274 GPUBatch *DRW_cache_mesh_surface_weights_get(Object *ob)
3275 {
3276   BLI_assert(ob->type == OB_MESH);
3277   return DRW_mesh_batch_cache_get_surface_weights(ob->data);
3278 }
3279
3280 GPUBatch *DRW_cache_mesh_face_wireframe_get(Object *ob)
3281 {
3282   BLI_assert(ob->type == OB_MESH);
3283   return DRW_mesh_batch_cache_get_wireframes_face(ob->data);
3284 }
3285
3286 void DRW_cache_mesh_sculpt_coords_ensure(Object *ob)
3287 {
3288   BLI_assert(ob->type == OB_MESH);
3289
3290   Mesh *me = ob->data;
3291   DRW_mesh_cache_sculpt_coords_ensure(me);
3292 }
3293
3294 /** \} */
3295
3296 /* -------------------------------------------------------------------- */
3297 /** \name Curve
3298  * \{ */
3299
3300 GPUBatch *DRW_cache_curve_edge_wire_get(Object *ob)
3301 {
3302   BLI_assert(ob->type == OB_CURVE);
3303
3304   struct Curve *cu = ob->data;
3305   return DRW_curve_batch_cache_get_wire_edge(cu);
3306 }
3307
3308 GPUBatch *DRW_cache_curve_edge_normal_get(Object *ob)
3309 {
3310   BLI_assert(ob->type == OB_CURVE);
3311
3312   struct Curve *cu = ob->data;
3313   return DRW_curve_batch_cache_get_normal_edge(cu);
3314 }
3315
3316 GPUBatch *DRW_cache_curve_edge_overlay_get(Object *ob)
3317 {
3318   BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF));
3319
3320   struct Curve *cu = ob->data;
3321   return DRW_curve_batch_cache_get_edit_edges(cu);
3322 }
3323
3324 GPUBatch *DRW_cache_curve_vert_overlay_get(Object *ob, bool handles)
3325 {
3326   BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF));
3327
3328   struct Curve *cu = ob->data;
3329   return DRW_curve_batch_cache_get_edit_verts(cu, handles);
3330 }
3331
3332 GPUBatch *DRW_cache_curve_surface_get(Object *ob)
3333 {
3334   BLI_assert(ob->type == OB_CURVE);
3335
3336   struct Curve *cu = ob->data;
3337   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3338   if (mesh_eval != NULL) {
3339     return DRW_mesh_batch_cache_get_surface(mesh_eval);
3340   }
3341   else {
3342     return DRW_curve_batch_cache_get_triangles_with_normals(cu);
3343   }
3344 }
3345
3346 GPUBatch *DRW_cache_curve_loose_edges_get(Object *ob)
3347 {
3348   BLI_assert(ob->type == OB_CURVE);
3349
3350   struct Curve *cu = ob->data;
3351   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3352   if (mesh_eval != NULL) {
3353     return DRW_mesh_batch_cache_get_loose_edges(mesh_eval);
3354   }
3355   else {
3356     /* TODO */
3357     UNUSED_VARS(cu);
3358     return NULL;
3359   }
3360 }
3361
3362 GPUBatch *DRW_cache_curve_face_wireframe_get(Object *ob)
3363 {
3364   BLI_assert(ob->type == OB_CURVE);
3365
3366   struct Curve *cu = ob->data;
3367   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3368   if (mesh_eval != NULL) {
3369     return DRW_mesh_batch_cache_get_wireframes_face(mesh_eval);
3370   }
3371   else {
3372     return DRW_curve_batch_cache_get_wireframes_face(cu);
3373   }
3374 }
3375
3376 GPUBatch *DRW_cache_curve_edge_detection_get(Object *ob, bool *r_is_manifold)
3377 {
3378   BLI_assert(ob->type == OB_CURVE);
3379   struct Curve *cu = ob->data;
3380   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3381   if (mesh_eval != NULL) {
3382     return DRW_mesh_batch_cache_get_edge_detection(mesh_eval, r_is_manifold);
3383   }
3384   else {
3385     return DRW_curve_batch_cache_get_edge_detection(cu, r_is_manifold);
3386   }
3387 }
3388
3389 /* Return list of batches */
3390 GPUBatch **DRW_cache_curve_surface_shaded_get(Object *ob,
3391                                               struct GPUMaterial **gpumat_array,
3392                                               uint gpumat_array_len)
3393 {
3394   BLI_assert(ob->type == OB_CURVE);
3395
3396   struct Curve *cu = ob->data;
3397   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3398   if (mesh_eval != NULL) {
3399     return DRW_mesh_batch_cache_get_surface_shaded(
3400         mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL);
3401   }
3402   else {
3403     return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len);
3404   }
3405 }
3406
3407 /** \} */
3408
3409 /* -------------------------------------------------------------------- */
3410 /** \name MetaBall
3411  * \{ */
3412
3413 GPUBatch *DRW_cache_mball_surface_get(Object *ob)
3414 {
3415   BLI_assert(ob->type == OB_MBALL);
3416   return DRW_metaball_batch_cache_get_triangles_with_normals(ob);
3417 }
3418
3419 GPUBatch *DRW_cache_mball_edge_detection_get(Object *ob, bool *r_is_manifold)
3420 {
3421   BLI_assert(ob->type == OB_MBALL);
3422   return DRW_metaball_batch_cache_get_edge_detection(ob, r_is_manifold);
3423 }
3424
3425 GPUBatch *DRW_cache_mball_face_wireframe_get(Object *ob)
3426 {
3427   BLI_assert(ob->type == OB_MBALL);
3428   return DRW_metaball_batch_cache_get_wireframes_face(ob);
3429 }
3430
3431 GPUBatch **DRW_cache_mball_surface_shaded_get(Object *ob,
3432                                               struct GPUMaterial **gpumat_array,
3433                                               uint gpumat_array_len)
3434 {
3435   BLI_assert(ob->type == OB_MBALL);
3436   MetaBall *mb = ob->data;
3437   return DRW_metaball_batch_cache_get_surface_shaded(ob, mb, gpumat_array, gpumat_array_len);
3438 }
3439
3440 /** \} */
3441
3442 /* -------------------------------------------------------------------- */
3443 /** \name Font
3444  * \{ */
3445
3446 GPUBatch *DRW_cache_text_edge_wire_get(Object *ob)
3447 {
3448   BLI_assert(ob->type == OB_FONT);
3449
3450   struct Curve *cu = ob->data;
3451   return DRW_curve_batch_cache_get_wire_edge(cu);
3452 }
3453
3454 GPUBatch *DRW_cache_text_surface_get(Object *ob)
3455 {
3456   BLI_assert(ob->type == OB_FONT);
3457   struct Curve *cu = ob->data;
3458   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3459   if (cu->editfont && (cu->flag & CU_FAST)) {
3460     return NULL;
3461   }
3462   if (mesh_eval != NULL) {
3463     return DRW_mesh_batch_cache_get_surface(mesh_eval);
3464   }
3465   else {
3466     return DRW_curve_batch_cache_get_triangles_with_normals(cu);
3467   }
3468 }
3469
3470 GPUBatch *DRW_cache_text_edge_detection_get(Object *ob, bool *r_is_manifold)
3471 {
3472   BLI_assert(ob->type == OB_FONT);
3473   struct Curve *cu = ob->data;
3474   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3475   if (cu->editfont && (cu->flag & CU_FAST)) {
3476     return NULL;
3477   }
3478   if (mesh_eval != NULL) {
3479     return DRW_mesh_batch_cache_get_edge_detection(mesh_eval, r_is_manifold);
3480   }
3481   else {
3482     return DRW_curve_batch_cache_get_edge_detection(cu, r_is_manifold);
3483   }
3484 }
3485
3486 GPUBatch *DRW_cache_text_loose_edges_get(Object *ob)
3487 {
3488   BLI_assert(ob->type == OB_FONT);
3489   struct Curve *cu = ob->data;
3490   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3491   if (cu->editfont && (cu->flag & CU_FAST)) {
3492     return NULL;
3493   }
3494   if (mesh_eval != NULL) {
3495     return DRW_mesh_batch_cache_get_loose_edges(mesh_eval);
3496   }
3497   else {
3498     /* TODO */
3499     return NULL;
3500   }
3501 }
3502
3503 GPUBatch *DRW_cache_text_face_wireframe_get(Object *ob)
3504 {
3505   BLI_assert(ob->type == OB_FONT);
3506   struct Curve *cu = ob->data;
3507   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3508   if (cu->editfont && (cu->flag & CU_FAST)) {
3509     return NULL;
3510   }
3511   if (mesh_eval != NULL) {
3512     return DRW_mesh_batch_cache_get_wireframes_face(mesh_eval);
3513   }
3514   else {
3515     return DRW_curve_batch_cache_get_wireframes_face(cu);
3516   }
3517 }
3518
3519 GPUBatch **DRW_cache_text_surface_shaded_get(Object *ob,
3520                                              struct GPUMaterial **gpumat_array,
3521                                              uint gpumat_array_len)
3522 {
3523   BLI_assert(ob->type == OB_FONT);
3524   struct Curve *cu = ob->data;
3525   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3526   if (cu->editfont && (cu->flag & CU_FAST)) {
3527     return NULL;
3528   }
3529   if (mesh_eval != NULL) {
3530     return DRW_mesh_batch_cache_get_surface_shaded(
3531         mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL);
3532   }
3533   else {
3534     return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len);
3535   }
3536 }
3537
3538 /** \} */
3539
3540 /* -------------------------------------------------------------------- */
3541 /** \name Surface
3542  * \{ */
3543
3544 GPUBatch *DRW_cache_surf_surface_get(Object *ob)
3545 {
3546   BLI_assert(ob->type == OB_SURF);
3547
3548   struct Curve *cu = ob->data;
3549   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3550   if (mesh_eval != NULL) {
3551     return DRW_mesh_batch_cache_get_surface(mesh_eval);
3552   }
3553   else {
3554     return DRW_curve_batch_cache_get_triangles_with_normals(cu);
3555   }
3556 }
3557
3558 GPUBatch *DRW_cache_surf_edge_wire_get(Object *ob)
3559 {
3560   BLI_assert(ob->type == OB_SURF);
3561
3562   struct Curve *cu = ob->data;
3563   return DRW_curve_batch_cache_get_wire_edge(cu);
3564 }
3565
3566 GPUBatch *DRW_cache_surf_face_wireframe_get(Object *ob)
3567 {
3568   BLI_assert(ob->type == OB_SURF);
3569
3570   struct Curve *cu = ob->data;
3571   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3572   if (mesh_eval != NULL) {
3573     return DRW_mesh_batch_cache_get_wireframes_face(mesh_eval);
3574   }
3575   else {
3576     return DRW_curve_batch_cache_get_wireframes_face(cu);
3577   }
3578 }
3579
3580 GPUBatch *DRW_cache_surf_edge_detection_get(Object *ob, bool *r_is_manifold)
3581 {
3582   BLI_assert(ob->type == OB_SURF);
3583   struct Curve *cu = ob->data;
3584   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3585   if (mesh_eval != NULL) {
3586     return DRW_mesh_batch_cache_get_edge_detection(mesh_eval, r_is_manifold);
3587   }
3588   else {
3589     return DRW_curve_batch_cache_get_edge_detection(cu, r_is_manifold);
3590   }
3591 }
3592
3593 GPUBatch *DRW_cache_surf_loose_edges_get(Object *ob)
3594 {
3595   BLI_assert(ob->type == OB_SURF);
3596
3597   struct Curve *cu = ob->data;
3598   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3599   if (mesh_eval != NULL) {
3600     return DRW_mesh_batch_cache_get_loose_edges(mesh_eval);
3601   }
3602   else {
3603     /* TODO */
3604     UNUSED_VARS(cu);
3605     return NULL;
3606   }
3607 }
3608
3609 /* Return list of batches */
3610 GPUBatch **DRW_cache_surf_surface_shaded_get(Object *ob,
3611                                              struct GPUMaterial **gpumat_array,
3612                                              uint gpumat_array_len)
3613 {
3614   BLI_assert(ob->type == OB_SURF);
3615
3616   struct Curve *cu = ob->data;
3617   struct Mesh *mesh_eval = ob->runtime.mesh_eval;
3618   if (mesh_eval != NULL) {
3619     return DRW_mesh_batch_cache_get_surface_shaded(
3620         mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL);
3621   }
3622   else {
3623     return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len);
3624   }
3625 }
3626
3627 /** \} */
3628
3629 /* -------------------------------------------------------------------- */
3630 /** \name Lattice
3631  * \{ */
3632
3633 GPUBatch *DRW_cache_lattice_verts_get(Object *ob)
3634 {
3635   BLI_assert(ob->type == OB_LATTICE);
3636
3637   struct Lattice *lt = ob->data;
3638   return DRW_lattice_batch_cache_get_all_verts(lt);
3639 }
3640
3641 GPUBatch *DRW_cache_lattice_wire_get(Object *ob, bool use_weight)
3642 {
3643   BLI_assert(ob->type == OB_LATTICE);
3644
3645   Lattice *lt = ob->data;
3646   int actdef = -1;
3647
3648   if (use_weight && ob->defbase.first && lt->editlatt->latt->dvert) {
3649     actdef = ob->actdef - 1;
3650   }
3651
3652   return DRW_lattice_batch_cache_get_all_edges(lt, use_weight, actdef);
3653 }
3654
3655 GPUBatch *DRW_cache_lattice_vert_overlay_get(Object *ob)
3656 {
3657   BLI_assert(ob->type == OB_LATTICE);
3658
3659   struct Lattice *lt = ob->data;
3660   return DRW_lattice_batch_cache_get_edit_verts(lt);
3661 }
3662
3663 /** \} */
3664
3665 /* -------------------------------------------------------------------- */
3666 /** \name Particles
3667  * \{ */
3668
3669 GPUBatch *DRW_cache_particles_get_hair(Object *object, ParticleSystem *psys, ModifierData *md)
3670 {
3671   return DRW_particles_batch_cache_get_hair(object, psys, md);
3672 }
3673
3674 GPUBatch *DRW_cache_particles_get_dots(Object *object, ParticleSystem *psys)
3675 {
3676   return DRW_particles_batch_cache_get_dots(object, psys);
3677 }
3678
3679 GPUBatch *DRW_cache_particles_get_edit_strands(Object *object,
3680                                                ParticleSystem *psys,
3681                                                struct PTCacheEdit *edit,
3682                                                bool use_weight)
3683 {
3684   return DRW_particles_batch_cache_get_edit_strands(object, psys, edit, use_weight);
3685 }
3686
3687 GPUBatch *DRW_cache_particles_get_edit_inner_points(Object *object,
3688                                                     ParticleSystem *psys,
3689                                                     struct PTCacheEdit *edit)
3690 {
3691   return DRW_particles_batch_cache_get_edit_inner_points(object, psys, edit);
3692 }
3693
3694 GPUBatch *DRW_cache_particles_get_edit_tip_points(Object *object,
3695                                                   ParticleSystem *psys,
3696                                                   struct PTCacheEdit *edit)
3697 {
3698   return DRW_particles_batch_cache_get_edit_tip_points(object, psys, edit);
3699 }
3700
3701 GPUBatch *DRW_cache_particles_get_prim(int type)
3702 {
3703   switch (type) {
3704     case PART_DRAW_CROSS:
3705       if (!SHC.drw_particle_cross) {
3706         static GPUVertFormat format = {0};
3707         static uint pos_id, axis_id;
3708
3709         if (format.attr_len == 0) {
3710           pos_id = GPU_vertformat_attr_add(&format, "inst_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
3711           axis_id = GPU_vertformat_attr_add(&format, "axis", GPU_COMP_I32, 1, GPU_FETCH_INT);
3712         }
3713
3714         GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
3715         GPU_vertbuf_data_alloc(vbo, 6);
3716
3717         /* X axis */
3718         float co[3] = {-1.0f, 0.0f, 0.0f};
3719         int axis = -1;
3720         GPU_vertbuf_attr_set(vbo, pos_id, 0, co);
3721         GPU_vertbuf_attr_set(vbo, axis_id, 0, &axis);
3722
3723         co[0] = 1.0f;
3724         GPU_vertbuf_attr_set(vbo, pos_id, 1, co);
3725         GPU_vertbuf_attr_set(vbo, axis_id, 1, &axis);
3726
3727         /* Y axis */
3728         co[0] = 0.0f;
3729         co[1] = -1.0f;
3730         GPU_vertbuf_attr_set(vbo, pos_id, 2, co);
3731         GPU_vertbuf_attr_set(vbo, axis_id, 2, &axis);
3732
3733         co[1] = 1.0f;
3734         GPU_vertbuf_attr_set(vbo, pos_id, 3, co);
3735         GPU_vertbuf_attr_set(vbo, axis_id, 3, &axis);
3736
3737         /* Z axis */
3738         co[1] = 0.0f;
3739         co[2] = -1.0f;
3740         GPU_vertbuf_attr_set(vbo, pos_id, 4, co);
3741         GPU_vertbuf_attr_set(vbo, axis_id, 4, &axis);
3742
3743         co[2] = 1.0f;
3744         GPU_vertbuf_attr_set(vbo, pos_id, 5, co);
3745         GPU_vertbuf_attr_set(vbo, axis_id, 5, &axis);
3746
3747         SHC.drw_particle_cross = GPU_batch_create_ex(
3748             GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
3749       }
3750
3751       return SHC.drw_particle_cross;
3752     case PART_DRAW_AXIS:
3753       if (!SHC.drw_particle_axis) {
3754         static GPUVertFormat format = {0};
3755         static uint pos_id, axis_id;
3756
3757         if (form