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