Draw Manager: draw curve normals

This commit is contained in:
Campbell Barton 2017-04-20 05:23:48 +10:00
parent 896d62d1c2
commit 72efee07ff
5 changed files with 206 additions and 11 deletions

View File

@ -32,6 +32,8 @@ void BKE_curve_batch_selection_dirty(struct Curve *cu);
void BKE_curve_batch_cache_clear(struct Curve *cu);
void BKE_curve_batch_cache_free(struct Curve *cu);
struct Batch *BKE_curve_batch_cache_get_wire_edge(struct Curve *cu, struct CurveCache *ob_curve_cache);
struct Batch *BKE_curve_batch_cache_get_normal_edge(
struct Curve *cu, struct CurveCache *ob_curve_cache, float normal_size);
struct Batch *BKE_curve_batch_cache_get_overlay_edges(struct Curve *cu);
struct Batch *BKE_curve_batch_cache_get_overlay_verts(struct Curve *cu);

View File

@ -107,6 +107,26 @@ static void curve_render_wire_verts_edges_len_get(
}
}
static int curve_render_normal_len_get(const ListBase *lb, const CurveCache *ob_curve_cache)
{
int normal_len = 0;
const BevList *bl;
const Nurb *nu;
for (bl = ob_curve_cache->bev.first, nu = lb->first; nu && bl; bl = bl->next, nu = nu->next) {
int nr = bl->nr;
int skip = nu->resolu / 16;
#if 0
while (nr-- > 0) { /* accounts for empty bevel lists */
normal_len += 1;
nr -= skip;
}
#else
normal_len += max_ii((nr + max_ii(skip - 1, 0)) / (skip + 1), 0);
#endif
}
return normal_len;
}
/* ---------------------------------------------------------------------- */
/* Curve Interface, indirect, partially cached access to complex data. */
@ -123,7 +143,15 @@ typedef struct CurveRenderData {
int edge_len;
} wire;
/* edit mode normal's */
struct {
/* 'edge_len == len * 2'
* 'vert_len == len * 3' */
int len;
} normal;
bool hide_handles;
bool hide_normals;
/* borrow from 'Object' */
CurveCache *ob_curve_cache;
@ -143,6 +171,8 @@ enum {
CU_DATATYPE_WIRE = 1 << 0,
/* Edit-mode verts and optionally handles */
CU_DATATYPE_OVERLAY = 1 << 1,
/* Edit-mode normals */
CU_DATATYPE_NORMAL = 1 << 2,
};
/*
@ -155,6 +185,8 @@ static CurveRenderData *curve_render_data_create(Curve *cu, CurveCache *ob_curve
ListBase *nurbs;
lrdata->hide_handles = (cu->drawflag & CU_HIDE_HANDLES) != 0;
lrdata->hide_normals = (cu->drawflag & CU_HIDE_NORMALS) != 0;
lrdata->actnu = cu->actnu;
lrdata->actvert = cu->actvert;
@ -181,6 +213,9 @@ static CurveRenderData *curve_render_data_create(Curve *cu, CurveCache *ob_curve
lrdata->actnu = cu->actnu;
lrdata->actvert = cu->actvert;
}
if (types & CU_DATATYPE_NORMAL) {
lrdata->normal.len = curve_render_normal_len_get(nurbs, lrdata->ob_curve_cache);
}
}
else {
nurbs = &cu->nurb;
@ -225,13 +260,11 @@ static int curve_render_data_wire_edges_len_get(const CurveRenderData *lrdata)
return lrdata->wire.edge_len;
}
#if 0
static const BPoint *curve_render_data_vert_bpoint(const CurveRenderData *lrdata, const int vert_idx)
static int curve_render_data_normal_len_get(const CurveRenderData *lrdata)
{
BLI_assert(lrdata->types & CU_DATATYPE_VERT);
return &lrdata->bp[vert_idx];
BLI_assert(lrdata->types & CU_DATATYPE_NORMAL);
return lrdata->normal.len;
}
#endif
enum {
VFLAG_VERTEX_SELECTED = 1 << 0,
@ -250,6 +283,14 @@ typedef struct CurveBatchCache {
ElementList *elem;
} wire;
/* normals */
struct {
VertexBuffer *verts;
VertexBuffer *edges;
Batch *batch;
ElementList *elem;
} normal;
/* control handles and vertices */
struct {
Batch *edges;
@ -260,6 +301,9 @@ typedef struct CurveBatchCache {
bool is_dirty;
bool hide_handles;
bool hide_normals;
float normal_size;
bool is_editmode;
} CurveBatchCache;
@ -289,6 +333,9 @@ static bool curve_batch_cache_valid(Curve *cu)
else if ((cache->hide_handles != ((cu->drawflag & CU_HIDE_HANDLES) != 0))) {
return false;
}
else if ((cache->hide_normals != ((cu->drawflag & CU_HIDE_NORMALS) != 0))) {
return false;
}
}
return true;
@ -306,6 +353,7 @@ static void curve_batch_cache_init(Curve *cu)
}
cache->hide_handles = (cu->flag & CU_HIDE_HANDLES) != 0;
cache->hide_normals = (cu->flag & CU_HIDE_NORMALS) != 0;
#if 0
ListBase *nurbs;
@ -368,6 +416,15 @@ void BKE_curve_batch_cache_clear(Curve *cu)
VERTEXBUFFER_DISCARD_SAFE(cache->wire.edges);
ELEMENTLIST_DISCARD_SAFE(cache->wire.elem);
}
if (cache->normal.batch) {
BATCH_DISCARD_ALL_SAFE(cache->normal.batch);
}
else {
VERTEXBUFFER_DISCARD_SAFE(cache->normal.verts);
VERTEXBUFFER_DISCARD_SAFE(cache->normal.edges);
ELEMENTLIST_DISCARD_SAFE(cache->normal.elem);
}
}
void BKE_curve_batch_cache_free(Curve *cu)
@ -417,7 +474,7 @@ static ElementList *curve_batch_cache_get_wire_edges(CurveRenderData *lrdata, Cu
if (cache->wire.edges == NULL) {
const int vert_len = curve_render_data_wire_verts_len_get(lrdata);
const int edge_len = curve_render_data_wire_edges_len_get(lrdata);
int edge_len_real = 0;
int edge_len_used = 0;
ElementListBuilder elb;
ElementListBuilder_init(&elb, PRIM_LINES, edge_len, vert_len);
@ -437,16 +494,16 @@ static ElementList *curve_batch_cache_get_wire_edges(CurveRenderData *lrdata, Cu
}
for (; i < i_end; i_prev = i++) {
add_line_vertices(&elb, i_prev, i);
edge_len_real += 1;
edge_len_used += 1;
}
}
}
if (lrdata->hide_handles) {
BLI_assert(edge_len_real <= edge_len);
BLI_assert(edge_len_used <= edge_len);
}
else {
BLI_assert(edge_len_real == edge_len);
BLI_assert(edge_len_used == edge_len);
}
cache->wire.elem = ElementList_build(&elb);
@ -455,6 +512,99 @@ static ElementList *curve_batch_cache_get_wire_edges(CurveRenderData *lrdata, Cu
return cache->wire.elem;
}
static VertexBuffer *curve_batch_cache_get_normal_verts(CurveRenderData *lrdata, CurveBatchCache *cache)
{
BLI_assert(lrdata->types & CU_DATATYPE_NORMAL);
BLI_assert(lrdata->ob_curve_cache != NULL);
if (cache->normal.verts == NULL) {
static VertexFormat format = { 0 };
static unsigned pos_id;
if (format.attrib_ct == 0) {
/* initialize vertex format */
pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT);
}
const int normal_len = curve_render_data_normal_len_get(lrdata);
const int vert_len = normal_len * 3;
VertexBuffer *vbo = cache->normal.verts = VertexBuffer_create_with_format(&format);
VertexBuffer_allocate_data(vbo, vert_len);
int vbo_len_used = 0;
const BevList *bl;
const Nurb *nu;
for (bl = lrdata->ob_curve_cache->bev.first, nu = lrdata->nurbs->first;
nu && bl;
bl = bl->next, nu = nu->next)
{
const BevPoint *bevp = bl->bevpoints;
int nr = bl->nr;
int skip = nu->resolu / 16;
while (nr-- > 0) { /* accounts for empty bevel lists */
const float fac = bevp->radius * cache->normal_size;
float vec_a[3]; /* Offset perpendicular to the curve */
float vec_b[3]; /* Delta along the curve */
vec_a[0] = fac;
vec_a[1] = 0.0f;
vec_a[2] = 0.0f;
vec_b[0] = -fac;
vec_b[1] = 0.0f;
vec_b[2] = 0.0f;
mul_qt_v3(bevp->quat, vec_a);
mul_qt_v3(bevp->quat, vec_b);
add_v3_v3(vec_a, bevp->vec);
add_v3_v3(vec_b, bevp->vec);
madd_v3_v3fl(vec_a, bevp->dir, -fac);
madd_v3_v3fl(vec_b, bevp->dir, -fac);
VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used++, vec_a);
VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used++, bevp->vec);
VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used++, vec_b);
bevp += skip + 1;
nr -= skip;
}
}
BLI_assert(vbo_len_used == vert_len);
}
return cache->normal.verts;
}
static ElementList *curve_batch_cache_get_normal_edges(CurveRenderData *lrdata, CurveBatchCache *cache)
{
BLI_assert(lrdata->types & CU_DATATYPE_NORMAL);
BLI_assert(lrdata->ob_curve_cache != NULL);
if (cache->normal.edges == NULL) {
const int normal_len = curve_render_data_normal_len_get(lrdata);
const int edge_len = normal_len * 2;
ElementListBuilder elb;
ElementListBuilder_init(&elb, PRIM_LINES, edge_len, normal_len * 2);
int vbo_len_used = 0;
for (int i = 0; i < normal_len; i++) {
add_line_vertices(&elb, vbo_len_used + 0, vbo_len_used + 1);
add_line_vertices(&elb, vbo_len_used + 1, vbo_len_used + 2);
vbo_len_used += 3;
}
BLI_assert(vbo_len_used == normal_len * 3);
cache->normal.elem = ElementList_build(&elb);
}
return cache->normal.elem;
}
static void curve_batch_cache_create_overlay_batches(Curve *cu)
{
/* Since CU_DATATYPE_OVERLAY is slow to generate, generate them all at once */
@ -618,10 +768,36 @@ Batch *BKE_curve_batch_cache_get_wire_edge(Curve *cu, CurveCache *ob_curve_cache
curve_render_data_free(lrdata);
}
return cache->wire.batch;
}
Batch *BKE_curve_batch_cache_get_normal_edge(Curve *cu, CurveCache *ob_curve_cache, float normal_size)
{
CurveBatchCache *cache = curve_batch_cache_get(cu);
if (cache->normal.batch != NULL) {
cache->normal_size = normal_size;
if (cache->normal_size != normal_size) {
BATCH_DISCARD_ALL_SAFE(cache->normal.batch);
}
}
cache->normal_size = normal_size;
if (cache->normal.batch == NULL) {
/* create batch from Curve */
CurveRenderData *lrdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_NORMAL);
cache->normal.batch = Batch_create(
PRIM_LINES,
curve_batch_cache_get_normal_verts(lrdata, cache),
curve_batch_cache_get_normal_edges(lrdata, cache));
curve_render_data_free(lrdata);
cache->normal_size = normal_size;
}
return cache->normal.batch;
}
Batch *BKE_curve_batch_cache_get_overlay_edges(Curve *cu)
{
CurveBatchCache *cache = curve_batch_cache_get(cu);

View File

@ -1588,6 +1588,14 @@ Batch *DRW_cache_curve_edge_wire_get(Object *ob)
return BKE_curve_batch_cache_get_wire_edge(cu, ob->curve_cache);
}
Batch *DRW_cache_curve_edge_normal_get(Object *ob, float normal_size)
{
BLI_assert(ob->type == OB_CURVE);
struct Curve *cu = ob->data;
return BKE_curve_batch_cache_get_normal_edge(cu, ob->curve_cache, normal_size);
}
Batch *DRW_cache_curve_edge_overlay_get(Object *ob)
{
BLI_assert(ob->type == OB_CURVE);

View File

@ -90,6 +90,7 @@ struct Batch *DRW_cache_mesh_verts_get(struct Object *ob);
/* Curve */
struct Batch *DRW_cache_curve_edge_wire_get(struct Object *ob);
struct Batch *DRW_cache_curve_edge_normal_get(struct Object *ob, float normal_size);
struct Batch *DRW_cache_curve_edge_overlay_get(struct Object *ob);
struct Batch *DRW_cache_curve_vert_overlay_get(struct Object *ob);
@ -98,4 +99,4 @@ struct Batch *DRW_cache_lattice_verts_get(struct Object *ob);
struct Batch *DRW_cache_lattice_wire_get(struct Object *ob);
struct Batch *DRW_cache_lattice_vert_overlay_get(struct Object *ob);
#endif /* __DRAW_CACHE_H__ */
#endif /* __DRAW_CACHE_H__ */

View File

@ -26,6 +26,8 @@
#include "DRW_engine.h"
#include "DRW_render.h"
#include "DNA_curve_types.h"
/* If builtin shaders are needed */
#include "GPU_shader.h"
@ -217,6 +219,7 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
if (ob->type == OB_CURVE) {
if (ob == obedit) {
Curve *cu = ob->data;
/* Get geometry cache */
struct Batch *geom;
@ -225,6 +228,11 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
geom = DRW_cache_curve_edge_wire_get(ob);
DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat);
if ((cu->drawflag & CU_HIDE_NORMALS) == 0) {
geom = DRW_cache_curve_edge_normal_get(ob, scene->toolsettings->normalsize);
DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat);
}
/* Add geom to a shading group */
geom = DRW_cache_curve_edge_overlay_get(ob);
if (geom) {