Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/intern')
-rw-r--r--source/blender/draw/intern/draw_cache.c54
-rw-r--r--source/blender/draw/intern/draw_cache.h2
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h81
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.c1047
-rw-r--r--source/blender/draw/intern/draw_cache_impl_displist.c168
-rw-r--r--source/blender/draw/intern/draw_cache_impl_lattice.c510
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c1448
-rw-r--r--source/blender/draw/intern/draw_manager.c25
8 files changed, 3310 insertions, 25 deletions
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 */