1373 lines
46 KiB
C++
1373 lines
46 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup overlay
|
|
*/
|
|
|
|
#include "GPU_batch_utils.hh"
|
|
#include "draw_cache.hh"
|
|
|
|
#include "overlay_private.hh"
|
|
|
|
namespace blender::draw::overlay {
|
|
|
|
static constexpr int diamond_nsegments = 4;
|
|
static constexpr int inner_nsegments = 8;
|
|
static constexpr int outer_nsegments = 10;
|
|
static constexpr int circle_nsegments = 32;
|
|
|
|
static constexpr float bone_box_verts[8][3] = {
|
|
{1.0f, 0.0f, 1.0f},
|
|
{1.0f, 0.0f, -1.0f},
|
|
{-1.0f, 0.0f, -1.0f},
|
|
{-1.0f, 0.0f, 1.0f},
|
|
{1.0f, 1.0f, 1.0f},
|
|
{1.0f, 1.0f, -1.0f},
|
|
{-1.0f, 1.0f, -1.0f},
|
|
{-1.0f, 1.0f, 1.0f},
|
|
};
|
|
|
|
static constexpr std::array<uint, 24> bone_box_wire_lines = {
|
|
0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7,
|
|
};
|
|
|
|
static const std::array<uint3, 12> bone_box_solid_tris{
|
|
uint3{0, 2, 1}, /* bottom */
|
|
{0, 3, 2},
|
|
|
|
{0, 1, 5}, /* sides */
|
|
{0, 5, 4},
|
|
|
|
{1, 2, 6},
|
|
{1, 6, 5},
|
|
|
|
{2, 3, 7},
|
|
{2, 7, 6},
|
|
|
|
{3, 0, 4},
|
|
{3, 4, 7},
|
|
|
|
{4, 5, 6}, /* top */
|
|
{4, 6, 7},
|
|
};
|
|
|
|
/**
|
|
* Store indices of generated verts from `bone_box_solid_tris` to define adjacency information.
|
|
* See `bone_octahedral_solid_tris` for more information.
|
|
*/
|
|
static const std::array<uint4, 12> bone_box_wire_lines_adjacency = {
|
|
uint4{4, 2, 0, 11},
|
|
{0, 1, 2, 8},
|
|
{2, 4, 1, 14},
|
|
{1, 0, 4, 20}, /* bottom */
|
|
{0, 8, 11, 14},
|
|
{2, 14, 8, 20},
|
|
{1, 20, 14, 11},
|
|
{4, 11, 20, 8}, /* top */
|
|
{20, 0, 11, 2},
|
|
{11, 2, 8, 1},
|
|
{8, 1, 14, 4},
|
|
{14, 4, 20, 0}, /* sides */
|
|
};
|
|
|
|
/* aligned with bone_box_solid_tris */
|
|
static const std::array<float3, 12> bone_box_solid_normals = {
|
|
float3{0.0f, -1.0f, 0.0f},
|
|
{0.0f, -1.0f, 0.0f},
|
|
|
|
{1.0f, 0.0f, 0.0f},
|
|
{1.0f, 0.0f, 0.0f},
|
|
|
|
{0.0f, 0.0f, -1.0f},
|
|
{0.0f, 0.0f, -1.0f},
|
|
|
|
{-1.0f, 0.0f, 0.0f},
|
|
{-1.0f, 0.0f, 0.0f},
|
|
|
|
{0.0f, 0.0f, 1.0f},
|
|
{0.0f, 0.0f, 1.0f},
|
|
|
|
{0.0f, 1.0f, 0.0f},
|
|
{0.0f, 1.0f, 0.0f},
|
|
};
|
|
|
|
static const std::array<float3, 6> bone_octahedral_verts{
|
|
float3{0.0f, 0.0f, 0.0f},
|
|
{0.1f, 0.1f, 0.1f},
|
|
{0.1f, 0.1f, -0.1f},
|
|
{-0.1f, 0.1f, -0.1f},
|
|
{-0.1f, 0.1f, 0.1f},
|
|
{0.0f, 1.0f, 0.0f},
|
|
};
|
|
|
|
/**
|
|
* NOTE: This is not the correct normals.
|
|
* The correct smooth normals for the equator vertices should be
|
|
* {+-0.943608f * M_SQRT1_2, -0.331048f, +-0.943608f * M_SQRT1_2}
|
|
* but it creates problems for outlines when bones are scaled.
|
|
*/
|
|
static const std::array<float3, 6> bone_octahedral_smooth_normals{
|
|
float3{0.0f, -1.0f, 0.0f},
|
|
{float(M_SQRT1_2), 0.0f, float(M_SQRT1_2)},
|
|
{float(M_SQRT1_2), 0.0f, -float(M_SQRT1_2)},
|
|
{-float(M_SQRT1_2), 0.0f, -float(M_SQRT1_2)},
|
|
{-float(M_SQRT1_2), 0.0f, float(M_SQRT1_2)},
|
|
{0.0f, 1.0f, 0.0f},
|
|
};
|
|
|
|
static const std::array<uint2, 12> bone_octahedral_wire_lines = {
|
|
uint2{0, 1},
|
|
{1, 5},
|
|
{5, 3},
|
|
{3, 0},
|
|
{0, 4},
|
|
{4, 5},
|
|
{5, 2},
|
|
{2, 0},
|
|
{1, 2},
|
|
{2, 3},
|
|
{3, 4},
|
|
{4, 1},
|
|
};
|
|
|
|
static const std::array<uint3, 8> bone_octahedral_solid_tris = {
|
|
uint3{2, 1, 0}, /* bottom */
|
|
{3, 2, 0},
|
|
{4, 3, 0},
|
|
{1, 4, 0},
|
|
|
|
{5, 1, 2}, /* top */
|
|
{5, 2, 3},
|
|
{5, 3, 4},
|
|
{5, 4, 1},
|
|
};
|
|
|
|
/**
|
|
* Store indices of generated verts from `bone_octahedral_solid_tris` to define adjacency
|
|
* information.
|
|
* Example: triangle {2, 1, 0} is adjacent to {3, 2, 0}, {1, 4, 0} and {5, 1, 2}.
|
|
* {2, 1, 0} becomes {0, 1, 2}
|
|
* {3, 2, 0} becomes {3, 4, 5}
|
|
* {1, 4, 0} becomes {9, 10, 11}
|
|
* {5, 1, 2} becomes {12, 13, 14}
|
|
* According to opengl specification it becomes (starting from
|
|
* the first vertex of the first face aka. vertex 2):
|
|
* {0, 12, 1, 10, 2, 3}
|
|
*/
|
|
static const std::array<uint4, 12> bone_octahedral_wire_lines_adjacency = {
|
|
uint4{0, 1, 2, 6},
|
|
{0, 12, 1, 6},
|
|
{0, 3, 12, 6},
|
|
{0, 2, 3, 6},
|
|
{1, 6, 2, 3},
|
|
{1, 12, 6, 3},
|
|
{1, 0, 12, 3},
|
|
{1, 2, 0, 3},
|
|
{2, 0, 1, 12},
|
|
{2, 3, 0, 12},
|
|
{2, 6, 3, 12},
|
|
{2, 1, 6, 12},
|
|
};
|
|
|
|
/* aligned with bone_octahedral_solid_tris */
|
|
static const float bone_octahedral_solid_normals[8][3] = {
|
|
{M_SQRT1_2, -M_SQRT1_2, 0.00000000f},
|
|
{-0.00000000f, -M_SQRT1_2, -M_SQRT1_2},
|
|
{-M_SQRT1_2, -M_SQRT1_2, 0.00000000f},
|
|
{0.00000000f, -M_SQRT1_2, M_SQRT1_2},
|
|
{0.99388373f, 0.11043154f, -0.00000000f},
|
|
{0.00000000f, 0.11043154f, -0.99388373f},
|
|
{-0.99388373f, 0.11043154f, 0.00000000f},
|
|
{0.00000000f, 0.11043154f, 0.99388373f},
|
|
};
|
|
|
|
static void append_line_loop(
|
|
Vector<Vertex> &dest, Span<float2> verts, float z, VertexClass flag, bool dashed = false)
|
|
{
|
|
const int step = dashed ? 2 : 1;
|
|
for (const int i : IndexRange(verts.size() / step)) {
|
|
for (const int j : IndexRange(2)) {
|
|
const float2 &cv = verts[(i * step + j) % verts.size()];
|
|
dest.append({{cv[0], cv[1], z}, flag});
|
|
}
|
|
}
|
|
}
|
|
|
|
static float light_distance_z_get(char axis, const bool start)
|
|
{
|
|
switch (axis) {
|
|
case 'x': /* - X */
|
|
return start ? 0.4f : 0.3f;
|
|
case 'X': /* + X */
|
|
return start ? 0.6f : 0.7f;
|
|
case 'y': /* - Y */
|
|
return start ? 1.4f : 1.3f;
|
|
case 'Y': /* + Y */
|
|
return start ? 1.6f : 1.7f;
|
|
case 'z': /* - Z */
|
|
return start ? 2.4f : 2.3f;
|
|
case 'Z': /* + Z */
|
|
return start ? 2.6f : 2.7f;
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
/* A single ring of vertices. */
|
|
static Vector<float2> ring_vertices(const float radius,
|
|
const int segments,
|
|
const bool half = false)
|
|
{
|
|
Vector<float2> verts;
|
|
const float full = (half ? 1.0f : 2.0f) * math::numbers::pi;
|
|
for (const int angle_i : IndexRange(segments + (half ? 1 : 0))) {
|
|
const float angle = (full * angle_i) / segments;
|
|
verts.append(radius * float2(math::cos(angle), math::sin(angle)));
|
|
}
|
|
return verts;
|
|
}
|
|
|
|
/* Returns lines segment geometry forming 3 circles, one on each axis. */
|
|
static Vector<Vertex> sphere_axes_circles(const float radius,
|
|
const VertexClass vclass,
|
|
const int segments)
|
|
{
|
|
Vector<float2> ring = ring_vertices(radius, segments);
|
|
|
|
Vector<Vertex> verts;
|
|
for (int axis : IndexRange(3)) {
|
|
for (int i : IndexRange(segments)) {
|
|
for (int j : IndexRange(2)) {
|
|
float2 cv = ring[(i + j) % segments];
|
|
if (axis == 0) {
|
|
verts.append({{cv[0], cv[1], 0.0f}, vclass});
|
|
}
|
|
else if (axis == 1) {
|
|
verts.append({{cv[0], 0.0f, cv[1]}, vclass});
|
|
}
|
|
else {
|
|
verts.append({{0.0f, cv[0], cv[1]}, vclass});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return verts;
|
|
}
|
|
|
|
static void light_append_direction_line(const char axis,
|
|
Span<float2> diamond,
|
|
Vector<Vertex> &verts)
|
|
{
|
|
const float zsta = light_distance_z_get(axis, true);
|
|
const float zend = light_distance_z_get(axis, false);
|
|
verts.append({{0.0, 0.0, zsta}, VCLASS_LIGHT_DIST});
|
|
verts.append({{0.0, 0.0, zend}, VCLASS_LIGHT_DIST});
|
|
append_line_loop(verts, diamond, zsta, VCLASS_LIGHT_DIST | VCLASS_SCREENSPACE);
|
|
append_line_loop(verts, diamond, zend, VCLASS_LIGHT_DIST | VCLASS_SCREENSPACE);
|
|
}
|
|
|
|
static void light_append_direction_line(Vector<Vertex> &verts)
|
|
{
|
|
const Vector<float2> diamond = ring_vertices(1.2f, diamond_nsegments);
|
|
light_append_direction_line('z', diamond, verts);
|
|
}
|
|
|
|
static VertShaded sphere_lat_lon_vert(const float2 &lat_pt, const float2 &lon_pt)
|
|
{
|
|
const float x = lon_pt.y * lat_pt.x;
|
|
const float y = lon_pt.x;
|
|
const float z = lon_pt.y * lat_pt.y;
|
|
return VertShaded{{x, y, z}, VCLASS_EMPTY_SCALED, {x, y, z}};
|
|
}
|
|
|
|
static void append_sphere(Vector<VertShaded> &dest, const eDRWLevelOfDetail level_of_detail)
|
|
{
|
|
/* Sphere shape resolution */
|
|
/* Low */
|
|
constexpr int drw_sphere_shape_latitude_low = 32;
|
|
constexpr int drw_sphere_shape_longitude_low = 24;
|
|
/* Medium */
|
|
constexpr int drw_sphere_shape_latitude_medium = 64;
|
|
constexpr int drw_sphere_shape_longitude_medium = 48;
|
|
/* High */
|
|
constexpr int drw_sphere_shape_latitude_high = 80;
|
|
constexpr int drw_sphere_shape_longitude_high = 60;
|
|
|
|
BLI_assert(level_of_detail >= DRW_LOD_LOW && level_of_detail < DRW_LOD_MAX);
|
|
const std::array<Vector<float2>, DRW_LOD_MAX> latitude_rings = {
|
|
ring_vertices(1.0f, drw_sphere_shape_latitude_low),
|
|
ring_vertices(1.0f, drw_sphere_shape_latitude_medium),
|
|
ring_vertices(1.0f, drw_sphere_shape_latitude_high)};
|
|
const std::array<Vector<float2>, DRW_LOD_MAX> longitude_half_rings = {
|
|
ring_vertices(1.0f, drw_sphere_shape_longitude_low, true),
|
|
ring_vertices(1.0f, drw_sphere_shape_longitude_medium, true),
|
|
ring_vertices(1.0f, drw_sphere_shape_longitude_high, true)};
|
|
|
|
const Vector<float2> &latitude_ring = latitude_rings[level_of_detail];
|
|
const Vector<float2> &longitude_half_ring = longitude_half_rings[level_of_detail];
|
|
|
|
for (const int i : latitude_ring.index_range()) {
|
|
const float2 lat_pt = latitude_ring[i];
|
|
const float2 next_lat_pt = latitude_ring[(i + 1) % latitude_ring.size()];
|
|
for (const int j : IndexRange(longitude_half_ring.size() - 1)) {
|
|
const float2 lon_pt = longitude_half_ring[j];
|
|
const float2 next_lon_pt = longitude_half_ring[j + 1];
|
|
if (j != 0) { /* Pole */
|
|
dest.append(sphere_lat_lon_vert(next_lat_pt, next_lon_pt));
|
|
dest.append(sphere_lat_lon_vert(next_lat_pt, lon_pt));
|
|
dest.append(sphere_lat_lon_vert(lat_pt, lon_pt));
|
|
}
|
|
if (j != longitude_half_ring.index_range().last(1)) { /* Pole */
|
|
dest.append(sphere_lat_lon_vert(lat_pt, next_lon_pt));
|
|
dest.append(sphere_lat_lon_vert(next_lat_pt, next_lon_pt));
|
|
dest.append(sphere_lat_lon_vert(lat_pt, lon_pt));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ShapeCache::ShapeCache()
|
|
{
|
|
UNUSED_VARS(bone_octahedral_wire_lines);
|
|
|
|
/* Armature Octahedron. */
|
|
{
|
|
Vector<VertShaded> verts;
|
|
for (int tri = 0; tri < 8; tri++) {
|
|
for (int v = 0; v < 3; v++) {
|
|
verts.append({bone_octahedral_verts[bone_octahedral_solid_tris[tri][v]],
|
|
VCLASS_NONE,
|
|
bone_octahedral_solid_normals[tri]});
|
|
}
|
|
}
|
|
bone_octahedron = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_TRIS, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
{
|
|
GPUIndexBufBuilder elb;
|
|
GPU_indexbuf_init(&elb, GPU_PRIM_LINES_ADJ, 12, 24);
|
|
|
|
for (auto line : bone_octahedral_wire_lines_adjacency) {
|
|
GPU_indexbuf_add_line_adj_verts(&elb, line[0], line[1], line[2], line[3]);
|
|
}
|
|
gpu::IndexBuf *ibo = GPU_indexbuf_build(&elb);
|
|
|
|
/* NOTE: Reuses the same VBO as bone_octahedron. Thus has the same vertex format. */
|
|
bone_octahedron_wire = BatchPtr(GPU_batch_create_ex(
|
|
GPU_PRIM_LINES_ADJ, bone_octahedron.get()->verts[0], ibo, GPU_BATCH_OWNS_INDEX));
|
|
}
|
|
|
|
/* Armature Sphere. */
|
|
{
|
|
constexpr int resolution = 64;
|
|
Vector<float2> ring = ring_vertices(0.05f, resolution);
|
|
|
|
Vector<Vertex> verts;
|
|
for (int a : IndexRange(resolution + 1)) {
|
|
float2 cv = ring[a % resolution];
|
|
verts.append({{cv.x, cv.y, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
}
|
|
|
|
bone_sphere = BatchPtr(GPU_batch_create_ex(
|
|
GPU_PRIM_TRI_FAN, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
{
|
|
bone_sphere_wire = BatchPtr(
|
|
GPU_batch_create(GPU_PRIM_LINE_STRIP, bone_sphere.get()->verts[0], nullptr));
|
|
}
|
|
|
|
/* Armature Stick. */
|
|
{
|
|
const StickBoneFlag bone = StickBoneFlag(COL_BONE | POS_BONE);
|
|
/* Gather as a strip and add to main buffer as a list of triangles. */
|
|
Vector<VertexBone> vert_strip;
|
|
vert_strip.append({{0.0f, 1.0f, 0.0f}, StickBoneFlag(bone | POS_HEAD | COL_HEAD | COL_WIRE)});
|
|
vert_strip.append({{0.0f, 1.0f, 0.0f}, StickBoneFlag(bone | POS_TAIL | COL_TAIL | COL_WIRE)});
|
|
vert_strip.append({{0.0f, 0.0f, 0.0f}, StickBoneFlag(bone | POS_HEAD | COL_HEAD)});
|
|
vert_strip.append({{0.0f, 0.0f, 0.0f}, StickBoneFlag(bone | POS_TAIL | COL_TAIL)});
|
|
vert_strip.append({{0.0f, -1.0f, 0.0f}, StickBoneFlag(bone | POS_HEAD | COL_HEAD | COL_WIRE)});
|
|
vert_strip.append({{0.0f, -1.0f, 0.0f}, StickBoneFlag(bone | POS_TAIL | COL_TAIL | COL_WIRE)});
|
|
|
|
Vector<VertexBone> verts;
|
|
/* Bone rectangle */
|
|
for (int t : IndexRange(vert_strip.size() - 2)) {
|
|
/* NOTE: Don't care about winding.
|
|
* Theses triangles are facing the camera and should not be backface culled. */
|
|
verts.append(vert_strip[t]);
|
|
verts.append(vert_strip[t + 1]);
|
|
verts.append(vert_strip[t + 2]);
|
|
}
|
|
|
|
constexpr int resolution = 12;
|
|
Vector<float2> ring = ring_vertices(2.0f, resolution);
|
|
for (int a : IndexRange(resolution)) {
|
|
float2 cv1 = ring[a % resolution];
|
|
float2 cv2 = ring[(a + 1) % resolution];
|
|
/* Head point. */
|
|
verts.append({{0.0f, 0.0f, 0.0f}, StickBoneFlag(POS_HEAD | COL_HEAD)});
|
|
verts.append({{cv1.x, cv1.y, 0.0f}, StickBoneFlag(POS_HEAD | COL_HEAD | COL_WIRE)});
|
|
verts.append({{cv2.x, cv2.y, 0.0f}, StickBoneFlag(POS_HEAD | COL_HEAD | COL_WIRE)});
|
|
/* Tail point. */
|
|
verts.append({{0.0f, 0.0f, 0.0f}, StickBoneFlag(POS_TAIL | COL_TAIL)});
|
|
verts.append({{cv1.x, cv1.y, 0.0f}, StickBoneFlag(POS_TAIL | COL_TAIL | COL_WIRE)});
|
|
verts.append({{cv2.x, cv2.y, 0.0f}, StickBoneFlag(POS_TAIL | COL_TAIL | COL_WIRE)});
|
|
}
|
|
|
|
bone_stick = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_TRIS, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
|
|
/* Armature BBones. */
|
|
{
|
|
Vector<VertShaded> verts;
|
|
for (int tri = 0; tri < 12; tri++) {
|
|
for (int v = 0; v < 3; v++) {
|
|
verts.append({bone_box_verts[bone_box_solid_tris[tri][v]],
|
|
VCLASS_NONE,
|
|
bone_box_solid_normals[tri]});
|
|
}
|
|
}
|
|
bone_box = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_TRIS, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
{
|
|
GPUIndexBufBuilder elb;
|
|
GPU_indexbuf_init(&elb, GPU_PRIM_LINES_ADJ, 12, 36);
|
|
|
|
for (auto line : bone_box_wire_lines_adjacency) {
|
|
GPU_indexbuf_add_line_adj_verts(&elb, line[0], line[1], line[2], line[3]);
|
|
}
|
|
gpu::IndexBuf *ibo = GPU_indexbuf_build(&elb);
|
|
|
|
/* NOTE: Reuses the same VBO as bone_box. Thus has the same vertex format. */
|
|
bone_box_wire = BatchPtr(GPU_batch_create_ex(
|
|
GPU_PRIM_LINES_ADJ, bone_box.get()->verts[0], ibo, GPU_BATCH_OWNS_INDEX));
|
|
}
|
|
|
|
/* Armature Envelope. */
|
|
{
|
|
constexpr int lon_res = 24;
|
|
constexpr int lat_res = 24;
|
|
constexpr float lon_inc = 2.0f * M_PI / lon_res;
|
|
constexpr float lat_inc = M_PI / lat_res;
|
|
|
|
auto lat_lon_to_co = [](const float lat, const float lon) {
|
|
return float3(sinf(lat) * cosf(lon), sinf(lat) * sinf(lon), cosf(lat));
|
|
};
|
|
|
|
Vector<Vertex> verts;
|
|
float lon = 0.0f;
|
|
for (int i = 0; i < lon_res; i++, lon += lon_inc) {
|
|
float lat = 0.0f;
|
|
/* NOTE: the poles are duplicated on purpose, to restart the strip. */
|
|
for (int j = 0; j < lat_res; j++, lat += lat_inc) {
|
|
verts.append({lat_lon_to_co(lat, lon), VCLASS_NONE});
|
|
verts.append({lat_lon_to_co(lat, lon + lon_inc), VCLASS_NONE});
|
|
}
|
|
/* Closing the loop */
|
|
verts.append({lat_lon_to_co(M_PI, lon), VCLASS_NONE});
|
|
verts.append({lat_lon_to_co(M_PI, lon + lon_inc), VCLASS_NONE});
|
|
}
|
|
|
|
bone_envelope = BatchPtr(GPU_batch_create_ex(
|
|
GPU_PRIM_TRI_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
{
|
|
constexpr int circle_resolution = 64;
|
|
float2 v0, v1, v2;
|
|
|
|
auto circle_pt = [](const float angle) { return float2(sinf(angle), cosf(angle)); };
|
|
|
|
Vector<VertexTriple> verts;
|
|
/* Output 3 verts for each position. See shader for explanation. */
|
|
v0 = circle_pt((2.0f * M_PI * -2) / float(circle_resolution));
|
|
v1 = circle_pt((2.0f * M_PI * -1) / float(circle_resolution));
|
|
for (int a = 0; a <= circle_resolution; a++, v0 = v1, v1 = v2) {
|
|
v2 = circle_pt((2.0f * M_PI * a) / float(circle_resolution));
|
|
verts.append({v0, v1, v2});
|
|
}
|
|
|
|
bone_envelope_wire = BatchPtr(GPU_batch_create_ex(
|
|
GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
|
|
/* Degrees of freedom. */
|
|
{
|
|
constexpr int resolution = 16;
|
|
|
|
Vector<Vertex> verts;
|
|
auto set_vert = [&](const float x, const float y, const int quarter) {
|
|
verts.append({{(quarter % 2 == 0) ? -x : x, (quarter < 2) ? -y : y, 0.0f}, VCLASS_NONE});
|
|
};
|
|
|
|
for (int quarter : IndexRange(4)) {
|
|
float prev_z = 0.0f;
|
|
for (int i : IndexRange(1, resolution - 1)) {
|
|
float z = sinf(M_PI_2 * i / float(resolution - 1));
|
|
float prev_x = 0.0f;
|
|
for (int j : IndexRange(1, resolution - i)) {
|
|
float x = sinf(M_PI_2 * j / float(resolution - 1));
|
|
if (j == resolution - i) {
|
|
/* Pole triangle. */
|
|
set_vert(prev_x, z, quarter);
|
|
set_vert(prev_x, prev_z, quarter);
|
|
set_vert(x, prev_z, quarter);
|
|
}
|
|
else {
|
|
/* Quad. */
|
|
set_vert(x, z, quarter);
|
|
set_vert(x, prev_z, quarter);
|
|
set_vert(prev_x, z, quarter);
|
|
|
|
set_vert(x, prev_z, quarter);
|
|
set_vert(prev_x, prev_z, quarter);
|
|
set_vert(prev_x, z, quarter);
|
|
}
|
|
prev_x = x;
|
|
}
|
|
prev_z = z;
|
|
}
|
|
}
|
|
|
|
bone_degrees_of_freedom = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_TRIS, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
{
|
|
constexpr int resolution = 16 * 4;
|
|
Vector<float2> ring = ring_vertices(1.0f, resolution);
|
|
|
|
Vector<Vertex> verts;
|
|
for (int a : IndexRange(resolution + 1)) {
|
|
float2 cv = ring[a % resolution];
|
|
verts.append({{cv.x, cv.y, 0.0f}, VCLASS_NONE});
|
|
}
|
|
|
|
bone_degrees_of_freedom_wire = BatchPtr(GPU_batch_create_ex(
|
|
GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
|
|
/* quad_wire */
|
|
{
|
|
Vector<Vertex> verts;
|
|
verts.append({{-1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{-1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{-1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{+1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{+1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{+1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{+1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{-1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
|
|
quad_wire = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* quad_solid */
|
|
{
|
|
const Array<float2> quad = {{-1.0f, 1.0f}, {1.0f, 1.0f}, {-1.0f, -1.0f}, {1.0f, -1.0f}};
|
|
Vector<Vertex> verts;
|
|
for (const float2 &point : quad) {
|
|
verts.append({{point, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
}
|
|
quad_solid = BatchPtr(GPU_batch_create_ex(
|
|
GPU_PRIM_TRI_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* plain_axes */
|
|
{
|
|
Vector<Vertex> verts;
|
|
verts.append({{0.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{0.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{-1.0f, 0.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{+1.0f, 0.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{0.0f, 0.0f, -1.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{0.0f, 0.0f, +1.0f}, VCLASS_EMPTY_SCALED});
|
|
|
|
plain_axes = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* single_arrow */
|
|
{
|
|
Vector<Vertex> verts;
|
|
float p[3][3] = {{0}};
|
|
p[0][2] = 1.0f;
|
|
p[1][0] = 0.035f;
|
|
p[1][1] = 0.035f;
|
|
p[2][0] = -0.035f;
|
|
p[2][1] = 0.035f;
|
|
p[1][2] = p[2][2] = 0.75f;
|
|
for (int sides : IndexRange(4)) {
|
|
if (sides % 2 == 1) {
|
|
p[1][0] = -p[1][0];
|
|
p[2][1] = -p[2][1];
|
|
}
|
|
else {
|
|
p[1][1] = -p[1][1];
|
|
p[2][0] = -p[2][0];
|
|
}
|
|
for (int i = 0, a = 1; i < 2; i++, a++) {
|
|
verts.append({{p[i][0], p[i][1], p[i][2]}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{p[a][0], p[a][1], p[a][2]}, VCLASS_EMPTY_SCALED});
|
|
}
|
|
}
|
|
verts.append({{0.0f, 0.0f, 0.0}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{0.0f, 0.0f, 0.75f}, VCLASS_EMPTY_SCALED});
|
|
|
|
single_arrow = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* cube */
|
|
{
|
|
Vector<Vertex> verts;
|
|
for (auto index : bone_box_wire_lines) {
|
|
float x = bone_box_verts[index][0];
|
|
float y = bone_box_verts[index][1] * 2.0 - 1.0f;
|
|
float z = bone_box_verts[index][2];
|
|
verts.append({{x, y, z}, VCLASS_EMPTY_SCALED});
|
|
}
|
|
|
|
cube = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* cube_solid */
|
|
{
|
|
cube_solid = BatchPtr(GPU_batch_unit_cube());
|
|
}
|
|
/* circle */
|
|
{
|
|
constexpr int resolution = 64;
|
|
Vector<float2> ring = ring_vertices(1.0f, resolution);
|
|
|
|
Vector<Vertex> verts;
|
|
for (int a : IndexRange(resolution + 1)) {
|
|
float2 cv1 = ring[(a + 0) % resolution];
|
|
float2 cv2 = ring[(a + 1) % resolution];
|
|
verts.append({{cv1.x, 0.0f, cv1.y}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{cv2.x, 0.0f, cv2.y}, VCLASS_EMPTY_SCALED});
|
|
}
|
|
|
|
circle = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* empty_sphere */
|
|
{
|
|
Vector<Vertex> verts = sphere_axes_circles(1.0f, VCLASS_EMPTY_SCALED, 32);
|
|
|
|
empty_sphere = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* empty_cone */
|
|
{
|
|
constexpr int resolution = 8;
|
|
Vector<float2> ring = ring_vertices(1.0f, resolution);
|
|
|
|
Vector<Vertex> verts;
|
|
for (int i : IndexRange(resolution)) {
|
|
float2 cv = ring[i % resolution];
|
|
/* Cone sides. */
|
|
verts.append({{cv[0], 0.0f, cv[1]}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{0.0f, 2.0f, 0.0f}, VCLASS_EMPTY_SCALED});
|
|
/* Base ring. */
|
|
for (int j : IndexRange(2)) {
|
|
float2 cv = ring[(i + j) % resolution];
|
|
verts.append({{cv[0], 0.0f, cv[1]}, VCLASS_EMPTY_SCALED});
|
|
}
|
|
}
|
|
|
|
empty_cone = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* cylinder */
|
|
{
|
|
constexpr int n_segments = 12;
|
|
const Vector<float2> ring = ring_vertices(1.0f, n_segments);
|
|
Vector<Vertex> verts;
|
|
/* top ring */
|
|
append_line_loop(verts, ring, 1.0f, VCLASS_EMPTY_SCALED);
|
|
/* bottom ring */
|
|
append_line_loop(verts, ring, -1.0f, VCLASS_EMPTY_SCALED);
|
|
/* cylinder sides */
|
|
for (const float2 &point : ring) {
|
|
verts.append({{point.x, point.y, 1.0f}, VCLASS_EMPTY_SCALED});
|
|
verts.append({{point.x, point.y, -1.0f}, VCLASS_EMPTY_SCALED});
|
|
}
|
|
cylinder = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* capsule body */
|
|
{
|
|
const Vector<float2> diamond = ring_vertices(1.0f, 4);
|
|
Vector<Vertex> verts;
|
|
for (const float2 &point : diamond) {
|
|
verts.append({{point.x, point.y, 1.0f}, VCLASS_NONE});
|
|
verts.append({{point.x, point.y, 0.0f}, VCLASS_NONE});
|
|
}
|
|
capsule_body = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* capsule cap */
|
|
{
|
|
constexpr int n_segments = 24;
|
|
const Vector<float2> ring = ring_vertices(1.0f, n_segments);
|
|
Vector<Vertex> verts;
|
|
/* Base circle */
|
|
append_line_loop(verts, ring, 0.0f, VCLASS_NONE);
|
|
for (const int i : IndexRange(n_segments / 2)) {
|
|
const float2 &point = ring[i];
|
|
const float2 &next_point = ring[i + 1];
|
|
/* Y half circle */
|
|
verts.append({{point.x, 0.0f, point.y}, VCLASS_NONE});
|
|
verts.append({{next_point.x, 0.0f, next_point.y}, VCLASS_NONE});
|
|
/* X half circle */
|
|
verts.append({{0.0f, point.x, point.y}, VCLASS_NONE});
|
|
verts.append({{0.0f, next_point.x, next_point.y}, VCLASS_NONE});
|
|
}
|
|
capsule_cap = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* arrows */
|
|
{
|
|
float2 x_axis_name_scale = {0.0215f, 0.025f};
|
|
Vector<float2> x_axis_name = {
|
|
float2(0.9f, 1.0f) * x_axis_name_scale,
|
|
float2(-1.0f, -1.0f) * x_axis_name_scale,
|
|
float2(-0.9f, 1.0f) * x_axis_name_scale,
|
|
float2(1.0f, -1.0f) * x_axis_name_scale,
|
|
};
|
|
|
|
float2 y_axis_name_scale = {0.0175f, 0.025f};
|
|
Vector<float2> y_axis_name = {
|
|
float2(-1.0f, 1.0f) * y_axis_name_scale,
|
|
float2(0.0f, -0.1f) * y_axis_name_scale,
|
|
float2(1.0f, 1.0f) * y_axis_name_scale,
|
|
float2(0.0f, -0.1f) * y_axis_name_scale,
|
|
float2(0.0f, -0.1f) * y_axis_name_scale,
|
|
float2(0.0f, -1.0f) * y_axis_name_scale,
|
|
};
|
|
|
|
float2 z_axis_name_scale = {0.02f, 0.025f};
|
|
Vector<float2> z_axis_name = {
|
|
float2(-0.95f, 1.00f) * z_axis_name_scale,
|
|
float2(0.95f, 1.00f) * z_axis_name_scale,
|
|
float2(0.95f, 1.00f) * z_axis_name_scale,
|
|
float2(0.95f, 0.90f) * z_axis_name_scale,
|
|
float2(0.95f, 0.90f) * z_axis_name_scale,
|
|
float2(-1.00f, -0.90f) * z_axis_name_scale,
|
|
float2(-1.00f, -0.90f) * z_axis_name_scale,
|
|
float2(-1.00f, -1.00f) * z_axis_name_scale,
|
|
float2(-1.00f, -1.00f) * z_axis_name_scale,
|
|
float2(1.00f, -1.00f) * z_axis_name_scale,
|
|
};
|
|
|
|
float2 axis_marker_scale = {0.007f, 0.007f};
|
|
Vector<float2> axis_marker = {
|
|
#if 0 /* square */
|
|
float2(-1.0f, 1.0f) * axis_marker_scale,
|
|
float2(1.0f, 1.0f) * axis_marker_scale,
|
|
float2(1.0f, 1.0f) * axis_marker_scale,
|
|
float2(1.0f, -1.0f) * axis_marker_scale,
|
|
float2(1.0f, -1.0f) * axis_marker_scale,
|
|
float2(-1.0f, -1.0f) * axis_marker_scale,
|
|
float2(-1.0f, -1.0f) * axis_marker_scale,
|
|
float2(-1.0f, 1.0f) * axis_marker_scale,
|
|
#else /* diamond */
|
|
float2(-1.0f, 0.0f) * axis_marker_scale,
|
|
float2(0.0f, 1.0f) * axis_marker_scale,
|
|
float2(0.0f, 1.0f) * axis_marker_scale,
|
|
float2(1.0f, 0.0f) * axis_marker_scale,
|
|
float2(1.0f, 0.0f) * axis_marker_scale,
|
|
float2(0.0f, -1.0f) * axis_marker_scale,
|
|
float2(0.0f, -1.0f) * axis_marker_scale,
|
|
float2(-1.0f, 0.0f) * axis_marker_scale,
|
|
#endif
|
|
};
|
|
|
|
Vector<Vertex> verts;
|
|
for (int axis : IndexRange(3)) {
|
|
/* Vertex layout is XY screen position and axis in Z.
|
|
* Fractional part of Z is a positive offset at axis unit position. */
|
|
VertexClass flag = VCLASS_EMPTY_AXES | VCLASS_SCREENALIGNED;
|
|
/* Center to axis line. */
|
|
/* NOTE: overlay_armature_shape_wire_vert.glsl expects the axis verts at the origin to be the
|
|
* only ones with this coordinates (it derives the VCLASS from it). */
|
|
float pos_on_axis = float(axis) + 1e-8f;
|
|
verts.append({{0.0f, 0.0f, 0.0f}, VCLASS_NONE});
|
|
verts.append({{0.0f, 0.0f, pos_on_axis}, flag});
|
|
/* Axis end marker. */
|
|
constexpr int marker_fill_layer = 6;
|
|
for (int j = 1; j < marker_fill_layer + 1; j++) {
|
|
for (float2 axis_marker_vert : axis_marker) {
|
|
verts.append({{axis_marker_vert * ((4.0f * j) / marker_fill_layer), pos_on_axis}, flag});
|
|
}
|
|
}
|
|
/* Axis name. */
|
|
const Vector<float2> *axis_names[3] = {&x_axis_name, &y_axis_name, &z_axis_name};
|
|
for (float2 axis_name_vert : *(axis_names[axis])) {
|
|
VertexClass flag = VCLASS_EMPTY_AXES | VCLASS_EMPTY_AXES_NAME | VCLASS_SCREENALIGNED;
|
|
verts.append({{axis_name_vert * 4.0f, pos_on_axis + 0.25f}, flag});
|
|
}
|
|
}
|
|
arrows = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* metaball_wire_circle */
|
|
{
|
|
constexpr int resolution = 64;
|
|
constexpr float radius = 1.0f;
|
|
Vector<float2> ring = ring_vertices(radius, resolution);
|
|
|
|
Vector<Vertex> verts;
|
|
for (int i : IndexRange(resolution + 1)) {
|
|
float2 cv = ring[i % resolution];
|
|
verts.append({{cv[0], cv[1], 0.0f}, VCLASS_SCREENALIGNED});
|
|
}
|
|
metaball_wire_circle = BatchPtr(GPU_batch_create_ex(
|
|
GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
};
|
|
/* speaker */
|
|
{
|
|
constexpr int segments = 16;
|
|
constexpr float bottom_r = 0.5f;
|
|
constexpr float bottom_z = -0.125f;
|
|
constexpr float step_z = 0.25f;
|
|
const Vector<float2> diamond = ring_vertices(bottom_r, 4);
|
|
Vector<float2> ring = ring_vertices(bottom_r, segments);
|
|
Vector<Vertex> verts;
|
|
|
|
append_line_loop(verts, ring, bottom_z, VCLASS_NONE);
|
|
for (float2 &point : ring) {
|
|
point *= 0.5f;
|
|
}
|
|
for (const int j : IndexRange(1, 2)) {
|
|
const float z = step_z * j + bottom_z;
|
|
append_line_loop(verts, ring, z, VCLASS_NONE);
|
|
}
|
|
|
|
for (const float2 &point : diamond) {
|
|
Vertex vertex{float3(point, bottom_z)};
|
|
verts.append(vertex);
|
|
vertex.pos = float3(point * 0.5f, bottom_z + step_z);
|
|
verts.append(vertex);
|
|
verts.append(vertex);
|
|
vertex.pos.z += step_z;
|
|
verts.append(vertex);
|
|
}
|
|
speaker = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* camera distances */
|
|
{
|
|
const Vector<float2> diamond = ring_vertices(1.5f, 5);
|
|
const Vector<float2> cross = {{1.0f, 0.0f}, {-1.0f, 0.0f}, {0.0f, 1.0f}, {0.0f, -1.0f}};
|
|
|
|
Vector<Vertex> verts;
|
|
verts.append({{0.0f, 0.0f, 0.0f}, VCLASS_CAMERA_DIST});
|
|
verts.append({{0.0f, 0.0f, 1.0f}, VCLASS_CAMERA_DIST});
|
|
|
|
append_line_loop(verts, diamond, 0.0f, VCLASS_CAMERA_DIST | VCLASS_SCREENSPACE);
|
|
append_line_loop(verts, diamond, 1.0f, VCLASS_CAMERA_DIST | VCLASS_SCREENSPACE);
|
|
|
|
/* Focus cross */
|
|
for (const float2 &point : cross) {
|
|
verts.append({{point.x, point.y, 2.0f}, VCLASS_CAMERA_DIST});
|
|
}
|
|
camera_distances = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* camera frame */
|
|
{
|
|
const Vector<float2> rect{{-1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, -1.0f}};
|
|
Vector<Vertex> verts;
|
|
/* Frame */
|
|
append_line_loop(verts, rect, 1.0f, VCLASS_CAMERA_FRAME);
|
|
/* Wires to origin. */
|
|
for (const float2 &point : rect) {
|
|
verts.append({{point.x, point.y, 1.0f}, VCLASS_CAMERA_FRAME});
|
|
verts.append({{point.x, point.y, 0.0f}, VCLASS_CAMERA_FRAME});
|
|
}
|
|
camera_frame = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* camera tria */
|
|
{
|
|
const Vector<float2> triangle = {{-1.0f, 1.0f}, {1.0f, 1.0f}, {0.0f, 0.0f}};
|
|
Vector<Vertex> verts;
|
|
/* Wire */
|
|
append_line_loop(verts, triangle, 1.0f, VCLASS_CAMERA_FRAME);
|
|
camera_tria_wire = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
|
|
verts.clear();
|
|
/* Triangle */
|
|
for (const float2 &point : triangle) {
|
|
verts.append({{point.x, point.y, 1.0f}, VCLASS_CAMERA_FRAME});
|
|
}
|
|
camera_tria = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_TRIS, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* camera volume */
|
|
{
|
|
Vector<Vertex> verts;
|
|
for (const uint3 &tri : bone_box_solid_tris) {
|
|
for (const int i : IndexRange(uint3::type_length)) {
|
|
const int v = tri[i];
|
|
const float x = bone_box_verts[v][2];
|
|
const float y = bone_box_verts[v][0];
|
|
const float z = bone_box_verts[v][1];
|
|
verts.append({{x, y, z}, VCLASS_CAMERA_FRAME | VCLASS_CAMERA_VOLUME});
|
|
}
|
|
}
|
|
camera_volume = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_TRIS, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* camera volume wire */
|
|
{
|
|
Vector<Vertex> verts;
|
|
for (int i : bone_box_wire_lines) {
|
|
const float x = bone_box_verts[i][2];
|
|
const float y = bone_box_verts[i][0];
|
|
const float z = bone_box_verts[i][1];
|
|
verts.append({{x, y, z}, VCLASS_CAMERA_FRAME | VCLASS_CAMERA_VOLUME});
|
|
}
|
|
camera_volume_wire = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* spheres */
|
|
{
|
|
Vector<VertShaded> verts;
|
|
append_sphere(verts, DRW_LOD_LOW);
|
|
sphere_low_detail = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_TRIS, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* ground line */
|
|
{
|
|
const Vector<float2> ring = ring_vertices(1.35f, diamond_nsegments);
|
|
|
|
Vector<Vertex> verts;
|
|
/* Ground Point */
|
|
append_line_loop(verts, ring, 0.0f, VCLASS_NONE);
|
|
/* Ground Line */
|
|
verts.append({{0.0, 0.0, 1.0}, VCLASS_NONE});
|
|
verts.append({{0.0, 0.0, 0.0}, VCLASS_NONE});
|
|
|
|
ground_line = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* image_quad */
|
|
{
|
|
const Array<float2> quad = {{0.0f, 1.0f}, {1.0f, 1.0f}, {0.0f, 0.0f}, {1.0f, 0.0f}};
|
|
Vector<Vertex> verts;
|
|
for (const float2 &point : quad) {
|
|
verts.append({{point, 0.75f}, VCLASS_NONE});
|
|
}
|
|
image_quad = BatchPtr(GPU_batch_create_ex(
|
|
GPU_PRIM_TRI_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* light spot volume */
|
|
{
|
|
Vector<Vertex> verts;
|
|
|
|
/* Cone apex */
|
|
verts.append({{0.0f, 0.0f, 0.0f}, VCLASS_NONE});
|
|
/* Cone silhouette */
|
|
for (const int angle_i : IndexRange(circle_nsegments + 1)) {
|
|
const float angle = (2.0f * math::numbers::pi * angle_i) / circle_nsegments;
|
|
const float s = sinf(-angle);
|
|
const float c = cosf(-angle);
|
|
verts.append({{s, c, -1.0f}, VCLASS_LIGHT_SPOT_SHAPE});
|
|
}
|
|
light_spot_volume = BatchPtr(GPU_batch_create_ex(
|
|
GPU_PRIM_TRI_FAN, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* light icon outer lines */
|
|
{
|
|
constexpr float r = 9.0f;
|
|
const Vector<float2> ring = ring_vertices(r * 1.33f, outer_nsegments * 2);
|
|
|
|
Vector<Vertex> verts;
|
|
append_line_loop(verts, ring, 0.0f, VCLASS_SCREENSPACE, true);
|
|
light_icon_outer_lines = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* light icon inner lines */
|
|
{
|
|
constexpr float r = 9.0f;
|
|
const Vector<float2> diamond = ring_vertices(r * 0.3f, diamond_nsegments);
|
|
const Vector<float2> ring = ring_vertices(r, inner_nsegments * 2);
|
|
|
|
Vector<Vertex> verts;
|
|
append_line_loop(verts, diamond, 0.0f, VCLASS_SCREENSPACE);
|
|
append_line_loop(verts, ring, 0.0f, VCLASS_SCREENSPACE, true);
|
|
|
|
light_icon_inner_lines = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* light icon sun rays */
|
|
{
|
|
constexpr int num_rays = 8;
|
|
constexpr float r = 9.0f;
|
|
const Vector<float2> ring = ring_vertices(r, num_rays);
|
|
const std::array<float, 4> scales{1.6f, 1.9f, 2.2f, 2.5f};
|
|
|
|
Vector<Vertex> verts;
|
|
for (const float2 &point : ring) {
|
|
for (float scale : scales) {
|
|
float2 scaled = point * scale;
|
|
verts.append({{scaled.x, scaled.y, 0.0f}, VCLASS_SCREENSPACE});
|
|
}
|
|
}
|
|
light_icon_sun_rays = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* light point lines */
|
|
{
|
|
const Vector<float2> ring = ring_vertices(1.0f, circle_nsegments);
|
|
|
|
Vector<Vertex> verts;
|
|
append_line_loop(verts, ring, 0.0f, VCLASS_SCREENALIGNED | VCLASS_LIGHT_AREA_SHAPE);
|
|
light_point_lines = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* light sun lines */
|
|
{
|
|
Vector<Vertex> verts;
|
|
/* Direction Line */
|
|
verts.append({{0.0, 0.0, 0.0}, VCLASS_NONE});
|
|
verts.append({{0.0, 0.0, -20.0}, VCLASS_NONE}); /* Good default. */
|
|
light_sun_lines = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* light spot lines */
|
|
{
|
|
const Vector<float2> ring = ring_vertices(1.0f, circle_nsegments);
|
|
|
|
Vector<Vertex> verts;
|
|
/* Light area */
|
|
append_line_loop(verts, ring, 0.0f, VCLASS_SCREENALIGNED | VCLASS_LIGHT_AREA_SHAPE);
|
|
/* Cone cap */
|
|
append_line_loop(verts, ring, 0.0f, VCLASS_LIGHT_SPOT_SHAPE);
|
|
append_line_loop(verts, ring, 0.0f, VCLASS_LIGHT_SPOT_SHAPE | VCLASS_LIGHT_SPOT_BLEND);
|
|
/* Cone silhouette */
|
|
for (const float2 &point : ring) {
|
|
verts.append({{0.0f, 0.0f, 0.0f}, VCLASS_NONE});
|
|
verts.append({{point.x, point.y, -1.0f}, VCLASS_LIGHT_SPOT_SHAPE | VCLASS_LIGHT_SPOT_CONE});
|
|
}
|
|
|
|
light_append_direction_line(verts);
|
|
|
|
light_spot_lines = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* light area disk lines */
|
|
{
|
|
const Vector<float2> ring = ring_vertices(0.5f, circle_nsegments);
|
|
|
|
Vector<Vertex> verts;
|
|
/* Light area */
|
|
append_line_loop(verts, ring, 0.0f, VCLASS_LIGHT_AREA_SHAPE);
|
|
|
|
light_append_direction_line(verts);
|
|
|
|
light_area_disk_lines = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* light area square lines */
|
|
{
|
|
const Array<float2> rect{{-0.5f, -0.5f}, {-0.5f, 0.5f}, {0.5f, 0.5f}, {0.5f, -0.5f}};
|
|
|
|
Vector<Vertex> verts;
|
|
/* Light area */
|
|
append_line_loop(verts, rect, 0.0f, VCLASS_LIGHT_AREA_SHAPE);
|
|
|
|
light_append_direction_line(verts);
|
|
|
|
light_area_square_lines = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* field_force */
|
|
{
|
|
constexpr int circle_resol = 32;
|
|
constexpr VertexClass flag = VCLASS_EMPTY_SIZE | VCLASS_SCREENALIGNED;
|
|
constexpr std::array<float, 2> scales{2.0f, 0.75};
|
|
Vector<float2> ring = ring_vertices(1.0f, circle_resol);
|
|
|
|
Vector<Vertex> verts;
|
|
|
|
append_line_loop(verts, ring, 0.0f, flag);
|
|
for (const float scale : scales) {
|
|
for (float2 &point : ring) {
|
|
point *= scale;
|
|
}
|
|
append_line_loop(verts, ring, 0.0f, flag);
|
|
}
|
|
|
|
field_force = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* field_wind */
|
|
{
|
|
constexpr int circle_resol = 32;
|
|
const Vector<float2> ring = ring_vertices(1.0f, circle_resol);
|
|
|
|
Vector<Vertex> verts;
|
|
|
|
for (const int i : IndexRange(4)) {
|
|
const float z = 0.05f * float(i);
|
|
append_line_loop(verts, ring, z, VCLASS_EMPTY_SIZE);
|
|
}
|
|
|
|
field_wind = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* field_vortex */
|
|
{
|
|
constexpr int spiral_resol = 32;
|
|
const Vector<float2> ring = ring_vertices(1.0f, spiral_resol);
|
|
|
|
Vector<Vertex> verts;
|
|
|
|
for (const int i : IndexRange(ring.size() * 2 + 1)) {
|
|
/* r: [-1, .., 0, .., 1] */
|
|
const float r = (i - spiral_resol) / float(spiral_resol);
|
|
/* index: [9, spiral_resol - 1, spiral_resol - 2, .., 2, 1, 0, 1, 2, .., spiral_resol - 1, 0]
|
|
*/
|
|
const float2 point = ring[abs(spiral_resol - i) % spiral_resol] * r;
|
|
verts.append({float3(point.y, point.x, 0.0f), VCLASS_EMPTY_SIZE});
|
|
}
|
|
field_vortex = BatchPtr(GPU_batch_create_ex(
|
|
GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* field_curve */
|
|
{
|
|
constexpr int circle_resol = 32;
|
|
const Vector<float2> ring = ring_vertices(1.0f, circle_resol);
|
|
|
|
Vector<Vertex> verts;
|
|
|
|
append_line_loop(verts, ring, 0.0f, VCLASS_EMPTY_SIZE | VCLASS_SCREENALIGNED);
|
|
|
|
field_curve = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* field_sphere_limit */
|
|
{
|
|
constexpr int circle_resol = 32 * 2;
|
|
const Vector<float2> ring = ring_vertices(1.0f, circle_resol);
|
|
|
|
Vector<Vertex> verts;
|
|
|
|
append_line_loop(verts, ring, 0.0f, VCLASS_EMPTY_SIZE | VCLASS_SCREENALIGNED, true);
|
|
|
|
field_sphere_limit = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* field_tube_limit */
|
|
{
|
|
constexpr int circle_resol = 32;
|
|
constexpr int side_stipple = 32;
|
|
const Vector<float2> ring = ring_vertices(1.0f, circle_resol);
|
|
const Vector<float2> diamond = ring_vertices(1.0f, 4);
|
|
|
|
Vector<Vertex> verts;
|
|
|
|
/* Caps */
|
|
for (const int i : IndexRange(2)) {
|
|
const float z = i * 2.0f - 1.0f;
|
|
append_line_loop(verts, ring, z, VCLASS_EMPTY_SIZE, true);
|
|
}
|
|
/* Side Edges */
|
|
for (const float2 &point : diamond) {
|
|
for (const int i : IndexRange(side_stipple)) {
|
|
const float z = (i / float(side_stipple)) * 2.0f - 1.0f;
|
|
verts.append({float3(point.y, point.x, z), VCLASS_EMPTY_SIZE});
|
|
}
|
|
}
|
|
|
|
field_tube_limit = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* field_cone_limit */
|
|
{
|
|
constexpr int circle_resol = 32;
|
|
constexpr int side_stipple = 32;
|
|
const Vector<float2> ring = ring_vertices(1.0f, circle_resol);
|
|
const Vector<float2> diamond = ring_vertices(1.0f, 4);
|
|
|
|
Vector<Vertex> verts;
|
|
|
|
/* Caps */
|
|
for (const int i : IndexRange(2)) {
|
|
const float z = i * 2.0f - 1.0f;
|
|
append_line_loop(verts, ring, z, VCLASS_EMPTY_SIZE, true);
|
|
}
|
|
/* Side Edges */
|
|
for (const float2 &point : diamond) {
|
|
for (const int i : IndexRange(side_stipple)) {
|
|
const float z = (i / float(side_stipple)) * 2.0f - 1.0f;
|
|
verts.append({float3(point.y * z, point.x * z, z), VCLASS_EMPTY_SIZE});
|
|
}
|
|
}
|
|
|
|
field_cone_limit = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* lightprobe_cube */
|
|
{
|
|
constexpr float r = 14.0f;
|
|
constexpr VertexClass flag = VCLASS_SCREENSPACE;
|
|
/* Icon */
|
|
constexpr float sin_pi_3 = 0.86602540378f;
|
|
constexpr float cos_pi_3 = 0.5f;
|
|
const Array<float2, 6> points = {
|
|
float2(0.0f, 1.0f) * r,
|
|
float2(sin_pi_3, cos_pi_3) * r,
|
|
float2(sin_pi_3, -cos_pi_3) * r,
|
|
float2(0.0f, -1.0f) * r,
|
|
float2(-sin_pi_3, -cos_pi_3) * r,
|
|
float2(-sin_pi_3, cos_pi_3) * r,
|
|
};
|
|
|
|
Vector<Vertex> verts;
|
|
|
|
append_line_loop(verts, points, 0.0f, flag);
|
|
for (const int i : IndexRange(3)) {
|
|
const float2 &point = points[i * 2 + 1];
|
|
verts.append(Vertex{{point, 0.0f}, flag});
|
|
verts.append(Vertex{{0.0f, 0.0f, 0.0f}, flag});
|
|
}
|
|
|
|
/* Direction Lines */
|
|
const Vector<float2> diamond = ring_vertices(1.2f, diamond_nsegments);
|
|
const std::string axes = "zZyYxX";
|
|
for (const char axis : axes) {
|
|
light_append_direction_line(axis, diamond, verts);
|
|
}
|
|
|
|
lightprobe_cube = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* lightprobe_planar */
|
|
{
|
|
constexpr float r = 20.0f;
|
|
/* Icon */
|
|
constexpr float sin_pi_3 = 0.86602540378f;
|
|
const Array<float2, 4> points = {
|
|
float2(0.0f, 0.5f) * r,
|
|
float2(sin_pi_3, 0.0f) * r,
|
|
float2(0.0f, -0.5f) * r,
|
|
float2(-sin_pi_3, 0.0f) * r,
|
|
};
|
|
|
|
Vector<Vertex> verts;
|
|
|
|
append_line_loop(verts, points, 0.0f, VCLASS_SCREENSPACE);
|
|
lightprobe_planar = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* lightprobe_grid */
|
|
{
|
|
constexpr float r = 14.0f;
|
|
constexpr VertexClass flag = VCLASS_SCREENSPACE;
|
|
/* Icon */
|
|
constexpr float sin_pi_3 = 0.86602540378f;
|
|
constexpr float cos_pi_3 = 0.5f;
|
|
const Array<float2, 6> points = {float2(0.0f, 1.0f) * r,
|
|
float2(sin_pi_3, cos_pi_3) * r,
|
|
float2(sin_pi_3, -cos_pi_3) * r,
|
|
float2(0.0f, -1.0f) * r,
|
|
float2(-sin_pi_3, -cos_pi_3) * r,
|
|
float2(-sin_pi_3, cos_pi_3) * r};
|
|
Vector<Vertex> verts;
|
|
|
|
append_line_loop(verts, points, 0.0f, flag);
|
|
/* Internal wires. */
|
|
for (const int i : IndexRange(6)) {
|
|
const float2 tr = points[(i / 2) * 2 + 1] * -0.5f;
|
|
const float2 t1 = points[i] + tr;
|
|
const float2 t2 = points[(i + 1) % 6] + tr;
|
|
verts.append({{t1, 0.0f}, flag});
|
|
verts.append({{t2, 0.0f}, flag});
|
|
}
|
|
for (const int i : IndexRange(3)) {
|
|
const float2 &point = points[i * 2 + 1];
|
|
verts.append(Vertex{{point, 0.0f}, flag});
|
|
verts.append(Vertex{{0.0f, 0.0f, 0.0f}, flag});
|
|
}
|
|
/* Direction Lines */
|
|
const Vector<float2> diamond = ring_vertices(1.2f, diamond_nsegments);
|
|
const std::string axes = "zZyYxX";
|
|
for (const char axis : axes) {
|
|
light_append_direction_line(axis, diamond, verts);
|
|
}
|
|
|
|
lightprobe_grid = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* grid */
|
|
{
|
|
constexpr int resolution = 8;
|
|
std::array<float, resolution + 1> steps;
|
|
/* [-1, 1] divided into "resolution" steps. */
|
|
for (const int i : IndexRange(resolution + 1)) {
|
|
steps[i] = -1.0f + float(i * 2) / resolution;
|
|
}
|
|
|
|
Vector<Vertex> verts;
|
|
verts.reserve(resolution * resolution * 6);
|
|
for (const int x : IndexRange(resolution)) {
|
|
for (const int y : IndexRange(resolution)) {
|
|
verts.append(Vertex{{steps[x], steps[y], 0.0f}});
|
|
verts.append(Vertex{{steps[x + 1], steps[y], 0.0f}});
|
|
verts.append(Vertex{{steps[x], steps[y + 1], 0.0f}});
|
|
|
|
verts.append(Vertex{{steps[x], steps[y + 1], 0.0f}});
|
|
verts.append(Vertex{{steps[x + 1], steps[y], 0.0f}});
|
|
verts.append(Vertex{{steps[x + 1], steps[y + 1], 0.0f}});
|
|
}
|
|
}
|
|
grid = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_TRIS, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* cursor circle */
|
|
{
|
|
const int segments = 16;
|
|
|
|
const float red[3] = {1.0f, 0.0f, 0.0f};
|
|
const float white[3] = {1.0f, 1.0f, 1.0f};
|
|
|
|
Vector<VertexWithColor> verts;
|
|
|
|
for (int i = 0; i < segments + 1; i++) {
|
|
float angle = float(2 * M_PI) * (float(i) / float(segments));
|
|
verts.append({0.5f * float3(cosf(angle), sinf(angle), 0.0f), (i % 2 == 0) ? red : white});
|
|
}
|
|
|
|
cursor_circle = BatchPtr(GPU_batch_create_ex(
|
|
GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
/* cursor lines */
|
|
{
|
|
const float f5 = 0.25f;
|
|
const float f20 = 1.0f;
|
|
|
|
float crosshair_color[3];
|
|
UI_GetThemeColor3fv(TH_VIEW_OVERLAY, crosshair_color);
|
|
|
|
Vector<VertexWithColor> verts;
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
float3 axis(0.0f);
|
|
axis[i] = 1.0f;
|
|
verts.append({f5 * axis, crosshair_color});
|
|
verts.append({f20 * axis, crosshair_color});
|
|
axis[i] = -1.0f;
|
|
verts.append({f5 * axis, crosshair_color});
|
|
verts.append({f20 * axis, crosshair_color});
|
|
}
|
|
|
|
cursor_lines = BatchPtr(
|
|
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
|
}
|
|
}
|
|
|
|
} // namespace blender::draw::overlay
|