diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-04-15 09:46:17 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-04-19 17:38:44 +0300 |
commit | cdba73c8faf7ec28de66b380ed2952d42a2aac38 (patch) | |
tree | a8c07ccfcbf3fe513ba1c83cfc392a0d5a903841 /source/blender | |
parent | ce6b01f203caae98a648bb3024479dba2e033c2a (diff) |
Draw Manager: curve support
Draws the curve centerline and editmode verts/handles.
Handle theme colors, and normal display still need adding.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_curve_render.h | 38 | ||||
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curve.c | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curve_render.c | 641 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object_update.c | 6 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 1 | ||||
-rw-r--r-- | source/blender/draw/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 44 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.h | 5 | ||||
-rw-r--r-- | source/blender/draw/modes/edit_curve_mode.c | 108 | ||||
-rw-r--r-- | source/blender/draw/modes/object_mode.c | 12 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/edit_curve_overlay_frag.glsl | 26 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl | 39 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/space_view3d.c | 9 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_curve_types.h | 1 |
15 files changed, 904 insertions, 33 deletions
diff --git a/source/blender/blenkernel/BKE_curve_render.h b/source/blender/blenkernel/BKE_curve_render.h new file mode 100644 index 00000000000..f05dc691d06 --- /dev/null +++ b/source/blender/blenkernel/BKE_curve_render.h @@ -0,0 +1,38 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_CURVE_RENDER_H__ +#define __BKE_CURVE_RENDER_H__ + +/** \file BKE_curve_render.h + * \ingroup bke + */ + +struct Batch; +struct Curve; + +void BKE_curve_batch_cache_dirty(struct Curve *cu); +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_overlay_edges(struct Curve *cu); +struct Batch *BKE_curve_batch_cache_get_overlay_verts(struct Curve *cu); + +#endif /* __BKE_CURVE_RENDER_H__ */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 770e4ab3479..d8cba908f4a 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -93,6 +93,7 @@ set(SRC intern/context.c intern/crazyspace.c intern/curve.c + intern/curve_render.c intern/customdata.c intern/customdata_file.c intern/data_transfer.c @@ -225,6 +226,7 @@ set(SRC BKE_context.h BKE_crazyspace.h BKE_curve.h + BKE_curve_render.h BKE_customdata.h BKE_customdata_file.h BKE_data_transfer.h diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 8a08c32f31b..10da97f5761 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -52,6 +52,7 @@ #include "BKE_animsys.h" #include "BKE_curve.h" +#include "BKE_curve_render.h" #include "BKE_displist.h" #include "BKE_font.h" #include "BKE_global.h" @@ -127,6 +128,8 @@ void BKE_curve_free(Curve *cu) { BKE_animdata_free((ID *)cu, false); + BKE_curve_batch_cache_free(cu); + BKE_nurbList_free(&cu->nurb); BKE_curve_editfont_free(cu); diff --git a/source/blender/blenkernel/intern/curve_render.c b/source/blender/blenkernel/intern/curve_render.c new file mode 100644 index 00000000000..36ddbc48131 --- /dev/null +++ b/source/blender/blenkernel/intern/curve_render.c @@ -0,0 +1,641 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 by Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/curve_render.c + * \ingroup bke + * + * \brief Curve API for render engines + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" + +#include "DNA_curve_types.h" + +#include "BKE_curve.h" +#include "BKE_curve_render.h" + +#include "GPU_batch.h" + +#define SELECT 1 + +/** + * TODO + * - Ensure `CurveCache`, `SEQUENCER_DAG_WORKAROUND`. + * - Check number of verts/edges to see if cache is valid. + * - Check if 'overlay_edges' can use single attribyte per edge, not 2 (for selection drawing). + */ + +/* ---------------------------------------------------------------------- */ +/* Curve Interface, direct access to basic data. */ + +static void curve_render_overlay_verts_edges_len_get( + ListBase *lb, bool hide_handles, + int *r_vert_len, int *r_edge_len) +{ + BLI_assert(r_vert_len || r_edge_len); + int vert_len = 0; + int edge_len = 0; + for (Nurb *nu = lb->first; nu; nu = nu->next) { + if (nu->bezt) { + vert_len += hide_handles ? nu->pntsu : (nu->pntsu * 3); + /* 2x handles per point*/ + edge_len += 2 * nu->pntsu; + } + else if (nu->bp) { + vert_len += nu->pntsu; + /* segments between points */ + edge_len += nu->pntsu - 1; + } + } + if (r_vert_len) { + *r_vert_len = vert_len; + } + if (r_edge_len) { + *r_edge_len = edge_len; + } +} + +static void curve_render_wire_verts_edges_len_get( + const CurveCache *ob_curve_cache, + int *r_vert_len, int *r_edge_len) +{ + BLI_assert(r_vert_len || r_edge_len); + int vert_len = 0; + int edge_len = 0; + for (const BevList *bl = ob_curve_cache->bev.first; bl; bl = bl->next) { + if (bl->nr > 0) { + const bool is_cyclic = bl->poly != -1; + + /* verts */ + vert_len += bl->nr; + + /* edges */ + edge_len += bl->nr; + if (!is_cyclic) { + edge_len -= 1; + } + } + } + if (r_vert_len) { + *r_vert_len = vert_len; + } + if (r_edge_len) { + *r_edge_len = edge_len; + } +} + +/* ---------------------------------------------------------------------- */ +/* Curve Interface, indirect, partially cached access to complex data. */ + +typedef struct CurveRenderData { + int types; + + struct { + int vert_len; + int edge_len; + } overlay; + + struct { + int vert_len; + int edge_len; + } wire; + + bool hide_handles; + + /* borrow from 'Object' */ + CurveCache *ob_curve_cache; + + /* borrow from 'Curve' */ + struct EditNurb *edit_latt; + ListBase *nurbs; + + /* edit, index in nurb list */ + int actnu; + /* edit, index in active nurb (BPoint or BezTriple) */ + int actvert; +} CurveRenderData; + +enum { + /* Wire center-line */ + CU_DATATYPE_WIRE = 1 << 0, + /* Edit-mode verts and optionally handles */ + CU_DATATYPE_OVERLAY = 1 << 1, +}; + +/* + * ob_curve_cache can be NULL, only needed for CU_DATATYPE_WIRE + */ +static CurveRenderData *curve_render_data_create(Curve *cu, CurveCache *ob_curve_cache, const int types) +{ + CurveRenderData *lrdata = MEM_callocN(sizeof(*lrdata), __func__); + lrdata->types = types; + ListBase *nurbs; + + lrdata->hide_handles = (cu->drawflag & CU_HIDE_HANDLES) != 0; + lrdata->actnu = cu->actnu; + lrdata->actvert = cu->actvert; + + lrdata->ob_curve_cache = ob_curve_cache; + + if (types & CU_DATATYPE_WIRE) { + curve_render_wire_verts_edges_len_get( + lrdata->ob_curve_cache, + &lrdata->wire.vert_len, &lrdata->wire.edge_len); + } + + if (cu->editnurb) { + EditNurb *editnurb = cu->editnurb; + nurbs = &editnurb->nurbs; + + lrdata->edit_latt = editnurb; + + if (types & CU_DATATYPE_OVERLAY) { + curve_render_overlay_verts_edges_len_get( + nurbs, lrdata->hide_handles, + &lrdata->overlay.vert_len, + lrdata->hide_handles ? NULL : &lrdata->overlay.edge_len); + + lrdata->actnu = cu->actnu; + lrdata->actvert = cu->actvert; + } + } + else { + nurbs = &cu->nurb; + } + + lrdata->nurbs = nurbs; + + return lrdata; +} + +static void curve_render_data_free(CurveRenderData *lrdata) +{ +#if 0 + if (lrdata->loose_verts) { + MEM_freeN(lrdata->loose_verts); + } +#endif + MEM_freeN(lrdata); +} + +static int curve_render_data_overlay_verts_len_get(const CurveRenderData *lrdata) +{ + BLI_assert(lrdata->types & CU_DATATYPE_OVERLAY); + return lrdata->overlay.vert_len; +} + +static int curve_render_data_overlay_edges_len_get(const CurveRenderData *lrdata) +{ + BLI_assert(lrdata->types & CU_DATATYPE_OVERLAY); + return lrdata->overlay.edge_len; +} + +static int curve_render_data_wire_verts_len_get(const CurveRenderData *lrdata) +{ + BLI_assert(lrdata->types & CU_DATATYPE_WIRE); + return lrdata->wire.vert_len; +} + +static int curve_render_data_wire_edges_len_get(const CurveRenderData *lrdata) +{ + BLI_assert(lrdata->types & CU_DATATYPE_WIRE); + return lrdata->wire.edge_len; +} + +#if 0 +static const BPoint *curve_render_data_vert_bpoint(const CurveRenderData *lrdata, const int vert_idx) +{ + BLI_assert(lrdata->types & CU_DATATYPE_VERT); + return &lrdata->bp[vert_idx]; +} +#endif + +enum { + VFLAG_VERTEX_SELECTED = 1 << 0, + VFLAG_VERTEX_ACTIVE = 1 << 1, +}; + +/* ---------------------------------------------------------------------- */ +/* Curve Batch Cache */ + +typedef struct CurveBatchCache { + VertexBuffer *wire_verts; + VertexBuffer *wire_edges; + Batch *wire_batch; + + ElementList *wire_elem; + + /* control handles and vertices */ + Batch *overlay_edges; + Batch *overlay_verts; + + /* settings to determine if cache is invalid */ + bool is_dirty; + + bool hide_handles; + + bool is_editmode; +} CurveBatchCache; + +/* Batch cache management. */ + +static bool curve_batch_cache_valid(Curve *cu) +{ + CurveBatchCache *cache = cu->batch_cache; + + if (cache == NULL) { + return false; + } + + if (cache->is_editmode != (cu->editnurb != NULL)) { + return false; + } + + if (cache->is_dirty == false) { + return true; + } + else { + /* TODO: check number of vertices/edges? */ + if (cache->is_editmode) { + return false; + } + else if ((cache->hide_handles != ((cu->drawflag & CU_HIDE_HANDLES) != 0))) { + return false; + } + } + + return true; +} + +static void curve_batch_cache_init(Curve *cu) +{ + CurveBatchCache *cache = cu->batch_cache; + + if (!cache) { + cache = cu->batch_cache = MEM_callocN(sizeof(*cache), __func__); + } + else { + memset(cache, 0, sizeof(*cache)); + } + + cache->hide_handles = (cu->flag & CU_HIDE_HANDLES) != 0; + +#if 0 + ListBase *nurbs; + if (cu->editnurb) { + EditNurb *editnurb = cu->editnurb; + nurbs = &editnurb->nurbs; + } + else { + nurbs = &cu->nurb; + } +#endif + + cache->is_editmode = cu->editnurb != NULL; + + cache->is_dirty = false; +} + +static CurveBatchCache *curve_batch_cache_get(Curve *cu) +{ + if (!curve_batch_cache_valid(cu)) { + BKE_curve_batch_cache_clear(cu); + curve_batch_cache_init(cu); + } + return cu->batch_cache; +} + +void BKE_curve_batch_cache_dirty(Curve *cu) +{ + CurveBatchCache *cache = cu->batch_cache; + if (cache) { + cache->is_dirty = true; + } +} + +void BKE_curve_batch_selection_dirty(Curve *cu) +{ + CurveBatchCache *cache = cu->batch_cache; + if (cache) { + BATCH_DISCARD_ALL_SAFE(cache->overlay_verts); + BATCH_DISCARD_ALL_SAFE(cache->overlay_edges); + } +} + +void BKE_curve_batch_cache_clear(Curve *cu) +{ + CurveBatchCache *cache = cu->batch_cache; + if (!cache) { + return; + } + + BATCH_DISCARD_ALL_SAFE(cache->overlay_verts); + BATCH_DISCARD_ALL_SAFE(cache->overlay_edges); + + if (cache->wire_batch) { + /* Also handles: 'cache->wire_verts', 'cache->wire_edges', 'cache->wire_elem' */ + BATCH_DISCARD_ALL_SAFE(cache->wire_batch); + } + else { + VERTEXBUFFER_DISCARD_SAFE(cache->wire_verts); + VERTEXBUFFER_DISCARD_SAFE(cache->wire_edges); + ELEMENTLIST_DISCARD_SAFE(cache->wire_elem); + } +} + +void BKE_curve_batch_cache_free(Curve *cu) +{ + BKE_curve_batch_cache_clear(cu); + MEM_SAFE_FREE(cu->batch_cache); +} + +/* Batch cache usage. */ +static VertexBuffer *curve_batch_cache_get_wire_verts(CurveRenderData *lrdata, CurveBatchCache *cache) +{ + BLI_assert(lrdata->types & CU_DATATYPE_WIRE); + BLI_assert(lrdata->ob_curve_cache != NULL); + + if (cache->wire_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 vert_len = curve_render_data_wire_verts_len_get(lrdata); + + VertexBuffer *vbo = cache->wire_verts = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, vert_len); + int vbo_len_used = 0; + for (const BevList *bl = lrdata->ob_curve_cache->bev.first; bl; bl = bl->next) { + if (bl->nr > 0) { + const int i_end = vbo_len_used + bl->nr; + for (const BevPoint *bevp = bl->bevpoints; vbo_len_used < i_end; vbo_len_used++, bevp++) { + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used, bevp->vec); + } + } + } + BLI_assert(vbo_len_used == vert_len); + } + + return cache->wire_verts; +} + +static ElementList *curve_batch_cache_get_wire_edges(CurveRenderData *lrdata, CurveBatchCache *cache) +{ + BLI_assert(lrdata->types & CU_DATATYPE_WIRE); + BLI_assert(lrdata->ob_curve_cache != NULL); + + 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; + + ElementListBuilder elb; + ElementListBuilder_init(&elb, PRIM_LINES, edge_len, vert_len); + + int i = 0; + for (const BevList *bl = lrdata->ob_curve_cache->bev.first; bl; bl = bl->next) { + if (bl->nr > 0) { + const bool is_cyclic = bl->poly != -1; + const int i_end = i + (bl->nr); + int i_prev; + if (is_cyclic) { + i_prev = i + (bl->nr - 1); + } + else { + i_prev = i; + i += 1; + } + for (; i < i_end; i_prev = i++) { + add_line_vertices(&elb, i_prev, i); + edge_len_real += 1; + } + } + } + + if (lrdata->hide_handles) { + BLI_assert(edge_len_real <= edge_len); + } + else { + BLI_assert(edge_len_real == edge_len); + } + + cache->wire_elem = ElementList_build(&elb); + } + + return cache->wire_elem; +} + +static void curve_batch_cache_create_overlay_batches(Curve *cu) +{ + /* Since CU_DATATYPE_OVERLAY is slow to generate, generate them all at once */ + int options = CU_DATATYPE_OVERLAY; + + CurveBatchCache *cache = curve_batch_cache_get(cu); + CurveRenderData *lrdata = curve_render_data_create(cu, NULL, options); + + if (cache->overlay_verts == NULL) { + static VertexFormat format = { 0 }; + static unsigned pos_id, data_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); + data_id = VertexFormat_add_attrib(&format, "data", COMP_U8, 1, KEEP_INT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + const int vbo_len_capacity = curve_render_data_overlay_verts_len_get(lrdata); + int vbo_len_used = 0; + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + int i = 0; + for (Nurb *nu = lrdata->nurbs->first; nu; nu = nu->next) { + if (nu->bezt) { + int a = 0; + for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) { + if (bezt->hide == false) { + const bool is_active = (i == lrdata->actvert); + char vflag; + + if (lrdata->hide_handles) { + vflag = (bezt->f2 & SELECT) ? + (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0; + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used, bezt->vec[1]); + VertexBuffer_set_attrib(vbo, data_id, vbo_len_used, &vflag); + vbo_len_used += 1; + } + else { + for (int j = 0; j < 3; j++) { + vflag = ((&bezt->f1)[j] & SELECT) ? + (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0; + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used, bezt->vec[j]); + VertexBuffer_set_attrib(vbo, data_id, vbo_len_used, &vflag); + vbo_len_used += 1; + } + } + } + i += 1; + } + } + else if (nu->bp) { + int a = 0; + for (const BPoint *bp = nu->bp; a < nu->pntsu; a++, bp++) { + if (bp->hide == false) { + const bool is_active = (i == lrdata->actvert); + char vflag; + vflag = (bp->f1 & SELECT) ? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0; + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used, bp->vec); + VertexBuffer_set_attrib(vbo, data_id, vbo_len_used, &vflag); + vbo_len_used += 1; + } + i += 1; + } + } + i += nu->pntsu; + } + if (vbo_len_capacity != vbo_len_used) { + VertexBuffer_resize_data(vbo, vbo_len_used); + } + + cache->overlay_verts = Batch_create(PRIM_POINTS, vbo, NULL); + } + + + if ((cache->overlay_edges == NULL) && (lrdata->hide_handles == false)) { + /* Note: we could reference indices to vertices (above) */ + + static VertexFormat format = { 0 }; + static unsigned pos_id, data_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); + data_id = VertexFormat_add_attrib(&format, "data", COMP_U8, 1, KEEP_INT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + const int edge_len = curve_render_data_overlay_edges_len_get(lrdata); + const int vbo_len_capacity = edge_len * 2; + int vbo_len_used = 0; + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + int i = 0; + for (Nurb *nu = lrdata->nurbs->first; nu; nu = nu->next) { + if (nu->bezt) { + int a = 0; + for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) { + if (bezt->hide == false) { + const bool is_active = (i == lrdata->actvert); + char vflag; + + vflag = (bezt->f1 & SELECT) ? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0; + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used, bezt->vec[0]); + VertexBuffer_set_attrib(vbo, data_id, vbo_len_used, &vflag); + vbo_len_used += 1; + + /* same vertex twice, only check different selection */ + for (int j = 0; j < 2; j++) { + vflag = ((j ? bezt->f3 : bezt->f1) & SELECT) ? + (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0; + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used, bezt->vec[1]); + VertexBuffer_set_attrib(vbo, data_id, vbo_len_used, &vflag); + vbo_len_used += 1; + } + + vflag = (bezt->f3 & SELECT) ? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0; + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used, bezt->vec[2]); + VertexBuffer_set_attrib(vbo, data_id, vbo_len_used, &vflag); + vbo_len_used += 1; + } + i += 1; + } + } + else if (nu->bp) { + int a = 1; + for (const BPoint *bp_prev = nu->bp, *bp_curr = &nu->bp[1]; a < nu->pntsu; a++, bp_prev = bp_curr++) { + if ((bp_prev->hide == false) && (bp_curr->hide == false)) { + char vflag; + vflag = ((bp_prev->f1 & SELECT) && (bp_curr->f1 & SELECT)) ? VFLAG_VERTEX_SELECTED : 0; + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used, bp_prev->vec); + VertexBuffer_set_attrib(vbo, data_id, vbo_len_used, &vflag); + vbo_len_used += 1; + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used, bp_curr->vec); + VertexBuffer_set_attrib(vbo, data_id, vbo_len_used, &vflag); + vbo_len_used += 1; + + } + } + } + } + if (vbo_len_capacity != vbo_len_used) { + VertexBuffer_resize_data(vbo, vbo_len_used); + } + + cache->overlay_edges = Batch_create(PRIM_LINES, vbo, NULL); + } + + curve_render_data_free(lrdata); +} + +Batch *BKE_curve_batch_cache_get_wire_edge(Curve *cu, CurveCache *ob_curve_cache) +{ + CurveBatchCache *cache = curve_batch_cache_get(cu); + + if (cache->wire_batch == NULL) { + /* create batch from Curve */ + CurveRenderData *lrdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_WIRE); + + cache->wire_batch = Batch_create( + PRIM_LINES, + curve_batch_cache_get_wire_verts(lrdata, cache), + curve_batch_cache_get_wire_edges(lrdata, cache)); + + curve_render_data_free(lrdata); + } + + return cache->wire_batch; +} + +Batch *BKE_curve_batch_cache_get_overlay_edges(Curve *cu) +{ + CurveBatchCache *cache = curve_batch_cache_get(cu); + + if (cache->overlay_edges == NULL) { + curve_batch_cache_create_overlay_batches(cu); + } + + return cache->overlay_edges; +} + +Batch *BKE_curve_batch_cache_get_overlay_verts(Curve *cu) +{ + CurveBatchCache *cache = curve_batch_cache_get(cu); + + if (cache->overlay_verts == NULL) { + curve_batch_cache_create_overlay_batches(cu); + } + + return cache->overlay_verts; +} diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 374da48c648..495857bc21b 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -58,8 +58,9 @@ #include "BKE_material.h" #include "BKE_image.h" -#include "BKE_mesh_render.h" +#include "BKE_curve_render.h" #include "BKE_lattice_render.h" +#include "BKE_mesh_render.h" #include "DEG_depsgraph.h" @@ -351,6 +352,9 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx, case OB_LATTICE: BKE_lattice_batch_cache_dirty(ob->data); break; + case OB_CURVE: + BKE_curve_batch_cache_dirty(ob->data); + break; } ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a1718b5d84d..e5d5e20c8f2 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3854,6 +3854,7 @@ static void direct_link_curve(FileData *fd, Curve *cu) cu->editnurb = NULL; cu->editfont = NULL; + cu->batch_cache = NULL; for (nu = cu->nurb.first; nu; nu = nu->next) { nu->bezt = newdataadr(fd, nu->bezt); diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 75dc9cadb60..87c42caf541 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -130,6 +130,8 @@ data_to_c_simple(modes/shaders/edit_mesh_overlay_facedot_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_mix_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_frag.glsl SRC) +data_to_c_simple(modes/shaders/edit_curve_overlay_frag.glsl SRC) +data_to_c_simple(modes/shaders/edit_curve_overlay_loosevert_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_lattice_overlay_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_lattice_overlay_loosevert_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_normals_vert.glsl SRC) diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 8e6c64943bd..92acc8073df 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -31,8 +31,9 @@ #include "BLI_utildefines.h" #include "BLI_math.h" -#include "BKE_mesh_render.h" +#include "BKE_curve_render.h" #include "BKE_lattice_render.h" +#include "BKE_mesh_render.h" #include "GPU_batch.h" @@ -1592,6 +1593,47 @@ Batch *DRW_cache_mesh_verts_get(Object *ob) /* -------------------------------------------------------------------- */ +/** \name Curve + * \{ */ + +Batch *DRW_cache_curve_edge_wire_get(Object *ob) +{ + Batch *surface = NULL; + + BLI_assert(ob->type == OB_CURVE); + + struct Curve *cu = ob->data; + surface = BKE_curve_batch_cache_get_wire_edge(cu, ob->curve_cache); + + return surface; +} + +Batch *DRW_cache_curve_edge_overlay_get(Object *ob) +{ + Batch *surface = NULL; + + BLI_assert(ob->type == OB_CURVE); + + struct Curve *cu = ob->data; + surface = BKE_curve_batch_cache_get_overlay_edges(cu); + + return surface; +} + +Batch *DRW_cache_curve_vert_overlay_get(Object *ob) +{ + Batch *surface = NULL; + + BLI_assert(ob->type == OB_CURVE); + + struct Curve *cu = ob->data; + surface = BKE_curve_batch_cache_get_overlay_verts(cu); + + return surface; +} + +/* -------------------------------------------------------------------- */ + /** \name Lattice * \{ */ diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index b4f6590b5dd..daf807a27ea 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -88,6 +88,11 @@ struct Batch *DRW_cache_mesh_surface_get(struct Object *ob); struct Batch *DRW_cache_mesh_surface_verts_get(struct Object *ob); 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_overlay_get(struct Object *ob); +struct Batch *DRW_cache_curve_vert_overlay_get(struct Object *ob); + /* Lattice */ struct Batch *DRW_cache_lattice_verts_get(struct Object *ob); struct Batch *DRW_cache_lattice_wire_get(struct Object *ob); diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c index 084550a0445..8aabae588a3 100644 --- a/source/blender/draw/modes/edit_curve_mode.c +++ b/source/blender/draw/modes/edit_curve_mode.c @@ -39,6 +39,14 @@ extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */ extern struct GlobalsUboStorage ts; /* draw_common.c */ +extern char datatoc_common_globals_lib_glsl[]; +extern char datatoc_edit_curve_overlay_loosevert_vert_glsl[]; +extern char datatoc_edit_curve_overlay_frag_glsl[]; + +extern char datatoc_gpu_shader_3D_vert_glsl[]; +extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; +extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[]; + /* *********** LISTS *********** */ /* All lists are per viewport specific datas. * They are all free when viewport changes engines @@ -50,7 +58,9 @@ typedef struct EDIT_CURVE_PassList { /* Declare all passes here and init them in * EDIT_CURVE_cache_init(). * Only contains (DRWPass *) */ - struct DRWPass *pass; + struct DRWPass *wire_pass; + struct DRWPass *overlay_edge_pass; + struct DRWPass *overlay_vert_pass; } EDIT_CURVE_PassList; typedef struct EDIT_CURVE_FramebufferList { @@ -93,15 +103,22 @@ static struct { * Add sources to source/blender/draw/modes/shaders * init in EDIT_CURVE_engine_init(); * free in EDIT_CURVE_engine_free(); */ - struct GPUShader *custom_shader; -} e_data = {NULL}; /* Engine data */ + struct GPUShader *wire_sh; -typedef struct g_data { + struct GPUShader *overlay_edge_sh; /* handles and nurbs control cage */ + struct GPUShader *overlay_vert_sh; +} e_data = {NULL}; /* Engine data */ +typedef struct g_data { /* This keeps the references of the shading groups for * easy access in EDIT_CURVE_cache_populate() */ - DRWShadingGroup *group; + + /* resulting curve as 'wire' for curves (and optionally normals) */ + DRWShadingGroup *wire_shgrp; + + DRWShadingGroup *overlay_edge_shgrp; + DRWShadingGroup *overlay_vert_shgrp; } g_data; /* Transient data */ /* *********** FUNCTIONS *********** */ @@ -132,8 +149,19 @@ static void EDIT_CURVE_engine_init(void *vedata) * tex, 2); */ - if (!e_data.custom_shader) { - e_data.custom_shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + if (!e_data.wire_sh) { + e_data.wire_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + } + + if (!e_data.overlay_edge_sh) { + e_data.overlay_edge_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + } + + if (!e_data.overlay_vert_sh) { + e_data.overlay_vert_sh = DRW_shader_create_with_lib( + datatoc_edit_curve_overlay_loosevert_vert_glsl, NULL, + datatoc_edit_curve_overlay_frag_glsl, + datatoc_common_globals_lib_glsl, NULL); } } @@ -150,22 +178,28 @@ static void EDIT_CURVE_cache_init(void *vedata) } { - /* Create a pass */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND | DRW_STATE_WIRE; - psl->pass = DRW_pass_create("My Pass", state); - - /* Create a shadingGroup using a function in draw_common.c or custom one */ - /* - * stl->g_data->group = shgroup_dynlines_uniform_color(psl->pass, ts.colorWire); - * -- or -- - * stl->g_data->group = DRW_shgroup_create(e_data.custom_shader, psl->pass); - */ - stl->g_data->group = DRW_shgroup_create(e_data.custom_shader, psl->pass); - - /* Uniforms need a pointer to it's value so be sure it's accessible at - * any given time (i.e. use static vars) */ - static float color[4] = {0.2f, 0.5f, 0.3f, 1.0}; - DRW_shgroup_uniform_vec4(stl->g_data->group, "color", color, 1); + /* Center-Line (wire) */ + psl->wire_pass = DRW_pass_create( + "Curve Wire", + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WIRE); + stl->g_data->wire_shgrp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass); + + + /* TODO: following handle theme colors, + * For now use overlay vert shader for handles (we want them colored): + * TH_NURB_ULINE, TH_NURB_SEL_ULINE, TH_HANDLE_* */ + psl->overlay_edge_pass = DRW_pass_create( + "Curve Handle Overlay", + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_WIRE); + /* TODO: following handle theme colors, + * For now use overlay vert shader for handles (we want them colored) */ + stl->g_data->overlay_edge_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_edge_pass); + + psl->overlay_vert_pass = DRW_pass_create( + "Curve Vert Overlay", + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH); + + stl->g_data->overlay_vert_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_vert_pass); } } @@ -175,15 +209,29 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob) { EDIT_CURVE_PassList *psl = ((EDIT_CURVE_Data *)vedata)->psl; EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl; + const struct bContext *C = DRW_get_context(); + Scene *scene = CTX_data_scene(C); + Object *obedit = scene->obedit; UNUSED_VARS(psl, stl); - if (ob->type == OB_MESH) { - /* Get geometry cache */ - struct Batch *geom = DRW_cache_mesh_surface_get(ob); + if (ob->type == OB_CURVE) { + if (ob == obedit) { + /* Get geometry cache */ + struct Batch *geom; + +// geom = DRW_cache_mesh_surface_get(ob); + + geom = DRW_cache_curve_edge_wire_get(ob); + 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); + DRW_shgroup_call_add(stl->g_data->overlay_edge_shgrp, geom, ob->obmat); - /* Add geom to a shading group */ - DRW_shgroup_call_add(stl->g_data->group, geom, ob->obmat); + geom = DRW_cache_curve_vert_overlay_get(ob); + DRW_shgroup_call_add(stl->g_data->overlay_vert_shgrp, geom, ob->obmat); + } } } @@ -219,7 +267,9 @@ static void EDIT_CURVE_draw_scene(void *vedata) */ /* ... or just render passes on default framebuffer. */ - DRW_draw_pass(psl->pass); + DRW_draw_pass(psl->wire_pass); + DRW_draw_pass(psl->overlay_edge_pass); + DRW_draw_pass(psl->overlay_vert_pass); /* If you changed framebuffer, double check you rebind * the default one with its textures attached before finishing */ diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index 3162189b411..cda5e5a9617 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -1190,6 +1190,18 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) } break; } + + case OB_CURVE: + { + Object *obedit = scene->obedit; + if (ob != obedit) { + struct Batch *geom = DRW_cache_curve_edge_wire_get(ob); + int theme_id = DRW_object_wire_theme_get(ob, sl, NULL); + DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_shgroup_or(stl, theme_id, stl->g_data->wire); + DRW_shgroup_call_add(shgroup, geom, ob->obmat); + } + break; + } case OB_LAMP: DRW_shgroup_lamp(stl, ob, sl); break; diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_frag.glsl new file mode 100644 index 00000000000..57e96143c75 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_curve_overlay_frag.glsl @@ -0,0 +1,26 @@ + +flat in int vertFlag; + +#define VERTEX_SELECTED (1 << 0) +#define VERTEX_ACTIVE (1 << 1) + +#if __VERSION__ == 120 + #define FragColor gl_FragColor +#else + out vec4 FragColor; +#endif + +void main() +{ + /* TODO: vertex size */ + + if ((vertFlag & VERTEX_SELECTED) != 0) { + FragColor = colorVertexSelect; + } + else if ((vertFlag & VERTEX_ACTIVE) != 0) { + FragColor = colorEditMeshActive; + } + else { + FragColor = colorVertex; + } +} diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl new file mode 100644 index 00000000000..1af529e5482 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl @@ -0,0 +1,39 @@ + +/* Draw Curve Vertices */ + +uniform mat4 ModelViewProjectionMatrix; +uniform vec2 viewportSize; + +in vec3 pos; +in int data; + +/* these are the same for all vertices + * and does not need interpolation */ +flat out int vertFlag; +flat out int clipCase; + +/* See fragment shader */ +noperspective out vec4 eData1; +flat out vec4 eData2; + +/* project to screen space */ +vec2 proj(vec4 pos) +{ + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +void main() +{ + clipCase = 0; + + vec4 pPos = ModelViewProjectionMatrix * vec4(pos, 1.0); + + /* only verterx position 0 is used */ + eData1 = eData2 = vec4(1e10); + eData2.zw = proj(pPos); + + vertFlag = data; + + gl_PointSize = sizeEdgeFix; + gl_Position = pPos; +} diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 5c3b669d64e..97400335bfe 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -47,12 +47,14 @@ #include "BKE_icons.h" #include "BKE_library.h" #include "BKE_main.h" -#include "BKE_lattice_render.h" -#include "BKE_mesh_render.h" #include "BKE_object.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_curve_render.h" +#include "BKE_lattice_render.h" +#include "BKE_mesh_render.h" + #include "ED_space_api.h" #include "ED_screen.h" #include "ED_transform.h" @@ -932,6 +934,9 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w case OB_MESH: BKE_mesh_batch_selection_dirty(ob->data); break; + case OB_CURVE: + BKE_curve_batch_selection_dirty(ob->data); + break; case OB_LATTICE: BKE_lattice_batch_selection_dirty(ob->data); break; diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 902fa4ce987..e598c32173c 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -266,6 +266,7 @@ typedef struct Curve { char pad2[2]; + void *batch_cache; } Curve; #define CURVE_VFONT_ANY(cu) \ |