diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-04-21 14:14:11 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-04-21 15:06:06 +0300 |
commit | bfa888cef28955501195dfbee002bc793685e527 (patch) | |
tree | a7ed19cdc57089f3c728337761bd08a23764814d /source/blender/draw | |
parent | c7f00feabaa334cd839a9e7904ee0fc1b8d8d718 (diff) |
Cleanup: move draw-cache creation from BKE to DRW
Creating draw-cache should only ever be used by the draw-manager.
Diffstat (limited to 'source/blender/draw')
-rw-r--r-- | source/blender/draw/CMakeLists.txt | 15 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 54 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.h | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl.h | 81 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_curve.c | 1047 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_displist.c | 168 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_lattice.c | 510 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_mesh.c | 1448 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 25 |
9 files changed, 3321 insertions, 29 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 87c42caf541..61f95f8a176 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -34,13 +34,14 @@ set(INC ../blenkernel ../blenlib ../blentranslation - ../imbuf + ../bmesh ../depsgraph - ../makesdna - ../makesrna - ../gpu ../editors/include ../editors/space_view3d + ../gpu + ../imbuf + ../makesdna + ../makesrna ../render/extern/include ../render/intern/include ../windowmanager @@ -60,6 +61,11 @@ set(SRC intern/draw_view.c intern/draw_armature.c + intern/draw_cache_impl_curve.c + intern/draw_cache_impl_displist.c + intern/draw_cache_impl_lattice.c + intern/draw_cache_impl_mesh.c + engines/clay/clay.c engines/clay/clay.h @@ -87,6 +93,7 @@ set(SRC intern/DRW_render.h intern/draw_common.h intern/draw_cache.h + intern/draw_cache_impl.h intern/draw_view.h modes/draw_mode_engines.h diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index b868435c382..259d066d4f4 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -32,13 +32,10 @@ #include "BLI_utildefines.h" #include "BLI_math.h" -#include "BKE_curve_render.h" -#include "BKE_lattice_render.h" -#include "BKE_mesh_render.h" - #include "GPU_batch.h" #include "draw_cache.h" +#include "draw_cache_impl.h" static struct DRWShapeCache { Batch *drw_single_vertice; @@ -1544,6 +1541,13 @@ Batch *DRW_cache_single_vert_get(void) /** \name Meshes * \{ */ +Batch *DRW_cache_mesh_surface_overlay_get(Object *ob) +{ + BLI_assert(ob->type == OB_MESH); + Mesh *me = ob->data; + return DRW_mesh_batch_cache_get_all_triangles(me); +} + void DRW_cache_mesh_wire_overlay_get( Object *ob, Batch **r_tris, Batch **r_ledges, Batch **r_lverts) @@ -1552,9 +1556,9 @@ void DRW_cache_mesh_wire_overlay_get( Mesh *me = ob->data; - *r_tris = BKE_mesh_batch_cache_get_overlay_triangles(me); - *r_ledges = BKE_mesh_batch_cache_get_overlay_loose_edges(me); - *r_lverts = BKE_mesh_batch_cache_get_overlay_loose_verts(me); + *r_tris = DRW_mesh_batch_cache_get_overlay_triangles(me); + *r_ledges = DRW_mesh_batch_cache_get_overlay_loose_edges(me); + *r_lverts = DRW_mesh_batch_cache_get_overlay_loose_verts(me); } Batch *DRW_cache_face_centers_get(Object *ob) @@ -1563,7 +1567,7 @@ Batch *DRW_cache_face_centers_get(Object *ob) Mesh *me = ob->data; - return BKE_mesh_batch_cache_get_overlay_facedots(me); + return DRW_mesh_batch_cache_get_overlay_facedots(me); } Batch *DRW_cache_mesh_wire_outline_get(Object *ob) @@ -1571,7 +1575,7 @@ Batch *DRW_cache_mesh_wire_outline_get(Object *ob) BLI_assert(ob->type == OB_MESH); Mesh *me = ob->data; - return BKE_mesh_batch_cache_get_fancy_edges(me); + return DRW_mesh_batch_cache_get_fancy_edges(me); } Batch *DRW_cache_mesh_surface_get(Object *ob) @@ -1579,7 +1583,7 @@ Batch *DRW_cache_mesh_surface_get(Object *ob) BLI_assert(ob->type == OB_MESH); Mesh *me = ob->data; - return BKE_mesh_batch_cache_get_triangles_with_normals(me); + return DRW_mesh_batch_cache_get_triangles_with_normals(me); } Batch *DRW_cache_mesh_surface_verts_get(Object *ob) @@ -1587,7 +1591,7 @@ Batch *DRW_cache_mesh_surface_verts_get(Object *ob) BLI_assert(ob->type == OB_MESH); Mesh *me = ob->data; - return BKE_mesh_batch_cache_get_points_with_normals(me); + return DRW_mesh_batch_cache_get_points_with_normals(me); } Batch *DRW_cache_mesh_verts_get(Object *ob) @@ -1595,7 +1599,7 @@ Batch *DRW_cache_mesh_verts_get(Object *ob) BLI_assert(ob->type == OB_MESH); Mesh *me = ob->data; - return BKE_mesh_batch_cache_get_all_verts(me); + return DRW_mesh_batch_cache_get_all_verts(me); } /** \} */ @@ -1610,7 +1614,7 @@ Batch *DRW_cache_curve_edge_wire_get(Object *ob) BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - return BKE_curve_batch_cache_get_wire_edge(cu, ob->curve_cache); + return DRW_curve_batch_cache_get_wire_edge(cu, ob->curve_cache); } Batch *DRW_cache_curve_edge_normal_get(Object *ob, float normal_size) @@ -1618,7 +1622,7 @@ 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); + return DRW_curve_batch_cache_get_normal_edge(cu, ob->curve_cache, normal_size); } Batch *DRW_cache_curve_edge_overlay_get(Object *ob) @@ -1626,7 +1630,7 @@ Batch *DRW_cache_curve_edge_overlay_get(Object *ob) BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - return BKE_curve_batch_cache_get_overlay_edges(cu); + return DRW_curve_batch_cache_get_overlay_edges(cu); } Batch *DRW_cache_curve_vert_overlay_get(Object *ob) @@ -1634,7 +1638,7 @@ Batch *DRW_cache_curve_vert_overlay_get(Object *ob) BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - return BKE_curve_batch_cache_get_overlay_verts(cu); + return DRW_curve_batch_cache_get_overlay_verts(cu); } Batch *DRW_cache_curve_surface_get(Object *ob) @@ -1642,7 +1646,7 @@ Batch *DRW_cache_curve_surface_get(Object *ob) BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - return BKE_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache); + return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache); } /** \} */ @@ -1657,7 +1661,7 @@ Batch *DRW_cache_text_edge_wire_get(Object *ob) BLI_assert(ob->type == OB_FONT); struct Curve *cu = ob->data; - return BKE_curve_batch_cache_get_wire_edge(cu, ob->curve_cache); + return DRW_curve_batch_cache_get_wire_edge(cu, ob->curve_cache); } Batch *DRW_cache_text_surface_get(Object *ob) @@ -1667,21 +1671,21 @@ Batch *DRW_cache_text_surface_get(Object *ob) if (cu->editfont && (cu->flag & CU_FAST)) { return NULL; } - return BKE_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache); + return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache); } Batch *DRW_cache_text_cursor_overlay_get(Object *ob) { BLI_assert(ob->type == OB_FONT); struct Curve *cu = ob->data; - return BKE_curve_batch_cache_get_overlay_cursor(cu); + return DRW_curve_batch_cache_get_overlay_cursor(cu); } Batch *DRW_cache_text_select_overlay_get(Object *ob) { BLI_assert(ob->type == OB_FONT); struct Curve *cu = ob->data; - return BKE_curve_batch_cache_get_overlay_select(cu); + return DRW_curve_batch_cache_get_overlay_select(cu); } /** \} */ @@ -1696,7 +1700,7 @@ Batch *DRW_cache_surf_surface_get(Object *ob) BLI_assert(ob->type == OB_SURF); struct Curve *cu = ob->data; - return BKE_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache); + return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache); } /** \} */ @@ -1711,7 +1715,7 @@ Batch *DRW_cache_lattice_verts_get(Object *ob) BLI_assert(ob->type == OB_LATTICE); struct Lattice *lt = ob->data; - return BKE_lattice_batch_cache_get_all_verts(lt); + return DRW_lattice_batch_cache_get_all_verts(lt); } Batch *DRW_cache_lattice_wire_get(Object *ob) @@ -1719,7 +1723,7 @@ Batch *DRW_cache_lattice_wire_get(Object *ob) BLI_assert(ob->type == OB_LATTICE); struct Lattice *lt = ob->data; - return BKE_lattice_batch_cache_get_all_edges(lt); + return DRW_lattice_batch_cache_get_all_edges(lt); } Batch *DRW_cache_lattice_vert_overlay_get(Object *ob) @@ -1727,7 +1731,7 @@ Batch *DRW_cache_lattice_vert_overlay_get(Object *ob) BLI_assert(ob->type == OB_LATTICE); struct Lattice *lt = ob->data; - return BKE_lattice_batch_cache_get_overlay_verts(lt); + return DRW_lattice_batch_cache_get_overlay_verts(lt); } /** \} */ diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 3d4963e617b..17e9467d1d9 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -82,6 +82,7 @@ struct Batch *DRW_cache_bone_point_wire_outline_get(void); struct Batch *DRW_cache_bone_arrows_get(void); /* Meshes */ +struct Batch *DRW_cache_mesh_surface_overlay_get(struct Object *ob); void DRW_cache_mesh_wire_overlay_get( struct Object *ob, struct Batch **r_tris, struct Batch **r_ledges, struct Batch **r_lverts); @@ -91,6 +92,7 @@ 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_surface_get(struct Object *ob); struct Batch *DRW_cache_curve_surface_verts_get(struct Object *ob); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h new file mode 100644 index 00000000000..e4318aa576a --- /dev/null +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -0,0 +1,81 @@ +/* + * Copyright 2016, Blender Foundation. + * + * 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. + * + * Contributor(s): Blender Institute + * + */ + +/** \file draw_cache_impl.h + * \ingroup draw + */ + +#ifndef __DRAW_CACHE_IMPL_H__ +#define __DRAW_CACHE_IMPL_H__ + +struct Batch; +struct ListBase; +struct CurveCache; + +struct Curve; +struct Lattice; +struct Mesh; + +/* Expose via BKE callbacks */ +void DRW_curve_batch_cache_dirty(struct Curve *cu, int mode); +void DRW_curve_batch_cache_free(struct Curve *cu); + +void DRW_mesh_batch_cache_dirty(struct Mesh *me, int mode); +void DRW_mesh_batch_cache_free(struct Mesh *me); + +void DRW_lattice_batch_cache_dirty(struct Lattice *lt, int mode); +void DRW_lattice_batch_cache_free(struct Lattice *lt); + +/* Curve */ +struct Batch *DRW_curve_batch_cache_get_wire_edge(struct Curve *cu, struct CurveCache *ob_curve_cache); +struct Batch *DRW_curve_batch_cache_get_normal_edge( + struct Curve *cu, struct CurveCache *ob_curve_cache, float normal_size); +struct Batch *DRW_curve_batch_cache_get_overlay_edges(struct Curve *cu); +struct Batch *DRW_curve_batch_cache_get_overlay_verts(struct Curve *cu); + +struct Batch *DRW_curve_batch_cache_get_triangles_with_normals(struct Curve *cu, struct CurveCache *ob_curve_cache); + +/* Curve (Font) */ +struct Batch *DRW_curve_batch_cache_get_overlay_cursor(struct Curve *cu); +struct Batch *DRW_curve_batch_cache_get_overlay_select(struct Curve *cu); + +/* DispList */ +struct Batch *BLI_displist_batch_calc_surface(struct ListBase *lb); + +/* Lattice */ +struct Batch *DRW_lattice_batch_cache_get_all_edges(struct Lattice *lt); +struct Batch *DRW_lattice_batch_cache_get_all_verts(struct Lattice *lt); +struct Batch *DRW_lattice_batch_cache_get_overlay_verts(struct Lattice *lt); + +/* Mesh */ + +struct Batch *DRW_mesh_batch_cache_get_all_edges(struct Mesh *me); +struct Batch *DRW_mesh_batch_cache_get_all_triangles(struct Mesh *me); +struct Batch *DRW_mesh_batch_cache_get_triangles_with_normals(struct Mesh *me); +struct Batch *DRW_mesh_batch_cache_get_points_with_normals(struct Mesh *me); +struct Batch *DRW_mesh_batch_cache_get_all_verts(struct Mesh *me); +struct Batch *DRW_mesh_batch_cache_get_fancy_edges(struct Mesh *me); +struct Batch *DRW_mesh_batch_cache_get_overlay_triangles(struct Mesh *me); +struct Batch *DRW_mesh_batch_cache_get_overlay_loose_edges(struct Mesh *me); +struct Batch *DRW_mesh_batch_cache_get_overlay_loose_verts(struct Mesh *me); +struct Batch *DRW_mesh_batch_cache_get_overlay_facedots(struct Mesh *me); + +#endif /* __DRAW_CACHE_IMPL_H__ */ diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c new file mode 100644 index 00000000000..9f3c10db61e --- /dev/null +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -0,0 +1,1047 @@ +/* + * ***** 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 draw_cache_impl_curve.c + * \ingroup draw + * + * \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_font.h" + +#include "GPU_batch.h" + +#include "draw_cache_impl.h" /* own include */ + +#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). + */ + +static void curve_batch_cache_clear(Curve *cu); + +/* ---------------------------------------------------------------------- */ +/* 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; + } +} + +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. */ + +typedef struct CurveRenderData { + int types; + + struct { + int vert_len; + int edge_len; + } overlay; + + struct { + int vert_len; + int edge_len; + } wire; + + /* edit mode normal's */ + struct { + /* 'edge_len == len * 2' + * 'vert_len == len * 3' */ + int len; + } normal; + + struct { + EditFont *edit_font; + } text; + + bool hide_handles; + bool hide_normals; + + /* borrow from 'Object' */ + CurveCache *ob_curve_cache; + + /* borrow from 'Curve' */ + 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, + /* Edit-mode normals */ + CU_DATATYPE_NORMAL = 1 << 2, + /* Geometry */ + CU_DATATYPE_SURFACE = 1 << 3, + /* Text */ + CU_DATATYPE_TEXT_SELECT = 1 << 4, +}; + +/* + * 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 *rdata = MEM_callocN(sizeof(*rdata), __func__); + rdata->types = types; + ListBase *nurbs; + + rdata->hide_handles = (cu->drawflag & CU_HIDE_HANDLES) != 0; + rdata->hide_normals = (cu->drawflag & CU_HIDE_NORMALS) != 0; + + rdata->actnu = cu->actnu; + rdata->actvert = cu->actvert; + + rdata->ob_curve_cache = ob_curve_cache; + + if (types & CU_DATATYPE_WIRE) { + curve_render_wire_verts_edges_len_get( + rdata->ob_curve_cache, + &rdata->wire.vert_len, &rdata->wire.edge_len); + } + + if (cu->editnurb) { + EditNurb *editnurb = cu->editnurb; + nurbs = &editnurb->nurbs; + + if (types & CU_DATATYPE_OVERLAY) { + curve_render_overlay_verts_edges_len_get( + nurbs, rdata->hide_handles, + &rdata->overlay.vert_len, + rdata->hide_handles ? NULL : &rdata->overlay.edge_len); + + rdata->actnu = cu->actnu; + rdata->actvert = cu->actvert; + } + if (types & CU_DATATYPE_NORMAL) { + rdata->normal.len = curve_render_normal_len_get(nurbs, rdata->ob_curve_cache); + } + } + else { + nurbs = &cu->nurb; + } + + rdata->nurbs = nurbs; + + rdata->text.edit_font = cu->editfont; + + return rdata; +} + +static void curve_render_data_free(CurveRenderData *rdata) +{ +#if 0 + if (rdata->loose_verts) { + MEM_freeN(rdata->loose_verts); + } +#endif + MEM_freeN(rdata); +} + +static int curve_render_data_overlay_verts_len_get(const CurveRenderData *rdata) +{ + BLI_assert(rdata->types & CU_DATATYPE_OVERLAY); + return rdata->overlay.vert_len; +} + +static int curve_render_data_overlay_edges_len_get(const CurveRenderData *rdata) +{ + BLI_assert(rdata->types & CU_DATATYPE_OVERLAY); + return rdata->overlay.edge_len; +} + +static int curve_render_data_wire_verts_len_get(const CurveRenderData *rdata) +{ + BLI_assert(rdata->types & CU_DATATYPE_WIRE); + return rdata->wire.vert_len; +} + +static int curve_render_data_wire_edges_len_get(const CurveRenderData *rdata) +{ + BLI_assert(rdata->types & CU_DATATYPE_WIRE); + return rdata->wire.edge_len; +} + +static int curve_render_data_normal_len_get(const CurveRenderData *rdata) +{ + BLI_assert(rdata->types & CU_DATATYPE_NORMAL); + return rdata->normal.len; +} + +enum { + VFLAG_VERTEX_SELECTED = 1 << 0, + VFLAG_VERTEX_ACTIVE = 1 << 1, +}; + +/* ---------------------------------------------------------------------- */ +/* Curve Batch Cache */ + +typedef struct CurveBatchCache { + /* center-line */ + struct { + VertexBuffer *verts; + VertexBuffer *edges; + Batch *batch; + ElementList *elem; + } wire; + + /* normals */ + struct { + VertexBuffer *verts; + VertexBuffer *edges; + Batch *batch; + ElementList *elem; + } normal; + + /* control handles and vertices */ + struct { + Batch *edges; + Batch *verts; + } overlay; + + struct { + Batch *batch; + } surface; + + /* 3d text */ + struct { + Batch *select; + Batch *cursor; + } text; + + /* settings to determine if cache is invalid */ + bool is_dirty; + + bool hide_handles; + bool hide_normals; + + float normal_size; + + 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) || (cu->editfont != NULL))) { + return false; + } + + if (cache->is_editmode) { + if (cu->editnurb) { + 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; + } + } + else if (cu->editfont) { + /* TODO */ + } + } + + if (cache->is_dirty == false) { + return true; + } + else { + /* TODO: check number of vertices/edges? */ + if (cache->is_editmode) { + 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->drawflag & CU_HIDE_HANDLES) != 0; + cache->hide_normals = (cu->drawflag & CU_HIDE_NORMALS) != 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) || (cu->editfont != NULL); + + cache->is_dirty = false; +} + +static CurveBatchCache *curve_batch_cache_get(Curve *cu) +{ + if (!curve_batch_cache_valid(cu)) { + curve_batch_cache_clear(cu); + curve_batch_cache_init(cu); + } + return cu->batch_cache; +} + +void DRW_curve_batch_cache_dirty(Curve *cu, int mode) +{ + CurveBatchCache *cache = cu->batch_cache; + if (cache == NULL) { + return; + } + switch (mode) { + case BKE_CURVE_BATCH_DIRTY_ALL: + cache->is_dirty = true; + break; + case BKE_CURVE_BATCH_DIRTY_SELECT: + /* editnurb */ + BATCH_DISCARD_ALL_SAFE(cache->overlay.verts); + BATCH_DISCARD_ALL_SAFE(cache->overlay.edges); + + /* editfont */ + BATCH_DISCARD_ALL_SAFE(cache->text.select); + BATCH_DISCARD_ALL_SAFE(cache->text.cursor); + break; + default: + BLI_assert(0); + } +} + +static void 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); + + BATCH_DISCARD_ALL_SAFE(cache->surface.batch); + + if (cache->wire.batch) { + BATCH_DISCARD_ALL_SAFE(cache->wire.batch); + cache->wire.verts = NULL; + cache->wire.edges = NULL; + cache->wire.elem = NULL; + } + else { + VERTEXBUFFER_DISCARD_SAFE(cache->wire.verts); + VERTEXBUFFER_DISCARD_SAFE(cache->wire.edges); + ELEMENTLIST_DISCARD_SAFE(cache->wire.elem); + } + + if (cache->normal.batch) { + BATCH_DISCARD_ALL_SAFE(cache->normal.batch); + cache->normal.verts = NULL; + cache->normal.edges = NULL; + cache->normal.elem = NULL; + } + else { + VERTEXBUFFER_DISCARD_SAFE(cache->normal.verts); + VERTEXBUFFER_DISCARD_SAFE(cache->normal.edges); + ELEMENTLIST_DISCARD_SAFE(cache->normal.elem); + } + + /* 3d text */ + BATCH_DISCARD_ALL_SAFE(cache->text.cursor); + BATCH_DISCARD_ALL_SAFE(cache->text.select); +} + +void DRW_curve_batch_cache_free(Curve *cu) +{ + curve_batch_cache_clear(cu); + MEM_SAFE_FREE(cu->batch_cache); +} + +/* -------------------------------------------------------------------- */ + +/** \name Private Curve Cache API + * \{ */ + +/* Batch cache usage. */ +static VertexBuffer *curve_batch_cache_get_wire_verts(CurveRenderData *rdata, CurveBatchCache *cache) +{ + BLI_assert(rdata->types & CU_DATATYPE_WIRE); + BLI_assert(rdata->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(rdata); + + 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 = rdata->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 *rdata, CurveBatchCache *cache) +{ + BLI_assert(rdata->types & CU_DATATYPE_WIRE); + BLI_assert(rdata->ob_curve_cache != NULL); + + if (cache->wire.edges == NULL) { + const int vert_len = curve_render_data_wire_verts_len_get(rdata); + const int edge_len = curve_render_data_wire_edges_len_get(rdata); + int edge_len_used = 0; + + ElementListBuilder elb; + ElementListBuilder_init(&elb, PRIM_LINES, edge_len, vert_len); + + int i = 0; + for (const BevList *bl = rdata->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_used += 1; + } + } + } + + if (rdata->hide_handles) { + BLI_assert(edge_len_used <= edge_len); + } + else { + BLI_assert(edge_len_used == edge_len); + } + + cache->wire.elem = ElementList_build(&elb); + } + + return cache->wire.elem; +} + +static VertexBuffer *curve_batch_cache_get_normal_verts(CurveRenderData *rdata, CurveBatchCache *cache) +{ + BLI_assert(rdata->types & CU_DATATYPE_NORMAL); + BLI_assert(rdata->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(rdata); + 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 = rdata->ob_curve_cache->bev.first, nu = rdata->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; + + mul_qt_v3(bevp->quat, vec_a); + madd_v3_v3fl(vec_a, bevp->dir, -fac); + + reflect_v3_v3v3(vec_b, vec_a, bevp->dir); + negate_v3(vec_b); + + add_v3_v3(vec_a, bevp->vec); + add_v3_v3(vec_b, bevp->vec); + + 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 *rdata, CurveBatchCache *cache) +{ + BLI_assert(rdata->types & CU_DATATYPE_NORMAL); + BLI_assert(rdata->ob_curve_cache != NULL); + + if (cache->normal.edges == NULL) { + const int normal_len = curve_render_data_normal_len_get(rdata); + const int vert_len = normal_len * 3; + const int edge_len = normal_len * 2; + + ElementListBuilder elb; + ElementListBuilder_init(&elb, PRIM_LINES, edge_len, vert_len); + + 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 == vert_len); + + 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 */ + int options = CU_DATATYPE_OVERLAY; + + CurveBatchCache *cache = curve_batch_cache_get(cu); + CurveRenderData *rdata = 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(rdata); + int vbo_len_used = 0; + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + int i = 0; + for (Nurb *nu = rdata->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 == rdata->actvert); + char vflag; + + if (rdata->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 == rdata->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) && (rdata->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(rdata); + 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 = rdata->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 == rdata->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(rdata); +} + +static Batch *curve_batch_cache_get_pos_and_normals(CurveRenderData *rdata, CurveBatchCache *cache) +{ + BLI_assert(rdata->types & CU_DATATYPE_SURFACE); + if (cache->surface.batch == NULL) { + cache->surface.batch = BLI_displist_batch_calc_surface(&rdata->ob_curve_cache->disp); + } + return cache->surface.batch; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Private Object/Font Cache API + * \{ */ + + +static Batch *curve_batch_cache_get_overlay_select(CurveRenderData *rdata, CurveBatchCache *cache) +{ + BLI_assert(rdata->types & CU_DATATYPE_TEXT_SELECT); + if (cache->text.select == NULL) { + EditFont *ef = rdata->text.edit_font; + static VertexFormat format = { 0 }; + static unsigned int pos_id; + if (format.attrib_ct == 0) { + pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + const int vbo_len_capacity = ef->selboxes_len * 6; + int vbo_len_used = 0; + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + + float box[4][3]; + + /* fill in xy below */ + box[0][2] = box[1][2] = box[2][2] = box[3][2] = 0.001; + + for (int i = 0; i < ef->selboxes_len; i++) { + EditFontSelBox *sb = &ef->selboxes[i]; + + float selboxw; + if (i + 1 != ef->selboxes_len) { + if (ef->selboxes[i + 1].y == sb->y) + selboxw = ef->selboxes[i + 1].x - sb->x; + else + selboxw = sb->w; + } + else { + selboxw = sb->w; + } + + if (sb->rot == 0.0f) { + copy_v2_fl2(box[0], sb->x, sb->y); + copy_v2_fl2(box[1], sb->x + selboxw, sb->y); + copy_v2_fl2(box[2], sb->x + selboxw, sb->y + sb->h); + copy_v2_fl2(box[3], sb->x, sb->y + sb->h); + } + else { + float mat[2][2]; + + angle_to_mat2(mat, sb->rot); + + copy_v2_fl2(box[0], sb->x, sb->y); + + copy_v2_fl2(box[1], selboxw, 0.0f); + mul_m2v2(mat, box[1]); + add_v2_v2(box[1], &sb->x); + + copy_v2_fl2(box[2], selboxw, sb->h); + mul_m2v2(mat, box[2]); + add_v2_v2(box[2], &sb->x); + + copy_v2_fl2(box[3], 0.0f, sb->h); + mul_m2v2(mat, box[3]); + add_v2_v2(box[3], &sb->x); + } + + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used++, box[0]); + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used++, box[1]); + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used++, box[2]); + + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used++, box[0]); + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used++, box[2]); + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used++, box[3]); + } + BLI_assert(vbo_len_used == vbo_len_capacity); + cache->text.select = Batch_create(PRIM_TRIANGLES, vbo, NULL); + } + return cache->text.select; +} + +static Batch *curve_batch_cache_get_overlay_cursor(CurveRenderData *rdata, CurveBatchCache *cache) +{ + BLI_assert(rdata->types & CU_DATATYPE_TEXT_SELECT); + if (cache->text.cursor == NULL) { + static VertexFormat format = { 0 }; + static unsigned int pos_id; + if (format.attrib_ct == 0) { + pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 2, KEEP_FLOAT); + } + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + const int vbo_len_capacity = 4; + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + for (int i = 0; i < 4; i++) { + VertexBuffer_set_attrib(vbo, pos_id, i, rdata->text.edit_font->textcurs[i]); + } + cache->text.cursor = Batch_create(PRIM_TRIANGLE_FAN, vbo, NULL); + } + return cache->text.cursor; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Public Object/Curve API + * \{ */ + +Batch *DRW_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 *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_WIRE); + + cache->wire.batch = Batch_create( + PRIM_LINES, + curve_batch_cache_get_wire_verts(rdata, cache), + curve_batch_cache_get_wire_edges(rdata, cache)); + + curve_render_data_free(rdata); + } + return cache->wire.batch; +} + +Batch *DRW_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 *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_NORMAL); + + cache->normal.batch = Batch_create( + PRIM_LINES, + curve_batch_cache_get_normal_verts(rdata, cache), + curve_batch_cache_get_normal_edges(rdata, cache)); + + curve_render_data_free(rdata); + cache->normal_size = normal_size; + } + return cache->normal.batch; +} + +Batch *DRW_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 *DRW_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; +} + +Batch *DRW_curve_batch_cache_get_triangles_with_normals( + struct Curve *cu, struct CurveCache *ob_curve_cache) +{ + CurveBatchCache *cache = curve_batch_cache_get(cu); + + if (cache->surface.batch == NULL) { + CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE); + + curve_batch_cache_get_pos_and_normals(rdata, cache); + + curve_render_data_free(rdata); + } + + return cache->surface.batch; +} + + +/* -------------------------------------------------------------------- */ + +/** \name Public Object/Font API + * \{ */ + +Batch *DRW_curve_batch_cache_get_overlay_select(Curve *cu) +{ + CurveBatchCache *cache = curve_batch_cache_get(cu); + + if (cache->text.select == NULL) { + CurveRenderData *rdata = curve_render_data_create(cu, NULL, CU_DATATYPE_TEXT_SELECT); + + curve_batch_cache_get_overlay_select(rdata, cache); + + curve_render_data_free(rdata); + } + + return cache->text.select; +} + +Batch *DRW_curve_batch_cache_get_overlay_cursor(Curve *cu) +{ + CurveBatchCache *cache = curve_batch_cache_get(cu); + + if (cache->text.cursor == NULL) { + CurveRenderData *rdata = curve_render_data_create(cu, NULL, CU_DATATYPE_TEXT_SELECT); + + curve_batch_cache_get_overlay_cursor(rdata, cache); + + curve_render_data_free(rdata); + } + + return cache->text.cursor; +} + +/** \} */
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c new file mode 100644 index 00000000000..f18d02f5ee7 --- /dev/null +++ b/source/blender/draw/intern/draw_cache_impl_displist.c @@ -0,0 +1,168 @@ +/* + * ***** 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 draw_cache_impl_displist.c + * \ingroup draw + * + * \brief DispList API for render engines + * + * \note DispList may be removed soon! This is a utility for object types that use render. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" + +#include "DNA_curve_types.h" + +#include "BKE_displist.h" + +#include "GPU_batch.h" + +#include "draw_cache_impl.h" /* own include */ + +static int dl_vert_len(const DispList *dl) +{ + switch (dl->type) { + case DL_INDEX3: + case DL_INDEX4: + return dl->nr; + case DL_SURF: + return dl->parts * dl->nr; + } + return 0; +} + +static int dl_tri_len(const DispList *dl) +{ + switch (dl->type) { + case DL_INDEX3: + return dl->parts; + case DL_INDEX4: + return dl->parts * 2; + case DL_SURF: + return dl->totindex * 2; + } + return 0; +} + +/* see: displist_get_allverts */ +static int curve_render_surface_vert_len_get(const ListBase *lb) +{ + int vert_len = 0; + for (const DispList *dl = lb->first; dl; dl = dl->next) { + vert_len += dl_vert_len(dl); + } + return vert_len; +} + +static int curve_render_surface_tri_len_get(const ListBase *lb) +{ + int tri_len = 0; + for (const DispList *dl = lb->first; dl; dl = dl->next) { + tri_len += dl_tri_len(dl); + } + return tri_len; +} + +Batch *BLI_displist_batch_calc_surface(ListBase *lb) +{ + const int tri_len = curve_render_surface_tri_len_get(lb); + if (tri_len == 0) { + return NULL; + } + + static VertexFormat format = { 0 }; + static unsigned int pos_id, nor_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); + nor_id = VertexFormat_add_attrib(&format, "nor", COMP_F32, 3, KEEP_FLOAT); + } + + const int vert_len = curve_render_surface_vert_len_get(lb); + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + { + const int vbo_len_capacity = vert_len; + int vbo_len_used = 0; + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + + BKE_displist_normals_add(lb); + + for (const DispList *dl = lb->first; dl; dl = dl->next) { + const bool ndata_is_single = dl->type == DL_INDEX3; + if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { + const float *fp_co = dl->verts; + const float *fp_no = dl->nors; + const int vbo_end = vbo_len_used + dl_vert_len(dl); + while (vbo_len_used < vbo_end) { + VertexBuffer_set_attrib(vbo, pos_id, vbo_len_used, fp_co); + if (fp_no) { + VertexBuffer_set_attrib(vbo, nor_id, vbo_len_used, fp_no); + if (ndata_is_single == false) { + fp_no += 3; + } + } + fp_co += 3; + vbo_len_used += 1; + } + } + } + } + + { + ElementListBuilder elb; + ElementListBuilder_init(&elb, PRIM_TRIANGLES, tri_len, vert_len); + + int ofs = 0; + int tri_len_used = 0; + for (const DispList *dl = lb->first; dl; dl = dl->next) { + if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { + if (dl->type == DL_INDEX3) { + const int *idx = dl->index; + const int i_end = dl->parts; + for (int i = 0; i < i_end; i++) { + add_triangle_vertices(&elb, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs); + tri_len_used += 1; + idx += 3; + } + } + else if (ELEM(dl->type, DL_INDEX4, DL_SURF)) { + const int *idx = dl->index; + const int i_end = dl->totindex; + for (int i = 0; i < i_end; i++) { + add_triangle_vertices(&elb, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs); + tri_len_used += 1; + add_triangle_vertices(&elb, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs); + tri_len_used += 1; + idx += 4; + } + } + ofs += dl_vert_len(dl); + } + } + + return Batch_create(PRIM_TRIANGLES, vbo, ElementList_build(&elb)); + } +} diff --git a/source/blender/draw/intern/draw_cache_impl_lattice.c b/source/blender/draw/intern/draw_cache_impl_lattice.c new file mode 100644 index 00000000000..444b4e641f6 --- /dev/null +++ b/source/blender/draw/intern/draw_cache_impl_lattice.c @@ -0,0 +1,510 @@ +/* + * ***** 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. + * + * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file draw_cache_impl_lattice.c + * \ingroup draw + * + * \brief Lattice API for render engines + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" + +#include "DNA_curve_types.h" +#include "DNA_lattice_types.h" + +#include "BKE_lattice.h" + +#include "GPU_batch.h" + +#include "draw_cache_impl.h" /* own include */ + +#define SELECT 1 + +/** + * TODO + * - 'DispList' is currently not used + * (we could avoid using since it will be removed) + */ + +static void lattice_batch_cache_clear(Lattice *lt); + +/* ---------------------------------------------------------------------- */ +/* Lattice Interface, direct access to basic data. */ + +static int vert_len_calc(int u, int v, int w) +{ + if (u <= 0 || v <= 0 || w <= 0) { + return 0; + } + return u * v * w; +} + +static int edge_len_calc(int u, int v, int w) +{ + if (u <= 0 || v <= 0 || w <= 0) { + return 0; + } + return (((((u - 1) * v) + + ((v - 1) * u)) * w) + + ((w - 1) * (u * v))); +} + +static int lattice_render_verts_len_get(Lattice *lt) +{ + if (lt->editlatt) { + lt = lt->editlatt->latt; + } + + const int u = lt->pntsu; + const int v = lt->pntsv; + const int w = lt->pntsw; + + if ((lt->flag & LT_OUTSIDE) == 0) { + return vert_len_calc(u, v, w); + } + else { + /* TODO remove internal coords */ + return vert_len_calc(u, v, w); + } +} + +static int lattice_render_edges_len_get(Lattice *lt) +{ + if (lt->editlatt) { + lt = lt->editlatt->latt; + } + + const int u = lt->pntsu; + const int v = lt->pntsv; + const int w = lt->pntsw; + + if ((lt->flag & LT_OUTSIDE) == 0) { + return edge_len_calc(u, v, w); + } + else { + /* TODO remove internal coords */ + return edge_len_calc(u, v, w); + } +} + +/* ---------------------------------------------------------------------- */ +/* Lattice Interface, indirect, partially cached access to complex data. */ + +typedef struct LatticeRenderData { + int types; + + int vert_len; + int edge_len; + + struct { + int u_len, v_len, w_len; + } dims; + bool show_only_outside; + + struct EditLatt *edit_latt; + BPoint *bp; + + int actbp; +} LatticeRenderData; + +enum { + LR_DATATYPE_VERT = 1 << 0, + LR_DATATYPE_EDGE = 1 << 1, + LR_DATATYPE_OVERLAY = 1 << 2, +}; + +static LatticeRenderData *lattice_render_data_create(Lattice *lt, const int types) +{ + LatticeRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__); + rdata->types = types; + + if (lt->editlatt) { + EditLatt *editlatt = lt->editlatt; + lt = editlatt->latt; + + rdata->edit_latt = editlatt; + + if (types & (LR_DATATYPE_VERT)) { + rdata->vert_len = lattice_render_verts_len_get(lt); + } + if (types & (LR_DATATYPE_EDGE)) { + rdata->edge_len = lattice_render_edges_len_get(lt); + } + if (types & LR_DATATYPE_OVERLAY) { + rdata->actbp = lt->actbp; + } + } + else { + if (types & (LR_DATATYPE_VERT)) { + rdata->vert_len = lattice_render_verts_len_get(lt); + } + if (types & (LR_DATATYPE_EDGE)) { + rdata->edge_len = lattice_render_edges_len_get(lt); + /*no edge data */ + } + } + + rdata->bp = lt->def; + + rdata->dims.u_len = lt->pntsu; + rdata->dims.v_len = lt->pntsv; + rdata->dims.w_len = lt->pntsw; + + rdata->show_only_outside = (lt->flag & LT_OUTSIDE) != 0; + rdata->actbp = lt->actbp; + + return rdata; +} + +static void lattice_render_data_free(LatticeRenderData *rdata) +{ +#if 0 + if (rdata->loose_verts) { + MEM_freeN(rdata->loose_verts); + } +#endif + MEM_freeN(rdata); +} + +static int lattice_render_data_verts_len_get(const LatticeRenderData *rdata) +{ + BLI_assert(rdata->types & LR_DATATYPE_VERT); + return rdata->vert_len; +} + +static int lattice_render_data_edges_len_get(const LatticeRenderData *rdata) +{ + BLI_assert(rdata->types & LR_DATATYPE_EDGE); + return rdata->edge_len; +} + +static const BPoint *lattice_render_data_vert_bpoint(const LatticeRenderData *rdata, const int vert_idx) +{ + BLI_assert(rdata->types & LR_DATATYPE_VERT); + return &rdata->bp[vert_idx]; +} + +enum { + VFLAG_VERTEX_SELECTED = 1 << 0, + VFLAG_VERTEX_ACTIVE = 1 << 1, +}; + +/* ---------------------------------------------------------------------- */ +/* Lattice Batch Cache */ + +typedef struct LatticeBatchCache { + VertexBuffer *pos; + ElementList *edges; + + Batch *all_verts; + Batch *all_edges; + + Batch *overlay_verts; + + /* settings to determine if cache is invalid */ + bool is_dirty; + + struct { + int u_len, v_len, w_len; + } dims; + bool show_only_outside; + + bool is_editmode; +} LatticeBatchCache; + +/* Batch cache management. */ + +static bool lattice_batch_cache_valid(Lattice *lt) +{ + LatticeBatchCache *cache = lt->batch_cache; + + if (cache == NULL) { + return false; + } + + if (cache->is_editmode != (lt->editlatt != NULL)) { + return false; + } + + if (cache->is_dirty == false) { + return true; + } + else { + if (cache->is_editmode) { + return false; + } + else if ((cache->dims.u_len != lt->pntsu) || + (cache->dims.v_len != lt->pntsv) || + (cache->dims.w_len != lt->pntsw) || + ((cache->show_only_outside != ((lt->flag & LT_OUTSIDE) != 0)))) + { + return false; + } + } + + return true; +} + +static void lattice_batch_cache_init(Lattice *lt) +{ + LatticeBatchCache *cache = lt->batch_cache; + + if (!cache) { + cache = lt->batch_cache = MEM_callocN(sizeof(*cache), __func__); + } + else { + memset(cache, 0, sizeof(*cache)); + } + + cache->dims.u_len = lt->pntsu; + cache->dims.v_len = lt->pntsv; + cache->dims.w_len = lt->pntsw; + cache->show_only_outside = (lt->flag & LT_OUTSIDE) != 0; + + cache->is_editmode = lt->editlatt != NULL; + + cache->is_dirty = false; +} + +static LatticeBatchCache *lattice_batch_cache_get(Lattice *lt) +{ + if (!lattice_batch_cache_valid(lt)) { + lattice_batch_cache_clear(lt); + lattice_batch_cache_init(lt); + } + return lt->batch_cache; +} + +void DRW_lattice_batch_cache_dirty(Lattice *lt, int mode) +{ + LatticeBatchCache *cache = lt->batch_cache; + if (cache == NULL) { + return; + } + switch (mode) { + case BKE_LATTICE_BATCH_DIRTY_ALL: + cache->is_dirty = true; + break; + case BKE_LATTICE_BATCH_DIRTY_SELECT: + /* TODO Separate Flag vbo */ + BATCH_DISCARD_ALL_SAFE(cache->overlay_verts); + break; + default: + BLI_assert(0); + } +} + +static void lattice_batch_cache_clear(Lattice *lt) +{ + LatticeBatchCache *cache = lt->batch_cache; + if (!cache) { + return; + } + + BATCH_DISCARD_SAFE(cache->all_verts); + BATCH_DISCARD_SAFE(cache->all_edges); + BATCH_DISCARD_ALL_SAFE(cache->overlay_verts); + + VERTEXBUFFER_DISCARD_SAFE(cache->pos); + ELEMENTLIST_DISCARD_SAFE(cache->edges); +} + +void DRW_lattice_batch_cache_free(Lattice *lt) +{ + lattice_batch_cache_clear(lt); + MEM_SAFE_FREE(lt->batch_cache); +} + +/* Batch cache usage. */ +static VertexBuffer *lattice_batch_cache_get_pos(LatticeRenderData *rdata, LatticeBatchCache *cache) +{ + BLI_assert(rdata->types & LR_DATATYPE_VERT); + + if (cache->pos == 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 = lattice_render_data_verts_len_get(rdata); + + cache->pos = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(cache->pos, vert_len); + for (int i = 0; i < vert_len; ++i) { + const BPoint *bp = lattice_render_data_vert_bpoint(rdata, i); + VertexBuffer_set_attrib(cache->pos, pos_id, i, bp->vec); + } + } + + return cache->pos; +} + +static ElementList *lattice_batch_cache_get_edges(LatticeRenderData *rdata, LatticeBatchCache *cache) +{ + BLI_assert(rdata->types & (LR_DATATYPE_VERT | LR_DATATYPE_EDGE)); + + if (cache->edges == NULL) { + const int vert_len = lattice_render_data_verts_len_get(rdata); + const int edge_len = lattice_render_data_edges_len_get(rdata); + int edge_len_real = 0; + + ElementListBuilder elb; + ElementListBuilder_init(&elb, PRIM_LINES, edge_len, vert_len); + +#define LATT_INDEX(u, v, w) \ + ((((w) * rdata->dims.v_len + (v)) * rdata->dims.u_len) + (u)) + + for (int w = 0; w < rdata->dims.w_len; w++) { + int wxt = (w == 0 || w == rdata->dims.w_len - 1); + for (int v = 0; v < rdata->dims.v_len; v++) { + int vxt = (v == 0 || v == rdata->dims.v_len - 1); + for (int u = 0; u < rdata->dims.u_len; u++) { + int uxt = (u == 0 || u == rdata->dims.u_len - 1); + + if (w && ((uxt || vxt) || !rdata->show_only_outside)) { + add_line_vertices(&elb, LATT_INDEX(u, v, w - 1), LATT_INDEX(u, v, w)); + BLI_assert(edge_len_real <= edge_len); + edge_len_real++; + } + if (v && ((uxt || wxt) || !rdata->show_only_outside)) { + add_line_vertices(&elb, LATT_INDEX(u, v - 1, w), LATT_INDEX(u, v, w)); + BLI_assert(edge_len_real <= edge_len); + edge_len_real++; + } + if (u && ((vxt || wxt) || !rdata->show_only_outside)) { + add_line_vertices(&elb, LATT_INDEX(u - 1, v, w), LATT_INDEX(u, v, w)); + BLI_assert(edge_len_real <= edge_len); + edge_len_real++; + } + } + } + } + +#undef LATT_INDEX + + if (rdata->show_only_outside) { + BLI_assert(edge_len_real <= edge_len); + } + else { + BLI_assert(edge_len_real == edge_len); + } + + cache->edges = ElementList_build(&elb); + } + + return cache->edges; +} + +static void lattice_batch_cache_create_overlay_batches(Lattice *lt) +{ + /* Since LR_DATATYPE_OVERLAY is slow to generate, generate them all at once */ + int options = LR_DATATYPE_VERT | LR_DATATYPE_OVERLAY; + + LatticeBatchCache *cache = lattice_batch_cache_get(lt); + LatticeRenderData *rdata = lattice_render_data_create(lt, 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); + } + + const int vert_len = lattice_render_data_verts_len_get(rdata); + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, vert_len); + for (int i = 0; i < vert_len; ++i) { + const BPoint *bp = lattice_render_data_vert_bpoint(rdata, i); + + char vflag = 0; + if (bp->f1 & SELECT) { + if (i == rdata->actbp) { + vflag |= VFLAG_VERTEX_ACTIVE; + } + else { + vflag |= VFLAG_VERTEX_SELECTED; + } + } + + VertexBuffer_set_attrib(vbo, pos_id, i, bp->vec); + VertexBuffer_set_attrib(vbo, data_id, i, &vflag); + } + + cache->overlay_verts = Batch_create(PRIM_POINTS, vbo, NULL); + } + + lattice_render_data_free(rdata); +} + +Batch *DRW_lattice_batch_cache_get_all_edges(Lattice *lt) +{ + LatticeBatchCache *cache = lattice_batch_cache_get(lt); + + if (cache->all_edges == NULL) { + /* create batch from Lattice */ + LatticeRenderData *rdata = lattice_render_data_create(lt, LR_DATATYPE_VERT | LR_DATATYPE_EDGE); + + cache->all_edges = Batch_create(PRIM_LINES, lattice_batch_cache_get_pos(rdata, cache), + lattice_batch_cache_get_edges(rdata, cache)); + + lattice_render_data_free(rdata); + } + + return cache->all_edges; +} + +Batch *DRW_lattice_batch_cache_get_all_verts(Lattice *lt) +{ + LatticeBatchCache *cache = lattice_batch_cache_get(lt); + + if (cache->all_verts == NULL) { + LatticeRenderData *rdata = lattice_render_data_create(lt, LR_DATATYPE_VERT); + + cache->all_verts = Batch_create(PRIM_POINTS, lattice_batch_cache_get_pos(rdata, cache), NULL); + + lattice_render_data_free(rdata); + } + + return cache->all_verts; +} + +Batch *DRW_lattice_batch_cache_get_overlay_verts(Lattice *lt) +{ + LatticeBatchCache *cache = lattice_batch_cache_get(lt); + + if (cache->overlay_verts == NULL) { + lattice_batch_cache_create_overlay_batches(lt); + } + + return cache->overlay_verts; +} diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c new file mode 100644 index 00000000000..eaf854edacb --- /dev/null +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -0,0 +1,1448 @@ +/* + * ***** 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. + * + * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file draw_cache_impl_mesh.c + * \ingroup draw + * + * \brief Mesh API for render engines + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" +#include "BKE_editmesh.h" +#include "BKE_mesh.h" + +#include "bmesh.h" + +#include "GPU_batch.h" + +#include "draw_cache_impl.h" /* own include */ + +static void mesh_batch_cache_clear(Mesh *me); + +/* ---------------------------------------------------------------------- */ +/* Mesh/BMesh Interface, direct access to basic data. */ + +static int mesh_render_verts_len_get(Mesh *me) +{ + return me->edit_btmesh ? me->edit_btmesh->bm->totvert : me->totvert; +} + +static int mesh_render_edges_len_get(Mesh *me) +{ + return me->edit_btmesh ? me->edit_btmesh->bm->totedge : me->totedge; +} + +static int mesh_render_looptri_len_get(Mesh *me) +{ + return me->edit_btmesh ? me->edit_btmesh->tottri : poly_to_tri_count(me->totpoly, me->totloop); +} + +static int mesh_render_polys_len_get(Mesh *me) +{ + return me->edit_btmesh ? me->edit_btmesh->bm->totface : me->totpoly; +} + +static int UNUSED_FUNCTION(mesh_render_loops_len_get)(Mesh *me) +{ + return me->edit_btmesh ? me->edit_btmesh->bm->totloop : me->totloop; +} + +/* ---------------------------------------------------------------------- */ +/* Mesh/BMesh Interface, indirect, partially cached access to complex data. */ + +typedef struct EdgeAdjacentPolys { + int count; + int face_index[2]; +} EdgeAdjacentPolys; + +typedef struct EdgeDrawAttr { + unsigned char v_flag; + unsigned char e_flag; + unsigned char crease; + unsigned char bweight; +} EdgeDrawAttr; + +typedef struct MeshRenderData { + int types; + + int vert_len; + int edge_len; + int tri_len; + int loop_len; + int poly_len; + int loose_vert_len; + int loose_edge_len; + + BMEditMesh *edit_bmesh; + MVert *mvert; + MEdge *medge; + MLoop *mloop; + MPoly *mpoly; + + BMVert *eve_act; + BMEdge *eed_act; + BMFace *efa_act; + + int crease_ofs; + int bweight_ofs; + + /* Data created on-demand (usually not for bmesh-based data). */ + EdgeAdjacentPolys *edges_adjacent_polys; + MLoopTri *mlooptri; + int *loose_edges; + int *loose_verts; + + float (*poly_normals)[3]; + short (*poly_normals_short)[3]; + short (*vert_normals_short)[3]; +} MeshRenderData; + +enum { + MR_DATATYPE_VERT = 1 << 0, + MR_DATATYPE_EDGE = 1 << 1, + MR_DATATYPE_LOOPTRI = 1 << 2, + MR_DATATYPE_LOOP = 1 << 3, + MR_DATATYPE_POLY = 1 << 4, + MR_DATATYPE_OVERLAY = 1 << 5, +}; + +/** + * These functions look like they would be slow but they will typically return true on the first iteration. + * Only false when all attached elements are hidden. + */ +static bool bm_vert_has_visible_edge(const BMVert *v) +{ + const BMEdge *e_iter, *e_first; + + e_iter = e_first = v->e; + do { + if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) { + return true; + } + } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first); + return false; +} + +static bool bm_edge_has_visible_face(const BMEdge *e) +{ + const BMLoop *l_iter, *l_first; + l_iter = l_first = e->l; + do { + if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) { + return true; + } + } while ((l_iter = l_iter->radial_next) != l_first); + return false; +} + + +static MeshRenderData *mesh_render_data_create(Mesh *me, const int types) +{ + MeshRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__); + rdata->types = types; + + if (me->edit_btmesh) { + BMEditMesh *embm = me->edit_btmesh; + BMesh *bm = embm->bm; + + rdata->edit_bmesh = embm; + + int bm_ensure_types = 0; + if (types & (MR_DATATYPE_VERT)) { + rdata->vert_len = bm->totvert; + bm_ensure_types |= BM_VERT; + } + if (types & (MR_DATATYPE_EDGE)) { + rdata->edge_len = bm->totedge; + bm_ensure_types |= BM_EDGE; + } + if (types & MR_DATATYPE_LOOPTRI) { + BKE_editmesh_tessface_calc(embm); + rdata->tri_len = embm->tottri; + } + if (types & MR_DATATYPE_LOOP) { + rdata->loop_len = bm->totloop; + bm_ensure_types |= BM_LOOP; + } + if (types & MR_DATATYPE_POLY) { + rdata->poly_len = bm->totface; + bm_ensure_types |= BM_FACE; + } + if (types & MR_DATATYPE_OVERLAY) { + rdata->efa_act = BM_mesh_active_face_get(bm, false, true); + rdata->eed_act = BM_mesh_active_edge_get(bm); + rdata->eve_act = BM_mesh_active_vert_get(bm); + rdata->crease_ofs = CustomData_get_offset(&bm->edata, CD_CREASE); + rdata->bweight_ofs = CustomData_get_offset(&bm->edata, CD_BWEIGHT); + } + BM_mesh_elem_index_ensure(bm, bm_ensure_types); + BM_mesh_elem_table_ensure(bm, bm_ensure_types & ~BM_LOOP); + if (types & MR_DATATYPE_OVERLAY) { + rdata->loose_vert_len = rdata->loose_edge_len = 0; + + int *lverts = rdata->loose_verts = MEM_mallocN(rdata->vert_len * sizeof(int), "Loose Vert"); + int *ledges = rdata->loose_edges = MEM_mallocN(rdata->edge_len * sizeof(int), "Loose Edges"); + + { + BLI_assert((bm->elem_table_dirty & BM_VERT) == 0); + BMVert **vtable = bm->vtable; + for (int i = 0; i < bm->totvert; i++) { + const BMVert *v = vtable[i]; + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + /* Loose vert */ + if (v->e == NULL || !bm_vert_has_visible_edge(v)) { + lverts[rdata->loose_vert_len++] = i; + } + } + } + } + + { + BLI_assert((bm->elem_table_dirty & BM_EDGE) == 0); + BMEdge **etable = bm->etable; + for (int i = 0; i < bm->totedge; i++) { + const BMEdge *e = etable[i]; + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + /* Loose edge */ + if (e->l == NULL || !bm_edge_has_visible_face(e)) { + ledges[rdata->loose_edge_len++] = i; + } + } + } + } + + rdata->loose_verts = MEM_reallocN(rdata->loose_verts, rdata->loose_vert_len * sizeof(int)); + rdata->loose_edges = MEM_reallocN(rdata->loose_edges, rdata->loose_edge_len * sizeof(int)); + } + } + else { + if (types & (MR_DATATYPE_VERT)) { + rdata->vert_len = me->totvert; + rdata->mvert = CustomData_get_layer(&me->vdata, CD_MVERT); + } + if (types & (MR_DATATYPE_EDGE)) { + rdata->edge_len = me->totedge; + rdata->medge = CustomData_get_layer(&me->edata, CD_MEDGE); + } + if (types & MR_DATATYPE_LOOPTRI) { + const int tri_len = rdata->tri_len = poly_to_tri_count(me->totpoly, me->totloop); + rdata->mlooptri = MEM_mallocN(sizeof(*rdata->mlooptri) * tri_len, __func__); + BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, rdata->mlooptri); + } + if (types & MR_DATATYPE_LOOP) { + rdata->loop_len = me->totloop; + rdata->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP); + } + if (types & MR_DATATYPE_POLY) { + rdata->poly_len = me->totpoly; + rdata->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY); + } + } + + return rdata; +} + +static void mesh_render_data_free(MeshRenderData *rdata) +{ + if (rdata->loose_verts) { + MEM_freeN(rdata->loose_verts); + } + if (rdata->loose_edges) { + MEM_freeN(rdata->loose_edges); + } + if (rdata->edges_adjacent_polys) { + MEM_freeN(rdata->edges_adjacent_polys); + } + if (rdata->mlooptri) { + MEM_freeN(rdata->mlooptri); + } + if (rdata->poly_normals) { + MEM_freeN(rdata->poly_normals); + } + if (rdata->poly_normals_short) { + MEM_freeN(rdata->poly_normals_short); + } + if (rdata->vert_normals_short) { + MEM_freeN(rdata->vert_normals_short); + } + MEM_freeN(rdata); +} + +static int mesh_render_data_verts_len_get(const MeshRenderData *rdata) +{ + BLI_assert(rdata->types & MR_DATATYPE_VERT); + return rdata->vert_len; +} + +static int mesh_render_data_loose_verts_len_get(const MeshRenderData *rdata) +{ + BLI_assert(rdata->types & MR_DATATYPE_OVERLAY); + return rdata->loose_vert_len; +} + +static int mesh_render_data_edges_len_get(const MeshRenderData *rdata) +{ + BLI_assert(rdata->types & MR_DATATYPE_EDGE); + return rdata->edge_len; +} + +static int mesh_render_data_loose_edges_len_get(const MeshRenderData *rdata) +{ + BLI_assert(rdata->types & MR_DATATYPE_OVERLAY); + return rdata->loose_edge_len; +} + +static int mesh_render_data_looptri_len_get(const MeshRenderData *rdata) +{ + BLI_assert(rdata->types & MR_DATATYPE_LOOPTRI); + return rdata->tri_len; +} + +static int UNUSED_FUNCTION(mesh_render_data_loops_len_get)(const MeshRenderData *rdata) +{ + BLI_assert(rdata->types & MR_DATATYPE_LOOP); + return rdata->loop_len; +} + +static int mesh_render_data_polys_len_get(const MeshRenderData *rdata) +{ + BLI_assert(rdata->types & MR_DATATYPE_POLY); + return rdata->poly_len; +} + +static float *mesh_render_data_vert_co(const MeshRenderData *rdata, const int vert_idx) +{ + BLI_assert(rdata->types & MR_DATATYPE_VERT); + + if (rdata->edit_bmesh) { + BMesh *bm = rdata->edit_bmesh->bm; + BMVert *bv = BM_vert_at_index(bm, vert_idx); + return bv->co; + } + else { + return rdata->mvert[vert_idx].co; + } +} + +static short *mesh_render_data_vert_nor(const MeshRenderData *rdata, const int vert_idx) +{ + BLI_assert(rdata->types & MR_DATATYPE_VERT); + + if (rdata->edit_bmesh) { + static short fno[3]; + BMesh *bm = rdata->edit_bmesh->bm; + BMVert *bv = BM_vert_at_index(bm, vert_idx); + normal_float_to_short_v3(fno, bv->no); + return fno; + } + else { + return rdata->mvert[vert_idx].no; + } +} + +static bool mesh_render_data_edge_verts_indices_get( + const MeshRenderData *rdata, const int edge_idx, + int r_vert_idx[2]) +{ + BLI_assert(rdata->types & MR_DATATYPE_EDGE); + + if (rdata->edit_bmesh) { + const BMEdge *bm_edge = BM_edge_at_index(rdata->edit_bmesh->bm, edge_idx); + if (BM_elem_flag_test(bm_edge, BM_ELEM_HIDDEN)) { + return false; + } + r_vert_idx[0] = BM_elem_index_get(bm_edge->v1); + r_vert_idx[1] = BM_elem_index_get(bm_edge->v2); + } + else { + const MEdge *me = &rdata->medge[edge_idx]; + r_vert_idx[0] = me->v1; + r_vert_idx[1] = me->v2; + } + return true; +} + +static bool mesh_render_data_pnors_pcenter_select_get( + MeshRenderData *rdata, const int poly, + float r_pnors[3], float r_center[3], bool *r_selected) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); + + if (rdata->edit_bmesh) { + const BMFace *bf = BM_face_at_index(rdata->edit_bmesh->bm, poly); + if (BM_elem_flag_test(bf, BM_ELEM_HIDDEN)) { + return false; + } + BM_face_calc_center_mean(bf, r_center); + BM_face_calc_normal(bf, r_pnors); + *r_selected = (BM_elem_flag_test(bf, BM_ELEM_SELECT) != 0) ? true : false; + } + else { + MVert *mvert = rdata->mvert; + const MPoly *mpoly = rdata->mpoly + poly; + const MLoop *mloop = rdata->mloop + mpoly->loopstart; + + BKE_mesh_calc_poly_center(mpoly, mloop, mvert, r_center); + BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, r_pnors); + + *r_selected = false; /* No selection if not in edit mode */ + } + + return true; +} + +static bool mesh_render_data_edge_vcos_manifold_pnors( + MeshRenderData *rdata, const int edge_index, + float **r_vco1, float **r_vco2, float **r_pnor1, float **r_pnor2, bool *r_is_manifold) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); + + if (rdata->edit_bmesh) { + BMesh *bm = rdata->edit_bmesh->bm; + BMEdge *bm_edge = BM_edge_at_index(bm, edge_index); + if (BM_elem_flag_test(bm_edge, BM_ELEM_HIDDEN)) { + return false; + } + *r_vco1 = bm_edge->v1->co; + *r_vco2 = bm_edge->v2->co; + if (BM_edge_is_manifold(bm_edge)) { + *r_pnor1 = bm_edge->l->f->no; + *r_pnor2 = bm_edge->l->radial_next->f->no; + *r_is_manifold = true; + } + else { + *r_is_manifold = false; + } + } + else { + MVert *mvert = rdata->mvert; + MEdge *medge = rdata->medge; + EdgeAdjacentPolys *eap = rdata->edges_adjacent_polys; + float (*pnors)[3] = rdata->poly_normals; + + if (!eap) { + const MLoop *mloop = rdata->mloop; + const MPoly *mpoly = rdata->mpoly; + const int poly_len = rdata->poly_len; + const bool do_pnors = (pnors == NULL); + + eap = rdata->edges_adjacent_polys = MEM_callocN(sizeof(*eap) * rdata->edge_len, __func__); + if (do_pnors) { + pnors = rdata->poly_normals = MEM_mallocN(sizeof(*pnors) * poly_len, __func__); + } + + for (int i = 0; i < poly_len; i++, mpoly++) { + if (do_pnors) { + BKE_mesh_calc_poly_normal(mpoly, mloop + mpoly->loopstart, mvert, pnors[i]); + } + + const int loopend = mpoly->loopstart + mpoly->totloop; + for (int j = mpoly->loopstart; j < loopend; j++) { + const int edge_idx = mloop[j].e; + if (eap[edge_idx].count < 2) { + eap[edge_idx].face_index[eap[edge_idx].count] = i; + } + eap[edge_idx].count++; + } + } + } + BLI_assert(eap && pnors); + + *r_vco1 = mvert[medge[edge_index].v1].co; + *r_vco2 = mvert[medge[edge_index].v2].co; + if (eap[edge_index].count == 2) { + *r_pnor1 = pnors[eap[edge_index].face_index[0]]; + *r_pnor2 = pnors[eap[edge_index].face_index[1]]; + *r_is_manifold = true; + } + else { + *r_is_manifold = false; + } + } + + return true; +} + +static bool mesh_render_data_looptri_vert_indices_get( + const MeshRenderData *rdata, const int tri_idx, + int r_vert_idx[3]) +{ + BLI_assert(rdata->types & (MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP)); + + if (rdata->edit_bmesh) { + const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[tri_idx]; + if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) { + return false; + } + r_vert_idx[0] = BM_elem_index_get(bm_looptri[0]->v); + r_vert_idx[1] = BM_elem_index_get(bm_looptri[1]->v); + r_vert_idx[2] = BM_elem_index_get(bm_looptri[2]->v); + } + else { + const unsigned int *l_idx = rdata->mlooptri[tri_idx].tri; + const MLoop *l_tri[3] = {&rdata->mloop[l_idx[0]], &rdata->mloop[l_idx[1]], &rdata->mloop[l_idx[2]]}; + r_vert_idx[0] = l_tri[0]->v; + r_vert_idx[1] = l_tri[1]->v; + r_vert_idx[2] = l_tri[2]->v; + } + + return true; +} + +/** + * Version of #mesh_render_data_looptri_verts_indices_get that assigns + * edge indices too \a r_edges_idx (-1 for non-existant edges). + */ +static bool mesh_render_data_looptri_vert_edge_indices_get( + const MeshRenderData *rdata, const int tri_idx, + int r_vert_idx[3], int r_edges_idx[3]) +{ + BLI_assert(rdata->types & (MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP)); + + unsigned int e_pair_edge[2]; + unsigned int e_pair_loop[2]; + + if (rdata->edit_bmesh) { + const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[tri_idx]; + + if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) { + return false; + } + + /* assign 'r_edges_idx' & 'r_vert_idx' */ + int j, j_next; + for (j = 2, j_next = 0; j_next < 3; j = j_next++) { + const BMLoop *l = bm_looptri[j], *l_next = bm_looptri[j_next]; + const BMEdge *e = l->e; + ARRAY_SET_ITEMS(e_pair_edge, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2)); + ARRAY_SET_ITEMS(e_pair_loop, BM_elem_index_get(l->v), BM_elem_index_get(l_next->v)); + if ((e_pair_edge[0] == e_pair_loop[0] && e_pair_edge[1] == e_pair_loop[1]) || + (e_pair_edge[0] == e_pair_loop[1] && e_pair_edge[1] == e_pair_loop[0])) + { + r_edges_idx[j] = BM_elem_index_get(l->e); + } + else { + r_edges_idx[j] = -1; + } + r_vert_idx[j] = e_pair_loop[0]; /* BM_elem_index_get(l->v) */ + } + } + else { + const unsigned int *l_idx = rdata->mlooptri[tri_idx].tri; + const MLoop *l_tri[3] = {&rdata->mloop[l_idx[0]], &rdata->mloop[l_idx[1]], &rdata->mloop[l_idx[2]]}; + + /* assign 'r_edges_idx' & 'r_vert_idx' */ + int j, j_next; + for (j = 2, j_next = 0; j_next < 3; j = j_next++) { + const MLoop *l = l_tri[j], *l_next = l_tri[j_next]; + const MEdge *e = &rdata->medge[l->e]; \ + ARRAY_SET_ITEMS(e_pair_edge, e->v1, e->v2); + ARRAY_SET_ITEMS(e_pair_loop, l->v, l_next->v); + if ((e_pair_edge[0] == e_pair_loop[0] && e_pair_edge[1] == e_pair_loop[1]) || + (e_pair_edge[0] == e_pair_loop[1] && e_pair_edge[1] == e_pair_loop[0])) + { + r_edges_idx[j] = l->e; + } + else { + r_edges_idx[j] = -1; + } + r_vert_idx[j] = e_pair_loop[0]; /* l->v */ + } + } + + return true; +} + +static bool mesh_render_data_looptri_cos_nors_smooth_get( + MeshRenderData *rdata, const int tri_idx, + float *(*r_vert_cos)[3], short **r_tri_nor, short *(*r_vert_nors)[3], bool *r_is_smooth) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); + + if (rdata->edit_bmesh) { + const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[tri_idx]; + + if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) { + return false; + } + + short (*pnors_short)[3] = rdata->poly_normals_short; + short (*vnors_short)[3] = rdata->vert_normals_short; + + if (!pnors_short) { + BMesh *bm = rdata->edit_bmesh->bm; + BMIter fiter; + BMFace *face; + int i; + + pnors_short = rdata->poly_normals_short = MEM_mallocN(sizeof(*pnors_short) * rdata->poly_len, __func__); + BM_ITER_MESH_INDEX(face, &fiter, bm, BM_FACES_OF_MESH, i) { + normal_float_to_short_v3(pnors_short[i], face->no); + } + } + if (!vnors_short) { + BMesh *bm = rdata->edit_bmesh->bm; + BMIter viter; + BMVert *vert; + int i; + + vnors_short = rdata->vert_normals_short = MEM_mallocN(sizeof(*vnors_short) * rdata->vert_len, __func__); + BM_ITER_MESH_INDEX(vert, &viter, bm, BM_VERT, i) { + normal_float_to_short_v3(vnors_short[i], vert->no); + } + } + + (*r_vert_cos)[0] = bm_looptri[0]->v->co; + (*r_vert_cos)[1] = bm_looptri[1]->v->co; + (*r_vert_cos)[2] = bm_looptri[2]->v->co; + *r_tri_nor = pnors_short[BM_elem_index_get(bm_looptri[0]->f)]; + (*r_vert_nors)[0] = vnors_short[BM_elem_index_get(bm_looptri[0]->v)]; + (*r_vert_nors)[1] = vnors_short[BM_elem_index_get(bm_looptri[1]->v)]; + (*r_vert_nors)[2] = vnors_short[BM_elem_index_get(bm_looptri[2]->v)]; + + *r_is_smooth = BM_elem_flag_test_bool(bm_looptri[0]->f, BM_ELEM_SMOOTH); + } + else { + const MLoopTri *mlt = &rdata->mlooptri[tri_idx]; + short (*pnors_short)[3] = rdata->poly_normals_short; + + if (!pnors_short) { + float (*pnors)[3] = rdata->poly_normals; + + if (!pnors) { + pnors = rdata->poly_normals = MEM_mallocN(sizeof(*pnors) * rdata->poly_len, __func__); + BKE_mesh_calc_normals_poly( + rdata->mvert, NULL, rdata->vert_len, + rdata->mloop, rdata->mpoly, rdata->loop_len, rdata->poly_len, pnors, true); + } + + pnors_short = rdata->poly_normals_short = MEM_mallocN(sizeof(*pnors_short) * rdata->poly_len, __func__); + for (int i = 0; i < rdata->poly_len; i++) { + normal_float_to_short_v3(pnors_short[i], pnors[i]); + } + } + + (*r_vert_cos)[0] = rdata->mvert[rdata->mloop[mlt->tri[0]].v].co; + (*r_vert_cos)[1] = rdata->mvert[rdata->mloop[mlt->tri[1]].v].co; + (*r_vert_cos)[2] = rdata->mvert[rdata->mloop[mlt->tri[2]].v].co; + *r_tri_nor = pnors_short[mlt->poly]; + (*r_vert_nors)[0] = rdata->mvert[rdata->mloop[mlt->tri[0]].v].no; + (*r_vert_nors)[1] = rdata->mvert[rdata->mloop[mlt->tri[1]].v].no; + (*r_vert_nors)[2] = rdata->mvert[rdata->mloop[mlt->tri[2]].v].no; + + *r_is_smooth = (rdata->mpoly[mlt->poly].flag & ME_SMOOTH) != 0; + } + return true; +} + +/* First 2 bytes are bit flags + * 3rd is for sharp edges + * 4rd is for creased edges */ +enum { + VFLAG_VERTEX_ACTIVE = 1 << 0, + VFLAG_VERTEX_SELECTED = 1 << 1, + VFLAG_FACE_ACTIVE = 1 << 2, + VFLAG_FACE_SELECTED = 1 << 3, +}; + +enum { + VFLAG_EDGE_EXISTS = 1 << 0, + VFLAG_EDGE_ACTIVE = 1 << 1, + VFLAG_EDGE_SELECTED = 1 << 2, + VFLAG_EDGE_SEAM = 1 << 3, + VFLAG_EDGE_SHARP = 1 << 4, + /* Beware to not go over 1 << 7 + * (see gpu_shader_edit_mesh_overlay_geom.glsl) */ +}; + +static unsigned char mesh_render_data_looptri_flag(MeshRenderData *rdata, const int f) +{ + unsigned char fflag = 0; + + if (rdata->edit_bmesh) { + BMFace *bf = rdata->edit_bmesh->looptris[f][0]->f; + + if (bf == rdata->efa_act) + fflag |= VFLAG_FACE_ACTIVE; + + if (BM_elem_flag_test(bf, BM_ELEM_SELECT)) + fflag |= VFLAG_FACE_SELECTED; + } + + return fflag; +} + +static EdgeDrawAttr *mesh_render_data_edge_flag(MeshRenderData *rdata, const int e) +{ + static EdgeDrawAttr eattr; + memset(&eattr, 0, sizeof(eattr)); + + if (e == -1) { + return &eattr; + } + + /* if edge exists */ + if (rdata->edit_bmesh) { + BMesh *bm = rdata->edit_bmesh->bm; + BMEdge *be = NULL; + + be = BM_edge_at_index(bm, e); + + eattr.e_flag |= VFLAG_EDGE_EXISTS; + + if (be == rdata->eed_act) + eattr.e_flag |= VFLAG_EDGE_ACTIVE; + + if (BM_elem_flag_test(be, BM_ELEM_SELECT)) + eattr.e_flag |= VFLAG_EDGE_SELECTED; + + if (BM_elem_flag_test(be, BM_ELEM_SEAM)) + eattr.e_flag |= VFLAG_EDGE_SEAM; + + if (!BM_elem_flag_test(be, BM_ELEM_SMOOTH)) + eattr.e_flag |= VFLAG_EDGE_SHARP; + + /* Use a byte for value range */ + if (rdata->crease_ofs != -1) { + float crease = BM_ELEM_CD_GET_FLOAT(be, rdata->crease_ofs); + if (crease > 0) { + eattr.crease = (char)(crease * 255.0f); + } + } + + /* Use a byte for value range */ + if (rdata->bweight_ofs != -1) { + float bweight = BM_ELEM_CD_GET_FLOAT(be, rdata->bweight_ofs); + if (bweight > 0) { + eattr.bweight = (char)(bweight * 255.0f); + } + } + } + else { + eattr.e_flag |= VFLAG_EDGE_EXISTS; + } + + return &eattr; +} + +static unsigned char mesh_render_data_vertex_flag(MeshRenderData *rdata, const int v) +{ + + unsigned char vflag = 0; + + if (rdata->edit_bmesh) { + BMesh *bm = rdata->edit_bmesh->bm; + BMVert *bv = BM_vert_at_index(bm, v); + + /* Current vertex */ + if (bv == rdata->eve_act) + vflag |= VFLAG_VERTEX_ACTIVE; + + if (BM_elem_flag_test(bv, BM_ELEM_SELECT)) + vflag |= VFLAG_VERTEX_SELECTED; + } + + return vflag; +} + +static void add_overlay_tri( + MeshRenderData *rdata, VertexBuffer *vbo, const unsigned int pos_id, const unsigned int edgeMod_id, + const int tri_vert_idx[3], const int tri_edge_idx[3], const int f, const int base_vert_idx) +{ + const float *pos; + EdgeDrawAttr *eattr; + unsigned char fflag; + unsigned char vflag; + + pos = mesh_render_data_vert_co(rdata, tri_vert_idx[0]); + eattr = mesh_render_data_edge_flag(rdata, tri_edge_idx[1]); + fflag = mesh_render_data_looptri_flag(rdata, f); + vflag = mesh_render_data_vertex_flag(rdata, tri_vert_idx[0]); + eattr->v_flag = fflag | vflag; + VertexBuffer_set_attrib(vbo, pos_id, base_vert_idx + 0, pos); + VertexBuffer_set_attrib(vbo, edgeMod_id, base_vert_idx + 0, eattr); + + pos = mesh_render_data_vert_co(rdata, tri_vert_idx[1]); + eattr = mesh_render_data_edge_flag(rdata, tri_edge_idx[2]); + vflag = mesh_render_data_vertex_flag(rdata, tri_vert_idx[1]); + eattr->v_flag = fflag | vflag; + VertexBuffer_set_attrib(vbo, pos_id, base_vert_idx + 1, pos); + VertexBuffer_set_attrib(vbo, edgeMod_id, base_vert_idx + 1, eattr); + + pos = mesh_render_data_vert_co(rdata, tri_vert_idx[2]); + eattr = mesh_render_data_edge_flag(rdata, tri_edge_idx[0]); + vflag = mesh_render_data_vertex_flag(rdata, tri_vert_idx[2]); + eattr->v_flag = fflag | vflag; + VertexBuffer_set_attrib(vbo, pos_id, base_vert_idx + 2, pos); + VertexBuffer_set_attrib(vbo, edgeMod_id, base_vert_idx + 2, eattr); +} + +static void add_overlay_loose_edge( + MeshRenderData *rdata, VertexBuffer *vbo, const unsigned int pos_id, const unsigned int edgeMod_id, + const int v1, const int v2, const int e, const int base_vert_idx) +{ + EdgeDrawAttr *eattr = mesh_render_data_edge_flag(rdata, e); + const float *pos = mesh_render_data_vert_co(rdata, v1); + eattr->v_flag = mesh_render_data_vertex_flag(rdata, v1); + VertexBuffer_set_attrib(vbo, pos_id, base_vert_idx + 0, pos); + VertexBuffer_set_attrib(vbo, edgeMod_id, base_vert_idx + 0, eattr); + + pos = mesh_render_data_vert_co(rdata, v2); + eattr->v_flag = mesh_render_data_vertex_flag(rdata, v2); + VertexBuffer_set_attrib(vbo, pos_id, base_vert_idx + 1, pos); + VertexBuffer_set_attrib(vbo, edgeMod_id, base_vert_idx + 1, eattr); +} + +static void add_overlay_loose_vert( + MeshRenderData *rdata, VertexBuffer *vbo, const unsigned int pos_id, const unsigned int edgeMod_id, + const int v, const int base_vert_idx) +{ + unsigned char vflag[4] = {0, 0, 0, 0}; + const float *pos = mesh_render_data_vert_co(rdata, v); + vflag[0] = mesh_render_data_vertex_flag(rdata, v); + VertexBuffer_set_attrib(vbo, pos_id, base_vert_idx + 0, pos); + VertexBuffer_set_attrib(vbo, edgeMod_id, base_vert_idx + 0, vflag); +} + +/* ---------------------------------------------------------------------- */ +/* Mesh Batch Cache */ + +typedef struct MeshBatchCache { + VertexBuffer *pos_in_order; + VertexBuffer *nor_in_order; + ElementList *edges_in_order; + ElementList *triangles_in_order; + + Batch *all_verts; + Batch *all_edges; + Batch *all_triangles; + + VertexBuffer *pos_with_normals; + Batch *triangles_with_normals; + Batch *points_with_normals; + Batch *fancy_edges; /* owns its vertex buffer (not shared) */ + + /* TODO : split in 2 buffers to avoid unnecessary + * data transfer when selecting/deselecting + * and combine into one batch and use offsets to render + * Tri / edges / verts separately */ + Batch *overlay_triangles; + Batch *overlay_loose_verts; + Batch *overlay_loose_edges; + Batch *overlay_facedots; + + /* settings to determine if cache is invalid */ + bool is_dirty; + int edge_len; + int tri_len; + int poly_len; + int vert_len; + bool is_editmode; +} MeshBatchCache; + +/* Batch cache management. */ + +static bool mesh_batch_cache_valid(Mesh *me) +{ + MeshBatchCache *cache = me->batch_cache; + + if (cache == NULL) { + return false; + } + + if (cache->is_editmode != (me->edit_btmesh != NULL)) { + return false; + } + + if (cache->is_dirty == false) { + return true; + } + else { + if (cache->is_editmode) { + return false; + } + else if ((cache->vert_len != mesh_render_verts_len_get(me)) || + (cache->edge_len != mesh_render_edges_len_get(me)) || + (cache->tri_len != mesh_render_looptri_len_get(me)) || + (cache->poly_len != mesh_render_polys_len_get(me))) + { + return false; + } + } + + return true; +} + +static void mesh_batch_cache_init(Mesh *me) +{ + MeshBatchCache *cache = me->batch_cache; + + if (!cache) { + cache = me->batch_cache = MEM_callocN(sizeof(*cache), __func__); + } + else { + memset(cache, 0, sizeof(*cache)); + } + + cache->is_editmode = me->edit_btmesh != NULL; + + if (cache->is_editmode == false) { + cache->edge_len = mesh_render_edges_len_get(me); + cache->tri_len = mesh_render_looptri_len_get(me); + cache->poly_len = mesh_render_polys_len_get(me); + cache->vert_len = mesh_render_verts_len_get(me); + } + + cache->is_dirty = false; +} + +static MeshBatchCache *mesh_batch_cache_get(Mesh *me) +{ + if (!mesh_batch_cache_valid(me)) { + mesh_batch_cache_clear(me); + mesh_batch_cache_init(me); + } + return me->batch_cache; +} + +void DRW_mesh_batch_cache_dirty(Mesh *me, int mode) +{ + MeshBatchCache *cache = me->batch_cache; + if (cache == NULL) { + return; + } + switch (mode) { + case BKE_MESH_BATCH_DIRTY_ALL: + cache->is_dirty = true; + break; + case BKE_MESH_BATCH_DIRTY_SELECT: + /* TODO Separate Flag vbo */ + BATCH_DISCARD_ALL_SAFE(cache->overlay_triangles); + BATCH_DISCARD_ALL_SAFE(cache->overlay_loose_verts); + BATCH_DISCARD_ALL_SAFE(cache->overlay_loose_edges); + BATCH_DISCARD_ALL_SAFE(cache->overlay_facedots); + break; + default: + BLI_assert(0); + } +} + +static void mesh_batch_cache_clear(Mesh *me) +{ + MeshBatchCache *cache = me->batch_cache; + if (!cache) { + return; + } + + BATCH_DISCARD_SAFE(cache->all_verts); + BATCH_DISCARD_SAFE(cache->all_edges); + BATCH_DISCARD_SAFE(cache->all_triangles); + + VERTEXBUFFER_DISCARD_SAFE(cache->pos_in_order); + ELEMENTLIST_DISCARD_SAFE(cache->edges_in_order); + ELEMENTLIST_DISCARD_SAFE(cache->triangles_in_order); + + BATCH_DISCARD_ALL_SAFE(cache->overlay_triangles); + BATCH_DISCARD_ALL_SAFE(cache->overlay_loose_verts); + BATCH_DISCARD_ALL_SAFE(cache->overlay_loose_edges); + BATCH_DISCARD_ALL_SAFE(cache->overlay_facedots); + + BATCH_DISCARD_SAFE(cache->triangles_with_normals); + BATCH_DISCARD_SAFE(cache->points_with_normals); + VERTEXBUFFER_DISCARD_SAFE(cache->pos_with_normals); + + BATCH_DISCARD_ALL_SAFE(cache->fancy_edges); +} + +void DRW_mesh_batch_cache_free(Mesh *me) +{ + mesh_batch_cache_clear(me); + MEM_SAFE_FREE(me->batch_cache); +} + +/* Batch cache usage. */ + +static VertexBuffer *mesh_batch_cache_get_pos_and_normals(MeshRenderData *rdata, MeshBatchCache *cache) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); + + if (cache->pos_with_normals == NULL) { + unsigned int vidx = 0, nidx = 0; + + static VertexFormat format = { 0 }; + static unsigned int pos_id, nor_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); + nor_id = VertexFormat_add_attrib(&format, "nor", COMP_I16, 3, NORMALIZE_INT_TO_FLOAT); + } + + const int tri_len = mesh_render_data_looptri_len_get(rdata); + + VertexBuffer *vbo = cache->pos_with_normals = VertexBuffer_create_with_format(&format); + + const int vbo_len_capacity = tri_len * 3; + int vbo_len_used = 0; + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + + for (int i = 0; i < tri_len; i++) { + float *tri_vert_cos[3]; + short *tri_nor, *tri_vert_nors[3]; + bool is_smooth; + + if (mesh_render_data_looptri_cos_nors_smooth_get( + rdata, i, &tri_vert_cos, &tri_nor, &tri_vert_nors, &is_smooth)) + { + if (is_smooth) { + VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_vert_nors[0]); + VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_vert_nors[1]); + VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_vert_nors[2]); + } + else { + VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_nor); + VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_nor); + VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_nor); + } + + VertexBuffer_set_attrib(vbo, pos_id, vidx++, tri_vert_cos[0]); + VertexBuffer_set_attrib(vbo, pos_id, vidx++, tri_vert_cos[1]); + VertexBuffer_set_attrib(vbo, pos_id, vidx++, tri_vert_cos[2]); + } + } + vbo_len_used = vidx; + + if (vbo_len_capacity != vbo_len_used) { + VertexBuffer_resize_data(vbo, vbo_len_used); + } + } + return cache->pos_with_normals; +} +static VertexBuffer *mesh_batch_cache_get_pos_and_nor_in_order(MeshRenderData *rdata, MeshBatchCache *cache) +{ + BLI_assert(rdata->types & MR_DATATYPE_VERT); + + if (cache->pos_in_order == NULL) { + static VertexFormat format = { 0 }; + static unsigned pos_id, nor_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); + nor_id = VertexFormat_add_attrib(&format, "nor", COMP_I16, 3, NORMALIZE_INT_TO_FLOAT); + } + + VertexBuffer *vbo = cache->pos_in_order = VertexBuffer_create_with_format(&format); + const int vbo_len_capacity = mesh_render_data_verts_len_get(rdata); + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + for (int i = 0; i < vbo_len_capacity; ++i) { + VertexBuffer_set_attrib(vbo, pos_id, i, mesh_render_data_vert_co(rdata, i)); + VertexBuffer_set_attrib(vbo, nor_id, i, mesh_render_data_vert_nor(rdata, i)); + } + } + + return cache->pos_in_order; +} + +static ElementList *mesh_batch_cache_get_edges_in_order(MeshRenderData *rdata, MeshBatchCache *cache) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE)); + + if (cache->edges_in_order == NULL) { + printf("Caching edges in order...\n"); + const int vert_len = mesh_render_data_verts_len_get(rdata); + const int edge_len = mesh_render_data_edges_len_get(rdata); + + ElementListBuilder elb; + ElementListBuilder_init(&elb, PRIM_LINES, edge_len, vert_len); + for (int i = 0; i < edge_len; ++i) { + int vert_idx[2]; + if (mesh_render_data_edge_verts_indices_get(rdata, i, vert_idx)) { + add_line_vertices(&elb, vert_idx[0], vert_idx[1]); + } + } + cache->edges_in_order = ElementList_build(&elb); + } + + return cache->edges_in_order; +} + +static ElementList *mesh_batch_cache_get_triangles_in_order(MeshRenderData *rdata, MeshBatchCache *cache) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI)); + + if (cache->triangles_in_order == NULL) { + const int vert_len = mesh_render_data_verts_len_get(rdata); + const int tri_len = mesh_render_data_looptri_len_get(rdata); + + ElementListBuilder elb; + ElementListBuilder_init(&elb, PRIM_TRIANGLES, tri_len, vert_len); + for (int i = 0; i < tri_len; ++i) { + int tri_vert_idx[3]; + if (mesh_render_data_looptri_vert_indices_get(rdata, i, tri_vert_idx)) { + add_triangle_vertices(&elb, tri_vert_idx[0], tri_vert_idx[1], tri_vert_idx[2]); + } + } + cache->triangles_in_order = ElementList_build(&elb); + } + + return cache->triangles_in_order; +} + +Batch *DRW_mesh_batch_cache_get_all_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->all_edges == NULL) { + /* create batch from Mesh */ + MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_EDGE); + + cache->all_edges = Batch_create(PRIM_LINES, mesh_batch_cache_get_pos_and_nor_in_order(rdata, cache), + mesh_batch_cache_get_edges_in_order(rdata, cache)); + + mesh_render_data_free(rdata); + } + + return cache->all_edges; +} + +Batch *DRW_mesh_batch_cache_get_all_triangles(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->all_triangles == NULL) { + /* create batch from DM */ + MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI); + + cache->all_triangles = Batch_create(PRIM_TRIANGLES, mesh_batch_cache_get_pos_and_nor_in_order(rdata, cache), + mesh_batch_cache_get_triangles_in_order(rdata, cache)); + + mesh_render_data_free(rdata); + } + + return cache->all_triangles; +} + +Batch *DRW_mesh_batch_cache_get_triangles_with_normals(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->triangles_with_normals == NULL) { + MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY); + + cache->triangles_with_normals = Batch_create(PRIM_TRIANGLES, mesh_batch_cache_get_pos_and_normals(rdata, cache), NULL); + + mesh_render_data_free(rdata); + } + + return cache->triangles_with_normals; +} + +Batch *DRW_mesh_batch_cache_get_points_with_normals(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->points_with_normals == NULL) { + MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY); + + cache->points_with_normals = Batch_create(PRIM_POINTS, mesh_batch_cache_get_pos_and_normals(rdata, cache), NULL); + + mesh_render_data_free(rdata); + } + + return cache->points_with_normals; +} + +Batch *DRW_mesh_batch_cache_get_all_verts(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->all_verts == NULL) { + /* create batch from DM */ + MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT); + + cache->all_verts = Batch_create(PRIM_POINTS, mesh_batch_cache_get_pos_and_nor_in_order(rdata, cache), NULL); + + mesh_render_data_free(rdata); + } + + return cache->all_verts; +} + +Batch *DRW_mesh_batch_cache_get_fancy_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->fancy_edges == NULL) { + /* create batch from DM */ + static VertexFormat format = { 0 }; + static unsigned int pos_id, n1_id, n2_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); + +#if USE_10_10_10 /* takes 1/3 the space */ + n1_id = VertexFormat_add_attrib(&format, "N1", COMP_I10, 3, NORMALIZE_INT_TO_FLOAT); + n2_id = VertexFormat_add_attrib(&format, "N2", COMP_I10, 3, NORMALIZE_INT_TO_FLOAT); +#else + n1_id = VertexFormat_add_attrib(&format, "N1", COMP_F32, 3, KEEP_FLOAT); + n2_id = VertexFormat_add_attrib(&format, "N2", COMP_F32, 3, KEEP_FLOAT); +#endif + } + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + + MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_POLY); + + const int edge_len = mesh_render_data_edges_len_get(rdata); + + const int vbo_len_capacity = edge_len * 2; /* these are PRIM_LINE verts, not mesh verts */ + int vbo_len_used = 0; + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + for (int i = 0; i < edge_len; ++i) { + float *vcos1, *vcos2; + float *pnor1 = NULL, *pnor2 = NULL; + bool is_manifold; + + if (mesh_render_data_edge_vcos_manifold_pnors(rdata, i, &vcos1, &vcos2, &pnor1, &pnor2, &is_manifold)) { + +#if USE_10_10_10 + PackedNormal n1value = { .x = 0, .y = 0, .z = +511 }; + PackedNormal n2value = { .x = 0, .y = 0, .z = -511 }; + + if (is_manifold) { + n1value = convert_i10_v3(pnor1); + n2value = convert_i10_v3(pnor2); + } + + const PackedNormal *n1 = &n1value; + const PackedNormal *n2 = &n2value; +#else + const float dummy1[3] = { 0.0f, 0.0f, +1.0f }; + const float dummy2[3] = { 0.0f, 0.0f, -1.0f }; + + const float *n1 = (is_manifold) ? pnor1 : dummy1; + const float *n2 = (is_manifold) ? pnor2 : dummy2; +#endif + + VertexBuffer_set_attrib(vbo, pos_id, 2 * i, vcos1); + VertexBuffer_set_attrib(vbo, n1_id, 2 * i, n1); + VertexBuffer_set_attrib(vbo, n2_id, 2 * i, n2); + + VertexBuffer_set_attrib(vbo, pos_id, 2 * i + 1, vcos2); + VertexBuffer_set_attrib(vbo, n1_id, 2 * i + 1, n1); + VertexBuffer_set_attrib(vbo, n2_id, 2 * i + 1, n2); + + vbo_len_used += 2; + } + } + if (vbo_len_used != vbo_len_capacity) { + VertexBuffer_resize_data(vbo, vbo_len_used); + } + + cache->fancy_edges = Batch_create(PRIM_LINES, vbo, NULL); + + mesh_render_data_free(rdata); + } + + return cache->fancy_edges; +} + +static void mesh_batch_cache_create_overlay_batches(Mesh *me) +{ + /* Since MR_DATATYPE_OVERLAY is slow to generate, generate them all at once */ + int options = MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOPTRI | MR_DATATYPE_OVERLAY; + + MeshBatchCache *cache = mesh_batch_cache_get(me); + MeshRenderData *rdata = mesh_render_data_create(me, options); + + 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, 4, KEEP_INT); + } + + const int tri_len = mesh_render_data_looptri_len_get(rdata); + const int ledge_len = mesh_render_data_loose_edges_len_get(rdata); + const int lvert_len = mesh_render_data_loose_verts_len_get(rdata); + + if (cache->overlay_triangles == NULL) { + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + const int vbo_len_capacity = tri_len * 3; + int vbo_len_used = 0; + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + + for (int i = 0; i < tri_len; ++i) { + int tri_vert_idx[3], tri_edge_idx[3]; + if (mesh_render_data_looptri_vert_edge_indices_get(rdata, i, tri_vert_idx, tri_edge_idx)) { + add_overlay_tri( + rdata, vbo, pos_id, data_id, + tri_vert_idx, tri_edge_idx, i, vbo_len_used); + vbo_len_used += 3; + } + } + if (vbo_len_used != vbo_len_capacity) { + VertexBuffer_resize_data(vbo, vbo_len_used); + } + cache->overlay_triangles = Batch_create(PRIM_TRIANGLES, vbo, NULL); + } + + if (cache->overlay_loose_edges == NULL) { + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + const int vbo_len_capacity = ledge_len * 2; + int vbo_len_used = 0; + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + + for (int i = 0; i < ledge_len; ++i) { + int vert_idx[2]; + bool ok = mesh_render_data_edge_verts_indices_get(rdata, rdata->loose_edges[i], vert_idx); + assert(ok); /* we don't add */ + add_overlay_loose_edge( + rdata, vbo, pos_id, data_id, + vert_idx[0], vert_idx[1], rdata->loose_edges[i], vbo_len_used); + vbo_len_used += 2; + } + BLI_assert(vbo_len_used == vbo_len_capacity); + cache->overlay_loose_edges = Batch_create(PRIM_LINES, vbo, NULL); + } + + if (cache->overlay_loose_verts == NULL) { + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + const int vbo_len_capacity = lvert_len; + int vbo_len_used = 0; + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + + for (int i = 0; i < lvert_len; ++i) { + add_overlay_loose_vert(rdata, vbo, pos_id, data_id, + rdata->loose_verts[i], vbo_len_used); + vbo_len_used += 1; + } + BLI_assert(vbo_len_used == vbo_len_capacity); + cache->overlay_loose_verts = Batch_create(PRIM_POINTS, vbo, NULL); + } + + mesh_render_data_free(rdata); +} + +Batch *DRW_mesh_batch_cache_get_overlay_triangles(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->overlay_triangles == NULL) { + mesh_batch_cache_create_overlay_batches(me); + } + + return cache->overlay_triangles; +} + +Batch *DRW_mesh_batch_cache_get_overlay_loose_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->overlay_loose_edges == NULL) { + mesh_batch_cache_create_overlay_batches(me); + } + + return cache->overlay_loose_edges; +} + +Batch *DRW_mesh_batch_cache_get_overlay_loose_verts(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->overlay_loose_verts == NULL) { + mesh_batch_cache_create_overlay_batches(me); + } + + return cache->overlay_loose_verts; +} + +Batch *DRW_mesh_batch_cache_get_overlay_facedots(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->overlay_facedots == NULL) { + MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY); + + 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); +#if USE_10_10_10 + data_id = VertexFormat_add_attrib(&format, "norAndFlag", COMP_I10, 4, NORMALIZE_INT_TO_FLOAT); +#else + data_id = VertexFormat_add_attrib(&format, "norAndFlag", COMP_F32, 4, KEEP_FLOAT); +#endif + } + + const int vbo_len_capacity = mesh_render_data_polys_len_get(rdata); + int vbo_len_used = 0; + + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + + for (int i = 0; i < vbo_len_capacity; ++i) { + float pcenter[3], pnor[3]; + bool selected = false; + + if (mesh_render_data_pnors_pcenter_select_get(rdata, i, pnor, pcenter, &selected)) { + +#if USE_10_10_10 + PackedNormal nor = { .x = 0, .y = 0, .z = -511 }; + nor = convert_i10_v3(pnor); + nor.w = selected ? 1 : 0; + VertexBuffer_set_attrib(vbo, data_id, i, &nor); +#else + float nor[4] = {pnor[0], pnor[1], pnor[2], selected ? 1 : 0}; + VertexBuffer_set_attrib(vbo, data_id, i, nor); +#endif + + VertexBuffer_set_attrib(vbo, pos_id, i, pcenter); + + vbo_len_used += 1; + } + } + if (vbo_len_used != vbo_len_capacity) { + VertexBuffer_resize_data(vbo, vbo_len_used); + } + + cache->overlay_facedots = Batch_create(PRIM_POINTS, vbo, NULL); + + mesh_render_data_free(rdata); + } + + return cache->overlay_facedots; +} + +#undef MESH_RENDER_FUNCTION diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index bac64020309..1f0bf0cf79c 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -64,6 +64,9 @@ #include "UI_resources.h" +/* only for callbacks */ +#include "draw_cache_impl.h" + #include "draw_mode_engines.h" #include "clay.h" #include "eevee.h" @@ -1919,6 +1922,28 @@ void DRW_engines_register(void) DRW_engine_register(&draw_engine_pose_type); DRW_engine_register(&draw_engine_sculpt_type); #endif + + /* setup callbacks */ + { + /* BKE: curve.c */ + extern void *BKE_curve_batch_cache_dirty_cb; + extern void *BKE_curve_batch_cache_free_cb; + /* BKE: mesh.c */ + extern void *BKE_mesh_batch_cache_dirty_cb; + extern void *BKE_mesh_batch_cache_free_cb; + /* BKE: lattice.c */ + extern void *BKE_lattice_batch_cache_dirty_cb; + extern void *BKE_lattice_batch_cache_free_cb; + + BKE_curve_batch_cache_dirty_cb = DRW_curve_batch_cache_dirty; + BKE_curve_batch_cache_free_cb = DRW_curve_batch_cache_free; + + BKE_mesh_batch_cache_dirty_cb = DRW_mesh_batch_cache_dirty; + BKE_mesh_batch_cache_free_cb = DRW_mesh_batch_cache_free; + + BKE_lattice_batch_cache_dirty_cb = DRW_lattice_batch_cache_dirty; + BKE_lattice_batch_cache_free_cb = DRW_lattice_batch_cache_free; + } } extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */ |