Overlay Engine: Fix bone outline antialiasing

This commit is contained in:
2019-12-05 16:08:52 +01:00
parent 95ca3f6536
commit d40579c62b
10 changed files with 116 additions and 157 deletions

View File

@@ -322,6 +322,7 @@ data_to_c_simple(engines/overlay/shaders/armature_sphere_solid_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/armature_sphere_solid_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/armature_stick_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/armature_stick_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/armature_wire_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/armature_wire_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/depth_only_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/edit_curve_handle_geom.glsl SRC)

View File

@@ -204,12 +204,6 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_float_copy(grp, "alpha", pd->armature.transparent ? 0.4f : 1.0f);
cb->point_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
sh = OVERLAY_shader_armature_sphere(true);
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_state_disable(grp, DRW_STATE_CULL_BACK);
DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
cb->point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
sh = OVERLAY_shader_armature_shape(false);
cb->custom_solid = grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
@@ -217,9 +211,15 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
cb->box_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
cb->octa_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get());
sh = OVERLAY_shader_armature_sphere(true);
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_ALPHA);
DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
cb->point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
sh = OVERLAY_shader_armature_shape(true);
cb->custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_state_disable(grp, DRW_STATE_CULL_BACK);
DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_ALPHA);
DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
cb->box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get());
cb->octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get());
@@ -230,6 +230,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_degrees_of_freedom();
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_ALPHA);
cb->dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get());
grp = DRW_shgroup_create(sh, psl->armature_transp_ps);
@@ -258,7 +259,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_envelope(true);
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_state_disable(grp, DRW_STATE_CULL_BACK);
DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_ALPHA);
DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
cb->envelope_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_outline_get());
@@ -276,6 +277,8 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_wire();
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_ALPHA);
DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
cb->wire = BUF_LINE(grp, format);
}
}
@@ -2341,12 +2344,9 @@ void OVERLAY_pose_draw(OVERLAY_Data *vedata)
DRW_draw_pass(psl->armature_bone_select_ps);
if (DRW_state_is_fbo()) {
GPU_framebuffer_bind(fbl->overlay_line_in_front_fb);
GPU_framebuffer_clear_depth(fbl->overlay_line_in_front_fb, 1.0f);
GPU_framebuffer_bind(fbl->overlay_line_fb);
}
/* Selection still works because we are drawing only the pose bones in this case. */
DRW_draw_pass(psl->armature_ps[1]);
}
}

View File

@@ -44,6 +44,7 @@ extern char datatoc_armature_sphere_solid_frag_glsl[];
extern char datatoc_armature_sphere_solid_vert_glsl[];
extern char datatoc_armature_stick_frag_glsl[];
extern char datatoc_armature_stick_vert_glsl[];
extern char datatoc_armature_wire_frag_glsl[];
extern char datatoc_armature_wire_vert_glsl[];
extern char datatoc_depth_only_vert_glsl[];
extern char datatoc_edit_curve_handle_geom_glsl[];
@@ -296,7 +297,7 @@ GPUShader *OVERLAY_shader_armature_sphere(bool use_outline)
NULL},
.frag = (const char *[]){extensions,
datatoc_common_view_lib_glsl,
datatoc_gpu_shader_flat_color_frag_glsl,
datatoc_armature_wire_frag_glsl,
NULL},
.defs = (const char *[]){sh_cfg->def, NULL},
});
@@ -334,7 +335,8 @@ GPUShader *OVERLAY_shader_armature_shape(bool use_outline)
datatoc_common_view_lib_glsl,
datatoc_armature_shape_outline_geom_glsl,
NULL},
.frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
.frag =
(const char *[]){datatoc_common_view_lib_glsl, datatoc_armature_wire_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg->def, NULL},
});
}
@@ -363,7 +365,8 @@ GPUShader *OVERLAY_shader_armature_envelope(bool use_outline)
datatoc_common_view_lib_glsl,
datatoc_armature_envelope_outline_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
.frag =
(const char *[]){datatoc_common_view_lib_glsl, datatoc_armature_wire_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg->def, NULL},
});
}
@@ -407,10 +410,12 @@ GPUShader *OVERLAY_shader_armature_degrees_of_freedom(void)
if (!sh_data->armature_dof) {
sh_data->armature_dof = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg->lib,
datatoc_common_globals_lib_glsl,
datatoc_common_view_lib_glsl,
datatoc_armature_dof_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
.frag =
(const char *[]){datatoc_common_view_lib_glsl, datatoc_armature_wire_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg->def, NULL},
});
}
@@ -425,10 +430,12 @@ GPUShader *OVERLAY_shader_armature_wire(void)
if (!sh_data->armature_wire) {
sh_data->armature_wire = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg->lib,
datatoc_common_globals_lib_glsl,
datatoc_common_view_lib_glsl,
datatoc_armature_wire_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
.frag =
(const char *[]){datatoc_common_view_lib_glsl, datatoc_armature_wire_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg->def, NULL},
});
}

View File

@@ -8,6 +8,8 @@ in vec4 color;
in mat4 inst_obmat;
flat out vec4 finalColor;
flat out vec2 edgeStart;
noperspective out vec2 edgePos;
vec3 sphere_project(float ax, float az)
{
@@ -28,6 +30,14 @@ void main()
vec3 final_pos = sphere_project(pos.x * abs((pos.x > 0.0) ? amax.x : amin.x),
pos.y * abs((pos.y > 0.0) ? amax.y : amin.y));
gl_Position = ViewProjectionMatrix * (model_mat * vec4(final_pos, 1.0));
vec3 world_pos = (model_mat * vec4(final_pos, 1.0)).xyz;
gl_Position = point_world_to_ndc(world_pos);
finalColor = color;
edgeStart = edgePos = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
}

View File

@@ -12,6 +12,8 @@ in vec4 outlineColorSize;
in vec3 xAxis;
flat out vec4 finalColor;
flat out vec2 edgeStart;
noperspective out vec2 edgePos;
/* project to screen space */
vec2 proj(vec4 pos)
@@ -132,33 +134,27 @@ void main()
vec3 wpos2 = get_outline_point(
pos2, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
vec4 pos_4d = vec4(wpos1, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(pos_4d.xyz);
world_clip_planes_calc_clip_distance(wpos1);
#endif
vec4 V = ViewMatrix * pos_4d;
float pres_fac = (ProjectionMatrix[3][3] == 0.0) ? abs(V.z) : 1.0;
vec4 p0 = point_world_to_ndc(wpos0);
vec4 p1 = point_world_to_ndc(wpos1);
vec4 p2 = point_world_to_ndc(wpos2);
vec4 p0 = ViewProjectionMatrix * vec4(wpos0, 1.0);
vec4 p1 = ProjectionMatrix * V;
vec4 p2 = ViewProjectionMatrix * vec4(wpos2, 1.0);
gl_Position = p1;
/* compute position from 3 vertex because the change in direction
* can happen very quicky and lead to very thin edges. */
vec2 ss0 = proj(p0);
vec2 ss1 = proj(p1);
vec2 ss2 = proj(p2);
vec2 edge_dir = compute_dir(ss0, ss1, ss2);
vec2 ofs_dir = compute_dir(ss0, ss1, ss2);
float line_thickness = 2.0 * sizePixel;
bool outer = ((gl_VertexID & 1) == 1);
vec2 t = outlineColorSize.w * line_thickness * sizeViewportInv.xy;
t *= pres_fac;
t = (outer) ? t : vec2(0.0);
/* Offset away from the center to avoid overlap with solid shape. */
gl_Position.xy += ofs_dir * sizeViewportInv.xy * gl_Position.w;
gl_Position = p1;
gl_Position.xy += t * edge_dir;
edgeStart = edgePos = proj(gl_Position);
finalColor = vec4(outlineColorSize.rgb, 1.0);
}

View File

@@ -1,6 +1,6 @@
layout(lines_adjacency) in;
layout(triangle_strip, max_vertices = 6) out;
layout(line_strip, max_vertices = 2) out;
in vec4 pPos[];
in vec3 vPos[];
@@ -9,55 +9,8 @@ in vec2 ssNor[];
in vec4 vColSize[];
flat out vec4 finalColor;
vec2 compute_dir(vec2 v0, vec2 v1)
{
vec2 dir = normalize(v1 - v0);
dir = vec2(-dir.y, dir.x);
return dir;
}
void emit_edge(vec2 edge_dir, vec2 hidden_dir, vec2 thick, bool is_persp)
{
float fac = dot(-hidden_dir, edge_dir);
edge_dir *= (fac < 0.0) ? -1.0 : 1.0;
vec2 t = thick * (is_persp ? abs(vPos[1].z) : 1.0);
gl_Position = pPos[1];
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
#endif
EmitVertex();
gl_Position.xy += t * edge_dir;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
#endif
EmitVertex();
t = thick * (is_persp ? abs(vPos[2].z) : 1.0);
gl_Position = pPos[2];
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_set_clip_distance(gl_in[2].gl_ClipDistance);
#endif
EmitVertex();
gl_Position.xy += t * edge_dir;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_set_clip_distance(gl_in[2].gl_ClipDistance);
#endif
EmitVertex();
}
void emit_corner(const int e, vec2 thick, bool is_persp)
{
vec2 corner_dir = ssNor[e];
vec2 t = thick * (is_persp ? abs(vPos[e].z) : 1.0);
gl_Position = pPos[e] + vec4(t * corner_dir, 0.0, 0.0);
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_set_clip_distance(gl_in[e].gl_ClipDistance);
#endif
EmitVertex();
}
flat out vec2 edgeStart;
noperspective out vec2 edgePos;
void main(void)
{
@@ -91,9 +44,8 @@ void main(void)
return;
}
float line_thickness = 2.0 * sizePixel;
vec2 thick = vColSize[0].w * (line_thickness * sizeViewportInv.xy);
vec2 edge_dir = compute_dir(ssPos[1], ssPos[2]);
vec2 perp = normalize(ssPos[2] - ssPos[1]);
vec2 edge_dir = vec2(-perp.y, perp.x);
vec2 hidden_point;
/* Take the farthest point to compute edge direction
@@ -109,8 +61,30 @@ void main(void)
}
vec2 hidden_dir = normalize(hidden_point - ssPos[1]);
emit_corner(1, thick, is_persp);
emit_edge(edge_dir, hidden_dir, thick, is_persp);
emit_corner(2, thick, is_persp);
float fac = dot(-hidden_dir, edge_dir);
edge_dir *= (fac < 0.0) ? -1.0 : 1.0;
gl_Position = pPos[1];
/* Offset away from the center to avoid overlap with solid shape. */
gl_Position.xy += (edge_dir - perp) * sizeViewportInv.xy * gl_Position.w;
/* Improve AA bleeding inside bone silhouette. */
gl_Position.z -= 1e-4;
edgeStart = edgePos = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
#endif
EmitVertex();
gl_Position = pPos[2];
/* Offset away from the center to avoid overlap with solid shape. */
gl_Position.xy += (edge_dir + perp) * sizeViewportInv.xy * gl_Position.w;
/* Improve AA bleeding inside bone silhouette. */
gl_Position.z -= 1e-4;
edgeStart = edgePos = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_set_clip_distance(gl_in[2].gl_ClipDistance);
#endif
EmitVertex();
EndPrimitive();
}

View File

@@ -1,12 +1,13 @@
/* ---- Instantiated Attrs ---- */
in vec2 pos0;
in vec2 pos1;
in vec2 pos;
/* ---- Per instance Attrs ---- */
in mat4 inst_obmat;
flat out vec4 finalColor;
flat out vec2 edgeStart;
noperspective out vec2 edgePos;
/* project to screen space */
vec2 proj(vec4 pos)
@@ -14,18 +15,6 @@ vec2 proj(vec4 pos)
return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
}
vec2 compute_dir(vec2 v0, vec2 v1, vec2 c)
{
vec2 dir = normalize(v1 - v0);
dir = vec2(dir.y, -dir.x);
/* The model matrix can be scaled negativly.
* Use projected sphere center to determine
* the outline direction. */
vec2 cv = c - v0;
dir = (dot(dir, cv) > 0.0) ? -dir : dir;
return dir;
}
void main()
{
vec4 bone_color, state_color;
@@ -73,27 +62,17 @@ void main()
}
/* Camera oriented position (but still in local space) */
vec3 cam_pos0 = x_axis * pos0.x + y_axis * pos0.y + z_axis * z_ofs;
vec3 cam_pos1 = x_axis * pos1.x + y_axis * pos1.y + z_axis * z_ofs;
vec3 cam_pos0 = x_axis * pos.x + y_axis * pos.y + z_axis * z_ofs;
vec4 V = model_view_matrix * vec4(cam_pos0, 1.0);
vec4 p0 = ProjectionMatrix * V;
vec4 p1 = ProjectionMatrix * (model_view_matrix * vec4(cam_pos1, 1.0));
vec4 c = ProjectionMatrix * vec4(model_view_matrix[3].xyz, 1.0);
gl_Position = ProjectionMatrix * V;
vec4 center = ProjectionMatrix * vec4(model_view_matrix[3].xyz, 1.0);
vec2 ssc = proj(c);
vec2 ss0 = proj(p0);
vec2 ss1 = proj(p1);
vec2 edge_dir = compute_dir(ss0, ss1, ssc);
/* Offset away from the center to avoid overlap with solid shape. */
vec2 ofs_dir = normalize(proj(gl_Position) - proj(center));
gl_Position.xy += ofs_dir * sizeViewportInv.xy * gl_Position.w;
bool outer = ((gl_VertexID & 1) == 1);
vec2 t = bone_color.w * (2.0 * sizeViewportInv.xy);
t *= (is_persp) ? abs(V.z) : 1.0;
t = (outer) ? t : vec2(0.0);
gl_Position = p0;
gl_Position.xy += t * edge_dir;
edgeStart = edgePos = proj(gl_Position);
finalColor = vec4(bone_color.rgb, 1.0);

View File

@@ -0,0 +1,13 @@
flat in vec4 finalColor;
flat in vec2 edgeStart;
noperspective in vec2 edgePos;
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec4 lineOutput;
void main()
{
lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos);
fragColor = finalColor;
}

View File

@@ -3,6 +3,8 @@ in vec3 color;
in vec3 pos;
flat out vec4 finalColor;
flat out vec2 edgeStart;
noperspective out vec2 edgePos;
void main()
{
@@ -12,6 +14,8 @@ void main()
vec3 worldPosition = point_object_to_world(pos);
gl_Position = point_world_to_ndc(worldPosition);
edgeStart = edgePos = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(worldPosition);
#endif

View File

@@ -2071,7 +2071,7 @@ GPUBatch *DRW_cache_bone_envelope_outline_get(void)
}
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, (CIRCLE_RESOL + 1) * 2);
GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL + 1);
v0[0] = radius * sinf((2.0f * M_PI * -2) / ((float)CIRCLE_RESOL));
v0[1] = radius * cosf((2.0f * M_PI * -2) / ((float)CIRCLE_RESOL));
@@ -2080,29 +2080,18 @@ GPUBatch *DRW_cache_bone_envelope_outline_get(void)
/* Output 4 verts for each position. See shader for explanation. */
uint v = 0;
for (int a = 0; a < CIRCLE_RESOL; a++) {
for (int a = 0; a <= CIRCLE_RESOL; a++) {
v2[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
v2[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
copy_v2_v2(v0, v1);
copy_v2_v2(v1, v2);
}
v2[0] = 0.0f;
v2[1] = radius;
GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
SHC.drw_bone_envelope_outline = GPU_batch_create_ex(
GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
#undef CIRCLE_RESOL
}
return SHC.drw_bone_envelope_outline;
@@ -2191,44 +2180,30 @@ GPUBatch *DRW_cache_bone_point_wire_outline_get(void)
SHC.drw_bone_point_wire = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
#else
# define CIRCLE_RESOL 64
float v0[2], v1[2];
const float radius = 0.05f;
/* Position Only 2D format */
static GPUVertFormat format = {0};
static struct {
uint pos0, pos1;
uint pos;
} attr_id;
if (format.attr_len == 0) {
attr_id.pos0 = GPU_vertformat_attr_add(&format, "pos0", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
attr_id.pos1 = GPU_vertformat_attr_add(&format, "pos1", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
}
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, (CIRCLE_RESOL + 1) * 2);
v0[0] = radius * sinf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
v0[1] = radius * cosf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL + 1);
uint v = 0;
for (int a = 0; a < CIRCLE_RESOL; a++) {
v1[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
v1[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
copy_v2_v2(v0, v1);
for (int a = 0; a <= CIRCLE_RESOL; a++) {
float pos[2];
pos[0] = radius * sinf((2.0f * M_PI * a) / CIRCLE_RESOL);
pos[1] = radius * cosf((2.0f * M_PI * a) / CIRCLE_RESOL);
GPU_vertbuf_attr_set(vbo, attr_id.pos, v++, pos);
}
v1[0] = 0.0f;
v1[1] = radius;
GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
SHC.drw_bone_point_wire = GPU_batch_create_ex(
GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
# undef CIRCLE_RESOL
#endif
}