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:
-rw-r--r--source/blender/blenkernel/BKE_mesh.h1
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c18
-rw-r--r--source/blender/blenlib/BLI_math_geom.h1
-rw-r--r--source/blender/blenlib/intern/math_geom.c21
-rw-r--r--source/blender/draw/CMakeLists.txt2
-rw-r--r--source/blender/draw/intern/draw_cache.c6
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h249
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c4295
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h3
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c4873
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c35
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl6
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl25
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c12
-rw-r--r--source/blender/gpu/GPU_batch.h3
-rw-r--r--source/blender/gpu/GPU_element.h19
-rw-r--r--source/blender/gpu/GPU_vertex_format.h62
-rw-r--r--source/blender/gpu/intern/gpu_batch.c44
-rw-r--r--source/blender/gpu/intern/gpu_element.c100
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.c78
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format_private.h1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl11
-rw-r--r--source/blender/makesrna/intern/rna_scene.c2
23 files changed, 5149 insertions, 4718 deletions
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 924cfad37d6..94d118bde36 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -486,6 +486,7 @@ void BKE_mesh_calc_poly_center(const struct MPoly *mpoly,
float BKE_mesh_calc_poly_area(const struct MPoly *mpoly,
const struct MLoop *loopstart,
const struct MVert *mvarray);
+float BKE_mesh_calc_poly_uv_area(const struct MPoly *mpoly, const struct MLoopUV *uv_array);
void BKE_mesh_calc_poly_angles(const struct MPoly *mpoly,
const struct MLoop *loopstart,
const struct MVert *mvarray,
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index e28d50cbde4..2ea275cdfb0 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -2378,6 +2378,24 @@ float BKE_mesh_calc_poly_area(const MPoly *mpoly, const MLoop *loopstart, const
}
}
+float BKE_mesh_calc_poly_uv_area(const MPoly *mpoly, const MLoopUV *uv_array)
+{
+
+ int i, l_iter = mpoly->loopstart;
+ float area;
+ float(*vertexcos)[2] = BLI_array_alloca(vertexcos, (size_t)mpoly->totloop);
+
+ /* pack vertex cos into an array for area_poly_v2 */
+ for (i = 0; i < mpoly->totloop; i++, l_iter++) {
+ copy_v2_v2(vertexcos[i], uv_array[l_iter].uv);
+ }
+
+ /* finally calculate the area */
+ area = area_poly_v2((const float(*)[2])vertexcos, (unsigned int)mpoly->totloop);
+
+ return area;
+}
+
/**
* Calculate the volume and volume-weighted centroid of the volume
* formed by the polygon and the origin.
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index b1437dbe140..39b1b96d009 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -92,6 +92,7 @@ float volume_tetrahedron_signed_v3(const float v1[3],
const float v3[3],
const float v4[3]);
+bool is_edge_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
bool is_poly_convex_v2(const float verts[][2], unsigned int nr);
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index bb3d2786ca6..06fd5c70772 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -5730,6 +5730,27 @@ float form_factor_hemi_poly(
}
/**
+ * Check if the edge is convex or concave
+ * (depends on face winding)
+ * Copied from BM_edge_is_convex().
+ */
+bool is_edge_convex_v3(const float v1[3],
+ const float v2[3],
+ const float f1_no[3],
+ const float f2_no[3])
+{
+ if (!equals_v3v3(f1_no, f2_no)) {
+ float cross[3];
+ float l_dir[3];
+ cross_v3_v3v3(cross, f1_no, f2_no);
+ /* we assume contiguous normals, otherwise the result isn't meaningful */
+ sub_v3_v3v3(l_dir, v2, v1);
+ return (dot_v3v3(l_dir, cross) > 0.0f);
+ }
+ return false;
+}
+
+/**
* Evaluate if entire quad is a proper convex quad
*/
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index e34ad155f21..1112a7a87db 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -52,6 +52,7 @@ set(SRC
intern/draw_anim_viz.c
intern/draw_armature.c
intern/draw_cache.c
+ intern/draw_cache_extract_mesh.c
intern/draw_cache_impl_curve.c
intern/draw_cache_impl_displist.c
intern/draw_cache_impl_lattice.c
@@ -135,6 +136,7 @@ set(SRC
DRW_select_buffer.h
intern/DRW_render.h
intern/draw_cache.h
+ intern/draw_cache_extract.h
intern/draw_cache_impl.h
intern/draw_cache_inline.h
intern/draw_common.h
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index e2e98a2db5a..bad4b55eb1a 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -4033,7 +4033,7 @@ void drw_batch_cache_validate(Object *ob)
void drw_batch_cache_generate_requested(Object *ob)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
- const ToolSettings *ts = draw_ctx->scene->toolsettings;
+ const Scene *scene = draw_ctx->scene;
const enum eContextObjectMode mode = CTX_data_mode_enum_ex(
draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
const bool is_paint_mode = ELEM(
@@ -4047,13 +4047,13 @@ void drw_batch_cache_generate_requested(Object *ob)
struct Mesh *mesh_eval = ob->runtime.mesh_eval;
switch (ob->type) {
case OB_MESH:
- DRW_mesh_batch_cache_create_requested(ob, (Mesh *)ob->data, ts, is_paint_mode, use_hide);
+ DRW_mesh_batch_cache_create_requested(ob, (Mesh *)ob->data, scene, is_paint_mode, use_hide);
break;
case OB_CURVE:
case OB_FONT:
case OB_SURF:
if (mesh_eval) {
- DRW_mesh_batch_cache_create_requested(ob, mesh_eval, ts, is_paint_mode, use_hide);
+ DRW_mesh_batch_cache_create_requested(ob, mesh_eval, scene, is_paint_mode, use_hide);
}
DRW_curve_batch_cache_create_requested(ob);
break;
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
new file mode 100644
index 00000000000..5a06210fe8e
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_CACHE_EXTRACT_MESH_H__
+#define __DRAW_CACHE_EXTRACT_MESH_H__
+
+/* Vertex Group Selection and display options */
+typedef struct DRW_MeshWeightState {
+ int defgroup_active;
+ int defgroup_len;
+
+ short flags;
+ char alert_mode;
+
+ /* Set of all selected bones for Multipaint. */
+ bool *defgroup_sel; /* [defgroup_len] */
+ int defgroup_sel_count;
+} DRW_MeshWeightState;
+
+/* DRW_MeshWeightState.flags */
+enum {
+ DRW_MESH_WEIGHT_STATE_MULTIPAINT = (1 << 0),
+ DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE = (1 << 1),
+};
+
+typedef struct DRW_MeshCDMask {
+ uint32_t uv : 8;
+ uint32_t tan : 8;
+ uint32_t vcol : 8;
+ uint32_t orco : 1;
+ uint32_t tan_orco : 1;
+} DRW_MeshCDMask;
+
+typedef enum eMRIterType {
+ MR_ITER_LOOPTRI = 1 << 0,
+ MR_ITER_LOOP = 1 << 1,
+ MR_ITER_LEDGE = 1 << 2,
+ MR_ITER_LVERT = 1 << 3,
+} eMRIterType;
+
+typedef enum eMRDataType {
+ MR_DATA_POLY_NOR = 1 << 1,
+ MR_DATA_LOOP_NOR = 1 << 2,
+ MR_DATA_LOOPTRI = 1 << 3,
+ /** Force loop normals calculation. */
+ MR_DATA_TAN_LOOP_NOR = 1 << 4,
+} eMRDataType;
+
+typedef enum eMRExtractType {
+ MR_EXTRACT_BMESH,
+ MR_EXTRACT_MAPPED,
+ MR_EXTRACT_MESH,
+} eMRExtractType;
+
+BLI_INLINE int mesh_render_mat_len_get(Mesh *me)
+{
+ return MAX2(1, me->totcol);
+}
+
+typedef struct MeshBufferCache {
+ /* Every VBO below contains at least enough
+ * data for every loops in the mesh (except fdots).
+ * For some VBOs, it extends to (in this exact order) :
+ * loops + loose_edges*2 + loose_verts */
+ struct {
+ GPUVertBuf *pos_nor; /* extend */
+ GPUVertBuf *lnor; /* extend */
+ GPUVertBuf *edge_fac; /* extend */
+ GPUVertBuf *weights; /* extend */
+ GPUVertBuf *uv_tan;
+ GPUVertBuf *vcol;
+ GPUVertBuf *orco;
+ /* Only for edit mode. */
+ GPUVertBuf *edit_data; /* extend */
+ GPUVertBuf *edituv_data;
+ GPUVertBuf *stretch_area;
+ GPUVertBuf *stretch_angle;
+ GPUVertBuf *mesh_analysis;
+ GPUVertBuf *fdots_pos;
+ GPUVertBuf *fdots_nor;
+ GPUVertBuf *fdots_uv;
+ // GPUVertBuf *fdots_edit_data; /* inside fdots_nor for now. */
+ GPUVertBuf *fdots_edituv_data;
+ /* Selection */
+ GPUVertBuf *vert_idx; /* extend */
+ GPUVertBuf *edge_idx; /* extend */
+ GPUVertBuf *poly_idx;
+ GPUVertBuf *fdot_idx;
+ } vbo;
+ /* Index Buffers:
+ * Only need to be updated when topology changes. */
+ struct {
+ /* Indices to vloops. */
+ GPUIndexBuf *tris; /* Ordered per material. */
+ GPUIndexBuf *lines; /* Loose edges last. */
+ GPUIndexBuf *points;
+ GPUIndexBuf *fdots;
+ /* 3D overlays. */
+ GPUIndexBuf *lines_paint_mask; /* no loose edges. */
+ GPUIndexBuf *lines_adjacency;
+ /* Uv overlays. (visibility can differ from 3D view) */
+ GPUIndexBuf *edituv_tris;
+ GPUIndexBuf *edituv_lines;
+ GPUIndexBuf *edituv_points;
+ GPUIndexBuf *edituv_fdots;
+ } ibo;
+} MeshBufferCache;
+
+typedef enum DRWBatchFlag {
+ MBC_SURFACE = (1 << 0),
+ MBC_SURFACE_WEIGHTS = (1 << 1),
+ MBC_EDIT_TRIANGLES = (1 << 2),
+ MBC_EDIT_VERTICES = (1 << 3),
+ MBC_EDIT_EDGES = (1 << 4),
+ MBC_EDIT_VNOR = (1 << 5),
+ MBC_EDIT_LNOR = (1 << 6),
+ MBC_EDIT_FACEDOTS = (1 << 7),
+ MBC_EDIT_MESH_ANALYSIS = (1 << 8),
+ MBC_EDITUV_FACES_STRECH_AREA = (1 << 9),
+ MBC_EDITUV_FACES_STRECH_ANGLE = (1 << 10),
+ MBC_EDITUV_FACES = (1 << 11),
+ MBC_EDITUV_EDGES = (1 << 12),
+ MBC_EDITUV_VERTS = (1 << 13),
+ MBC_EDITUV_FACEDOTS = (1 << 14),
+ MBC_EDIT_SELECTION_VERTS = (1 << 15),
+ MBC_EDIT_SELECTION_EDGES = (1 << 16),
+ MBC_EDIT_SELECTION_FACES = (1 << 17),
+ MBC_EDIT_SELECTION_FACEDOTS = (1 << 18),
+ MBC_ALL_VERTS = (1 << 19),
+ MBC_ALL_EDGES = (1 << 20),
+ MBC_LOOSE_EDGES = (1 << 21),
+ MBC_EDGE_DETECTION = (1 << 22),
+ MBC_WIRE_EDGES = (1 << 23),
+ MBC_WIRE_LOOPS = (1 << 24),
+ MBC_WIRE_LOOPS_UVS = (1 << 25),
+ MBC_SURF_PER_MAT = (1 << 26),
+} DRWBatchFlag;
+
+#define MBC_EDITUV \
+ (MBC_EDITUV_FACES_STRECH_AREA | MBC_EDITUV_FACES_STRECH_ANGLE | MBC_EDITUV_FACES | \
+ MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS)
+
+#define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \
+ for (MeshBufferCache *mbc = &batch_cache->final; \
+ mbc == &batch_cache->final || mbc == &batch_cache->cage || mbc == &batch_cache->uv_cage; \
+ mbc = (mbc == &batch_cache->final) ? \
+ &batch_cache->cage : \
+ ((mbc == &batch_cache->cage) ? &batch_cache->uv_cage : NULL))
+
+typedef struct MeshBatchCache {
+ MeshBufferCache final, cage, uv_cage;
+
+ struct {
+ /* Surfaces / Render */
+ GPUBatch *surface;
+ GPUBatch *surface_weights;
+ /* Edit mode */
+ GPUBatch *edit_triangles;
+ GPUBatch *edit_vertices;
+ GPUBatch *edit_edges;
+ GPUBatch *edit_vnor;
+ GPUBatch *edit_lnor;
+ GPUBatch *edit_fdots;
+ GPUBatch *edit_mesh_analysis;
+ /* Edit UVs */
+ GPUBatch *edituv_faces_strech_area;
+ GPUBatch *edituv_faces_strech_angle;
+ GPUBatch *edituv_faces;
+ GPUBatch *edituv_edges;
+ GPUBatch *edituv_verts;
+ GPUBatch *edituv_fdots;
+ /* Edit selection */
+ GPUBatch *edit_selection_verts;
+ GPUBatch *edit_selection_edges;
+ GPUBatch *edit_selection_faces;
+ GPUBatch *edit_selection_fdots;
+ /* Common display / Other */
+ GPUBatch *all_verts;
+ GPUBatch *all_edges;
+ GPUBatch *loose_edges;
+ GPUBatch *edge_detection;
+ GPUBatch *wire_edges; /* Individual edges with face normals. */
+ GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */
+ GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */
+ } batch;
+
+ GPUBatch **surface_per_mat;
+
+ /* arrays of bool uniform names (and value) that will be use to
+ * set srgb conversion for auto attributes.*/
+ char *auto_layer_names;
+ int *auto_layer_is_srgb;
+ int auto_layer_len;
+
+ DRWBatchFlag batch_requested;
+ DRWBatchFlag batch_ready;
+
+ /* settings to determine if cache is invalid */
+ int edge_len;
+ int tri_len;
+ int poly_len;
+ int vert_len;
+ int mat_len;
+ bool is_dirty; /* Instantly invalidates cache, skipping mesh check */
+ bool is_editmode;
+ bool is_uvsyncsel;
+
+ struct DRW_MeshWeightState weight_state;
+
+ DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time;
+
+ int lastmatch;
+
+ /* Valid only if edge_detection is up to date. */
+ bool is_manifold;
+
+ bool no_loose_wire;
+} MeshBatchCache;
+
+void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
+ MeshBufferCache mbc,
+ Mesh *me,
+ const bool do_final,
+ const bool do_uvedit,
+ const bool use_subsurf_fdots,
+ const DRW_MeshCDMask *cd_layer_used,
+ const ToolSettings *ts,
+ const bool use_hide);
+
+#endif /* __DRAW_CACHE_EXTRACT_MESH_H__ */
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
new file mode 100644
index 00000000000..f9d6c9ed582
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -0,0 +1,4295 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup draw
+ *
+ * \brief Extraction of Mesh data into VBO to feed to GPU.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_buffer.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_math_bits.h"
+#include "BLI_string.h"
+#include "BLI_alloca.h"
+#include "BLI_edgehash.h"
+#include "BLI_task.h"
+#include "BLI_jitter_2d.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
+#include "BKE_editmesh_tangent.h"
+#include "BKE_editmesh_bvh.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_object_deform.h"
+
+#include "atomic_ops.h"
+
+#include "bmesh.h"
+
+#include "GPU_batch.h"
+#include "GPU_extensions.h"
+#include "GPU_material.h"
+
+#include "DRW_render.h"
+
+#include "ED_mesh.h"
+#include "ED_uvedit.h"
+
+#include "draw_cache_inline.h"
+#include "draw_cache_impl.h"
+
+#include "draw_cache_extract.h"
+
+// #define DEBUG_TIME
+
+#ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+#endif
+
+/* ---------------------------------------------------------------------- */
+/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
+ * \{ */
+
+typedef struct MeshRenderData {
+ eMRExtractType extract_type;
+
+ int poly_len, edge_len, vert_len, loop_len;
+ int edge_loose_len;
+ int vert_loose_len;
+ int loop_loose_len;
+ int tri_len;
+ int mat_len;
+
+ bool use_hide;
+ bool use_subsurf_fdots;
+ bool use_final_mesh;
+
+ const ToolSettings *toolsettings;
+ /* HACK not supposed to be there but it's needed. */
+ struct MeshBatchCache *cache;
+ /** Edit Mesh */
+ BMEditMesh *edit_bmesh;
+ BMesh *bm;
+ EditMeshData *edit_data;
+ int *v_origindex, *e_origindex, *p_origindex;
+ int crease_ofs;
+ int bweight_ofs;
+ int freestyle_edge_ofs;
+ int freestyle_face_ofs;
+ /** Mesh */
+ Mesh *me;
+ const MVert *mvert;
+ const MEdge *medge;
+ const MLoop *mloop;
+ const MPoly *mpoly;
+ BMVert *eve_act;
+ BMEdge *eed_act;
+ BMFace *efa_act;
+ BMFace *efa_act_uv;
+ /* Data created on-demand (usually not for bmesh-based data). */
+ MLoopTri *mlooptri;
+ float (*loop_normals)[3];
+ float (*poly_normals)[3];
+ int *lverts, *ledges;
+} MeshRenderData;
+
+static MeshRenderData *mesh_render_data_create(Mesh *me,
+ const bool do_final,
+ const bool do_uvedit,
+ const eMRIterType iter_type,
+ const eMRDataType data_flag,
+ const DRW_MeshCDMask *UNUSED(cd_used),
+ const ToolSettings *ts)
+{
+ MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
+ mr->toolsettings = ts;
+ mr->mat_len = mesh_render_mat_len_get(me);
+
+ const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
+ const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI;
+
+ if (me->edit_mesh) {
+ BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final);
+ mr->bm = me->edit_mesh->bm;
+ mr->edit_bmesh = me->edit_mesh;
+ mr->edit_data = me->runtime.edit_data;
+ mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage;
+ bool use_mapped = !do_uvedit && mr->me && !mr->me->runtime.is_original;
+
+ int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE;
+
+ BM_mesh_elem_index_ensure(mr->bm, bm_ensure_types);
+ BM_mesh_elem_table_ensure(mr->bm, bm_ensure_types & ~BM_LOOP);
+
+ mr->efa_act_uv = EDBM_uv_active_face_get(mr->edit_bmesh, false, false);
+ mr->efa_act = BM_mesh_active_face_get(mr->bm, false, true);
+ mr->eed_act = BM_mesh_active_edge_get(mr->bm);
+ mr->eve_act = BM_mesh_active_vert_get(mr->bm);
+
+ mr->crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE);
+ mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT);
+#ifdef WITH_FREESTYLE
+ mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE);
+ mr->freestyle_face_ofs = CustomData_get_offset(&mr->bm->pdata, CD_FREESTYLE_FACE);
+#endif
+
+ if (use_mapped) {
+ mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
+ mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
+ mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+
+ use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
+ }
+
+ mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_BMESH;
+
+ /* Seems like the mesh_eval_final do not have the right origin indices.
+ * Force not mapped in this case. */
+ if (do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
+ // mr->edit_bmesh = NULL;
+ mr->extract_type = MR_EXTRACT_MESH;
+ }
+ }
+ else {
+ mr->me = me;
+ mr->edit_bmesh = NULL;
+ mr->extract_type = MR_EXTRACT_MESH;
+ }
+
+ if (mr->extract_type != MR_EXTRACT_BMESH) {
+ /* Mesh */
+ mr->vert_len = mr->me->totvert;
+ mr->edge_len = mr->me->totedge;
+ mr->loop_len = mr->me->totloop;
+ mr->poly_len = mr->me->totpoly;
+ mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
+
+ mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT);
+ mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE);
+ mr->mloop = CustomData_get_layer(&mr->me->ldata, CD_MLOOP);
+ mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY);
+
+ mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
+ mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
+ mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+
+ if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
+ mr->poly_normals = MEM_mallocN(sizeof(*mr->poly_normals) * mr->poly_len, __func__);
+ BKE_mesh_calc_normals_poly((MVert *)mr->mvert,
+ NULL,
+ mr->vert_len,
+ mr->mloop,
+ mr->mpoly,
+ mr->loop_len,
+ mr->poly_len,
+ mr->poly_normals,
+ true);
+ }
+ if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
+ mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
+ short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL);
+ BKE_mesh_normals_loop_split(mr->me->mvert,
+ mr->vert_len,
+ mr->me->medge,
+ mr->edge_len,
+ mr->me->mloop,
+ mr->loop_normals,
+ mr->loop_len,
+ mr->me->mpoly,
+ mr->poly_normals,
+ mr->poly_len,
+ is_auto_smooth,
+ split_angle,
+ NULL,
+ clnors,
+ NULL);
+ }
+ if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
+ mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI");
+ BKE_mesh_recalc_looptri(mr->me->mloop,
+ mr->me->mpoly,
+ mr->me->mvert,
+ mr->me->totloop,
+ mr->me->totpoly,
+ mr->mlooptri);
+ }
+ if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
+ mr->vert_loose_len = 0;
+ mr->edge_loose_len = 0;
+
+ BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, "lvert map");
+
+ mr->ledges = MEM_mallocN(mr->edge_len * sizeof(int), __func__);
+ const MEdge *medge = mr->medge;
+ for (int e = 0; e < mr->edge_len; e++, medge++) {
+ if (medge->flag & ME_LOOSEEDGE) {
+ mr->ledges[mr->edge_loose_len++] = e;
+ }
+ /* Tag verts as not loose. */
+ BLI_BITMAP_ENABLE(lvert_map, medge->v1);
+ BLI_BITMAP_ENABLE(lvert_map, medge->v2);
+ }
+ if (mr->edge_loose_len < mr->edge_len) {
+ mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges));
+ }
+
+ mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
+ for (int v = 0; v < mr->vert_len; v++) {
+ if (!BLI_BITMAP_TEST(lvert_map, v)) {
+ mr->lverts[mr->vert_loose_len++] = v;
+ }
+ }
+ if (mr->vert_loose_len < mr->vert_len) {
+ mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts));
+ }
+
+ MEM_freeN(lvert_map);
+
+ mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2;
+ }
+ }
+ else {
+ /* BMesh */
+ BMesh *bm = mr->bm;
+
+ mr->vert_len = bm->totvert;
+ mr->edge_len = bm->totedge;
+ mr->loop_len = bm->totloop;
+ mr->poly_len = bm->totface;
+ mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
+
+ if (data_flag & MR_DATA_POLY_NOR) {
+ /* Use bmface->no instead. */
+ }
+ if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
+ mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
+ int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL);
+ BM_loops_calc_normal_vcos(mr->bm,
+ NULL,
+ NULL,
+ NULL,
+ is_auto_smooth,
+ split_angle,
+ mr->loop_normals,
+ NULL,
+ NULL,
+ clnors_offset,
+ false);
+ }
+ if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
+ /* Edit mode ensures this is valid, no need to calculate. */
+ BLI_assert((bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL));
+ }
+ if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
+ int elem_id;
+ BMIter iter;
+ BMVert *eve;
+ BMEdge *ede;
+ mr->vert_loose_len = 0;
+ mr->edge_loose_len = 0;
+
+ mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
+ if (eve->e == NULL) {
+ mr->lverts[mr->vert_loose_len++] = elem_id;
+ }
+ }
+ if (mr->vert_loose_len < mr->vert_len) {
+ mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts));
+ }
+
+ mr->ledges = MEM_mallocN(mr->edge_len * sizeof(*mr->ledges), __func__);
+ BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
+ if (ede->l == NULL) {
+ mr->ledges[mr->edge_loose_len++] = elem_id;
+ }
+ }
+ if (mr->edge_loose_len < mr->edge_len) {
+ mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges));
+ }
+
+ mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2;
+ }
+ }
+ return mr;
+}
+
+static void mesh_render_data_free(MeshRenderData *mr)
+{
+ MEM_SAFE_FREE(mr->mlooptri);
+ MEM_SAFE_FREE(mr->poly_normals);
+ MEM_SAFE_FREE(mr->loop_normals);
+
+ MEM_SAFE_FREE(mr->lverts);
+ MEM_SAFE_FREE(mr->ledges);
+
+ MEM_freeN(mr);
+}
+
+BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx)
+{
+ return ((mr->p_origindex != NULL) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
+ BM_face_at_index(mr->bm, mr->p_origindex[idx]) :
+ NULL;
+}
+
+BLI_INLINE BMEdge *bm_original_edge_get(const MeshRenderData *mr, int idx)
+{
+ return ((mr->e_origindex != NULL) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
+ BM_edge_at_index(mr->bm, mr->e_origindex[idx]) :
+ NULL;
+}
+
+BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx)
+{
+ return ((mr->v_origindex != NULL) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
+ BM_vert_at_index(mr->bm, mr->v_origindex[idx]) :
+ NULL;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Mesh Elements Extract Iter
+ * \{ */
+
+typedef void *(ExtractInitFn)(const MeshRenderData *mr, void *buffer);
+typedef void(ExtractEditTriFn)(const MeshRenderData *mr, int t, BMLoop **e, void *data);
+typedef void(ExtractEditLoopFn)(const MeshRenderData *mr, int l, BMLoop *el, void *data);
+typedef void(ExtractEditLedgeFn)(const MeshRenderData *mr, int e, BMEdge *ed, void *data);
+typedef void(ExtractEditLvertFn)(const MeshRenderData *mr, int v, BMVert *ev, void *data);
+typedef void(ExtractTriFn)(const MeshRenderData *mr, int t, const MLoopTri *mlt, void *data);
+typedef void(ExtractLoopFn)(
+ const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data);
+typedef void(ExtractLedgeFn)(const MeshRenderData *mr, int e, const MEdge *medge, void *data);
+typedef void(ExtractLvertFn)(const MeshRenderData *mr, int v, const MVert *mvert, void *data);
+typedef void(ExtractFinishFn)(const MeshRenderData *mr, void *buffer, void *data);
+
+typedef struct MeshExtract {
+ /** Executed on main thread and return user data for iter functions. */
+ ExtractInitFn *init;
+ /** Executed on one (or more if use_threading) worker thread(s). */
+ ExtractEditTriFn *iter_looptri_bm;
+ ExtractTriFn *iter_looptri;
+ ExtractEditLoopFn *iter_loop_bm;
+ ExtractLoopFn *iter_loop;
+ ExtractEditLedgeFn *iter_ledge_bm;
+ ExtractLedgeFn *iter_ledge;
+ ExtractEditLvertFn *iter_lvert_bm;
+ ExtractLvertFn *iter_lvert;
+ /** Executed on one worker thread after all elements iterations. */
+ ExtractFinishFn *finish;
+ /** Used to request common data. */
+ const eMRDataType data_flag;
+ /** Used to know if the element callbacks are threadsafe and can be parallelized. */
+ const bool use_threading;
+} MeshExtract;
+
+BLI_INLINE eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
+{
+ eMRIterType type = 0;
+ SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri), MR_ITER_LOOPTRI);
+ SET_FLAG_FROM_TEST(type, (ext->iter_loop_bm || ext->iter_loop), MR_ITER_LOOP);
+ SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge), MR_ITER_LEDGE);
+ SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert), MR_ITER_LVERT);
+ return type;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Triangles Indices
+ * \{ */
+
+typedef struct MeshExtract_Tri_Data {
+ GPUIndexBufBuilder elb;
+ int *tri_mat_start;
+ int *tri_mat_end;
+} MeshExtract_Tri_Data;
+
+static void *extract_tris_init(const MeshRenderData *mr, void *UNUSED(ibo))
+{
+ MeshExtract_Tri_Data *data = MEM_callocN(sizeof(*data), __func__);
+
+ size_t mat_tri_idx_size = sizeof(int) * mr->mat_len;
+ data->tri_mat_start = MEM_callocN(mat_tri_idx_size, __func__);
+ data->tri_mat_end = MEM_callocN(mat_tri_idx_size, __func__);
+
+ int *mat_tri_len = data->tri_mat_start;
+ /* Count how many triangle for each material. */
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMIter iter;
+ BMFace *efa;
+ BM_ITER_MESH (efa, &iter, mr->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ mat_tri_len[efa->mat_nr] += efa->len - 2;
+ }
+ }
+ }
+ else {
+ const MPoly *mpoly = mr->mpoly;
+ for (int p = 0; p < mr->poly_len; p++, mpoly++) {
+ if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) {
+ mat_tri_len[mpoly->mat_nr] += mpoly->totloop - 2;
+ }
+ }
+ }
+ /* Accumulate tri len per mat to have correct offsets. */
+ int ofs = mat_tri_len[0];
+ mat_tri_len[0] = 0;
+ for (int i = 1; i < mr->mat_len; i++) {
+ int tmp = mat_tri_len[i];
+ mat_tri_len[i] = ofs;
+ ofs += tmp;
+ }
+
+ memcpy(data->tri_mat_end, mat_tri_len, mat_tri_idx_size);
+
+ int visible_tri_tot = ofs;
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, visible_tri_tot, mr->loop_len);
+
+ return data;
+}
+
+static void extract_tris_looptri_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(t),
+ BMLoop **elt,
+ void *_data)
+{
+ if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
+ MeshExtract_Tri_Data *data = _data;
+ int *mat_tri_ofs = data->tri_mat_end;
+ GPU_indexbuf_set_tri_verts(&data->elb,
+ mat_tri_ofs[elt[0]->f->mat_nr]++,
+ BM_elem_index_get(elt[0]),
+ BM_elem_index_get(elt[1]),
+ BM_elem_index_get(elt[2]));
+ }
+}
+
+static void extract_tris_looptri_mesh(const MeshRenderData *mr,
+ int UNUSED(t),
+ const MLoopTri *mlt,
+ void *_data)
+{
+ const MPoly *mpoly = &mr->mpoly[mlt->poly];
+ if (!(mpoly->flag & ME_HIDE)) {
+ MeshExtract_Tri_Data *data = _data;
+ int *mat_tri_ofs = data->tri_mat_end;
+ GPU_indexbuf_set_tri_verts(
+ &data->elb, mat_tri_ofs[mpoly->mat_nr]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
+ }
+}
+
+static void extract_tris_finish(const MeshRenderData *mr, void *ibo, void *_data)
+{
+ MeshExtract_Tri_Data *data = _data;
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+ /* HACK Create ibo subranges and assign them to each GPUBatch. */
+ if (mr->use_final_mesh && mr->cache->surface_per_mat && mr->cache->surface_per_mat[0]) {
+ BLI_assert(mr->cache->surface_per_mat[0]->elem == ibo);
+ for (int i = 0; i < mr->mat_len; ++i) {
+ /* Multiply by 3 because these are triangle indices. */
+ int start = data->tri_mat_start[i] * 3;
+ int len = data->tri_mat_end[i] * 3 - data->tri_mat_start[i] * 3;
+ GPUIndexBuf *sub_ibo = GPU_indexbuf_create_subrange(ibo, start, len);
+ /* WARNING: We modify the GPUBatch here! */
+ GPU_batch_elembuf_set(mr->cache->surface_per_mat[i], sub_ibo, true);
+ }
+ }
+ MEM_freeN(data->tri_mat_start);
+ MEM_freeN(data->tri_mat_end);
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_tris = {extract_tris_init,
+ extract_tris_looptri_bmesh,
+ extract_tris_looptri_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_tris_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edges Indices
+ * \{ */
+
+static void *extract_lines_init(const MeshRenderData *mr, void *UNUSED(buf))
+{
+ GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
+ /* Put loose edges at the end. */
+ GPU_indexbuf_init(
+ elb, GPU_PRIM_LINES, mr->edge_len + mr->edge_loose_len, mr->loop_len + mr->loop_loose_len);
+ return elb;
+}
+
+static void extract_lines_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *elb)
+{
+ if (!BM_elem_flag_test(loop->e, BM_ELEM_HIDDEN)) {
+ GPU_indexbuf_set_line_verts(elb, BM_elem_index_get(loop->e), l, BM_elem_index_get(loop->next));
+ }
+ else {
+ GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(loop->e));
+ }
+}
+
+static void extract_lines_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *mpoly,
+ void *elb)
+{
+ const MEdge *medge = &mr->medge[mloop->e];
+ if (!((mr->use_hide && (medge->flag & ME_HIDE)) ||
+ ((mr->extract_type == MR_EXTRACT_MAPPED) &&
+ (mr->e_origindex[mloop->e] == ORIGINDEX_NONE)))) {
+ int loopend = mpoly->totloop + mpoly->loopstart - 1;
+ int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1);
+ GPU_indexbuf_set_line_verts(elb, mloop->e, l, other_loop);
+ }
+ else {
+ GPU_indexbuf_set_line_restart(elb, mloop->e);
+ }
+}
+
+static void extract_lines_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *elb)
+{
+ int ledge_idx = mr->edge_len + e;
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ int l = mr->loop_len + e * 2;
+ GPU_indexbuf_set_line_verts(elb, ledge_idx, l, l + 1);
+ }
+ else {
+ GPU_indexbuf_set_line_restart(elb, ledge_idx);
+ }
+ /* Don't render the edge twice. */
+ GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed));
+}
+
+static void extract_lines_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *medge,
+ void *elb)
+{
+ int ledge_idx = mr->edge_len + e;
+ int edge_idx = mr->ledges[e];
+ if (!((mr->use_hide && (medge->flag & ME_HIDE)) ||
+ ((mr->extract_type == MR_EXTRACT_MAPPED) &&
+ (mr->e_origindex[edge_idx] == ORIGINDEX_NONE)))) {
+ int l = mr->loop_len + e * 2;
+ GPU_indexbuf_set_line_verts(elb, ledge_idx, l, l + 1);
+ }
+ else {
+ GPU_indexbuf_set_line_restart(elb, ledge_idx);
+ }
+ /* Don't render the edge twice. */
+ GPU_indexbuf_set_line_restart(elb, edge_idx);
+}
+
+static void extract_lines_finish(const MeshRenderData *mr, void *ibo, void *elb)
+{
+ GPU_indexbuf_build_in_place(elb, ibo);
+ MEM_freeN(elb);
+ /* HACK Create ibo subranges and assign them to GPUBatch. */
+ if (mr->use_final_mesh && mr->cache->batch.loose_edges) {
+ BLI_assert(mr->cache->batch.loose_edges->elem == ibo);
+ /* Multiply by 2 because these are edges indices. */
+ int start = mr->edge_len * 2;
+ int len = mr->edge_loose_len * 2;
+ GPUIndexBuf *sub_ibo = GPU_indexbuf_create_subrange(ibo, start, len);
+ /* WARNING: We modify the GPUBatch here! */
+ GPU_batch_elembuf_set(mr->cache->batch.loose_edges, sub_ibo, true);
+ }
+}
+
+const MeshExtract extract_lines = {extract_lines_init,
+ NULL,
+ NULL,
+ extract_lines_loop_bmesh,
+ extract_lines_loop_mesh,
+ extract_lines_ledge_bmesh,
+ extract_lines_ledge_mesh,
+ NULL,
+ NULL,
+ extract_lines_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Point Indices
+ * \{ */
+
+static void *extract_points_init(const MeshRenderData *mr, void *UNUSED(buf))
+{
+ GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
+ GPU_indexbuf_init(elb, GPU_PRIM_POINTS, mr->vert_len, mr->loop_len + mr->loop_loose_len);
+ return elb;
+}
+
+BLI_INLINE void vert_set_bmesh(GPUIndexBufBuilder *elb, BMVert *eve, int loop)
+{
+ int vert_idx = BM_elem_index_get(eve);
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ GPU_indexbuf_set_point_vert(elb, vert_idx, loop);
+ }
+ else {
+ GPU_indexbuf_set_point_restart(elb, vert_idx);
+ }
+}
+
+BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb,
+ const MeshRenderData *mr,
+ int vert_idx,
+ int loop)
+{
+ const MVert *mvert = &mr->mvert[vert_idx];
+ if (!((mr->use_hide && (mvert->flag & ME_HIDE)) ||
+ ((mr->extract_type == MR_EXTRACT_MAPPED) &&
+ (mr->v_origindex[vert_idx] == ORIGINDEX_NONE)))) {
+ GPU_indexbuf_set_point_vert(elb, vert_idx, loop);
+ }
+ else {
+ GPU_indexbuf_set_point_restart(elb, vert_idx);
+ }
+}
+
+static void extract_points_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *elb)
+{
+ vert_set_bmesh(elb, loop->v, l);
+}
+
+static void extract_points_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *UNUSED(mpoly),
+ void *elb)
+{
+ vert_set_mesh(elb, mr, mloop->v, l);
+}
+
+static void extract_points_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *elb)
+{
+ vert_set_bmesh(elb, eed->v1, mr->loop_len + e * 2);
+ vert_set_bmesh(elb, eed->v2, mr->loop_len + e * 2 + 1);
+}
+
+static void extract_points_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *medge,
+ void *elb)
+{
+ vert_set_mesh(elb, mr, medge->v1, mr->loop_len + e * 2);
+ vert_set_mesh(elb, mr, medge->v2, mr->loop_len + e * 2 + 1);
+}
+
+static void extract_points_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *elb)
+{
+ vert_set_bmesh(elb, eve, mr->loop_len + mr->edge_loose_len * 2 + v);
+}
+
+static void extract_points_lvert_mesh(const MeshRenderData *mr,
+ int v,
+ const MVert *UNUSED(mvert),
+ void *elb)
+{
+ vert_set_mesh(elb, mr, mr->lverts[v], mr->loop_len + mr->edge_loose_len * 2 + v);
+}
+
+static void extract_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb)
+{
+ GPU_indexbuf_build_in_place(elb, ibo);
+ MEM_freeN(elb);
+}
+
+const MeshExtract extract_points = {extract_points_init,
+ NULL,
+ NULL,
+ extract_points_loop_bmesh,
+ extract_points_loop_mesh,
+ extract_points_ledge_bmesh,
+ extract_points_ledge_mesh,
+ extract_points_lvert_bmesh,
+ extract_points_lvert_mesh,
+ extract_points_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Facedots Indices
+ * \{ */
+
+static void *extract_fdots_init(const MeshRenderData *mr, void *UNUSED(buf))
+{
+ GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
+ GPU_indexbuf_init(elb, GPU_PRIM_POINTS, mr->poly_len, mr->poly_len);
+ return elb;
+}
+
+static void extract_fdots_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(l),
+ BMLoop *loop,
+ void *elb)
+{
+ int face_idx = BM_elem_index_get(loop->f);
+ if (!BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN)) {
+ GPU_indexbuf_set_point_vert(elb, face_idx, face_idx);
+ }
+ else {
+ GPU_indexbuf_set_point_restart(elb, face_idx);
+ }
+}
+
+static void extract_fdots_loop_mesh(const MeshRenderData *mr,
+ int UNUSED(l),
+ const MLoop *mloop,
+ int p,
+ const MPoly *mpoly,
+ void *elb)
+{
+ const MVert *mvert = &mr->mvert[mloop->v];
+ if ((!mr->use_subsurf_fdots || (mvert->flag & ME_VERT_FACEDOT)) &&
+ !(mr->use_hide && (mpoly->flag & ME_HIDE))) {
+ GPU_indexbuf_set_point_vert(elb, p, p);
+ }
+ else {
+ GPU_indexbuf_set_point_restart(elb, p);
+ }
+}
+
+static void extract_fdots_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb)
+{
+ GPU_indexbuf_build_in_place(elb, ibo);
+ MEM_freeN(elb);
+}
+
+const MeshExtract extract_fdots = {extract_fdots_init,
+ NULL,
+ NULL,
+ extract_fdots_loop_bmesh,
+ extract_fdots_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_fdots_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Paint Mask Line Indices
+ * \{ */
+
+typedef struct MeshExtract_LinePaintMask_Data {
+ GPUIndexBufBuilder elb;
+ /** One bit per edge set if face is selected. */
+ BLI_bitmap select_map[0];
+} MeshExtract_LinePaintMask_Data;
+
+static void *extract_lines_paint_mask_init(const MeshRenderData *mr, void *UNUSED(buf))
+{
+ size_t bitmap_size = BLI_BITMAP_SIZE(mr->edge_len);
+ MeshExtract_LinePaintMask_Data *data = MEM_callocN(sizeof(*data) + bitmap_size, __func__);
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES, mr->edge_len, mr->loop_len);
+ return data;
+}
+
+static void extract_lines_paint_mask_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *mpoly,
+ void *_data)
+{
+ MeshExtract_LinePaintMask_Data *data = (MeshExtract_LinePaintMask_Data *)_data;
+ if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) {
+ int loopend = mpoly->totloop + mpoly->loopstart - 1;
+ int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1);
+ int edge_idx = mloop->e;
+ if (mpoly->flag & ME_FACE_SEL) {
+ if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, edge_idx)) {
+ /* Hide edge as it has more than 2 selected loop. */
+ GPU_indexbuf_set_line_restart(&data->elb, edge_idx);
+ }
+ else {
+ /* First selected loop. Set edge visible, overwritting any unsel loop. */
+ GPU_indexbuf_set_line_verts(&data->elb, edge_idx, l, other_loop);
+ }
+ }
+ else {
+ /* Set theses unselected loop only if this edge has no other selected loop. */
+ if (!BLI_BITMAP_TEST(data->select_map, edge_idx)) {
+ GPU_indexbuf_set_line_verts(&data->elb, edge_idx, l, other_loop);
+ }
+ }
+ }
+}
+static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
+ void *ibo,
+ void *_data)
+{
+ MeshExtract_LinePaintMask_Data *data = (MeshExtract_LinePaintMask_Data *)_data;
+
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_lines_paint_mask = {extract_lines_paint_mask_init,
+ NULL,
+ NULL,
+ NULL,
+ extract_lines_paint_mask_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_lines_paint_mask_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Line Adjacency Indices
+ * \{ */
+
+#define NO_EDGE INT_MAX
+
+typedef struct MeshExtract_LineAdjacency_Data {
+ GPUIndexBufBuilder elb;
+ EdgeHash *eh;
+ bool is_manifold;
+ /* Array to convert vert index to any loop index of this vert. */
+ uint vert_to_loop[0];
+} MeshExtract_LineAdjacency_Data;
+
+static void *extract_lines_adjacency_init(const MeshRenderData *mr, void *UNUSED(buf))
+{
+ /* Similar to poly_to_tri_count().
+ * There is always loop + tri - 1 edges inside a polygon.
+ * Cummulate for all polys and you get : */
+ uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len;
+
+ size_t vert_to_loop_size = sizeof(uint) * mr->vert_len;
+
+ MeshExtract_LineAdjacency_Data *data = MEM_callocN(sizeof(*data) + vert_to_loop_size, __func__);
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, mr->loop_len);
+ data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
+ data->is_manifold = true;
+ return data;
+}
+
+BLI_INLINE void lines_adjacency_triangle(
+ uint v1, uint v2, uint v3, uint l1, uint l2, uint l3, MeshExtract_LineAdjacency_Data *data)
+{
+ GPUIndexBufBuilder *elb = &data->elb;
+ /* Iter around the triangle's edges. */
+ for (int e = 0; e < 3; e++) {
+ uint tmp = v1;
+ v1 = v2, v2 = v3, v3 = tmp;
+ tmp = l1;
+ l1 = l2, l2 = l3, l3 = tmp;
+
+ bool inv_indices = (v2 > v3);
+ void **pval;
+ bool value_is_init = BLI_edgehash_ensure_p(data->eh, v2, v3, &pval);
+ int v_data = POINTER_AS_INT(*pval);
+ if (!value_is_init || v_data == NO_EDGE) {
+ /* Save the winding order inside the sign bit. Because the
+ * edgehash sort the keys and we need to compare winding later. */
+ int value = (int)l1 + 1; /* 0 cannot be signed so add one. */
+ *pval = POINTER_FROM_INT((inv_indices) ? -value : value);
+ /* Store loop indices for remaining non-manifold edges. */
+ data->vert_to_loop[v2] = l2;
+ data->vert_to_loop[v3] = l3;
+ }
+ else {
+ /* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
+ *pval = POINTER_FROM_INT(NO_EDGE);
+ bool inv_opposite = (v_data < 0);
+ uint l_opposite = (uint)abs(v_data) - 1;
+ /* TODO Make this part threadsafe. */
+ if (inv_opposite == inv_indices) {
+ /* Don't share edge if triangles have non matching winding. */
+ GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l1);
+ GPU_indexbuf_add_line_adj_verts(elb, l_opposite, l2, l3, l_opposite);
+ data->is_manifold = false;
+ }
+ else {
+ GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l_opposite);
+ }
+ }
+ }
+}
+
+static void extract_lines_adjacency_looptri_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(t),
+ BMLoop **elt,
+ void *data)
+{
+ if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
+ lines_adjacency_triangle(BM_elem_index_get(elt[0]->v),
+ BM_elem_index_get(elt[1]->v),
+ BM_elem_index_get(elt[2]->v),
+ BM_elem_index_get(elt[0]),
+ BM_elem_index_get(elt[1]),
+ BM_elem_index_get(elt[2]),
+ data);
+ }
+}
+
+static void extract_lines_adjacency_looptri_mesh(const MeshRenderData *mr,
+ int UNUSED(t),
+ const MLoopTri *mlt,
+ void *data)
+{
+ const MPoly *mpoly = &mr->mpoly[mlt->poly];
+ if (!(mpoly->flag & ME_HIDE)) {
+ lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v,
+ mr->mloop[mlt->tri[1]].v,
+ mr->mloop[mlt->tri[2]].v,
+ mlt->tri[0],
+ mlt->tri[1],
+ mlt->tri[2],
+ data);
+ }
+}
+
+static void extract_lines_adjacency_finish(const MeshRenderData *mr, void *ibo, void *_data)
+{
+ MeshExtract_LineAdjacency_Data *data = (MeshExtract_LineAdjacency_Data *)_data;
+ /* Create edges for remaining non manifold edges. */
+ EdgeHashIterator *ehi = BLI_edgehashIterator_new(data->eh);
+ for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
+ uint v2, v3, l1, l2, l3;
+ int v_data = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
+ if (v_data != NO_EDGE) {
+ BLI_edgehashIterator_getKey(ehi, &v2, &v3);
+ l1 = (uint)abs(v_data) - 1;
+ if (v_data < 0) { /* inv_opposite */
+ SWAP(uint, v2, v3);
+ }
+ l2 = data->vert_to_loop[v2];
+ l3 = data->vert_to_loop[v3];
+ GPU_indexbuf_add_line_adj_verts(&data->elb, l1, l2, l3, l1);
+ data->is_manifold = false;
+ }
+ }
+ BLI_edgehashIterator_free(ehi);
+ BLI_edgehash_free(data->eh, NULL);
+
+ mr->cache->is_manifold = data->is_manifold;
+
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+ MEM_freeN(data);
+}
+
+#undef NO_EDGE
+
+const MeshExtract extract_lines_adjacency = {extract_lines_adjacency_init,
+ extract_lines_adjacency_looptri_bmesh,
+ extract_lines_adjacency_looptri_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_lines_adjacency_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV Triangles Indices
+ * \{ */
+
+typedef struct MeshExtract_EditUvElem_Data {
+ GPUIndexBufBuilder elb;
+ bool sync_selection;
+} MeshExtract_EditUvElem_Data;
+
+static void *extract_edituv_tris_init(const MeshRenderData *mr, void *UNUSED(ibo))
+{
+ MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, mr->tri_len, mr->loop_len);
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+ return data;
+}
+
+BLI_INLINE void edituv_tri_add(
+ MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, int v1, int v2, int v3)
+{
+ if (!hidden && (data->sync_selection || selected)) {
+ GPU_indexbuf_add_tri_verts(&data->elb, v1, v2, v3);
+ }
+}
+
+static void extract_edituv_tris_looptri_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(t),
+ BMLoop **elt,
+ void *data)
+{
+ edituv_tri_add(data,
+ BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN),
+ BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT),
+ BM_elem_index_get(elt[0]),
+ BM_elem_index_get(elt[1]),
+ BM_elem_index_get(elt[2]));
+}
+
+static void extract_edituv_tris_looptri_mesh(const MeshRenderData *mr,
+ int UNUSED(t),
+ const MLoopTri *mlt,
+ void *data)
+{
+ const MPoly *mpoly = &mr->mpoly[mlt->poly];
+ edituv_tri_add(data,
+ (mpoly->flag & ME_HIDE) != 0,
+ (mpoly->flag & ME_FACE_SEL) != 0,
+ mlt->tri[0],
+ mlt->tri[1],
+ mlt->tri[2]);
+}
+
+static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data)
+{
+ MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data;
+ GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
+ MEM_freeN(extract_data);
+}
+
+const MeshExtract extract_edituv_tris = {extract_edituv_tris_init,
+ extract_edituv_tris_looptri_bmesh,
+ extract_edituv_tris_looptri_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_edituv_tris_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV Line Indices around faces
+ * \{ */
+
+static void *extract_edituv_lines_init(const MeshRenderData *mr, void *UNUSED(ibo))
+{
+ MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES, mr->loop_len, mr->loop_len);
+
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+ return data;
+}
+
+BLI_INLINE void edituv_edge_add(
+ MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, int v1, int v2)
+{
+ if (!hidden && (data->sync_selection || selected)) {
+ GPU_indexbuf_add_line_verts(&data->elb, v1, v2);
+ }
+}
+
+static void extract_edituv_lines_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *data)
+{
+ edituv_edge_add(data,
+ BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN),
+ BM_elem_flag_test(loop->f, BM_ELEM_SELECT),
+ l,
+ BM_elem_index_get(loop->next));
+}
+
+static void extract_edituv_lines_loop_mesh(const MeshRenderData *mr,
+ int loop_idx,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *mpoly,
+ void *data)
+{
+ int loopend = mpoly->totloop + mpoly->loopstart - 1;
+ int loop_next_idx = (loop_idx == loopend) ? mpoly->loopstart : (loop_idx + 1);
+ const bool real_edge = (mr->extract_type == MR_EXTRACT_MAPPED &&
+ mr->e_origindex[mloop->e] != ORIGINDEX_NONE);
+ edituv_edge_add(data,
+ (mpoly->flag & ME_HIDE) != 0 || !real_edge,
+ (mpoly->flag & ME_FACE_SEL) != 0,
+ loop_idx,
+ loop_next_idx);
+}
+
+static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data)
+{
+ MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data;
+ GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
+ MEM_freeN(extract_data);
+}
+
+const MeshExtract extract_edituv_lines = {extract_edituv_lines_init,
+ NULL,
+ NULL,
+ extract_edituv_lines_loop_bmesh,
+ extract_edituv_lines_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_edituv_lines_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV Points Indices
+ * \{ */
+
+static void *extract_edituv_points_init(const MeshRenderData *mr, void *UNUSED(ibo))
+{
+ MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_POINTS, mr->loop_len, mr->loop_len);
+
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+ return data;
+}
+
+BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data,
+ bool hidden,
+ bool selected,
+ int v1)
+{
+ if (!hidden && (data->sync_selection || selected)) {
+ GPU_indexbuf_add_point_vert(&data->elb, v1);
+ }
+}
+
+static void extract_edituv_points_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *data)
+{
+ edituv_point_add(data,
+ BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN),
+ BM_elem_flag_test(loop->f, BM_ELEM_SELECT),
+ l);
+}
+
+static void extract_edituv_points_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *mpoly,
+ void *data)
+{
+ const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED &&
+ mr->v_origindex[mloop->v] != ORIGINDEX_NONE);
+ edituv_point_add(
+ data, ((mpoly->flag & ME_HIDE) != 0) || !real_vert, (mpoly->flag & ME_FACE_SEL) != 0, l);
+}
+
+static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data)
+{
+ MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data;
+ GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
+ MEM_freeN(extract_data);
+}
+
+const MeshExtract extract_edituv_points = {extract_edituv_points_init,
+ NULL,
+ NULL,
+ extract_edituv_points_loop_bmesh,
+ extract_edituv_points_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_edituv_points_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV Facedots Indices
+ * \{ */
+
+static void *extract_edituv_fdots_init(const MeshRenderData *mr, void *UNUSED(ibo))
+{
+ MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_POINTS, mr->poly_len, mr->poly_len);
+
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+ return data;
+}
+
+BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data,
+ bool hidden,
+ bool selected,
+ int face_idx)
+{
+ if (!hidden && (data->sync_selection || selected)) {
+ GPU_indexbuf_set_point_vert(&data->elb, face_idx, face_idx);
+ }
+ else {
+ GPU_indexbuf_set_point_restart(&data->elb, face_idx);
+ }
+}
+
+static void extract_edituv_fdots_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(l),
+ BMLoop *loop,
+ void *data)
+{
+ edituv_facedot_add(data,
+ BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN),
+ BM_elem_flag_test(loop->f, BM_ELEM_SELECT),
+ BM_elem_index_get(loop->f));
+}
+
+static void extract_edituv_fdots_loop_mesh(const MeshRenderData *mr,
+ int UNUSED(l),
+ const MLoop *mloop,
+ int p,
+ const MPoly *mpoly,
+ void *data)
+{
+ const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED &&
+ mr->p_origindex[p] != ORIGINDEX_NONE);
+ const bool subd_fdot = (!mr->use_subsurf_fdots ||
+ (mr->mvert[mloop->v].flag & ME_VERT_FACEDOT) != 0);
+ edituv_facedot_add(data,
+ ((mpoly->flag & ME_HIDE) != 0) || !real_fdot || !subd_fdot,
+ (mpoly->flag & ME_FACE_SEL) != 0,
+ p);
+}
+
+static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = (MeshExtract_EditUvElem_Data *)_data;
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_edituv_fdots = {extract_edituv_fdots_init,
+ NULL,
+ NULL,
+ extract_edituv_fdots_loop_bmesh,
+ extract_edituv_fdots_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_edituv_fdots_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Position and Vertex Normal
+ * \{ */
+
+typedef struct PosNorLoop {
+ float pos[3];
+ GPUPackedNormal nor;
+} PosNorLoop;
+
+typedef struct MeshExtract_PosNor_Data {
+ PosNorLoop *vbo_data;
+ GPUPackedNormal packed_nor[];
+} MeshExtract_PosNor_Data;
+
+static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* WARNING Adjust PosNorLoop struct accordingly. */
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_alias_add(&format, "vnor");
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
+
+ /* Pack normals per vert, reduce amount of computation. */
+ size_t packed_nor_len = sizeof(GPUPackedNormal) * mr->vert_len;
+ MeshExtract_PosNor_Data *data = MEM_mallocN(sizeof(*data) + packed_nor_len, __func__);
+ data->vbo_data = (PosNorLoop *)vbo->data;
+
+ /* Quicker than doing it for each loop. */
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMIter iter;
+ BMVert *eve;
+ int v;
+ BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) {
+ data->packed_nor[v] = GPU_normal_convert_i10_v3(eve->no);
+ }
+ }
+ else {
+ const MVert *mvert = mr->mvert;
+ for (int v = 0; v < mr->vert_len; v++, mvert++) {
+ data->packed_nor[v] = GPU_normal_convert_i10_s3(mvert->no);
+ }
+ }
+ return data;
+}
+
+static void extract_pos_nor_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_PosNor_Data *data = _data;
+ PosNorLoop *vert = data->vbo_data + l;
+ copy_v3_v3(vert->pos, loop->v->co);
+ vert->nor = data->packed_nor[BM_elem_index_get(loop->v)];
+}
+
+static void extract_pos_nor_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *mpoly,
+ void *_data)
+{
+ MeshExtract_PosNor_Data *data = _data;
+ PosNorLoop *vert = data->vbo_data + l;
+ const MVert *mvert = &mr->mvert[mloop->v];
+ copy_v3_v3(vert->pos, mvert->co);
+ vert->nor = data->packed_nor[mloop->v];
+ /* Flag for paint mode overlay. */
+ if (mpoly->flag & ME_HIDE)
+ vert->nor.w = -1;
+ else if (mpoly->flag & ME_FACE_SEL)
+ vert->nor.w = 1;
+ else
+ vert->nor.w = 0;
+}
+
+static void extract_pos_nor_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *_data)
+{
+ int l = mr->loop_len + e * 2;
+ MeshExtract_PosNor_Data *data = _data;
+ PosNorLoop *vert = data->vbo_data + l;
+ copy_v3_v3(vert[0].pos, eed->v1->co);
+ copy_v3_v3(vert[1].pos, eed->v2->co);
+ vert[0].nor = data->packed_nor[BM_elem_index_get(eed->v1)];
+ vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)];
+}
+
+static void extract_pos_nor_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *medge,
+ void *_data)
+{
+ int l = mr->loop_len + e * 2;
+ MeshExtract_PosNor_Data *data = _data;
+ PosNorLoop *vert = data->vbo_data + l;
+ copy_v3_v3(vert[0].pos, mr->mvert[medge->v1].co);
+ copy_v3_v3(vert[1].pos, mr->mvert[medge->v2].co);
+ vert[0].nor = data->packed_nor[medge->v1];
+ vert[1].nor = data->packed_nor[medge->v2];
+}
+
+static void extract_pos_nor_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *_data)
+{
+ int l = mr->loop_len + mr->edge_loose_len * 2 + v;
+ MeshExtract_PosNor_Data *data = _data;
+ PosNorLoop *vert = data->vbo_data + l;
+ copy_v3_v3(vert->pos, eve->co);
+ vert->nor = data->packed_nor[BM_elem_index_get(eve)];
+}
+
+static void extract_pos_nor_lvert_mesh(const MeshRenderData *mr,
+ int v,
+ const MVert *mvert,
+ void *_data)
+{
+ int l = mr->loop_len + mr->edge_loose_len * 2 + v;
+ int v_idx = mr->lverts[v];
+ MeshExtract_PosNor_Data *data = _data;
+ PosNorLoop *vert = data->vbo_data + l;
+ copy_v3_v3(vert->pos, mvert->co);
+ vert->nor = data->packed_nor[v_idx];
+}
+
+static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(vbo), void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_pos_nor = {extract_pos_nor_init,
+ NULL,
+ NULL,
+ extract_pos_nor_loop_bmesh,
+ extract_pos_nor_loop_mesh,
+ extract_pos_nor_ledge_bmesh,
+ extract_pos_nor_ledge_mesh,
+ extract_pos_nor_lvert_bmesh,
+ extract_pos_nor_lvert_mesh,
+ extract_pos_nor_finish,
+ 0,
+ true};
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Loop Normal
+ * \{ */
+
+static void *extract_lnor_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_alias_add(&format, "lnor");
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ return vbo->data;
+}
+
+static void extract_lnor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *data)
+{
+ if (mr->loop_normals) {
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->loop_normals[l]);
+ }
+ else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) {
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(loop->v->no);
+ }
+ else {
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(loop->f->no);
+ }
+}
+
+static void extract_lnor_loop_mesh(
+ const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data)
+{
+ if (mr->loop_normals) {
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->loop_normals[l]);
+ }
+ else if (mpoly->flag & ME_SMOOTH) {
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_s3(mr->mvert[mloop->v].no);
+ }
+ else {
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->poly_normals[p]);
+ }
+}
+
+const MeshExtract extract_lnor = {extract_lnor_init,
+ NULL,
+ NULL,
+ extract_lnor_loop_bmesh,
+ extract_lnor_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ MR_DATA_LOOP_NOR,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract UV / Tangent layers
+ * \{ */
+
+static void *extract_uv_tan_init(const MeshRenderData *mr, void *buf)
+{
+ GPUVertFormat format = {0};
+ GPU_vertformat_deinterleave(&format);
+
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+ CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
+ uint32_t uv_layers = mr->cache->cd_used.uv;
+ uint32_t tan_layers = mr->cache->cd_used.tan;
+ float(*orco)[3] = CustomData_get_layer(cd_vdata, CD_ORCO);
+ bool orco_allocated = false;
+ const bool use_orco_tan = mr->cache->cd_used.tan_orco != 0;
+
+ /* XXX FIXME XXX */
+ /* We use a hash to identify each data layer based on its name.
+ * Gawain then search for this name in the current shader and bind if it exists.
+ * NOTE : This is prone to hash collision.
+ * One solution to hash collision would be to format the cd layer name
+ * to a safe glsl var name, but without name clash.
+ * NOTE 2 : Replicate changes to code_generate_vertex_new() in gpu_codegen.c */
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (uv_layers & (1 << i)) {
+ char attr_name[32];
+ const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
+ uint hash = BLI_ghashutil_strhash_p(layer_name);
+ /* UV layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "u%u", hash);
+ GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ /* Auto layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%u", hash);
+ GPU_vertformat_alias_add(&format, attr_name);
+ /* Active render layer name. */
+ if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
+ GPU_vertformat_alias_add(&format, "u");
+ }
+ /* Active display layer name. */
+ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
+ GPU_vertformat_alias_add(&format, "au");
+ /* Alias to pos for edit uvs. */
+ GPU_vertformat_alias_add(&format, "pos");
+ }
+ /* Stencil mask uv layer name. */
+ if (i == CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV)) {
+ GPU_vertformat_alias_add(&format, "mu");
+ }
+ }
+ }
+
+ int tan_len = 0;
+ char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME];
+
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (tan_layers & (1 << i)) {
+ char attr_name[32];
+ const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
+ uint hash = BLI_ghashutil_strhash_p(layer_name);
+ /* Tangent layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "t%u", hash);
+ GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ /* Active render layer name. */
+ if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
+ GPU_vertformat_alias_add(&format, "t");
+ }
+ /* Active display layer name. */
+ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
+ GPU_vertformat_alias_add(&format, "at");
+ }
+
+ BLI_strncpy(tangent_names[tan_len++], layer_name, MAX_CUSTOMDATA_LAYER_NAME);
+ }
+ }
+ if (use_orco_tan && orco == NULL) {
+ /* If orco is not available compute it ourselves */
+ orco_allocated = true;
+ orco = MEM_mallocN(sizeof(*orco) * mr->vert_len, __func__);
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMesh *bm = mr->bm;
+ for (int v = 0; v < mr->vert_len; v++) {
+ copy_v3_v3(orco[v], BM_vert_at_index(bm, v)->co);
+ }
+ }
+ else {
+ const MVert *mvert = mr->mvert;
+ for (int v = 0; v < mr->vert_len; v++, mvert++) {
+ copy_v3_v3(orco[v], mvert->co);
+ }
+ }
+ BKE_mesh_orco_verts_transform(mr->me, orco, mr->vert_len, 0);
+ }
+
+ /* Start Fresh */
+ CustomData_free_layers(cd_ldata, CD_TANGENT, mr->loop_len);
+
+ if (tan_len != 0 || use_orco_tan) {
+ short tangent_mask = 0;
+ bool calc_active_tangent = false;
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BKE_editmesh_loop_tangent_calc(mr->edit_bmesh,
+ calc_active_tangent,
+ tangent_names,
+ tan_len,
+ mr->poly_normals,
+ mr->loop_normals,
+ orco,
+ cd_ldata,
+ mr->loop_len,
+ &tangent_mask);
+ }
+ else {
+ BKE_mesh_calc_loop_tangent_ex(mr->mvert,
+ mr->mpoly,
+ mr->poly_len,
+ mr->mloop,
+ mr->mlooptri,
+ mr->tri_len,
+ cd_ldata,
+ calc_active_tangent,
+ tangent_names,
+ tan_len,
+ mr->poly_normals,
+ mr->loop_normals,
+ orco,
+ cd_ldata,
+ mr->loop_len,
+ &tangent_mask);
+ }
+ }
+
+ if (use_orco_tan) {
+ char attr_name[32];
+ const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_TANGENT, 0);
+ uint hash = BLI_ghashutil_strhash_p(layer_name);
+ BLI_snprintf(attr_name, sizeof(*attr_name), "t%u", hash);
+ GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "t");
+ GPU_vertformat_alias_add(&format, "at");
+ }
+
+ if (orco_allocated) {
+ MEM_SAFE_FREE(orco);
+ }
+
+ int v_len = mr->loop_len;
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ /* VBO will not be used, only allocate minimum of memory. */
+ v_len = 1;
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+
+ float(*uv_data)[2] = (float(*)[2])vbo->data;
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (uv_layers & (1 << i)) {
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPUV, i);
+ BMIter f_iter, l_iter;
+ BMFace *efa;
+ BMLoop *loop;
+ BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs);
+ memcpy(uv_data, luv->uv, sizeof(*uv_data));
+ uv_data++;
+ }
+ }
+ }
+ else {
+ MLoopUV *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i);
+ for (int l = 0; l < mr->loop_len; l++, uv_data++, layer_data++) {
+ memcpy(uv_data, layer_data->uv, sizeof(*uv_data));
+ }
+ }
+ }
+ }
+ /* Start tan_data after uv_data. */
+ float(*tan_data)[4] = (float(*)[4])uv_data;
+ for (int i = 0; i < tan_len; i++) {
+ void *layer_data = CustomData_get_layer_named(cd_ldata, CD_TANGENT, tangent_names[i]);
+ memcpy(tan_data, layer_data, sizeof(*tan_data) * mr->loop_len);
+ tan_data += mr->loop_len;
+ }
+ if (use_orco_tan) {
+ void *layer_data = CustomData_get_layer_n(cd_ldata, CD_TANGENT, 0);
+ memcpy(tan_data, layer_data, sizeof(*tan_data) * mr->loop_len);
+ }
+
+ CustomData_free_layers(cd_ldata, CD_TANGENT, mr->loop_len);
+
+ return NULL;
+}
+
+const MeshExtract extract_uv_tan = {extract_uv_tan_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract VCol
+ * \{ */
+
+static void *extract_vcol_init(const MeshRenderData *mr, void *buf)
+{
+ GPUVertFormat format = {0};
+ GPU_vertformat_deinterleave(&format);
+
+ CustomData *cd_ldata = &mr->me->ldata;
+ uint32_t vcol_layers = mr->cache->cd_used.vcol;
+
+ /* XXX FIXME XXX */
+ /* We use a hash to identify each data layer based on its name.
+ * Gawain then search for this name in the current shader and bind if it exists.
+ * NOTE : This is prone to hash collision.
+ * One solution to hash collision would be to format the cd layer name
+ * to a safe glsl var name, but without name clash.
+ * NOTE 2 : Replicate changes to code_generate_vertex_new() in gpu_codegen.c */
+ for (int i = 0; i < 8; i++) {
+ if (vcol_layers & (1 << i)) {
+ char attr_name[32];
+ const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i);
+ uint hash = BLI_ghashutil_strhash_p(layer_name);
+
+ BLI_snprintf(attr_name, sizeof(attr_name), "c%u", hash);
+ GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) {
+ GPU_vertformat_alias_add(&format, "c");
+ }
+ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) {
+ GPU_vertformat_alias_add(&format, "ac");
+ }
+ /* Gather number of auto layers. */
+ /* We only do vcols that are not overridden by uvs */
+ if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%u", hash);
+ GPU_vertformat_alias_add(&format, attr_name);
+ }
+ }
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ MLoopCol *vcol_data = (MLoopCol *)vbo->data;
+ for (int i = 0; i < 8; i++) {
+ if (vcol_layers & (1 << i)) {
+ void *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
+ memcpy(vcol_data, layer_data, sizeof(*vcol_data) * mr->loop_len);
+ vcol_data += mr->loop_len;
+ }
+ }
+ return NULL;
+}
+
+const MeshExtract extract_vcol = {
+ extract_vcol_init, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, false};
+
+/** \} */ /** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Orco
+ * \{ */
+
+typedef struct MeshExtract_Orco_Data {
+ float (*vbo_data)[4];
+ float (*orco)[3];
+} MeshExtract_Orco_Data;
+
+static void *extract_orco_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
+ * attribs. This is a substential waste of Vram and should be done another way.
+ * Unfortunately, at the time of writting, I did not found any other "non disruptive"
+ * alternative. */
+ GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ CustomData *cd_vdata = &mr->me->vdata;
+
+ MeshExtract_Orco_Data *data = MEM_mallocN(sizeof(*data), __func__);
+ data->vbo_data = (float(*)[4])vbo->data;
+ data->orco = CustomData_get_layer(cd_vdata, CD_ORCO);
+ /* Make sure orco layer was requested only if needed! */
+ BLI_assert(data->orco);
+ return data;
+}
+
+static void extract_orco_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *data)
+{
+ MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data;
+ float *loop_orco = orco_data->vbo_data[l];
+ copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]);
+ loop_orco[3] = 0.0; /* Tag as not a generic attrib */
+}
+
+static void extract_orco_loop_mesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *UNUSED(mpoly),
+ void *data)
+{
+ MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data;
+ float *loop_orco = orco_data->vbo_data[l];
+ copy_v3_v3(loop_orco, orco_data->orco[mloop->v]);
+ loop_orco[3] = 0.0; /* Tag as not a generic attrib */
+}
+
+static void extract_orco_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_orco = {extract_orco_init,
+ NULL,
+ NULL,
+ extract_orco_loop_bmesh,
+ extract_orco_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_orco_finish,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edge Factor
+ * Defines how much an edge is visible.
+ * \{ */
+
+typedef struct MeshExtract_EdgeFac_Data {
+ uchar *vbo_data;
+ bool use_edge_render;
+ /* Number of loop per edge. */
+ uchar edge_loop_count[0];
+} MeshExtract_EdgeFac_Data;
+
+static float loop_edge_factor_get(const float f_no[3],
+ const float v_co[3],
+ const float v_no[3],
+ const float v_next_co[3])
+{
+ float enor[3], evec[3];
+ sub_v3_v3v3(evec, v_next_co, v_co);
+ cross_v3_v3v3(enor, v_no, evec);
+ normalize_v3(enor);
+ float d = fabsf(dot_v3v3(enor, f_no));
+ /* Rescale to the slider range. */
+ d *= (1.0f / 0.065f);
+ CLAMP(d, 0.0f, 1.0f);
+ return d;
+}
+
+static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
+
+ MeshExtract_EdgeFac_Data *data;
+
+ if (mr->extract_type == MR_EXTRACT_MESH) {
+ size_t edge_loop_count_size = sizeof(uint32_t) * mr->edge_len;
+ data = MEM_callocN(sizeof(*data) + edge_loop_count_size, __func__);
+
+ /* HACK(fclem) Detecting the need for edge render.
+ * We could have a flag in the mesh instead or check the modifier stack. */
+ const MEdge *medge = mr->medge;
+ for (int e = 0; e < mr->edge_len; e++, medge++) {
+ if ((medge->flag & ME_EDGERENDER) == 0) {
+ data->use_edge_render = true;
+ break;
+ }
+ }
+ }
+ else {
+ data = MEM_callocN(sizeof(*data), __func__);
+ /* HACK to bypass non-manifold check in mesh_edge_fac_finish(). */
+ data->use_edge_render = true;
+ }
+
+ data->vbo_data = vbo->data;
+ return data;
+}
+
+static void extract_edge_fac_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
+ if (BM_edge_is_manifold(loop->e)) {
+ float ratio = loop_edge_factor_get(loop->f->no, loop->v->co, loop->v->no, loop->next->v->co);
+ data->vbo_data[l] = ratio * 253 + 1;
+ }
+ else {
+ data->vbo_data[l] = 255;
+ }
+}
+
+static void extract_edge_fac_loop_mesh(
+ const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data)
+{
+ MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
+ if (data->use_edge_render) {
+ const MEdge *medge = &mr->medge[mloop->e];
+ data->vbo_data[l] = (medge->flag & ME_EDGERENDER) ? 255 : 0;
+ }
+ else {
+ /* Count loop per edge to detect non-manifold. */
+ if (data->edge_loop_count[mloop->e] < 3) {
+ data->edge_loop_count[mloop->e]++;
+ }
+ if (data->edge_loop_count[mloop->e] == 2) {
+ /* Manifold */
+ int loopend = mpoly->totloop + mpoly->loopstart - 1;
+ int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1);
+ const MLoop *mloop_next = &mr->mloop[other_loop];
+ const MVert *v1 = &mr->mvert[mloop->v];
+ const MVert *v2 = &mr->mvert[mloop_next->v];
+ float vnor_f[3];
+ normal_short_to_float_v3(vnor_f, v1->no);
+ float ratio = loop_edge_factor_get(mr->poly_normals[p], v1->co, vnor_f, v2->co);
+ data->vbo_data[l] = ratio * 253 + 1;
+ }
+ else {
+ /* Non-manifold */
+ data->vbo_data[l] = 255;
+ }
+ }
+}
+
+static void extract_edge_fac_ledge_bmesh(const MeshRenderData *mr,
+ int e,
+ BMEdge *UNUSED(eed),
+ void *_data)
+{
+ MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
+ data->vbo_data[mr->loop_len + e * 2 + 0] = 255;
+ data->vbo_data[mr->loop_len + e * 2 + 1] = 255;
+}
+
+static void extract_edge_fac_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *UNUSED(edge),
+ void *_data)
+{
+ MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
+ data->vbo_data[mr->loop_len + e * 2 + 0] = 255;
+ data->vbo_data[mr->loop_len + e * 2 + 1] = 255;
+}
+
+static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_data)
+{
+ MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
+
+ if (GPU_crappy_amd_driver()) {
+ GPUVertBuf *vbo = (GPUVertBuf *)buf;
+ /* Some AMD drivers strangely crash with VBOs with a one byte format.
+ * To workaround we reinit the vbo with another format and convert
+ * all bytes to floats. */
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ /* We keep the data reference in data->vbo_data. */
+ vbo->data = NULL;
+ GPU_vertbuf_clear(vbo);
+
+ int buf_len = mr->loop_len + mr->loop_loose_len;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, buf_len);
+
+ float *fdata = (float *)vbo->data;
+ for (int l = 0; l < buf_len; l++, fdata++) {
+ *fdata = data->vbo_data[l] / 255.0f;
+ }
+ /* Free old byte data. */
+ MEM_freeN(data->vbo_data);
+ }
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_edge_fac = {extract_edge_fac_init,
+ NULL,
+ NULL,
+ extract_edge_fac_loop_bmesh,
+ extract_edge_fac_loop_mesh,
+ extract_edge_fac_ledge_bmesh,
+ extract_edge_fac_ledge_mesh,
+ NULL,
+ NULL,
+ extract_edge_fac_finish,
+ MR_DATA_POLY_NOR,
+ false};
+
+/** \} */
+/* ---------------------------------------------------------------------- */
+/** \name Extract Vertex Weight
+ * \{ */
+
+typedef struct MeshExtract_Weight_Data {
+ float *vbo_data;
+ const DRW_MeshWeightState *wstate;
+ const MDeformVert *dvert; /* For Mesh. */
+ int cd_ofs; /* For BMesh. */
+} MeshExtract_Weight_Data;
+
+static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate)
+{
+ /* Error state. */
+ if ((wstate->defgroup_active < 0) && (wstate->defgroup_len > 0)) {
+ return -2.0f;
+ }
+ else if (dvert == NULL) {
+ return (wstate->alert_mode != OB_DRAW_GROUPUSER_NONE) ? -1.0f : 0.0f;
+ }
+
+ float input = 0.0f;
+ if (wstate->flags & DRW_MESH_WEIGHT_STATE_MULTIPAINT) {
+ /* Multi-Paint feature */
+ input = BKE_defvert_multipaint_collective_weight(
+ dvert,
+ wstate->defgroup_len,
+ wstate->defgroup_sel,
+ wstate->defgroup_sel_count,
+ (wstate->flags & DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE) != 0);
+ /* make it black if the selected groups have no weight on a vertex */
+ if (input == 0.0f) {
+ return -1.0f;
+ }
+ }
+ else {
+ /* default, non tricky behavior */
+ input = defvert_find_weight(dvert, wstate->defgroup_active);
+
+ if (input == 0.0f) {
+ switch (wstate->alert_mode) {
+ case OB_DRAW_GROUPUSER_ACTIVE:
+ return -1.0f;
+ break;
+ case OB_DRAW_GROUPUSER_ALL:
+ if (defvert_is_weight_zero(dvert, wstate->defgroup_len)) {
+ return -1.0f;
+ }
+ break;
+ }
+ }
+ }
+ CLAMP(input, 0.0f, 1.0f);
+ return input;
+}
+
+static void *extract_weights_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
+
+ MeshExtract_Weight_Data *data = MEM_callocN(sizeof(*data), __func__);
+ data->vbo_data = (float *)vbo->data;
+ data->wstate = &mr->cache->weight_state;
+
+ if (data->wstate->defgroup_active == -1) {
+ /* Nothing to show. */
+ data->dvert = NULL;
+ data->cd_ofs = -1;
+ }
+ else if (mr->extract_type == MR_EXTRACT_BMESH) {
+ data->dvert = NULL;
+ data->cd_ofs = CustomData_get_offset(&mr->bm->vdata, CD_MDEFORMVERT);
+ }
+ else {
+ data->dvert = CustomData_get_layer(&mr->me->vdata, CD_MDEFORMVERT);
+ data->cd_ofs = -1;
+ }
+ return data;
+}
+
+static void extract_weights_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_Weight_Data *data = (MeshExtract_Weight_Data *)_data;
+ const MDeformVert *dvert = (data->cd_ofs != -1) ? BM_ELEM_CD_GET_VOID_P(loop->v, data->cd_ofs) :
+ NULL;
+ data->vbo_data[l] = evaluate_vertex_weight(dvert, data->wstate);
+}
+
+static void extract_weights_loop_mesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *UNUSED(mpoly),
+ void *_data)
+{
+ MeshExtract_Weight_Data *data = (MeshExtract_Weight_Data *)_data;
+ const MDeformVert *dvert = data->dvert ? &data->dvert[mloop->v] : NULL;
+ data->vbo_data[l] = evaluate_vertex_weight(dvert, data->wstate);
+}
+
+static void extract_weights_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_weights = {extract_weights_init,
+ NULL,
+ NULL,
+ extract_weights_loop_bmesh,
+ extract_weights_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_weights_finish,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit Mode Data / Flags
+ * \{ */
+
+typedef struct EditLoopData {
+ uchar v_flag;
+ uchar e_flag;
+ uchar crease;
+ uchar bweight;
+} EditLoopData;
+
+static void mesh_render_data_face_flag(const MeshRenderData *mr,
+ BMFace *efa,
+ const int cd_ofs,
+ EditLoopData *eattr)
+{
+ if (efa == mr->efa_act) {
+ eattr->v_flag |= VFLAG_FACE_ACTIVE;
+ }
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ eattr->v_flag |= VFLAG_FACE_SELECTED;
+ }
+
+ if (efa == mr->efa_act_uv) {
+ eattr->v_flag |= VFLAG_FACE_UV_ACTIVE;
+ }
+ if ((cd_ofs != -1) && uvedit_face_select_test_ex(mr->toolsettings, (BMFace *)efa, cd_ofs)) {
+ eattr->v_flag |= VFLAG_FACE_UV_SELECT;
+ }
+
+#ifdef WITH_FREESTYLE
+ if (mr->freestyle_face_ofs != -1) {
+ const FreestyleFace *ffa = BM_ELEM_CD_GET_VOID_P(efa, mr->freestyle_face_ofs);
+ if (ffa->flag & FREESTYLE_FACE_MARK) {
+ eattr->v_flag |= VFLAG_FACE_FREESTYLE;
+ }
+ }
+#endif
+}
+
+static void mesh_render_data_edge_flag(const MeshRenderData *mr, BMEdge *eed, EditLoopData *eattr)
+{
+ const ToolSettings *ts = mr->toolsettings;
+ const bool is_vertex_select_mode = (ts != NULL) && (ts->selectmode & SCE_SELECT_VERTEX) != 0;
+ const bool is_face_only_select_mode = (ts != NULL) && (ts->selectmode == SCE_SELECT_FACE);
+
+ if (eed == mr->eed_act) {
+ eattr->e_flag |= VFLAG_EDGE_ACTIVE;
+ }
+ if (!is_vertex_select_mode && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ eattr->e_flag |= VFLAG_EDGE_SELECTED;
+ }
+ if (is_vertex_select_mode && BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) {
+ eattr->e_flag |= VFLAG_EDGE_SELECTED;
+ eattr->e_flag |= VFLAG_VERT_SELECTED;
+ }
+ if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
+ eattr->e_flag |= VFLAG_EDGE_SEAM;
+ }
+ if (!BM_elem_flag_test(eed, BM_ELEM_SMOOTH)) {
+ eattr->e_flag |= VFLAG_EDGE_SHARP;
+ }
+
+ /* Use active edge color for active face edges because
+ * specular highlights make it hard to see T55456#510873.
+ *
+ * This isn't ideal since it can't be used when mixing edge/face modes
+ * but it's still better then not being able to see the active face. */
+ if (is_face_only_select_mode) {
+ if (mr->efa_act != NULL) {
+ if (BM_edge_in_face(eed, mr->efa_act)) {
+ eattr->e_flag |= VFLAG_EDGE_ACTIVE;
+ }
+ }
+ }
+
+ /* Use a byte for value range */
+ if (mr->crease_ofs != -1) {
+ float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->crease_ofs);
+ if (crease > 0) {
+ eattr->crease = (uchar)(crease * 255.0f);
+ }
+ }
+ /* Use a byte for value range */
+ if (mr->bweight_ofs != -1) {
+ float bweight = BM_ELEM_CD_GET_FLOAT(eed, mr->bweight_ofs);
+ if (bweight > 0) {
+ eattr->bweight = (uchar)(bweight * 255.0f);
+ }
+ }
+#ifdef WITH_FREESTYLE
+ if (mr->freestyle_edge_ofs != -1) {
+ const FreestyleEdge *fed = BM_ELEM_CD_GET_VOID_P(eed, mr->freestyle_edge_ofs);
+ if (fed->flag & FREESTYLE_EDGE_MARK) {
+ eattr->e_flag |= VFLAG_EDGE_FREESTYLE;
+ }
+ }
+#endif
+}
+
+static void mesh_render_data_loop_flag(const MeshRenderData *mr,
+ BMLoop *loop,
+ const int cd_ofs,
+ EditLoopData *eattr)
+{
+ if (cd_ofs == -1) {
+ return;
+ }
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs);
+ if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) {
+ eattr->v_flag |= VFLAG_VERT_UV_PINNED;
+ }
+ if (uvedit_uv_select_test_ex(mr->toolsettings, loop, cd_ofs)) {
+ eattr->v_flag |= VFLAG_VERT_UV_SELECT;
+ }
+}
+
+static void mesh_render_data_loop_edge_flag(const MeshRenderData *mr,
+ BMLoop *loop,
+ const int cd_ofs,
+ EditLoopData *eattr)
+{
+ if (cd_ofs == -1) {
+ return;
+ }
+ if (uvedit_edge_select_test_ex(mr->toolsettings, loop, cd_ofs)) {
+ eattr->v_flag |= VFLAG_EDGE_UV_SELECT;
+ eattr->v_flag |= VFLAG_VERT_UV_SELECT;
+ }
+}
+
+static void mesh_render_data_vert_flag(const MeshRenderData *mr, BMVert *eve, EditLoopData *eattr)
+{
+ if (eve == mr->eve_act) {
+ eattr->e_flag |= VFLAG_VERT_ACTIVE;
+ }
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ eattr->e_flag |= VFLAG_VERT_SELECTED;
+ }
+}
+
+static void *extract_edit_data_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* WARNING Adjust EditLoopData struct accordingly. */
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
+ GPU_vertformat_alias_add(&format, "flag");
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
+ return vbo->data;
+}
+
+static void extract_edit_data_loop_bmesh(const MeshRenderData *mr,
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ EditLoopData *data = (EditLoopData *)_data + l;
+ memset(data, 0x0, sizeof(*data));
+ mesh_render_data_face_flag(mr, loop->f, -1, data);
+ mesh_render_data_edge_flag(mr, loop->e, data);
+ mesh_render_data_vert_flag(mr, loop->v, data);
+}
+
+static void extract_edit_data_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int p,
+ const MPoly *UNUSED(mpoly),
+ void *_data)
+{
+ EditLoopData *data = (EditLoopData *)_data + l;
+ memset(data, 0x0, sizeof(*data));
+ BMFace *efa = bm_original_face_get(mr, p);
+ BMEdge *eed = bm_original_edge_get(mr, mloop->e);
+ BMVert *eve = bm_original_vert_get(mr, mloop->v);
+ if (efa) {
+ mesh_render_data_face_flag(mr, efa, -1, data);
+ }
+ if (eed) {
+ mesh_render_data_edge_flag(mr, eed, data);
+ }
+ if (eve) {
+ mesh_render_data_vert_flag(mr, eve, data);
+ }
+}
+
+static void extract_edit_data_ledge_bmesh(const MeshRenderData *mr,
+ int e,
+ BMEdge *eed,
+ void *_data)
+{
+ EditLoopData *data = (EditLoopData *)_data + mr->loop_len + e * 2;
+ memset(data, 0x0, sizeof(*data) * 2);
+ mesh_render_data_edge_flag(mr, eed, &data[0]);
+ data[1] = data[0];
+ mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
+ mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
+}
+
+static void extract_edit_data_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *edge,
+ void *_data)
+{
+ EditLoopData *data = (EditLoopData *)_data + mr->loop_len + e * 2;
+ memset(data, 0x0, sizeof(*data) * 2);
+ int e_idx = mr->ledges[e];
+ BMEdge *eed = bm_original_edge_get(mr, e_idx);
+ BMVert *eve1 = bm_original_vert_get(mr, edge->v1);
+ BMVert *eve2 = bm_original_vert_get(mr, edge->v2);
+ if (eed) {
+ mesh_render_data_edge_flag(mr, eed, &data[0]);
+ data[1] = data[0];
+ }
+ if (eve1) {
+ mesh_render_data_vert_flag(mr, eve1, &data[0]);
+ }
+ if (eve2) {
+ mesh_render_data_vert_flag(mr, eve2, &data[1]);
+ }
+}
+
+static void extract_edit_data_lvert_bmesh(const MeshRenderData *mr,
+ int v,
+ BMVert *eve,
+ void *_data)
+{
+ EditLoopData *data = (EditLoopData *)_data + mr->loop_len + mr->edge_loose_len * 2 + v;
+ memset(data, 0x0, sizeof(*data));
+ mesh_render_data_vert_flag(mr, eve, data);
+}
+
+static void extract_edit_data_lvert_mesh(const MeshRenderData *mr,
+ int v,
+ const MVert *UNUSED(mvert),
+ void *_data)
+{
+ EditLoopData *data = (EditLoopData *)_data + mr->loop_len + mr->edge_loose_len * 2 + v;
+ memset(data, 0x0, sizeof(*data));
+ int v_idx = mr->lverts[v];
+ BMVert *eve = bm_original_vert_get(mr, v_idx);
+ if (eve) {
+ mesh_render_data_vert_flag(mr, eve, data);
+ }
+}
+
+const MeshExtract extract_edit_data = {extract_edit_data_init,
+ NULL,
+ NULL,
+ extract_edit_data_loop_bmesh,
+ extract_edit_data_loop_mesh,
+ extract_edit_data_ledge_bmesh,
+ extract_edit_data_ledge_mesh,
+ extract_edit_data_lvert_bmesh,
+ extract_edit_data_lvert_mesh,
+ NULL,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV Data / Flags
+ * \{ */
+
+typedef struct MeshExtract_EditUVData_Data {
+ EditLoopData *vbo_data;
+ int cd_ofs;
+} MeshExtract_EditUVData_Data;
+
+static void *extract_edituv_data_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* WARNING Adjust EditLoopData struct accordingly. */
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
+ GPU_vertformat_alias_add(&format, "flag");
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ CustomData *cd_ldata = &mr->me->ldata;
+
+ MeshExtract_EditUVData_Data *data = MEM_callocN(sizeof(*data), __func__);
+ data->vbo_data = (EditLoopData *)vbo->data;
+ data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV);
+ return data;
+}
+
+static void extract_edituv_data_loop_bmesh(const MeshRenderData *mr,
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_EditUVData_Data *data = (MeshExtract_EditUVData_Data *)_data;
+ EditLoopData *eldata = data->vbo_data + l;
+ memset(eldata, 0x0, sizeof(*eldata));
+ mesh_render_data_loop_flag(mr, loop, data->cd_ofs, eldata);
+ mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata);
+}
+
+static void extract_edituv_data_loop_mesh(
+ const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data)
+{
+ MeshExtract_EditUVData_Data *data = (MeshExtract_EditUVData_Data *)_data;
+ EditLoopData *eldata = data->vbo_data + l;
+ memset(eldata, 0x0, sizeof(*eldata));
+ BMFace *efa = bm_original_face_get(mr, p);
+ if (efa) {
+ BMEdge *eed = bm_original_edge_get(mr, mloop->e);
+ BMVert *eve = bm_original_vert_get(mr, mloop->v);
+ if (eed && eve) {
+ /* Loop on an edge endpoint. */
+ BMLoop *loop = BM_face_edge_share_loop(efa, eed);
+ mesh_render_data_loop_flag(mr, loop, data->cd_ofs, eldata);
+ mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata);
+ }
+ else {
+ if (eed == NULL) {
+ /* Find if the loop's vert is not part of an edit edge.
+ * For this, we check if the previous loop was on an edge. */
+ int loopend = mpoly->loopstart + mpoly->totloop - 1;
+ int l_prev = (l == mpoly->loopstart) ? loopend : (l - 1);
+ const MLoop *mloop_prev = &mr->mloop[l_prev];
+ eed = bm_original_edge_get(mr, mloop_prev->e);
+ }
+ if (eed) {
+ /* Mapped points on an edge between two edit verts. */
+ BMLoop *loop = BM_face_edge_share_loop(efa, eed);
+ mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata);
+ }
+ }
+ }
+}
+
+static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr),
+ void *UNUSED(buf),
+ void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_edituv_data = {extract_edituv_data_init,
+ NULL,
+ NULL,
+ extract_edituv_data_loop_bmesh,
+ extract_edituv_data_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_edituv_data_finish,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV area stretch
+ * \{ */
+
+static void *extract_stretch_area_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "stretch", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ return NULL;
+}
+
+BLI_INLINE float area_ratio_get(float area, float uvarea)
+{
+ if (area >= FLT_EPSILON && uvarea >= FLT_EPSILON) {
+ /* Tag inversion by using the sign. */
+ return (area > uvarea) ? (uvarea / area) : -(area / uvarea);
+ }
+ return 0.0f;
+}
+
+BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio)
+{
+ ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio;
+ return (ratio > 1.0f) ? (1.0f / ratio) : ratio;
+}
+
+static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *UNUSED(data))
+{
+ float totarea = 0, totuvarea = 0;
+ float *area_ratio = MEM_mallocN(sizeof(float) * mr->poly_len, __func__);
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ CustomData *cd_ldata = &mr->bm->ldata;
+ int uv_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV);
+
+ BMFace *efa;
+ BMIter f_iter;
+ int f;
+ BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) {
+ float area = BM_face_calc_area(efa);
+ float uvarea = BM_face_calc_area_uv(efa, uv_ofs);
+ totarea += area;
+ totuvarea += uvarea;
+ area_ratio[f] = area_ratio_get(area, uvarea);
+ }
+ }
+ else if (mr->extract_type == MR_EXTRACT_MAPPED) {
+ const MLoopUV *uv_data = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
+ const MPoly *mpoly = mr->mpoly;
+ for (int p = 0; p < mr->poly_len; p++, mpoly++) {
+ float area = BKE_mesh_calc_poly_area(mpoly, &mr->mloop[mpoly->loopstart], mr->mvert);
+ float uvarea = BKE_mesh_calc_poly_uv_area(mpoly, uv_data);
+ totarea += area;
+ totuvarea += uvarea;
+ area_ratio[p] = area_ratio_get(area, uvarea);
+ }
+ }
+ else {
+ /* Should not happen. */
+ BLI_assert(0);
+ }
+
+ float tot_ratio, inv_tot_ratio;
+ if (totarea < FLT_EPSILON || totuvarea < FLT_EPSILON) {
+ tot_ratio = 0.0f;
+ inv_tot_ratio = 0.0f;
+ }
+ else {
+ tot_ratio = totarea / totuvarea;
+ inv_tot_ratio = totuvarea / totarea;
+ }
+
+ /* Convert in place to avoid an extra allocation */
+ uint16_t *poly_stretch = (uint16_t *)area_ratio;
+ for (int p = 0; p < mr->poly_len; p++) {
+ float stretch = area_ratio_to_stretch(area_ratio[p], tot_ratio, inv_tot_ratio);
+ poly_stretch[p] = (1.0f - stretch) * 65534.0f;
+ }
+
+ /* Copy face data for each loop. */
+ GPUVertBuf *vbo = buf;
+ uint16_t *loop_stretch = (uint16_t *)vbo->data;
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMFace *efa;
+ BMIter f_iter;
+ int f, l = 0;
+ BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) {
+ for (int i = 0; i < efa->len; i++, l++) {
+ loop_stretch[l] = poly_stretch[f];
+ }
+ }
+ }
+ else if (mr->extract_type == MR_EXTRACT_MAPPED) {
+ const MPoly *mpoly = mr->mpoly;
+ for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) {
+ for (int i = 0; i < mpoly->totloop; i++, l++) {
+ loop_stretch[l] = poly_stretch[p];
+ }
+ }
+ }
+ else {
+ /* Should not happen. */
+ BLI_assert(0);
+ }
+
+ MEM_freeN(area_ratio);
+}
+
+const MeshExtract extract_stretch_area = {extract_stretch_area_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ mesh_stretch_area_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV angle stretch
+ * \{ */
+
+typedef struct UVStretchAngle {
+ int16_t angle;
+ int16_t uv_angles[2];
+} UVStretchAngle;
+
+typedef struct MeshExtract_StretchAngle_Data {
+ UVStretchAngle *vbo_data;
+ MLoopUV *luv;
+ float auv[2][2], last_auv[2];
+ float av[2][3], last_av[3];
+ int cd_ofs;
+} MeshExtract_StretchAngle_Data;
+
+static void compute_normalize_edge_vectors(float auv[2][2],
+ float av[2][3],
+ const float uv[2],
+ const float uv_prev[2],
+ const float co[2],
+ const float co_prev[2])
+{
+ /* Move previous edge. */
+ copy_v2_v2(auv[0], auv[1]);
+ copy_v3_v3(av[0], av[1]);
+ /* 2d edge */
+ sub_v2_v2v2(auv[1], uv_prev, uv);
+ normalize_v2(auv[1]);
+ /* 3d edge */
+ sub_v3_v3v3(av[1], co_prev, co);
+ normalize_v3(av[1]);
+}
+
+static short v2_to_short_angle(float v[2])
+{
+ return atan2f(v[1], v[0]) * (float)M_1_PI * SHRT_MAX;
+}
+
+static void edituv_get_stretch_angle(float auv[2][2], float av[2][3], UVStretchAngle *r_stretch)
+{
+ /* Send uvs to the shader and let it compute the aspect corrected angle. */
+ r_stretch->uv_angles[0] = v2_to_short_angle(auv[0]);
+ r_stretch->uv_angles[1] = v2_to_short_angle(auv[1]);
+ /* Compute 3D angle here. */
+ r_stretch->angle = angle_normalized_v3v3(av[0], av[1]) * (float)M_1_PI * SHRT_MAX;
+
+#if 0 /* here for reference, this is done in shader now. */
+ float uvang = angle_normalized_v2v2(auv0, auv1);
+ float ang = angle_normalized_v3v3(av0, av1);
+ float stretch = fabsf(uvang - ang) / (float)M_PI;
+ return 1.0f - pow2f(1.0f - stretch);
+#endif
+}
+
+static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* WARNING Adjust UVStretchAngle struct accordingly. */
+ GPU_vertformat_attr_add(&format, "angle", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ MeshExtract_StretchAngle_Data *data = MEM_callocN(sizeof(*data), __func__);
+ data->vbo_data = (UVStretchAngle *)vbo->data;
+
+ /* Special iter nneded to save about half of the computing cost. */
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
+ }
+ else if (mr->extract_type == MR_EXTRACT_MAPPED) {
+ data->luv = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
+ }
+ else {
+ BLI_assert(0);
+ }
+ return data;
+}
+
+static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_StretchAngle_Data *data = (MeshExtract_StretchAngle_Data *)_data;
+ float(*auv)[2] = data->auv, *last_auv = data->last_auv;
+ float(*av)[3] = data->av, *last_av = data->last_av;
+ const MLoopUV *luv, *luv_next;
+ BMLoop *l_next = loop->next;
+ BMFace *efa = loop->f;
+ if (loop == efa->l_first) {
+ /* First loop in face. */
+ BMLoop *l_tmp = loop->prev;
+ BMLoop *l_next_tmp = loop;
+ luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs);
+ luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs);
+ compute_normalize_edge_vectors(
+ auv, av, luv->uv, luv_next->uv, l_tmp->v->co, l_next_tmp->v->co);
+ /* Save last edge. */
+ copy_v2_v2(last_auv, auv[1]);
+ copy_v3_v3(last_av, av[1]);
+ }
+ if (l_next == efa->l_first) {
+ /* Move previous edge. */
+ copy_v2_v2(auv[0], auv[1]);
+ copy_v3_v3(av[0], av[1]);
+ /* Copy already calculated last edge. */
+ copy_v2_v2(auv[1], last_auv);
+ copy_v3_v3(av[1], last_av);
+ }
+ else {
+ luv = BM_ELEM_CD_GET_VOID_P(loop, data->cd_ofs);
+ luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs);
+ compute_normalize_edge_vectors(auv, av, luv->uv, luv_next->uv, loop->v->co, l_next->v->co);
+ }
+ edituv_get_stretch_angle(auv, av, data->vbo_data + l);
+}
+
+static void extract_stretch_angle_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *UNUSED(mloop),
+ int UNUSED(p),
+ const MPoly *mpoly,
+ void *_data)
+{
+ MeshExtract_StretchAngle_Data *data = (MeshExtract_StretchAngle_Data *)_data;
+ float(*auv)[2] = data->auv, *last_auv = data->last_auv;
+ float(*av)[3] = data->av, *last_av = data->last_av;
+ int l_next = l + 1, loopend = mpoly->loopstart + mpoly->totloop;
+ const MVert *v, *v_next;
+ if (l == mpoly->loopstart) {
+ /* First loop in face. */
+ int l_tmp = loopend - 1;
+ int l_next_tmp = mpoly->loopstart;
+ v = &mr->mvert[mr->mloop[l_tmp].v];
+ v_next = &mr->mvert[mr->mloop[l_next_tmp].v];
+ compute_normalize_edge_vectors(
+ auv, av, data->luv[l_tmp].uv, data->luv[l_next_tmp].uv, v->co, v_next->co);
+ /* Save last edge. */
+ copy_v2_v2(last_auv, auv[1]);
+ copy_v3_v3(last_av, av[1]);
+ }
+ if (l_next == loopend) {
+ l_next = mpoly->loopstart;
+ /* Move previous edge. */
+ copy_v2_v2(auv[0], auv[1]);
+ copy_v3_v3(av[0], av[1]);
+ /* Copy already calculated last edge. */
+ copy_v2_v2(auv[1], last_auv);
+ copy_v3_v3(av[1], last_av);
+ }
+ else {
+ v = &mr->mvert[mr->mloop[l].v];
+ v_next = &mr->mvert[mr->mloop[l_next].v];
+ compute_normalize_edge_vectors(
+ auv, av, data->luv[l].uv, data->luv[l_next].uv, v->co, v_next->co);
+ }
+ edituv_get_stretch_angle(auv, av, data->vbo_data + l);
+}
+
+static void extract_stretch_angle_finish(const MeshRenderData *UNUSED(mr),
+ void *UNUSED(buf),
+ void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_stretch_angle = {extract_stretch_angle_init,
+ NULL,
+ NULL,
+ extract_stretch_angle_loop_bmesh,
+ extract_stretch_angle_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_stretch_angle_finish,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV angle stretch
+ * \{ */
+
+static void *extract_mesh_analysis_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ return NULL;
+}
+
+static void axis_from_enum_v3(float v[3], const char axis)
+{
+ zero_v3(v);
+ if (axis < 3) {
+ v[axis] = 1.0f;
+ }
+ else {
+ v[axis - 3] = -1.0f;
+ }
+}
+
+BLI_INLINE float overhang_remap(float fac, float min, float max, float minmax_irange)
+{
+ if (fac < min) {
+ fac = 1.0f;
+ }
+ else if (fac > max) {
+ fac = -1.0f;
+ }
+ else {
+ fac = (fac - min) * minmax_irange;
+ fac = 1.0f - fac;
+ CLAMP(fac, 0.0f, 1.0f);
+ }
+ return fac;
+}
+
+static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang)
+{
+ const MeshStatVis *statvis = &mr->toolsettings->statvis;
+ const float min = statvis->overhang_min / (float)M_PI;
+ const float max = statvis->overhang_max / (float)M_PI;
+ const char axis = statvis->overhang_axis;
+ BMEditMesh *em = mr->edit_bmesh;
+ BMIter iter;
+ BMesh *bm = em->bm;
+ BMFace *f;
+ float dir[3];
+ const float minmax_irange = 1.0f / (max - min);
+
+ BLI_assert(min <= max);
+
+ axis_from_enum_v3(dir, axis);
+
+ if (em && LIKELY(em->ob)) {
+ /* now convert into global space */
+ mul_transposed_mat3_m4_v3(em->ob->obmat, dir);
+ normalize_v3(dir);
+ }
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ int l = 0;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ float fac = angle_normalized_v3v3(f->no, dir) / (float)M_PI;
+ fac = overhang_remap(fac, min, max, minmax_irange);
+ for (int i = 0; i < f->len; i++, l++) {
+ r_overhang[l] = fac;
+ }
+ }
+ }
+ else {
+ const MPoly *mpoly = mr->mpoly;
+ for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) {
+ float fac = angle_normalized_v3v3(mr->poly_normals[p], dir) / (float)M_PI;
+ fac = overhang_remap(fac, min, max, minmax_irange);
+ for (int i = 0; i < mpoly->totloop; i++, l++) {
+ r_overhang[l] = fac;
+ }
+ }
+ }
+}
+
+/* so we can use jitter values for face interpolation */
+static void uv_from_jitter_v2(float uv[2])
+{
+ uv[0] += 0.5f;
+ uv[1] += 0.5f;
+ if (uv[0] + uv[1] > 1.0f) {
+ uv[0] = 1.0f - uv[0];
+ uv[1] = 1.0f - uv[1];
+ }
+
+ CLAMP(uv[0], 0.0f, 1.0f);
+ CLAMP(uv[1], 0.0f, 1.0f);
+}
+
+BLI_INLINE float thickness_remap(float fac, float min, float max, float minmax_irange)
+{
+ /* important not '<=' */
+ if (fac < max) {
+ fac = (fac - min) * minmax_irange;
+ fac = 1.0f - fac;
+ CLAMP(fac, 0.0f, 1.0f);
+ }
+ else {
+ fac = -1.0f;
+ }
+ return fac;
+}
+
+static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness)
+{
+ const float eps_offset = 0.00002f; /* values <= 0.00001 give errors */
+ /* cheating to avoid another allocation */
+ float *face_dists = r_thickness + (mr->loop_len - mr->poly_len);
+ BMEditMesh *em = mr->edit_bmesh;
+ const float scale = 1.0f / mat4_to_scale(em->ob->obmat);
+ const MeshStatVis *statvis = &mr->toolsettings->statvis;
+ const float min = statvis->thickness_min * scale;
+ const float max = statvis->thickness_max * scale;
+ const float minmax_irange = 1.0f / (max - min);
+ const int samples = statvis->thickness_samples;
+ float jit_ofs[32][2];
+ BLI_assert(samples <= 32);
+ BLI_assert(min <= max);
+
+ copy_vn_fl(face_dists, mr->poly_len, max);
+
+ BLI_jitter_init(jit_ofs, samples);
+ for (int j = 0; j < samples; j++) {
+ uv_from_jitter_v2(jit_ofs[j]);
+ }
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMesh *bm = em->bm;
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+
+ struct BMBVHTree *bmtree = BKE_bmbvh_new_from_editmesh(em, 0, NULL, false);
+ struct BMLoop *(*looptris)[3] = em->looptris;
+ for (int i = 0; i < mr->tri_len; i++) {
+ BMLoop **ltri = looptris[i];
+ const int index = BM_elem_index_get(ltri[0]->f);
+ const float *cos[3] = {ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co};
+ float ray_co[3];
+ float ray_no[3];
+
+ normal_tri_v3(ray_no, cos[2], cos[1], cos[0]);
+
+ for (int j = 0; j < samples; j++) {
+ float dist = face_dists[index];
+ interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]);
+ madd_v3_v3fl(ray_co, ray_no, eps_offset);
+
+ BMFace *f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, &dist, NULL, NULL);
+ if (f_hit && dist < face_dists[index]) {
+ float angle_fac = fabsf(dot_v3v3(ltri[0]->f->no, f_hit->no));
+ angle_fac = 1.0f - angle_fac;
+ angle_fac = angle_fac * angle_fac * angle_fac;
+ angle_fac = 1.0f - angle_fac;
+ dist /= angle_fac;
+ if (dist < face_dists[index]) {
+ face_dists[index] = dist;
+ }
+ }
+ }
+ }
+ BKE_bmbvh_free(bmtree);
+
+ BMIter iter;
+ BMFace *f;
+ int l = 0;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ float fac = face_dists[BM_elem_index_get(f)];
+ fac = thickness_remap(fac, min, max, minmax_irange);
+ for (int i = 0; i < f->len; i++, l++) {
+ r_thickness[l] = fac;
+ }
+ }
+ }
+ else {
+ BVHTreeFromMesh treeData = {NULL};
+
+ BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr->me, BVHTREE_FROM_LOOPTRI, 4);
+ const MLoopTri *mlooptri = mr->mlooptri;
+ for (int i = 0; i < mr->tri_len; i++, mlooptri++) {
+ const int index = mlooptri->poly;
+ const float *cos[3] = {mr->mvert[mr->mloop[mlooptri->tri[0]].v].co,
+ mr->mvert[mr->mloop[mlooptri->tri[1]].v].co,
+ mr->mvert[mr->mloop[mlooptri->tri[2]].v].co};
+ float ray_co[3];
+ float ray_no[3];
+
+ normal_tri_v3(ray_no, cos[2], cos[1], cos[0]);
+
+ for (int j = 0; j < samples; j++) {
+ interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]);
+ madd_v3_v3fl(ray_co, ray_no, eps_offset);
+
+ BVHTreeRayHit hit;
+ hit.index = -1;
+ hit.dist = face_dists[index];
+ if ((BLI_bvhtree_ray_cast(
+ tree, ray_co, ray_no, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) &&
+ hit.dist < face_dists[index]) {
+ float angle_fac = fabsf(dot_v3v3(mr->poly_normals[index], hit.no));
+ angle_fac = 1.0f - angle_fac;
+ angle_fac = angle_fac * angle_fac * angle_fac;
+ angle_fac = 1.0f - angle_fac;
+ hit.dist /= angle_fac;
+ if (hit.dist < face_dists[index]) {
+ face_dists[index] = hit.dist;
+ }
+ }
+ }
+ }
+
+ const MPoly *mpoly = mr->mpoly;
+ for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) {
+ float fac = face_dists[p];
+ fac = thickness_remap(fac, min, max, minmax_irange);
+ for (int i = 0; i < mpoly->totloop; i++, l++) {
+ r_thickness[l] = fac;
+ }
+ }
+ }
+}
+
+struct BVHTree_OverlapData {
+ const Mesh *me;
+ const MLoopTri *mlooptri;
+ float epsilon;
+};
+
+static bool bvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+{
+ struct BVHTree_OverlapData *data = userdata;
+ const Mesh *me = data->me;
+
+ const MLoopTri *tri_a = &data->mlooptri[index_a];
+ const MLoopTri *tri_b = &data->mlooptri[index_b];
+
+ if (UNLIKELY(tri_a->poly == tri_b->poly)) {
+ return false;
+ }
+
+ const float *tri_a_co[3] = {me->mvert[me->mloop[tri_a->tri[0]].v].co,
+ me->mvert[me->mloop[tri_a->tri[1]].v].co,
+ me->mvert[me->mloop[tri_a->tri[2]].v].co};
+ const float *tri_b_co[3] = {me->mvert[me->mloop[tri_b->tri[0]].v].co,
+ me->mvert[me->mloop[tri_b->tri[1]].v].co,
+ me->mvert[me->mloop[tri_b->tri[2]].v].co};
+ float ix_pair[2][3];
+ int verts_shared = 0;
+
+ verts_shared = (ELEM(tri_a_co[0], UNPACK3(tri_b_co)) + ELEM(tri_a_co[1], UNPACK3(tri_b_co)) +
+ ELEM(tri_a_co[2], UNPACK3(tri_b_co)));
+
+ /* if 2 points are shared, bail out */
+ if (verts_shared >= 2) {
+ return false;
+ }
+
+ return (isect_tri_tri_epsilon_v3(
+ UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1], data->epsilon) &&
+ /* if we share a vertex, check the intersection isn't a 'point' */
+ ((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
+}
+
+static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect)
+{
+ BMEditMesh *em = mr->edit_bmesh;
+
+ for (int l = 0; l < mr->loop_len; l++) {
+ r_intersect[l] = -1.0f;
+ }
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ uint overlap_len;
+ BMesh *bm = em->bm;
+
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+
+ struct BMBVHTree *bmtree = BKE_bmbvh_new_from_editmesh(em, 0, NULL, false);
+ BVHTreeOverlap *overlap = BKE_bmbvh_overlap(bmtree, bmtree, &overlap_len);
+
+ if (overlap) {
+ for (int i = 0; i < overlap_len; i++) {
+ BMFace *f_hit_pair[2] = {
+ em->looptris[overlap[i].indexA][0]->f,
+ em->looptris[overlap[i].indexB][0]->f,
+ };
+ for (int j = 0; j < 2; j++) {
+ BMFace *f_hit = f_hit_pair[j];
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f_hit);
+ int l = BM_elem_index_get(l_first);
+ for (int k = 0; k < f_hit->len; k++, l++) {
+ r_intersect[l] = 1.0f;
+ }
+ }
+ }
+ MEM_freeN(overlap);
+ }
+
+ BKE_bmbvh_free(bmtree);
+ }
+ else {
+ uint overlap_len;
+ BVHTreeFromMesh treeData = {NULL};
+
+ BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr->me, BVHTREE_FROM_LOOPTRI, 4);
+
+ struct BVHTree_OverlapData data = {
+ .me = mr->me, .mlooptri = mr->mlooptri, .epsilon = BLI_bvhtree_get_epsilon(tree)};
+
+ BVHTreeOverlap *overlap = BLI_bvhtree_overlap(tree, tree, &overlap_len, bvh_overlap_cb, &data);
+ if (overlap) {
+ for (int i = 0; i < overlap_len; i++) {
+ const MPoly *f_hit_pair[2] = {
+ &mr->mpoly[mr->mlooptri[overlap[i].indexA].poly],
+ &mr->mpoly[mr->mlooptri[overlap[i].indexB].poly],
+ };
+ for (int j = 0; j < 2; j++) {
+ const MPoly *f_hit = f_hit_pair[j];
+ int l = f_hit->loopstart;
+ for (int k = 0; k < f_hit->totloop; k++, l++) {
+ r_intersect[l] = 1.0f;
+ }
+ }
+ }
+ MEM_freeN(overlap);
+ }
+ }
+}
+
+BLI_INLINE float distort_remap(float fac, float min, float UNUSED(max), float minmax_irange)
+{
+ if (fac >= min) {
+ fac = (fac - min) * minmax_irange;
+ CLAMP(fac, 0.0f, 1.0f);
+ }
+ else {
+ /* fallback */
+ fac = -1.0f;
+ }
+ return fac;
+}
+
+static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort)
+{
+ BMEditMesh *em = mr->edit_bmesh;
+ const MeshStatVis *statvis = &mr->toolsettings->statvis;
+ const float min = statvis->distort_min;
+ const float max = statvis->distort_max;
+ const float minmax_irange = 1.0f / (max - min);
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMIter iter;
+ BMesh *bm = em->bm;
+ BMFace *f;
+
+ int l = 0;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ float fac = -1.0f;
+
+ if (f->len > 3) {
+ BMLoop *l_iter, *l_first;
+
+ fac = 0.0f;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ float no_corner[3];
+ BM_loop_calc_face_normal_safe(l_iter, no_corner);
+ /* simple way to detect (what is most likely) concave */
+ if (dot_v3v3(f->no, no_corner) < 0.0f) {
+ negate_v3(no_corner);
+ }
+ fac = max_ff(fac, angle_normalized_v3v3(f->no, no_corner));
+ } while ((l_iter = l_iter->next) != l_first);
+ fac *= 2.0f;
+ }
+
+ fac = distort_remap(fac, min, max, minmax_irange);
+ for (int i = 0; i < f->len; i++, l++) {
+ r_distort[l] = fac;
+ }
+ }
+ }
+ else {
+ const MPoly *mpoly = mr->mpoly;
+ for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) {
+ float fac = -1.0f;
+
+ if (mpoly->totloop > 3) {
+ float *f_no = mr->poly_normals[p];
+ fac = 0.0f;
+
+ for (int i = 1; i <= mpoly->totloop; i++) {
+ const MLoop *l_prev = &mr->mloop[mpoly->loopstart + (i - 1) % mpoly->totloop];
+ const MLoop *l_curr = &mr->mloop[mpoly->loopstart + (i + 0) % mpoly->totloop];
+ const MLoop *l_next = &mr->mloop[mpoly->loopstart + (i + 1) % mpoly->totloop];
+ float no_corner[3];
+ normal_tri_v3(no_corner,
+ mr->mvert[l_prev->v].co,
+ mr->mvert[l_curr->v].co,
+ mr->mvert[l_next->v].co);
+ /* simple way to detect (what is most likely) concave */
+ if (dot_v3v3(f_no, no_corner) < 0.0f) {
+ negate_v3(no_corner);
+ }
+ fac = max_ff(fac, angle_normalized_v3v3(f_no, no_corner));
+ }
+ fac *= 2.0f;
+ }
+
+ fac = distort_remap(fac, min, max, minmax_irange);
+ for (int i = 0; i < mpoly->totloop; i++, l++) {
+ r_distort[l] = fac;
+ }
+ }
+ }
+}
+
+BLI_INLINE float sharp_remap(float fac, float min, float UNUSED(max), float minmax_irange)
+{
+ /* important not '>=' */
+ if (fac > min) {
+ fac = (fac - min) * minmax_irange;
+ CLAMP(fac, 0.0f, 1.0f);
+ }
+ else {
+ /* fallback */
+ fac = -1.0f;
+ }
+ return fac;
+}
+
+static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp)
+{
+ BMEditMesh *em = mr->edit_bmesh;
+ const MeshStatVis *statvis = &mr->toolsettings->statvis;
+ const float min = statvis->sharp_min;
+ const float max = statvis->sharp_max;
+ const float minmax_irange = 1.0f / (max - min);
+
+ /* Can we avoid this extra allocation? */
+ float *vert_angles = MEM_mallocN(sizeof(float) * mr->vert_len, __func__);
+ copy_vn_fl(vert_angles, mr->vert_len, -M_PI);
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMIter iter, l_iter;
+ BMesh *bm = em->bm;
+ BMFace *efa;
+ BMEdge *e;
+ BMLoop *loop;
+ /* first assign float values to verts */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ float angle = BM_edge_calc_face_angle_signed(e);
+ float *col1 = &vert_angles[BM_elem_index_get(e->v1)];
+ float *col2 = &vert_angles[BM_elem_index_get(e->v2)];
+ *col1 = max_ff(*col1, angle);
+ *col2 = max_ff(*col2, angle);
+ }
+ /* Copy vert value to loops. */
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) {
+ int l = BM_elem_index_get(loop);
+ int v = BM_elem_index_get(loop->v);
+ r_sharp[l] = sharp_remap(vert_angles[v], min, max, minmax_irange);
+ }
+ }
+ }
+ else {
+ /* first assign float values to verts */
+ const MPoly *mpoly = mr->mpoly;
+
+ EdgeHash *eh = BLI_edgehash_new_ex(__func__, mr->edge_len);
+
+ for (int p = 0; p < mr->poly_len; p++, mpoly++) {
+ for (int i = 0; i < mpoly->totloop; i++) {
+ const MLoop *l_curr = &mr->mloop[mpoly->loopstart + (i + 0) % mpoly->totloop];
+ const MLoop *l_next = &mr->mloop[mpoly->loopstart + (i + 1) % mpoly->totloop];
+ const MVert *v_curr = &mr->mvert[l_curr->v];
+ const MVert *v_next = &mr->mvert[l_next->v];
+ float angle;
+ void **pval;
+ bool value_is_init = BLI_edgehash_ensure_p(eh, l_curr->v, l_next->v, &pval);
+ if (!value_is_init) {
+ *pval = mr->poly_normals[p];
+ /* non-manifold edge, yet... */
+ continue;
+ }
+ else if (*pval != NULL) {
+ const float *f1_no = mr->poly_normals[p];
+ const float *f2_no = *pval;
+ angle = angle_normalized_v3v3(f1_no, f2_no);
+ angle = is_edge_convex_v3(v_curr->co, v_next->co, f1_no, f2_no) ? angle : -angle;
+ /* Tag as manifold. */
+ *pval = NULL;
+ }
+ else {
+ /* non-manifold edge */
+ angle = DEG2RADF(90.0f);
+ }
+ float *col1 = &vert_angles[l_curr->v];
+ float *col2 = &vert_angles[l_next->v];
+ *col1 = max_ff(*col1, angle);
+ *col2 = max_ff(*col2, angle);
+ }
+ }
+ /* Remaining non manifold edges. */
+ EdgeHashIterator *ehi = BLI_edgehashIterator_new(eh);
+ for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
+ if (BLI_edgehashIterator_getValue(ehi) != NULL) {
+ uint v1, v2;
+ const float angle = DEG2RADF(90.0f);
+ BLI_edgehashIterator_getKey(ehi, &v1, &v2);
+ float *col1 = &vert_angles[v1];
+ float *col2 = &vert_angles[v2];
+ *col1 = max_ff(*col1, angle);
+ *col2 = max_ff(*col2, angle);
+ }
+ }
+ BLI_edgehashIterator_free(ehi);
+ BLI_edgehash_free(eh, NULL);
+
+ const MLoop *mloop = mr->mloop;
+ for (int l = 0; l < mr->loop_len; l++, mloop++) {
+ r_sharp[l] = sharp_remap(vert_angles[mloop->v], min, max, minmax_irange);
+ }
+ }
+
+ MEM_freeN(vert_angles);
+}
+
+static void extract_mesh_analysis_finish(const MeshRenderData *mr, void *buf, void *UNUSED(data))
+{
+ BLI_assert(mr->edit_bmesh);
+
+ GPUVertBuf *vbo = buf;
+ float *l_weight = (float *)vbo->data;
+
+ switch (mr->toolsettings->statvis.type) {
+ case SCE_STATVIS_OVERHANG:
+ statvis_calc_overhang(mr, l_weight);
+ break;
+ case SCE_STATVIS_THICKNESS:
+ statvis_calc_thickness(mr, l_weight);
+ break;
+ case SCE_STATVIS_INTERSECT:
+ statvis_calc_intersect(mr, l_weight);
+ break;
+ case SCE_STATVIS_DISTORT:
+ statvis_calc_distort(mr, l_weight);
+ break;
+ case SCE_STATVIS_SHARP:
+ statvis_calc_sharp(mr, l_weight);
+ break;
+ }
+}
+
+const MeshExtract extract_mesh_analysis = {extract_mesh_analysis_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_mesh_analysis_finish,
+ /* This is not needed for all vis type.
+ * Maybe split into different extract. */
+ MR_DATA_POLY_NOR | MR_DATA_LOOPTRI,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Facedots positions
+ * \{ */
+
+static void *extract_fdots_pos_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->poly_len);
+ if (!mr->use_subsurf_fdots) {
+ /* Clear so we can accumulate on it. */
+ memset(vbo->data, 0x0, mr->poly_len * vbo->format.stride);
+ }
+ return vbo->data;
+}
+
+static void extract_fdots_pos_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(l),
+ BMLoop *loop,
+ void *data)
+{
+ float(*center)[3] = (float(*)[3])data;
+ float w = 1.0f / (float)loop->f->len;
+ madd_v3_v3fl(center[BM_elem_index_get(loop->f)], loop->v->co, w);
+}
+
+static void extract_fdots_pos_loop_mesh(const MeshRenderData *mr,
+ int UNUSED(l),
+ const MLoop *mloop,
+ int p,
+ const MPoly *mpoly,
+ void *data)
+{
+ float(*center)[3] = (float(*)[3])data;
+ const MVert *mvert = &mr->mvert[mloop->v];
+ if (mr->use_subsurf_fdots) {
+ if (mvert->flag & ME_VERT_FACEDOT) {
+ copy_v3_v3(center[p], mvert->co);
+ }
+ }
+ else {
+ float w = 1.0f / (float)mpoly->totloop;
+ madd_v3_v3fl(center[p], mvert->co, w);
+ }
+}
+
+const MeshExtract extract_fdots_pos = {extract_fdots_pos_init,
+ NULL,
+ NULL,
+ extract_fdots_pos_loop_bmesh,
+ extract_fdots_pos_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Facedots Normal and edit flag
+ * \{ */
+
+static void *extract_fdots_nor_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->poly_len);
+
+ return NULL;
+}
+
+static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void *UNUSED(data))
+{
+ GPUVertBuf *vbo = buf;
+ GPUPackedNormal *nor = (GPUPackedNormal *)vbo->data;
+ BMFace *efa;
+
+ /* Quicker than doing it for each loop. */
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ for (int f = 0; f < mr->poly_len; f++) {
+ efa = BM_face_at_index(mr->bm, f);
+ nor[f] = GPU_normal_convert_i10_v3(efa->no);
+ /* Select / Active Flag. */
+ nor[f].w = BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == mr->efa_act) ? -1 : 1) : 0;
+ }
+ }
+ else {
+ for (int f = 0; f < mr->poly_len; f++) {
+ nor[f] = GPU_normal_convert_i10_v3(mr->poly_normals[f]);
+ if ((efa = bm_original_face_get(mr, f))) {
+ /* Select / Active Flag. */
+ nor[f].w = BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == mr->efa_act) ? -1 : 1) : 0;
+ }
+ }
+ }
+}
+
+const MeshExtract extract_fdots_nor = {extract_fdots_nor_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_fdots_nor_finish,
+ MR_DATA_POLY_NOR,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Facedots Normal and edit flag
+ * \{ */
+
+typedef struct MeshExtract_FdotUV_Data {
+ float (*vbo_data)[2];
+ MLoopUV *uv_data;
+} MeshExtract_FdotUV_Data;
+
+static void *extract_fdots_uv_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "u", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "au");
+ GPU_vertformat_alias_add(&format, "pos");
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->poly_len);
+
+ if (!mr->use_subsurf_fdots) {
+ /* Clear so we can accumulate on it. */
+ memset(vbo->data, 0x0, mr->poly_len * vbo->format.stride);
+ }
+
+ CustomData *cd_ldata = &mr->me->ldata;
+
+ MeshExtract_FdotUV_Data *data = MEM_callocN(sizeof(*data), __func__);
+ data->vbo_data = (float(*)[2])vbo->data;
+ data->uv_data = CustomData_get_layer(cd_ldata, CD_MLOOPUV);
+ return data;
+}
+
+static void extract_fdots_uv_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_FdotUV_Data *data = (MeshExtract_FdotUV_Data *)_data;
+ float w = 1.0f / (float)loop->f->len;
+ madd_v2_v2fl(data->vbo_data[BM_elem_index_get(loop->f)], data->uv_data[l].uv, w);
+}
+
+static void extract_fdots_uv_loop_mesh(
+ const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data)
+{
+ MeshExtract_FdotUV_Data *data = (MeshExtract_FdotUV_Data *)_data;
+ if (mr->use_subsurf_fdots) {
+ const MVert *mvert = &mr->mvert[mloop->v];
+ if (mvert->flag & ME_VERT_FACEDOT) {
+ copy_v2_v2(data->vbo_data[p], data->uv_data[l].uv);
+ }
+ }
+ else {
+ float w = 1.0f / (float)mpoly->totloop;
+ madd_v2_v2fl(data->vbo_data[p], data->uv_data[l].uv, w);
+ }
+}
+
+static void extract_fdots_uv_finish(const MeshRenderData *UNUSED(mr),
+ void *UNUSED(buf),
+ void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_fdots_uv = {extract_fdots_uv_init,
+ NULL,
+ NULL,
+ extract_fdots_uv_loop_bmesh,
+ extract_fdots_uv_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_fdots_uv_finish,
+ 0,
+ true};
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Facedots Edit UV flag
+ * \{ */
+
+typedef struct MeshExtract_EditUVFdotData_Data {
+ EditLoopData *vbo_data;
+ int cd_ofs;
+} MeshExtract_EditUVFdotData_Data;
+
+static void *extract_fdots_edituv_data_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "flag", GPU_COMP_U8, 4, GPU_FETCH_INT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->poly_len);
+
+ MeshExtract_EditUVFdotData_Data *data = MEM_callocN(sizeof(*data), __func__);
+ data->vbo_data = (EditLoopData *)vbo->data;
+ data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
+ return data;
+}
+
+static void extract_fdots_edituv_data_loop_bmesh(const MeshRenderData *mr,
+ int UNUSED(l),
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_EditUVFdotData_Data *data = (MeshExtract_EditUVFdotData_Data *)_data;
+ EditLoopData *eldata = data->vbo_data + BM_elem_index_get(loop->f);
+ memset(eldata, 0x0, sizeof(*eldata));
+ mesh_render_data_face_flag(mr, loop->f, data->cd_ofs, eldata);
+}
+
+static void extract_fdots_edituv_data_loop_mesh(const MeshRenderData *mr,
+ int UNUSED(l),
+ const MLoop *UNUSED(mloop),
+ int p,
+ const MPoly *UNUSED(mpoly),
+ void *_data)
+{
+ MeshExtract_EditUVFdotData_Data *data = (MeshExtract_EditUVFdotData_Data *)_data;
+ EditLoopData *eldata = data->vbo_data + p;
+ memset(eldata, 0x0, sizeof(*eldata));
+ BMFace *efa = bm_original_face_get(mr, p);
+ if (efa) {
+ mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata);
+ }
+}
+
+static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr),
+ void *UNUSED(buf),
+ void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_fdots_edituv_data = {extract_fdots_edituv_data_init,
+ NULL,
+ NULL,
+ extract_fdots_edituv_data_loop_bmesh,
+ extract_fdots_edituv_data_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_fdots_edituv_data_finish,
+ 0,
+ true};
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Selection Index
+ * \{ */
+
+static void *extract_select_idx_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* TODO rename "color" to something more descriptive. */
+ GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
+ return vbo->data;
+}
+
+/* TODO Use glVertexID to get loop index and use the data structure on the CPU to retreive the
+ * select element associated with this loop ID. This would remove the need for this separate index
+ * VBOs. We could upload the p/e/v_origindex as a buffer texture and sample it inside the shader to
+ * output original index. */
+
+static void extract_poly_idx_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *data)
+{
+ ((uint32_t *)data)[l] = BM_elem_index_get(loop->f);
+}
+
+static void extract_edge_idx_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *data)
+{
+ ((uint32_t *)data)[l] = BM_elem_index_get(loop->e);
+}
+
+static void extract_vert_idx_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *data)
+{
+ ((uint32_t *)data)[l] = BM_elem_index_get(loop->v);
+}
+
+static void extract_edge_idx_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *data)
+{
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = BM_elem_index_get(eed);
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = BM_elem_index_get(eed);
+}
+
+static void extract_vert_idx_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *data)
+{
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = BM_elem_index_get(eed->v1);
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = BM_elem_index_get(eed->v2);
+}
+
+static void extract_vert_idx_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *data)
+{
+ ((uint32_t *)data)[mr->loop_len + mr->edge_loose_len * 2 + v] = BM_elem_index_get(eve);
+}
+
+static void extract_poly_idx_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *UNUSED(mloop),
+ int p,
+ const MPoly *UNUSED(mpoly),
+ void *data)
+{
+ ((uint32_t *)data)[l] = (mr->p_origindex) ? mr->p_origindex[p] : p;
+}
+
+static void extract_edge_idx_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *UNUSED(mpoly),
+ void *data)
+{
+ ((uint32_t *)data)[l] = (mr->e_origindex) ? mr->e_origindex[mloop->e] : mloop->e;
+}
+
+static void extract_vert_idx_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *UNUSED(mpoly),
+ void *data)
+{
+ ((uint32_t *)data)[l] = (mr->v_origindex) ? mr->v_origindex[mloop->v] : mloop->v;
+}
+
+static void extract_edge_idx_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *UNUSED(medge),
+ void *data)
+{
+ int e_idx = mr->ledges[e];
+ int e_orig = (mr->e_origindex) ? mr->e_origindex[e_idx] : e_idx;
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = e_orig;
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = e_orig;
+}
+
+static void extract_vert_idx_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *medge,
+ void *data)
+{
+ int v1_orig = (mr->v_origindex) ? mr->v_origindex[medge->v1] : medge->v1;
+ int v2_orig = (mr->v_origindex) ? mr->v_origindex[medge->v2] : medge->v2;
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = v1_orig;
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = v2_orig;
+}
+
+static void extract_vert_idx_lvert_mesh(const MeshRenderData *mr,
+ int v,
+ const MVert *UNUSED(mvert),
+ void *data)
+{
+ int v_idx = mr->lverts[v];
+ int v_orig = (mr->v_origindex) ? mr->v_origindex[v_idx] : v_idx;
+ ((uint32_t *)data)[mr->loop_len + mr->edge_loose_len * 2 + v] = v_orig;
+}
+
+const MeshExtract extract_poly_idx = {extract_select_idx_init,
+ NULL,
+ NULL,
+ extract_poly_idx_loop_bmesh,
+ extract_poly_idx_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ true};
+
+const MeshExtract extract_edge_idx = {extract_select_idx_init,
+ NULL,
+ NULL,
+ extract_edge_idx_loop_bmesh,
+ extract_edge_idx_loop_mesh,
+ extract_edge_idx_ledge_bmesh,
+ extract_edge_idx_ledge_mesh,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ true};
+
+const MeshExtract extract_vert_idx = {extract_select_idx_init,
+ NULL,
+ NULL,
+ extract_vert_idx_loop_bmesh,
+ extract_vert_idx_loop_mesh,
+ extract_vert_idx_ledge_bmesh,
+ extract_vert_idx_ledge_mesh,
+ extract_vert_idx_lvert_bmesh,
+ extract_vert_idx_lvert_mesh,
+ NULL,
+ 0,
+ true};
+
+static void *extract_select_fdot_idx_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* TODO rename "color" to something more descriptive. */
+ GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->poly_len);
+ return vbo->data;
+}
+
+static void extract_fdot_idx_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(l),
+ BMLoop *loop,
+ void *data)
+{
+ ((uint32_t *)data)[BM_elem_index_get(loop->f)] = BM_elem_index_get(loop->f);
+}
+
+static void extract_fdot_idx_loop_mesh(const MeshRenderData *mr,
+ int UNUSED(l),
+ const MLoop *UNUSED(mloop),
+ int p,
+ const MPoly *UNUSED(mpoly),
+ void *data)
+{
+ ((uint32_t *)data)[p] = (mr->p_origindex) ? mr->p_origindex[p] : p;
+}
+
+const MeshExtract extract_fdot_idx = {extract_select_fdot_idx_init,
+ NULL,
+ NULL,
+ extract_fdot_idx_loop_bmesh,
+ extract_fdot_idx_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Loop
+ * \{ */
+
+typedef struct ExtractTaskData {
+ const MeshRenderData *mr;
+ const MeshExtract *extract;
+ eMRIterType iter_type;
+ int start, end;
+ /** Decremented each time a task is finished. */
+ int32_t *task_counter;
+ void *buf;
+ void *user_data;
+} ExtractTaskData;
+
+BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr,
+ const eMRIterType iter_type,
+ int start,
+ int end,
+ const MeshExtract *extract,
+ void *user_data)
+{
+ switch (mr->extract_type) {
+ case MR_EXTRACT_BMESH:
+ if (iter_type & MR_ITER_LOOPTRI) {
+ int t_end = min_ii(mr->tri_len, end);
+ for (int t = start; t < t_end; t++) {
+ BMLoop **elt = &mr->edit_bmesh->looptris[t][0];
+ extract->iter_looptri_bm(mr, t, elt, user_data);
+ }
+ }
+ if (iter_type & MR_ITER_LOOP) {
+ int l_end = min_ii(mr->poly_len, end);
+ for (int f = start; f < l_end; f++) {
+ BMFace *efa = BM_face_at_index(mr->bm, f);
+ BMLoop *loop;
+ BMIter l_iter;
+ BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) {
+ extract->iter_loop_bm(mr, BM_elem_index_get(loop), loop, user_data);
+ }
+ }
+ }
+ if (iter_type & MR_ITER_LEDGE) {
+ int le_end = min_ii(mr->edge_loose_len, end);
+ for (int e = start; e < le_end; e++) {
+ BMEdge *eed = BM_edge_at_index(mr->bm, mr->ledges[e]);
+ extract->iter_ledge_bm(mr, e, eed, user_data);
+ }
+ }
+ if (iter_type & MR_ITER_LVERT) {
+ int lv_end = min_ii(mr->vert_loose_len, end);
+ for (int v = start; v < lv_end; v++) {
+ BMVert *eve = BM_vert_at_index(mr->bm, mr->lverts[v]);
+ extract->iter_lvert_bm(mr, v, eve, user_data);
+ }
+ }
+ break;
+ case MR_EXTRACT_MAPPED:
+ case MR_EXTRACT_MESH:
+ if (iter_type & MR_ITER_LOOPTRI) {
+ int t_end = min_ii(mr->tri_len, end);
+ for (int t = start; t < t_end; t++) {
+ extract->iter_looptri(mr, t, &mr->mlooptri[t], user_data);
+ }
+ }
+ if (iter_type & MR_ITER_LOOP) {
+ int l_end = min_ii(mr->poly_len, end);
+ for (int p = start; p < l_end; p++) {
+ const MPoly *mpoly = &mr->mpoly[p];
+ int l = mpoly->loopstart;
+ for (int i = 0; i < mpoly->totloop; i++, l++) {
+ extract->iter_loop(mr, l, &mr->mloop[l], p, mpoly, user_data);
+ }
+ }
+ }
+ if (iter_type & MR_ITER_LEDGE) {
+ int le_end = min_ii(mr->edge_loose_len, end);
+ for (int e = start; e < le_end; e++) {
+ extract->iter_ledge(mr, e, &mr->medge[mr->ledges[e]], user_data);
+ }
+ }
+ if (iter_type & MR_ITER_LVERT) {
+ int lv_end = min_ii(mr->vert_loose_len, end);
+ for (int v = start; v < lv_end; v++) {
+ extract->iter_lvert(mr, v, &mr->mvert[mr->lverts[v]], user_data);
+ }
+ }
+ break;
+ }
+}
+
+static void extract_run(TaskPool *__restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ ExtractTaskData *data = taskdata;
+ mesh_extract_iter(
+ data->mr, data->iter_type, data->start, data->end, data->extract, data->user_data);
+
+ /* If this is the last task, we do the finish function. */
+ int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1);
+ if (remainin_tasks == 0 && data->extract->finish != NULL) {
+ data->extract->finish(data->mr, data->buf, data->user_data);
+ }
+}
+
+static void extract_range_task_create(
+ TaskPool *task_pool, ExtractTaskData *taskdata, const eMRIterType type, int start, int length)
+{
+ taskdata = MEM_dupallocN(taskdata);
+ atomic_add_and_fetch_int32(taskdata->task_counter, 1);
+ taskdata->iter_type = type;
+ taskdata->start = start;
+ taskdata->end = start + length;
+ BLI_task_pool_push(task_pool, extract_run, taskdata, true, TASK_PRIORITY_HIGH);
+}
+
+static void extract_task_create(TaskPool *task_pool,
+ const MeshRenderData *mr,
+ const MeshExtract *extract,
+ void *buf,
+ int32_t *task_counter)
+{
+ /* Divide extraction of the VBO/IBO into sensible chunks of works. */
+ ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), "ExtractTaskData");
+ taskdata->mr = mr;
+ taskdata->extract = extract;
+ taskdata->buf = buf;
+ taskdata->user_data = extract->init(mr, buf);
+ taskdata->iter_type = mesh_extract_iter_type(extract);
+ taskdata->task_counter = task_counter;
+ taskdata->start = 0;
+ taskdata->end = INT_MAX;
+
+ /* Simple heuristic. */
+ const bool use_thread = (mr->loop_len + mr->loop_loose_len) > 8192;
+ if (use_thread && extract->use_threading) {
+ /* Divide task into sensible chunks. */
+ const int chunk_size = 8192;
+ if (taskdata->iter_type & MR_ITER_LOOPTRI) {
+ for (int i = 0; i < mr->tri_len; i += chunk_size) {
+ extract_range_task_create(task_pool, taskdata, MR_ITER_LOOPTRI, i, chunk_size);
+ }
+ }
+ if (taskdata->iter_type & MR_ITER_LOOP) {
+ for (int i = 0; i < mr->poly_len; i += chunk_size) {
+ extract_range_task_create(task_pool, taskdata, MR_ITER_LOOP, i, chunk_size);
+ }
+ }
+ if (taskdata->iter_type & MR_ITER_LEDGE) {
+ for (int i = 0; i < mr->edge_loose_len; i += chunk_size) {
+ extract_range_task_create(task_pool, taskdata, MR_ITER_LEDGE, i, chunk_size);
+ }
+ }
+ if (taskdata->iter_type & MR_ITER_LVERT) {
+ for (int i = 0; i < mr->vert_loose_len; i += chunk_size) {
+ extract_range_task_create(task_pool, taskdata, MR_ITER_LVERT, i, chunk_size);
+ }
+ }
+ MEM_freeN(taskdata);
+ }
+ else if (use_thread) {
+ /* One task for the whole VBO. */
+ (*task_counter)++;
+ BLI_task_pool_push(task_pool, extract_run, taskdata, true, TASK_PRIORITY_HIGH);
+ }
+ else {
+ /* Single threaded extraction. */
+ (*task_counter)++;
+ extract_run(NULL, taskdata, -1);
+ MEM_freeN(taskdata);
+ }
+}
+
+void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
+ MeshBufferCache mbc,
+ Mesh *me,
+ const bool do_final,
+ const bool do_uvedit,
+ const bool use_subsurf_fdots,
+ const DRW_MeshCDMask *cd_layer_used,
+ const ToolSettings *ts,
+ const bool use_hide)
+{
+ eMRIterType iter_flag = 0;
+ eMRDataType data_flag = 0;
+
+#define TEST_ASSIGN(type, type_lowercase, name) \
+ do { \
+ if (DRW_TEST_ASSIGN_##type(mbc.type_lowercase.name)) { \
+ iter_flag |= mesh_extract_iter_type(&extract_##name); \
+ data_flag |= extract_##name.data_flag; \
+ } \
+ } while (0)
+
+ TEST_ASSIGN(VBO, vbo, pos_nor);
+ TEST_ASSIGN(VBO, vbo, lnor);
+ TEST_ASSIGN(VBO, vbo, uv_tan);
+ TEST_ASSIGN(VBO, vbo, vcol);
+ TEST_ASSIGN(VBO, vbo, orco);
+ TEST_ASSIGN(VBO, vbo, edge_fac);
+ TEST_ASSIGN(VBO, vbo, weights);
+ TEST_ASSIGN(VBO, vbo, edit_data);
+ TEST_ASSIGN(VBO, vbo, edituv_data);
+ TEST_ASSIGN(VBO, vbo, stretch_area);
+ TEST_ASSIGN(VBO, vbo, stretch_angle);
+ TEST_ASSIGN(VBO, vbo, mesh_analysis);
+ TEST_ASSIGN(VBO, vbo, fdots_pos);
+ TEST_ASSIGN(VBO, vbo, fdots_nor);
+ TEST_ASSIGN(VBO, vbo, fdots_uv);
+ TEST_ASSIGN(VBO, vbo, fdots_edituv_data);
+ TEST_ASSIGN(VBO, vbo, poly_idx);
+ TEST_ASSIGN(VBO, vbo, edge_idx);
+ TEST_ASSIGN(VBO, vbo, vert_idx);
+ TEST_ASSIGN(VBO, vbo, fdot_idx);
+
+ TEST_ASSIGN(IBO, ibo, tris);
+ TEST_ASSIGN(IBO, ibo, lines);
+ TEST_ASSIGN(IBO, ibo, points);
+ TEST_ASSIGN(IBO, ibo, fdots);
+ TEST_ASSIGN(IBO, ibo, lines_paint_mask);
+ TEST_ASSIGN(IBO, ibo, lines_adjacency);
+ TEST_ASSIGN(IBO, ibo, edituv_tris);
+ TEST_ASSIGN(IBO, ibo, edituv_lines);
+ TEST_ASSIGN(IBO, ibo, edituv_points);
+ TEST_ASSIGN(IBO, ibo, edituv_fdots);
+
+#undef TEST_ASSIGN
+
+#ifdef DEBUG_TIME
+ double rdata_start = PIL_check_seconds_timer();
+#endif
+
+ MeshRenderData *mr = mesh_render_data_create(
+ me, do_final, do_uvedit, iter_flag, data_flag, cd_layer_used, ts);
+ mr->cache = cache; /* HACK */
+ mr->use_hide = use_hide;
+ mr->use_subsurf_fdots = use_subsurf_fdots;
+ mr->use_final_mesh = do_final;
+
+#ifdef DEBUG_TIME
+ double rdata_end = PIL_check_seconds_timer();
+#endif
+
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+
+ task_scheduler = BLI_task_scheduler_get();
+ task_pool = BLI_task_pool_create(task_scheduler, NULL);
+
+ size_t counters_size = (sizeof(mbc) / sizeof(void *)) * sizeof(int32_t);
+ int32_t *task_counters = MEM_callocN(counters_size, __func__);
+ int counter_used = 0;
+
+#define EXTRACT(buf, name) \
+ if (mbc.buf.name) { \
+ extract_task_create( \
+ task_pool, mr, &extract_##name, mbc.buf.name, &task_counters[counter_used++]); \
+ }
+
+ EXTRACT(vbo, pos_nor);
+ EXTRACT(vbo, lnor);
+ EXTRACT(vbo, uv_tan);
+ EXTRACT(vbo, vcol);
+ EXTRACT(vbo, orco);
+ EXTRACT(vbo, edge_fac);
+ EXTRACT(vbo, weights);
+ EXTRACT(vbo, edit_data);
+ EXTRACT(vbo, edituv_data);
+ EXTRACT(vbo, stretch_area);
+ EXTRACT(vbo, stretch_angle);
+ EXTRACT(vbo, mesh_analysis);
+ EXTRACT(vbo, fdots_pos);
+ EXTRACT(vbo, fdots_nor);
+ EXTRACT(vbo, fdots_uv);
+ EXTRACT(vbo, fdots_edituv_data);
+ EXTRACT(vbo, poly_idx);
+ EXTRACT(vbo, edge_idx);
+ EXTRACT(vbo, vert_idx);
+ EXTRACT(vbo, fdot_idx);
+
+ EXTRACT(ibo, tris);
+ EXTRACT(ibo, lines);
+ EXTRACT(ibo, points);
+ EXTRACT(ibo, fdots);
+ EXTRACT(ibo, lines_paint_mask);
+ EXTRACT(ibo, lines_adjacency);
+ EXTRACT(ibo, edituv_tris);
+ EXTRACT(ibo, edituv_lines);
+ EXTRACT(ibo, edituv_points);
+ EXTRACT(ibo, edituv_fdots);
+
+#undef EXTRACT
+
+ /* TODO(fclem) Ideally, we should have one global pool for all
+ * objects and wait for finish only before drawing when buffers
+ * need to be ready. */
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ MEM_freeN(task_counters);
+
+ mesh_render_data_free(mr);
+
+#ifdef DEBUG_TIME
+ double end = PIL_check_seconds_timer();
+
+ static double avg = 0;
+ static double avg_fps = 0;
+ static double avg_rdata = 0;
+ static double end_prev = 0;
+
+ if (end_prev == 0) {
+ end_prev = end;
+ }
+
+ avg = avg * 0.95 + (end - rdata_end) * 0.05;
+ avg_fps = avg_fps * 0.95 + (end - end_prev) * 0.05;
+ avg_rdata = avg_rdata * 0.95 + (rdata_end - rdata_start) * 0.05;
+
+ printf(
+ "rdata %.0fms iter %.0fms (frame %.0fms)\n", avg_rdata * 1000, avg * 1000, avg_fps * 1000);
+
+ end_prev = end;
+#endif
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 4dc58972ce6..d392db63938 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -119,7 +119,7 @@ struct GPUBatch *DRW_lattice_batch_cache_get_edit_verts(struct Lattice *lt);
/* Mesh */
void DRW_mesh_batch_cache_create_requested(struct Object *ob,
struct Mesh *me,
- const struct ToolSettings *ts,
+ const struct Scene *scene,
const bool is_paint_mode,
const bool use_hide);
@@ -143,6 +143,7 @@ struct GPUBatch *DRW_mesh_batch_cache_get_surface_weights(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_edges(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edit_vnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(struct Mesh *me);
/* edit-mesh selection */
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index ba58dc3d9de..f498771b596 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -64,313 +64,12 @@
#include "ED_uvedit.h"
#include "draw_cache_inline.h"
+#include "draw_cache_extract.h"
#include "draw_cache_impl.h" /* own include */
static void mesh_batch_cache_clear(Mesh *me);
-/* Vertex Group Selection and display options */
-typedef struct DRW_MeshWeightState {
- int defgroup_active;
- int defgroup_len;
-
- short flags;
- char alert_mode;
-
- /* Set of all selected bones for Multipaint. */
- bool *defgroup_sel; /* [defgroup_len] */
- int defgroup_sel_count;
-} DRW_MeshWeightState;
-
-typedef struct DRW_MeshCDMask {
- uint32_t uv : 8;
- uint32_t tan : 8;
- uint32_t vcol : 8;
- uint32_t orco : 1;
- uint32_t tan_orco : 1;
-} DRW_MeshCDMask;
-
-/* DRW_MeshWeightState.flags */
-enum {
- DRW_MESH_WEIGHT_STATE_MULTIPAINT = (1 << 0),
- DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE = (1 << 1),
-};
-
-/* ---------------------------------------------------------------------- */
-/** \name BMesh Inline Wrappers
- * \{ */
-
-/**
- * Wrapper for #BM_vert_find_first_loop_visible
- * since most of the time this can be accessed directly without a function call.
- */
-BLI_INLINE BMLoop *bm_vert_find_first_loop_visible_inline(BMVert *v)
-{
- if (v->e) {
- BMLoop *l = v->e->l;
- if (l && !BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) {
- return l->v == v ? l : l->next;
- }
- return BM_vert_find_first_loop_visible(v);
- }
- return NULL;
-}
-
-BLI_INLINE BMLoop *bm_edge_find_first_loop_visible_inline(BMEdge *e)
-{
- if (e->l) {
- BMLoop *l = e->l;
- if (!BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) {
- return l;
- }
- return BM_edge_find_first_loop_visible(e);
- }
- return NULL;
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh/BMesh Interface (direct access to basic data).
- * \{ */
-
-static int mesh_render_verts_len_get(Mesh *me)
-{
- return me->edit_mesh ? me->edit_mesh->bm->totvert : me->totvert;
-}
-
-static int mesh_render_edges_len_get(Mesh *me)
-{
- return me->edit_mesh ? me->edit_mesh->bm->totedge : me->totedge;
-}
-
-static int mesh_render_looptri_len_get(Mesh *me)
-{
- return me->edit_mesh ? me->edit_mesh->tottri : poly_to_tri_count(me->totpoly, me->totloop);
-}
-
-static int mesh_render_polys_len_get(Mesh *me)
-{
- return me->edit_mesh ? me->edit_mesh->bm->totface : me->totpoly;
-}
-
-static int mesh_render_mat_len_get(Mesh *me)
-{
- return MAX2(1, me->totcol);
-}
-
-static int UNUSED_FUNCTION(mesh_render_loops_len_get)(Mesh *me)
-{
- return me->edit_mesh ? me->edit_mesh->bm->totloop : me->totloop;
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
- * \{ */
-
-typedef struct EdgeAdjacentPolys {
- int count;
- int face_index[2];
-} EdgeAdjacentPolys;
-
-typedef struct EdgeAdjacentVerts {
- int vert_index[2]; /* -1 if none */
-} EdgeAdjacentVerts;
-
-typedef struct EdgeDrawAttr {
- uchar v_flag;
- uchar e_flag;
- uchar crease;
- uchar bweight;
-} EdgeDrawAttr;
-
-typedef struct MeshRenderData {
- int types;
-
- int vert_len;
- int edge_len;
- int tri_len;
- int loop_len;
- int poly_len;
- int mat_len;
- int loose_vert_len;
- int loose_edge_len;
-
- /* Support for mapped mesh data. */
- struct {
- /* Must be set if we want to get mapped data. */
- bool use;
- bool supported;
-
- Mesh *me_cage;
-
- int vert_len;
- int edge_len;
- int tri_len;
- int loop_len;
- int poly_len;
-
- int *loose_verts;
- int loose_vert_len;
-
- int *loose_edges;
- int loose_edge_len;
-
- /* origindex layers */
- int *v_origindex;
- int *e_origindex;
- int *l_origindex;
- int *p_origindex;
- } mapped;
-
- BMEditMesh *edit_bmesh;
- struct EditMeshData *edit_data;
- const ToolSettings *toolsettings;
-
- Mesh *me;
-
- MVert *mvert;
- const MEdge *medge;
- const MLoop *mloop;
- const MPoly *mpoly;
- float (*orco)[3]; /* vertex coordinates normalized to bounding box */
- bool is_orco_allocated;
- MDeformVert *dvert;
- MLoopUV *mloopuv;
- MLoopCol *mloopcol;
- float (*loop_normals)[3];
-
- /* CustomData 'cd' cache for efficient access. */
- struct {
- struct {
- MLoopUV **uv;
- MLoopCol **vcol;
- float (**tangent)[4];
-
- int uv_len;
- int uv_active;
- int uv_render;
- int uv_mask_active;
-
- int vcol_len;
- int vcol_active;
- int vcol_render;
-
- int tangent_len;
- int tangent_active;
- int tangent_render;
-
- bool *auto_vcol;
- } layers;
-
- /* Custom-data offsets (only needed for BMesh access) */
- struct {
- int crease;
- int bweight;
- int *uv;
- int *vcol;
-#ifdef WITH_FREESTYLE
- int freestyle_edge;
- int freestyle_face;
-#endif
- } offset;
-
- struct {
- char (*auto_mix)[32];
- char (*uv)[32];
- char (*vcol)[32];
- char (*tangent)[32];
- } uuid;
-
- /* for certain cases we need an output loop-data storage (bmesh tangents) */
- struct {
- CustomData ldata;
- /* grr, special case variable (use in place of 'dm->tangent_mask') */
- short tangent_mask;
- } output;
- } cd;
-
- BMVert *eve_act;
- BMEdge *eed_act;
- BMFace *efa_act;
- BMFace *efa_act_uv;
-
- /* 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];
- float *vert_weight;
- char (*vert_color)[3];
- GPUPackedNormal *poly_normals_pack;
- GPUPackedNormal *vert_normals_pack;
- bool *edge_select_bool;
- bool *edge_visible_bool;
-} MeshRenderData;
-
-typedef enum eMRDataType {
- 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,
- MR_DATATYPE_SHADING = 1 << 6,
- MR_DATATYPE_DVERT = 1 << 7,
- MR_DATATYPE_LOOPCOL = 1 << 8,
- MR_DATATYPE_LOOPUV = 1 << 9,
- MR_DATATYPE_LOOSE_VERT = 1 << 10,
- MR_DATATYPE_LOOSE_EDGE = 1 << 11,
- MR_DATATYPE_LOOP_NORMALS = 1 << 12,
-} eMRDataType;
-
-#define MR_DATATYPE_VERT_LOOP_POLY (MR_DATATYPE_VERT | MR_DATATYPE_POLY | MR_DATATYPE_LOOP)
-#define MR_DATATYPE_VERT_LOOP_TRI_POLY (MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_LOOPTRI)
-#define MR_DATATYPE_LOOSE_VERT_EGDE (MR_DATATYPE_LOOSE_VERT | MR_DATATYPE_LOOSE_EDGE)
-
-/**
- * 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;
-}
-
-BLI_INLINE bool bm_vert_is_loose_and_visible(const BMVert *v)
-{
- return (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && (v->e == NULL || !bm_vert_has_visible_edge(v)));
-}
-
-BLI_INLINE bool bm_edge_is_loose_and_visible(const BMEdge *e)
-{
- return (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && (e->l == NULL || !bm_edge_has_visible_face(e)));
-}
-
/* Return true is all layers in _b_ are inside _a_. */
BLI_INLINE bool mesh_cd_layers_type_overlap(DRW_MeshCDMask a, DRW_MeshCDMask b)
{
@@ -523,43 +222,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
return cd_used;
}
-static void mesh_render_calc_normals_loop_and_poly(const Mesh *me,
- const float split_angle,
- MeshRenderData *rdata)
-{
- BLI_assert((me->flag & ME_AUTOSMOOTH) != 0);
-
- int totloop = me->totloop;
- int totpoly = me->totpoly;
- float(*loop_normals)[3] = MEM_mallocN(sizeof(*loop_normals) * totloop, __func__);
- float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
- short(*clnors)[2] = CustomData_get_layer(&me->ldata, CD_CUSTOMLOOPNORMAL);
-
- BKE_mesh_calc_normals_poly(
- me->mvert, NULL, me->totvert, me->mloop, me->mpoly, totloop, totpoly, poly_normals, false);
-
- BKE_mesh_normals_loop_split(me->mvert,
- me->totvert,
- me->medge,
- me->totedge,
- me->mloop,
- loop_normals,
- totloop,
- me->mpoly,
- poly_normals,
- totpoly,
- true,
- split_angle,
- NULL,
- clnors,
- NULL);
-
- rdata->loop_len = totloop;
- rdata->poly_len = totpoly;
- rdata->loop_normals = loop_normals;
- rdata->poly_normals = poly_normals;
-}
-
static void mesh_cd_extract_auto_layers_names_and_srgb(Mesh *me,
DRW_MeshCDMask cd_used,
char **r_auto_layers_names,
@@ -617,1265 +279,6 @@ static void mesh_cd_extract_auto_layers_names_and_srgb(Mesh *me,
*r_auto_layers_len = auto_is_srgb_ofs;
}
-/**
- * TODO(campbell): 'gpumat_array' may include materials linked to the object.
- * While not default, object materials should be supported.
- * Although this only impacts the data that's generated, not the materials that display.
- */
-static MeshRenderData *mesh_render_data_create_ex(Mesh *me,
- const int types,
- const DRW_MeshCDMask *cd_used,
- const ToolSettings *ts)
-{
- MeshRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__);
- rdata->types = types;
- rdata->toolsettings = ts;
- rdata->mat_len = mesh_render_mat_len_get(me);
-
- CustomData_reset(&rdata->cd.output.ldata);
-
- const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
- const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI;
-
- if (me->edit_mesh) {
- BMEditMesh *embm = me->edit_mesh;
- BMesh *bm = embm->bm;
-
- rdata->edit_bmesh = embm;
- rdata->edit_data = me->runtime.edit_data;
-
- if (embm->mesh_eval_cage && (embm->mesh_eval_cage->runtime.is_original == false)) {
- Mesh *me_cage = embm->mesh_eval_cage;
-
- rdata->mapped.me_cage = me_cage;
- if (types & MR_DATATYPE_VERT) {
- rdata->mapped.vert_len = me_cage->totvert;
- }
- if (types & MR_DATATYPE_EDGE) {
- rdata->mapped.edge_len = me_cage->totedge;
- }
- if (types & MR_DATATYPE_LOOP) {
- rdata->mapped.loop_len = me_cage->totloop;
- }
- if (types & MR_DATATYPE_POLY) {
- rdata->mapped.poly_len = me_cage->totpoly;
- }
- if (types & MR_DATATYPE_LOOPTRI) {
- rdata->mapped.tri_len = poly_to_tri_count(me_cage->totpoly, me_cage->totloop);
- }
- if (types & MR_DATATYPE_LOOPUV) {
- rdata->mloopuv = CustomData_get_layer(&me_cage->ldata, CD_MLOOPUV);
- }
-
- rdata->mapped.v_origindex = CustomData_get_layer(&me_cage->vdata, CD_ORIGINDEX);
- rdata->mapped.e_origindex = CustomData_get_layer(&me_cage->edata, CD_ORIGINDEX);
- rdata->mapped.l_origindex = CustomData_get_layer(&me_cage->ldata, CD_ORIGINDEX);
- rdata->mapped.p_origindex = CustomData_get_layer(&me_cage->pdata, CD_ORIGINDEX);
- rdata->mapped.supported = (rdata->mapped.v_origindex || rdata->mapped.e_origindex ||
- rdata->mapped.p_origindex);
- }
-
- 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) {
- bm_ensure_types |= BM_LOOP;
- }
- 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_LOOP_NORMALS) {
- BLI_assert(types & MR_DATATYPE_LOOP);
- if (is_auto_smooth) {
- rdata->loop_normals = MEM_mallocN(sizeof(*rdata->loop_normals) * bm->totloop, __func__);
- int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
- BM_loops_calc_normal_vcos(bm,
- NULL,
- NULL,
- NULL,
- true,
- split_angle,
- rdata->loop_normals,
- NULL,
- NULL,
- cd_loop_clnors_offset,
- false);
- }
- }
- if (types & MR_DATATYPE_OVERLAY) {
- rdata->efa_act_uv = EDBM_uv_active_face_get(embm, false, false);
- 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->cd.offset.crease = CustomData_get_offset(&bm->edata, CD_CREASE);
- rdata->cd.offset.bweight = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
-
-#ifdef WITH_FREESTYLE
- rdata->cd.offset.freestyle_edge = CustomData_get_offset(&bm->edata, CD_FREESTYLE_EDGE);
- rdata->cd.offset.freestyle_face = CustomData_get_offset(&bm->pdata, CD_FREESTYLE_FACE);
-#endif
- }
- if (types & (MR_DATATYPE_DVERT)) {
- bm_ensure_types |= BM_VERT;
- }
- if (rdata->edit_data != NULL) {
- bm_ensure_types |= BM_VERT;
- }
-
- BM_mesh_elem_index_ensure(bm, bm_ensure_types);
- BM_mesh_elem_table_ensure(bm, bm_ensure_types & ~BM_LOOP);
-
- if (types & MR_DATATYPE_LOOPTRI) {
- /* Edit mode ensures this is valid, no need to calculate. */
- BLI_assert((bm->totloop == 0) || (embm->looptris != NULL));
- int tottri = embm->tottri;
- MLoopTri *mlooptri = MEM_mallocN(sizeof(*rdata->mlooptri) * embm->tottri, __func__);
- for (int index = 0; index < tottri; index++) {
- BMLoop **bmtri = embm->looptris[index];
- MLoopTri *mtri = &mlooptri[index];
- mtri->tri[0] = BM_elem_index_get(bmtri[0]);
- mtri->tri[1] = BM_elem_index_get(bmtri[1]);
- mtri->tri[2] = BM_elem_index_get(bmtri[2]);
- }
- rdata->mlooptri = mlooptri;
- rdata->tri_len = tottri;
- }
-
- if (types & MR_DATATYPE_LOOSE_VERT) {
- BLI_assert(types & MR_DATATYPE_VERT);
- rdata->loose_vert_len = 0;
-
- {
- int *lverts = MEM_mallocN(rdata->vert_len * sizeof(int), __func__);
- BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
- for (int i = 0; i < bm->totvert; i++) {
- const BMVert *eve = BM_vert_at_index(bm, i);
- if (bm_vert_is_loose_and_visible(eve)) {
- lverts[rdata->loose_vert_len++] = i;
- }
- }
- rdata->loose_verts = MEM_reallocN(lverts, rdata->loose_vert_len * sizeof(int));
- }
-
- if (rdata->mapped.supported) {
- Mesh *me_cage = embm->mesh_eval_cage;
- rdata->mapped.loose_vert_len = 0;
-
- if (rdata->loose_vert_len) {
- int *lverts = MEM_mallocN(me_cage->totvert * sizeof(int), __func__);
- const int *v_origindex = rdata->mapped.v_origindex;
- for (int i = 0; i < me_cage->totvert; i++) {
- const int v_orig = v_origindex[i];
- if (v_orig != ORIGINDEX_NONE) {
- BMVert *eve = BM_vert_at_index(bm, v_orig);
- if (bm_vert_is_loose_and_visible(eve)) {
- lverts[rdata->mapped.loose_vert_len++] = i;
- }
- }
- }
- rdata->mapped.loose_verts = MEM_reallocN(lverts,
- rdata->mapped.loose_vert_len * sizeof(int));
- }
- }
- }
-
- if (types & MR_DATATYPE_LOOSE_EDGE) {
- BLI_assert(types & MR_DATATYPE_EDGE);
- rdata->loose_edge_len = 0;
-
- {
- int *ledges = MEM_mallocN(rdata->edge_len * sizeof(int), __func__);
- BLI_assert((bm->elem_table_dirty & BM_EDGE) == 0);
- for (int i = 0; i < bm->totedge; i++) {
- const BMEdge *eed = BM_edge_at_index(bm, i);
- if (bm_edge_is_loose_and_visible(eed)) {
- ledges[rdata->loose_edge_len++] = i;
- }
- }
- rdata->loose_edges = MEM_reallocN(ledges, rdata->loose_edge_len * sizeof(int));
- }
-
- if (rdata->mapped.supported) {
- Mesh *me_cage = embm->mesh_eval_cage;
- rdata->mapped.loose_edge_len = 0;
-
- if (rdata->loose_edge_len) {
- int *ledges = MEM_mallocN(me_cage->totedge * sizeof(int), __func__);
- const int *e_origindex = rdata->mapped.e_origindex;
- for (int i = 0; i < me_cage->totedge; i++) {
- const int e_orig = e_origindex[i];
- if (e_orig != ORIGINDEX_NONE) {
- BMEdge *eed = BM_edge_at_index(bm, e_orig);
- if (bm_edge_is_loose_and_visible(eed)) {
- ledges[rdata->mapped.loose_edge_len++] = i;
- }
- }
- }
- rdata->mapped.loose_edges = MEM_reallocN(ledges,
- rdata->mapped.loose_edge_len * sizeof(int));
- }
- }
- }
- }
- else {
- rdata->me = me;
-
- 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);
- MLoopTri *mlooptri = MEM_mallocN(sizeof(*mlooptri) * tri_len, __func__);
- BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mlooptri);
- rdata->mlooptri = mlooptri;
- }
- if (types & MR_DATATYPE_LOOP) {
- rdata->loop_len = me->totloop;
- rdata->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
- }
- if (types & MR_DATATYPE_LOOP_NORMALS) {
- BLI_assert(types & MR_DATATYPE_LOOP);
- if (is_auto_smooth) {
- mesh_render_calc_normals_loop_and_poly(me, split_angle, rdata);
- }
- }
- if (types & MR_DATATYPE_POLY) {
- rdata->poly_len = me->totpoly;
- rdata->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
- }
- if (types & MR_DATATYPE_DVERT) {
- rdata->vert_len = me->totvert;
- rdata->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
- }
- if (types & MR_DATATYPE_LOOPCOL) {
- rdata->loop_len = me->totloop;
- rdata->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
- }
- if (types & MR_DATATYPE_LOOPUV) {
- rdata->loop_len = me->totloop;
- rdata->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
- }
- }
-
- if (types & MR_DATATYPE_SHADING) {
- CustomData *cd_vdata, *cd_ldata;
-
- BLI_assert(cd_used != NULL);
-
- if (me->edit_mesh) {
- BMesh *bm = me->edit_mesh->bm;
- cd_vdata = &bm->vdata;
- cd_ldata = &bm->ldata;
- }
- else {
- cd_vdata = &me->vdata;
- cd_ldata = &me->ldata;
- }
-
- rdata->cd.layers.uv_active = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
- rdata->cd.layers.uv_render = CustomData_get_render_layer(cd_ldata, CD_MLOOPUV);
- rdata->cd.layers.uv_mask_active = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV);
- rdata->cd.layers.vcol_active = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL);
- rdata->cd.layers.vcol_render = CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL);
- rdata->cd.layers.tangent_active = rdata->cd.layers.uv_active;
- rdata->cd.layers.tangent_render = rdata->cd.layers.uv_render;
-
-#define CD_VALIDATE_ACTIVE_LAYER(active_index, used) \
- if ((active_index != -1) && (used & (1 << active_index)) == 0) { \
- active_index = -1; \
- } \
- ((void)0)
-
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.uv_active, cd_used->uv);
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.uv_render, cd_used->uv);
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.uv_mask_active, cd_used->uv);
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.tangent_active, cd_used->tan);
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.tangent_render, cd_used->tan);
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.vcol_active, cd_used->vcol);
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.vcol_render, cd_used->vcol);
-
-#undef CD_VALIDATE_ACTIVE_LAYER
-
- rdata->is_orco_allocated = false;
- if (cd_used->orco != 0) {
- rdata->orco = CustomData_get_layer(cd_vdata, CD_ORCO);
- /* If orco is not available compute it ourselves */
- if (!rdata->orco) {
- rdata->is_orco_allocated = true;
- if (me->edit_mesh) {
- BMesh *bm = me->edit_mesh->bm;
- rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh");
- BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
- for (int i = 0; i < bm->totvert; i++) {
- copy_v3_v3(rdata->orco[i], BM_vert_at_index(bm, i)->co);
- }
- BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0);
- }
- else {
- rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh");
- MVert *mvert = rdata->mvert;
- for (int a = 0; a < rdata->vert_len; a++, mvert++) {
- copy_v3_v3(rdata->orco[a], mvert->co);
- }
- BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0);
- }
- }
- }
- else {
- rdata->orco = NULL;
- }
-
- /* don't access mesh directly, instead use vars taken from BMesh or Mesh */
-#define me DONT_USE_THIS
-#ifdef me /* quiet warning */
-#endif
- struct {
- uint uv_len;
- uint vcol_len;
- } cd_layers_src = {
- .uv_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPUV),
- .vcol_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPCOL),
- };
-
- rdata->cd.layers.uv_len = min_ii(cd_layers_src.uv_len, count_bits_i(cd_used->uv));
- rdata->cd.layers.tangent_len = count_bits_i(cd_used->tan) + cd_used->tan_orco;
- rdata->cd.layers.vcol_len = min_ii(cd_layers_src.vcol_len, count_bits_i(cd_used->vcol));
-
- rdata->cd.layers.uv = MEM_mallocN(sizeof(*rdata->cd.layers.uv) * rdata->cd.layers.uv_len,
- __func__);
- rdata->cd.layers.vcol = MEM_mallocN(sizeof(*rdata->cd.layers.vcol) * rdata->cd.layers.vcol_len,
- __func__);
- rdata->cd.layers.tangent = MEM_mallocN(
- sizeof(*rdata->cd.layers.tangent) * rdata->cd.layers.tangent_len, __func__);
-
- rdata->cd.uuid.uv = MEM_mallocN(sizeof(*rdata->cd.uuid.uv) * rdata->cd.layers.uv_len,
- __func__);
- rdata->cd.uuid.vcol = MEM_mallocN(sizeof(*rdata->cd.uuid.vcol) * rdata->cd.layers.vcol_len,
- __func__);
- rdata->cd.uuid.tangent = MEM_mallocN(
- sizeof(*rdata->cd.uuid.tangent) * rdata->cd.layers.tangent_len, __func__);
-
- rdata->cd.offset.uv = MEM_mallocN(sizeof(*rdata->cd.offset.uv) * rdata->cd.layers.uv_len,
- __func__);
- rdata->cd.offset.vcol = MEM_mallocN(sizeof(*rdata->cd.offset.vcol) * rdata->cd.layers.vcol_len,
- __func__);
-
- /* Allocate max */
- rdata->cd.layers.auto_vcol = MEM_callocN(
- sizeof(*rdata->cd.layers.auto_vcol) * rdata->cd.layers.vcol_len, __func__);
- rdata->cd.uuid.auto_mix = MEM_mallocN(
- sizeof(*rdata->cd.uuid.auto_mix) * (rdata->cd.layers.vcol_len + rdata->cd.layers.uv_len),
- __func__);
-
- /* XXX FIXME XXX */
- /* We use a hash to identify each data layer based on its name.
- * Gawain then search for this name in the current shader and bind if it exists.
- * NOTE : This is prone to hash collision.
- * One solution to hash collision would be to format the cd layer name
- * to a safe glsl var name, but without name clash.
- * NOTE 2 : Replicate changes to code_generate_vertex_new() in gpu_codegen.c */
- if (rdata->cd.layers.vcol_len != 0) {
- int act_vcol = rdata->cd.layers.vcol_active;
- int ren_vcol = rdata->cd.layers.vcol_render;
- for (int i_src = 0, i_dst = 0; i_src < cd_layers_src.vcol_len; i_src++, i_dst++) {
- if ((cd_used->vcol & (1 << i_src)) == 0) {
- /* This is a non-used VCol slot. Skip. */
- i_dst--;
- if (rdata->cd.layers.vcol_active >= i_src) {
- act_vcol--;
- }
- if (rdata->cd.layers.vcol_render >= i_src) {
- ren_vcol--;
- }
- }
- else {
- const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i_src);
- uint hash = BLI_ghashutil_strhash_p(name);
- BLI_snprintf(rdata->cd.uuid.vcol[i_dst], sizeof(*rdata->cd.uuid.vcol), "c%u", hash);
- rdata->cd.layers.vcol[i_dst] = CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i_src);
- if (rdata->edit_bmesh) {
- rdata->cd.offset.vcol[i_dst] = CustomData_get_n_offset(
- &rdata->edit_bmesh->bm->ldata, CD_MLOOPCOL, i_src);
- }
-
- /* Gather number of auto layers. */
- /* We only do vcols that are not overridden by uvs */
- if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, name) == -1) {
- BLI_snprintf(rdata->cd.uuid.auto_mix[rdata->cd.layers.uv_len + i_dst],
- sizeof(*rdata->cd.uuid.auto_mix),
- "a%u",
- hash);
- rdata->cd.layers.auto_vcol[i_dst] = true;
- }
- }
- }
- /* Actual active Vcol slot inside vcol layers used for shading. */
- if (rdata->cd.layers.vcol_active != -1) {
- rdata->cd.layers.vcol_active = act_vcol;
- }
- if (rdata->cd.layers.vcol_render != -1) {
- rdata->cd.layers.vcol_render = ren_vcol;
- }
- }
-
- /* Start Fresh */
- CustomData_free_layers(cd_ldata, CD_TANGENT, rdata->loop_len);
- CustomData_free_layers(cd_ldata, CD_MLOOPTANGENT, rdata->loop_len);
-
- if (rdata->cd.layers.uv_len != 0) {
- int ren_uv = rdata->cd.layers.uv_render;
- int act_uv = rdata->cd.layers.uv_active;
- for (int i_src = 0, i_dst = 0; i_src < cd_layers_src.uv_len; i_src++, i_dst++) {
- if ((cd_used->uv & (1 << i_src)) == 0) {
- /* This is a non-used UV slot. Skip. */
- i_dst--;
- if (rdata->cd.layers.uv_render >= i_src) {
- ren_uv--;
- }
- if (rdata->cd.layers.uv_active >= i_src) {
- act_uv--;
- }
- }
- else {
- const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i_src);
- uint hash = BLI_ghashutil_strhash_p(name);
-
- BLI_snprintf(rdata->cd.uuid.uv[i_dst], sizeof(*rdata->cd.uuid.uv), "u%u", hash);
- rdata->cd.layers.uv[i_dst] = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i_src);
- if (rdata->edit_bmesh) {
- rdata->cd.offset.uv[i_dst] = CustomData_get_n_offset(
- &rdata->edit_bmesh->bm->ldata, CD_MLOOPUV, i_src);
- }
- BLI_snprintf(
- rdata->cd.uuid.auto_mix[i_dst], sizeof(*rdata->cd.uuid.auto_mix), "a%u", hash);
- }
- }
- /* Actual active / Render UV slot inside uv layers used for shading. */
- if (rdata->cd.layers.uv_render != -1) {
- rdata->cd.layers.uv_render = ren_uv;
- }
- if (rdata->cd.layers.uv_active != -1) {
- rdata->cd.layers.uv_active = act_uv;
- }
- }
-
- if (rdata->cd.layers.tangent_len != 0) {
-
- /* -------------------------------------------------------------------- */
- /* Pre-calculate tangents into 'rdata->cd.output.ldata' */
-
- BLI_assert(!CustomData_has_layer(&rdata->cd.output.ldata, CD_TANGENT));
-
- /* Tangent Names */
- char tangent_names[MAX_MTFACE][MAX_NAME];
- for (int i_src = 0, i_dst = 0; i_src < cd_layers_src.uv_len; i_src++, i_dst++) {
- if ((cd_used->tan & (1 << i_src)) == 0) {
- i_dst--;
- }
- else {
- BLI_strncpy(tangent_names[i_dst],
- CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i_src),
- MAX_NAME);
- }
- }
-
- /* If tangent from orco is requested, decrement tangent_len */
- int actual_tangent_len = (cd_used->tan_orco != 0) ? rdata->cd.layers.tangent_len - 1 :
- rdata->cd.layers.tangent_len;
- if (rdata->edit_bmesh) {
- BMEditMesh *em = rdata->edit_bmesh;
- BMesh *bm = em->bm;
-
- if (is_auto_smooth && rdata->loop_normals == NULL) {
- /* Should we store the previous array of `loop_normals` in somewhere? */
- rdata->loop_len = bm->totloop;
- rdata->loop_normals = MEM_mallocN(sizeof(*rdata->loop_normals) * rdata->loop_len,
- __func__);
- BM_loops_calc_normal_vcos(
- bm, NULL, NULL, NULL, true, split_angle, rdata->loop_normals, NULL, NULL, -1, false);
- }
-
- bool calc_active_tangent = false;
-
- BKE_editmesh_loop_tangent_calc(em,
- calc_active_tangent,
- tangent_names,
- actual_tangent_len,
- rdata->poly_normals,
- rdata->loop_normals,
- rdata->orco,
- &rdata->cd.output.ldata,
- bm->totloop,
- &rdata->cd.output.tangent_mask);
- }
- else {
-#undef me
-
- if (is_auto_smooth && rdata->loop_normals == NULL) {
- /* Should we store the previous array of `loop_normals` in CustomData? */
- mesh_render_calc_normals_loop_and_poly(me, split_angle, rdata);
- }
-
- bool calc_active_tangent = false;
-
- BKE_mesh_calc_loop_tangent_ex(me->mvert,
- me->mpoly,
- me->totpoly,
- me->mloop,
- rdata->mlooptri,
- rdata->tri_len,
- cd_ldata,
- calc_active_tangent,
- tangent_names,
- actual_tangent_len,
- rdata->poly_normals,
- rdata->loop_normals,
- rdata->orco,
- &rdata->cd.output.ldata,
- me->totloop,
- &rdata->cd.output.tangent_mask);
-
- /* If we store tangents in the mesh, set temporary. */
-#if 0
- CustomData_set_layer_flag(cd_ldata, CD_TANGENT, CD_FLAG_TEMPORARY);
-#endif
-
-#define me DONT_USE_THIS
-#ifdef me /* quiet warning */
-#endif
- }
-
- /* End tangent calculation */
- /* -------------------------------------------------------------------- */
-
- BLI_assert(CustomData_number_of_layers(&rdata->cd.output.ldata, CD_TANGENT) ==
- rdata->cd.layers.tangent_len);
-
- int i_dst = 0;
- int act_tan = rdata->cd.layers.tangent_active;
- int ren_tan = rdata->cd.layers.tangent_render;
- for (int i_src = 0; i_src < cd_layers_src.uv_len; i_src++, i_dst++) {
- if ((cd_used->tan & (1 << i_src)) == 0) {
- i_dst--;
- if (rdata->cd.layers.tangent_render >= i_src) {
- ren_tan--;
- }
- if (rdata->cd.layers.tangent_active >= i_src) {
- act_tan--;
- }
- }
- else {
- const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i_src);
- uint hash = BLI_ghashutil_strhash_p(name);
-
- BLI_snprintf(
- rdata->cd.uuid.tangent[i_dst], sizeof(*rdata->cd.uuid.tangent), "t%u", hash);
-
- /* Done adding tangents. */
-
- /* note: BKE_editmesh_loop_tangent_calc calculates 'CD_TANGENT',
- * not 'CD_MLOOPTANGENT' (as done below). It's OK, they're compatible. */
-
- /* note: normally we'd use 'i_src' here, but 'i_dst' is in sync with 'rdata->cd.output'
- */
- rdata->cd.layers.tangent[i_dst] = CustomData_get_layer_n(
- &rdata->cd.output.ldata, CD_TANGENT, i_dst);
- if (rdata->tri_len != 0) {
- BLI_assert(rdata->cd.layers.tangent[i_dst] != NULL);
- }
- }
- }
- /* Actual active rangent slot inside uv layers used for shading. */
- if (rdata->cd.layers.tangent_active != -1) {
- rdata->cd.layers.tangent_active = act_tan;
- }
- if (rdata->cd.layers.tangent_render != -1) {
- rdata->cd.layers.tangent_render = ren_tan;
- }
-
- if (cd_used->tan_orco != 0) {
- const char *name = CustomData_get_layer_name(&rdata->cd.output.ldata, CD_TANGENT, i_dst);
- uint hash = BLI_ghashutil_strhash_p(name);
- BLI_snprintf(rdata->cd.uuid.tangent[i_dst], sizeof(*rdata->cd.uuid.tangent), "t%u", hash);
-
- rdata->cd.layers.tangent[i_dst] = CustomData_get_layer_n(
- &rdata->cd.output.ldata, CD_TANGENT, i_dst);
- }
- }
-
-#undef me
- }
-
- return rdata;
-}
-
-/* Warning replace mesh pointer. */
-#define MBC_GET_FINAL_MESH(me) \
- /* Hack to show the final result. */ \
- const bool _use_em_final = ((me)->edit_mesh && (me)->edit_mesh->mesh_eval_final && \
- ((me)->edit_mesh->mesh_eval_final->runtime.is_original == false)); \
- Mesh _me_fake; \
- if (_use_em_final) { \
- _me_fake = *(me)->edit_mesh->mesh_eval_final; \
- _me_fake.mat = (me)->mat; \
- _me_fake.totcol = (me)->totcol; \
- (me) = &_me_fake; \
- } \
- ((void)0)
-
-static void mesh_render_data_free(MeshRenderData *rdata)
-{
- if (rdata->is_orco_allocated) {
- MEM_SAFE_FREE(rdata->orco);
- }
- MEM_SAFE_FREE(rdata->cd.offset.uv);
- MEM_SAFE_FREE(rdata->cd.offset.vcol);
- MEM_SAFE_FREE(rdata->cd.uuid.auto_mix);
- MEM_SAFE_FREE(rdata->cd.uuid.uv);
- MEM_SAFE_FREE(rdata->cd.uuid.vcol);
- MEM_SAFE_FREE(rdata->cd.uuid.tangent);
- MEM_SAFE_FREE(rdata->cd.layers.uv);
- MEM_SAFE_FREE(rdata->cd.layers.vcol);
- MEM_SAFE_FREE(rdata->cd.layers.tangent);
- MEM_SAFE_FREE(rdata->cd.layers.auto_vcol);
- MEM_SAFE_FREE(rdata->loose_verts);
- MEM_SAFE_FREE(rdata->loose_edges);
- MEM_SAFE_FREE(rdata->edges_adjacent_polys);
- MEM_SAFE_FREE(rdata->mlooptri);
- MEM_SAFE_FREE(rdata->loop_normals);
- MEM_SAFE_FREE(rdata->poly_normals);
- MEM_SAFE_FREE(rdata->poly_normals_pack);
- MEM_SAFE_FREE(rdata->vert_normals_pack);
- MEM_SAFE_FREE(rdata->vert_weight);
- MEM_SAFE_FREE(rdata->edge_select_bool);
- MEM_SAFE_FREE(rdata->edge_visible_bool);
- MEM_SAFE_FREE(rdata->vert_color);
-
- MEM_SAFE_FREE(rdata->mapped.loose_verts);
- MEM_SAFE_FREE(rdata->mapped.loose_edges);
-
- CustomData_free(&rdata->cd.output.ldata, rdata->loop_len);
-
- MEM_freeN(rdata);
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Accessor Functions
- * \{ */
-
-static const char *mesh_render_data_uv_auto_layer_uuid_get(const MeshRenderData *rdata, int layer)
-{
- BLI_assert(rdata->types & MR_DATATYPE_SHADING);
- return rdata->cd.uuid.auto_mix[layer];
-}
-
-static const char *mesh_render_data_vcol_auto_layer_uuid_get(const MeshRenderData *rdata,
- int layer)
-{
- BLI_assert(rdata->types & MR_DATATYPE_SHADING);
- return rdata->cd.uuid.auto_mix[rdata->cd.layers.uv_len + layer];
-}
-
-static const char *mesh_render_data_uv_layer_uuid_get(const MeshRenderData *rdata, int layer)
-{
- BLI_assert(rdata->types & MR_DATATYPE_SHADING);
- return rdata->cd.uuid.uv[layer];
-}
-
-static const char *mesh_render_data_vcol_layer_uuid_get(const MeshRenderData *rdata, int layer)
-{
- BLI_assert(rdata->types & MR_DATATYPE_SHADING);
- return rdata->cd.uuid.vcol[layer];
-}
-
-static const char *mesh_render_data_tangent_layer_uuid_get(const MeshRenderData *rdata, int layer)
-{
- BLI_assert(rdata->types & MR_DATATYPE_SHADING);
- return rdata->cd.uuid.tangent[layer];
-}
-
-static int UNUSED_FUNCTION(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_verts_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_VERT);
- return ((rdata->mapped.use == false) ? rdata->vert_len : rdata->mapped.vert_len);
-}
-
-static int UNUSED_FUNCTION(mesh_render_data_loose_verts_len_get)(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOSE_VERT);
- return rdata->loose_vert_len;
-}
-static int mesh_render_data_loose_verts_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOSE_VERT);
- return ((rdata->mapped.use == false) ? rdata->loose_vert_len : rdata->mapped.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_edges_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_EDGE);
- return ((rdata->mapped.use == false) ? rdata->edge_len : rdata->mapped.edge_len);
-}
-
-static int UNUSED_FUNCTION(mesh_render_data_loose_edges_len_get)(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOSE_EDGE);
- return rdata->loose_edge_len;
-}
-static int mesh_render_data_loose_edges_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOSE_EDGE);
- return ((rdata->mapped.use == false) ? rdata->loose_edge_len : rdata->mapped.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 mesh_render_data_looptri_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOPTRI);
- return ((rdata->mapped.use == false) ? rdata->tri_len : rdata->mapped.tri_len);
-}
-
-static int UNUSED_FUNCTION(mesh_render_data_mat_len_get)(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_POLY);
- return rdata->mat_len;
-}
-
-static int 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_loops_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOP);
- return ((rdata->mapped.use == false) ? rdata->loop_len : rdata->mapped.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 int mesh_render_data_polys_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_POLY);
- return ((rdata->mapped.use == false) ? rdata->poly_len : rdata->mapped.poly_len);
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-
-/** \name Internal Cache (Lazy Initialization)
- * \{ */
-
-/** Ensure #MeshRenderData.poly_normals_pack */
-static void mesh_render_data_ensure_poly_normals_pack(MeshRenderData *rdata)
-{
- GPUPackedNormal *pnors_pack = rdata->poly_normals_pack;
- if (pnors_pack == NULL) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter fiter;
- BMFace *efa;
- int i;
-
- pnors_pack = rdata->poly_normals_pack = MEM_mallocN(sizeof(*pnors_pack) * rdata->poly_len,
- __func__);
- if (rdata->edit_data && rdata->edit_data->vertexCos != NULL) {
- BKE_editmesh_cache_ensure_poly_normals(rdata->edit_bmesh, rdata->edit_data);
- const float(*pnors)[3] = rdata->edit_data->polyNos;
- for (i = 0; i < bm->totface; i++) {
- pnors_pack[i] = GPU_normal_convert_i10_v3(pnors[i]);
- }
- }
- else {
- BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
- pnors_pack[i] = GPU_normal_convert_i10_v3(efa->no);
- }
- }
- }
- else {
- 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_pack = rdata->poly_normals_pack = MEM_mallocN(sizeof(*pnors_pack) * rdata->poly_len,
- __func__);
- for (int i = 0; i < rdata->poly_len; i++) {
- pnors_pack[i] = GPU_normal_convert_i10_v3(pnors[i]);
- }
- }
- }
-}
-
-/** Ensure #MeshRenderData.vert_normals_pack */
-static void mesh_render_data_ensure_vert_normals_pack(MeshRenderData *rdata)
-{
- GPUPackedNormal *vnors_pack = rdata->vert_normals_pack;
- if (vnors_pack == NULL) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter viter;
- BMVert *eve;
- int i;
-
- vnors_pack = rdata->vert_normals_pack = MEM_mallocN(sizeof(*vnors_pack) * rdata->vert_len,
- __func__);
- BM_ITER_MESH_INDEX (eve, &viter, bm, BM_VERT, i) {
- vnors_pack[i] = GPU_normal_convert_i10_v3(eve->no);
- }
- }
- else {
- /* data from mesh used directly */
- BLI_assert(0);
- }
- }
-}
-
-/** Ensure #MeshRenderData.vert_color */
-static void UNUSED_FUNCTION(mesh_render_data_ensure_vert_color)(MeshRenderData *rdata)
-{
- char(*vcol)[3] = rdata->vert_color;
- if (vcol == NULL) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
- if (cd_loop_color_offset == -1) {
- goto fallback;
- }
-
- vcol = rdata->vert_color = MEM_mallocN(sizeof(*vcol) * rdata->loop_len, __func__);
-
- BMIter fiter;
- BMFace *efa;
- int i = 0;
-
- BM_ITER_MESH (efa, &fiter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- const MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_color_offset);
- vcol[i][0] = lcol->r;
- vcol[i][1] = lcol->g;
- vcol[i][2] = lcol->b;
- i += 1;
- } while ((l_iter = l_iter->next) != l_first);
- }
- BLI_assert(i == rdata->loop_len);
- }
- else {
- if (rdata->mloopcol == NULL) {
- goto fallback;
- }
-
- vcol = rdata->vert_color = MEM_mallocN(sizeof(*vcol) * rdata->loop_len, __func__);
-
- for (int i = 0; i < rdata->loop_len; i++) {
- vcol[i][0] = rdata->mloopcol[i].r;
- vcol[i][1] = rdata->mloopcol[i].g;
- vcol[i][2] = rdata->mloopcol[i].b;
- }
- }
- }
- return;
-
-fallback:
- vcol = rdata->vert_color = MEM_mallocN(sizeof(*vcol) * rdata->loop_len, __func__);
-
- for (int i = 0; i < rdata->loop_len; i++) {
- vcol[i][0] = 255;
- vcol[i][1] = 255;
- vcol[i][2] = 255;
- }
-}
-
-static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate)
-{
- float input = 0.0f;
- bool show_alert_color = false;
-
- if (wstate->flags & DRW_MESH_WEIGHT_STATE_MULTIPAINT) {
- /* Multi-Paint feature */
- input = BKE_defvert_multipaint_collective_weight(
- dvert,
- wstate->defgroup_len,
- wstate->defgroup_sel,
- wstate->defgroup_sel_count,
- (wstate->flags & DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE) != 0);
-
- /* make it black if the selected groups have no weight on a vertex */
- if (input == 0.0f) {
- show_alert_color = true;
- }
- }
- else {
- /* default, non tricky behavior */
- input = defvert_find_weight(dvert, wstate->defgroup_active);
-
- if (input == 0.0f) {
- switch (wstate->alert_mode) {
- case OB_DRAW_GROUPUSER_ACTIVE:
- show_alert_color = true;
- break;
-
- case OB_DRAW_GROUPUSER_ALL:
- show_alert_color = defvert_is_weight_zero(dvert, wstate->defgroup_len);
- break;
- }
- }
- }
-
- if (show_alert_color) {
- return -1.0f;
- }
- else {
- CLAMP(input, 0.0f, 1.0f);
- return input;
- }
-}
-
-/** Ensure #MeshRenderData.vert_weight */
-static void mesh_render_data_ensure_vert_weight(MeshRenderData *rdata,
- const struct DRW_MeshWeightState *wstate)
-{
- float *vweight = rdata->vert_weight;
- if (vweight == NULL) {
- if (wstate->defgroup_active == -1) {
- goto fallback;
- }
-
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
- if (cd_dvert_offset == -1) {
- goto fallback;
- }
-
- BMIter viter;
- BMVert *eve;
- int i;
-
- vweight = rdata->vert_weight = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__);
- BM_ITER_MESH_INDEX (eve, &viter, bm, BM_VERT, i) {
- const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- vweight[i] = evaluate_vertex_weight(dvert, wstate);
- }
- }
- else {
- if (rdata->dvert == NULL) {
- goto fallback;
- }
-
- vweight = rdata->vert_weight = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__);
- for (int i = 0; i < rdata->vert_len; i++) {
- vweight[i] = evaluate_vertex_weight(&rdata->dvert[i], wstate);
- }
- }
- }
- return;
-
-fallback:
- vweight = rdata->vert_weight = MEM_callocN(sizeof(*vweight) * rdata->vert_len, __func__);
-
- if ((wstate->defgroup_active < 0) && (wstate->defgroup_len > 0)) {
- copy_vn_fl(vweight, rdata->vert_len, -2.0f);
- }
- else if (wstate->alert_mode != OB_DRAW_GROUPUSER_NONE) {
- copy_vn_fl(vweight, rdata->vert_len, -1.0f);
- }
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Internal Cache Generation
- * \{ */
-
-static uchar mesh_render_data_face_flag(MeshRenderData *rdata, const BMFace *efa, const int cd_ofs)
-{
- uchar fflag = 0;
-
- if (efa == rdata->efa_act) {
- fflag |= VFLAG_FACE_ACTIVE;
- }
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- fflag |= VFLAG_FACE_SELECTED;
- }
-
- if (efa == rdata->efa_act_uv) {
- fflag |= VFLAG_FACE_UV_ACTIVE;
- }
- if ((cd_ofs != -1) && uvedit_face_select_test_ex(rdata->toolsettings, (BMFace *)efa, cd_ofs)) {
- fflag |= VFLAG_FACE_UV_SELECT;
- }
-
-#ifdef WITH_FREESTYLE
- if (rdata->cd.offset.freestyle_face != -1) {
- const FreestyleFace *ffa = BM_ELEM_CD_GET_VOID_P(efa, rdata->cd.offset.freestyle_face);
- if (ffa->flag & FREESTYLE_FACE_MARK) {
- fflag |= VFLAG_FACE_FREESTYLE;
- }
- }
-#endif
-
- return fflag;
-}
-
-static void mesh_render_data_edge_flag(const MeshRenderData *rdata,
- const BMEdge *eed,
- EdgeDrawAttr *eattr)
-{
- const ToolSettings *ts = rdata->toolsettings;
- const bool is_vertex_select_mode = (ts != NULL) && (ts->selectmode & SCE_SELECT_VERTEX) != 0;
- const bool is_face_only_select_mode = (ts != NULL) && (ts->selectmode == SCE_SELECT_FACE);
-
- if (eed == rdata->eed_act) {
- eattr->e_flag |= VFLAG_EDGE_ACTIVE;
- }
- if (!is_vertex_select_mode && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- eattr->e_flag |= VFLAG_EDGE_SELECTED;
- }
- if (is_vertex_select_mode && BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) &&
- BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) {
- eattr->e_flag |= VFLAG_EDGE_SELECTED;
- eattr->e_flag |= VFLAG_VERT_SELECTED;
- }
- if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
- eattr->e_flag |= VFLAG_EDGE_SEAM;
- }
- if (!BM_elem_flag_test(eed, BM_ELEM_SMOOTH)) {
- eattr->e_flag |= VFLAG_EDGE_SHARP;
- }
-
- /* Use active edge color for active face edges because
- * specular highlights make it hard to see T55456#510873.
- *
- * This isn't ideal since it can't be used when mixing edge/face modes
- * but it's still better then not being able to see the active face. */
- if (is_face_only_select_mode) {
- if (rdata->efa_act != NULL) {
- if (BM_edge_in_face(eed, rdata->efa_act)) {
- eattr->e_flag |= VFLAG_EDGE_ACTIVE;
- }
- }
- }
-
- /* Use a byte for value range */
- if (rdata->cd.offset.crease != -1) {
- float crease = BM_ELEM_CD_GET_FLOAT(eed, rdata->cd.offset.crease);
- if (crease > 0) {
- eattr->crease = (uchar)(crease * 255.0f);
- }
- }
- /* Use a byte for value range */
- if (rdata->cd.offset.bweight != -1) {
- float bweight = BM_ELEM_CD_GET_FLOAT(eed, rdata->cd.offset.bweight);
- if (bweight > 0) {
- eattr->bweight = (uchar)(bweight * 255.0f);
- }
- }
-#ifdef WITH_FREESTYLE
- if (rdata->cd.offset.freestyle_edge != -1) {
- const FreestyleEdge *fed = BM_ELEM_CD_GET_VOID_P(eed, rdata->cd.offset.freestyle_edge);
- if (fed->flag & FREESTYLE_EDGE_MARK) {
- eattr->e_flag |= VFLAG_EDGE_FREESTYLE;
- }
- }
-#endif
-}
-
-static void mesh_render_data_loop_flag(MeshRenderData *rdata,
- BMLoop *loop,
- const int cd_ofs,
- EdgeDrawAttr *eattr)
-{
- if (cd_ofs == -1) {
- return;
- }
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs);
- if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) {
- eattr->v_flag |= VFLAG_VERT_UV_PINNED;
- }
- if (uvedit_uv_select_test_ex(rdata->toolsettings, loop, cd_ofs)) {
- eattr->v_flag |= VFLAG_VERT_UV_SELECT;
- }
- if (uvedit_edge_select_test_ex(rdata->toolsettings, loop, cd_ofs)) {
- eattr->v_flag |= VFLAG_EDGE_UV_SELECT;
- }
-}
-
-static void mesh_render_data_vert_flag(MeshRenderData *rdata,
- const BMVert *eve,
- EdgeDrawAttr *eattr)
-{
- if (eve == rdata->eve_act) {
- eattr->e_flag |= VFLAG_VERT_ACTIVE;
- }
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- eattr->e_flag |= VFLAG_VERT_SELECTED;
- }
-}
-
-static bool add_edit_facedot(MeshRenderData *rdata,
- GPUVertBuf *vbo,
- const uint fdot_pos_id,
- const uint fdot_nor_flag_id,
- const int poly,
- const int base_vert_idx)
-{
- BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
- float pnor[3], center[3];
- int facedot_flag;
- if (rdata->edit_bmesh) {
- BMEditMesh *em = rdata->edit_bmesh;
- const BMFace *efa = BM_face_at_index(em->bm, poly);
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- return false;
- }
- if (rdata->edit_data && rdata->edit_data->vertexCos) {
- copy_v3_v3(center, rdata->edit_data->polyCos[poly]);
- copy_v3_v3(pnor, rdata->edit_data->polyNos[poly]);
- }
- else {
- BM_face_calc_center_median(efa, center);
- copy_v3_v3(pnor, efa->no);
- }
- facedot_flag = BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == em->bm->act_face) ? -1 : 1) :
- 0;
- }
- 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, center);
- BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, pnor);
- /* No selection if not in edit mode. */
- facedot_flag = 0;
- }
-
- GPUPackedNormal nor = GPU_normal_convert_i10_v3(pnor);
- nor.w = facedot_flag;
- GPU_vertbuf_attr_set(vbo, fdot_nor_flag_id, base_vert_idx, &nor);
- GPU_vertbuf_attr_set(vbo, fdot_pos_id, base_vert_idx, center);
-
- return true;
-}
-static bool add_edit_facedot_mapped(MeshRenderData *rdata,
- GPUVertBuf *vbo,
- const uint fdot_pos_id,
- const uint fdot_nor_flag_id,
- const int poly,
- const int base_vert_idx)
-{
- BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
- float pnor[3], center[3];
- const int *p_origindex = rdata->mapped.p_origindex;
- const int p_orig = p_origindex[poly];
- if (p_orig == ORIGINDEX_NONE) {
- return false;
- }
- BMEditMesh *em = rdata->edit_bmesh;
- const BMFace *efa = BM_face_at_index(em->bm, p_orig);
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- return false;
- }
-
- Mesh *me_cage = em->mesh_eval_cage;
- const MVert *mvert = me_cage->mvert;
- const MLoop *mloop = me_cage->mloop;
- const MPoly *mpoly = me_cage->mpoly;
-
- const MPoly *mp = mpoly + poly;
- const MLoop *ml = mloop + mp->loopstart;
-
- BKE_mesh_calc_poly_center(mp, ml, mvert, center);
- BKE_mesh_calc_poly_normal(mp, ml, mvert, pnor);
-
- GPUPackedNormal nor = GPU_normal_convert_i10_v3(pnor);
- nor.w = BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == em->bm->act_face) ? -1 : 1) : 0;
- GPU_vertbuf_attr_set(vbo, fdot_nor_flag_id, base_vert_idx, &nor);
- GPU_vertbuf_attr_set(vbo, fdot_pos_id, base_vert_idx, center);
-
- return true;
-}
-static bool add_edit_facedot_subdiv(MeshRenderData *rdata,
- GPUVertBuf *vbo,
- const uint fdot_pos_id,
- const uint fdot_nor_flag_id,
- const int vert,
- const int poly,
- const int base_vert_idx)
-{
- BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
- const int *p_origindex = rdata->mapped.p_origindex;
- const int p_orig = p_origindex[poly];
- if (p_orig == ORIGINDEX_NONE) {
- return false;
- }
- BMEditMesh *em = rdata->edit_bmesh;
- const BMFace *efa = BM_face_at_index(em->bm, p_orig);
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- return false;
- }
-
- Mesh *me_cage = em->mesh_eval_cage;
- const MVert *mvert = &me_cage->mvert[vert];
-
- GPUPackedNormal nor = GPU_normal_convert_i10_s3(mvert->no);
- nor.w = BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == em->bm->act_face) ? -1 : 1) : 0;
- GPU_vertbuf_attr_set(vbo, fdot_nor_flag_id, base_vert_idx, &nor);
- GPU_vertbuf_attr_set(vbo, fdot_pos_id, base_vert_idx, mvert->co);
-
- return true;
-}
-
/** \} */
/* ---------------------------------------------------------------------- */
@@ -1963,170 +366,6 @@ static void drw_mesh_weight_state_extract(Object *ob,
/** \name Mesh GPUBatch Cache
* \{ */
-typedef enum DRWBatchFlag {
- MBC_SURFACE = (1 << 0),
- MBC_SURFACE_WEIGHTS = (1 << 1),
- MBC_EDIT_TRIANGLES = (1 << 2),
- MBC_EDIT_VERTICES = (1 << 3),
- MBC_EDIT_EDGES = (1 << 4),
- MBC_EDIT_LNOR = (1 << 5),
- MBC_EDIT_FACEDOTS = (1 << 6),
- MBC_EDIT_MESH_ANALYSIS = (1 << 7),
- MBC_EDITUV_FACES_STRECH_AREA = (1 << 8),
- MBC_EDITUV_FACES_STRECH_ANGLE = (1 << 9),
- MBC_EDITUV_FACES = (1 << 10),
- MBC_EDITUV_EDGES = (1 << 11),
- MBC_EDITUV_VERTS = (1 << 12),
- MBC_EDITUV_FACEDOTS = (1 << 13),
- MBC_EDIT_SELECTION_VERTS = (1 << 14),
- MBC_EDIT_SELECTION_EDGES = (1 << 15),
- MBC_EDIT_SELECTION_FACES = (1 << 16),
- MBC_EDIT_SELECTION_FACEDOTS = (1 << 17),
- MBC_ALL_VERTS = (1 << 18),
- MBC_ALL_EDGES = (1 << 19),
- MBC_LOOSE_EDGES = (1 << 20),
- MBC_EDGE_DETECTION = (1 << 21),
- MBC_WIRE_EDGES = (1 << 22),
- MBC_WIRE_LOOPS = (1 << 23),
- MBC_WIRE_LOOPS_UVS = (1 << 24),
- MBC_SURF_PER_MAT = (1 << 25),
-} DRWBatchFlag;
-
-#define MBC_EDITUV \
- (MBC_EDITUV_FACES_STRECH_AREA | MBC_EDITUV_FACES_STRECH_ANGLE | MBC_EDITUV_FACES | \
- MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS)
-
-typedef struct MeshBatchCache {
- /* In order buffers: All verts only specified once
- * or once per loop. To be used with a GPUIndexBuf. */
- struct {
- /* Vertex data. */
- GPUVertBuf *pos_nor;
- GPUVertBuf *weights;
- /* Loop data. */
- GPUVertBuf *loop_pos_nor;
- GPUVertBuf *loop_uv_tan;
- GPUVertBuf *loop_vcol;
- GPUVertBuf *loop_edge_fac;
- GPUVertBuf *loop_orco;
- } ordered;
-
- /* Edit Mesh Data:
- * Edit cage can be different from final mesh so vertex count
- * might differ. */
- struct {
- /* TODO(fclem): Reuse ordered.loop_pos_nor and maybe even
- * ordered.loop_uv_tan when cage match final mesh. */
- GPUVertBuf *loop_pos_nor;
- GPUVertBuf *loop_data;
- GPUVertBuf *loop_lnor;
- GPUVertBuf *facedots_pos_nor_data;
- GPUVertBuf *loop_mesh_analysis;
- /* UV data without modifier applied.
- * Vertex count is always the one of the cage. */
- GPUVertBuf *loop_uv;
- GPUVertBuf *loop_uv_data;
- GPUVertBuf *loop_stretch_angle;
- GPUVertBuf *loop_stretch_area;
- GPUVertBuf *facedots_uv;
- GPUVertBuf *facedots_uv_data;
- /* Selection */
- GPUVertBuf *loop_vert_idx;
- GPUVertBuf *loop_edge_idx;
- GPUVertBuf *loop_face_idx;
- GPUVertBuf *facedots_idx;
- } edit;
-
- /* Index Buffers:
- * Only need to be updated when topology changes. */
- struct {
- /* Indices to verts. */
- GPUIndexBuf *surf_tris;
- GPUIndexBuf *edges_lines;
- GPUIndexBuf *edges_adj_lines;
- GPUIndexBuf *loose_edges_lines;
- /* Indices to vloops. */
- GPUIndexBuf *loops_tris;
- GPUIndexBuf *loops_lines;
- GPUIndexBuf *loops_lines_paint_mask;
- GPUIndexBuf *loops_line_strips;
- /* Edit mode. */
- GPUIndexBuf *edit_loops_points; /* verts */
- GPUIndexBuf *edit_loops_lines; /* edges */
- GPUIndexBuf *edit_loops_tris; /* faces */
- /* Edit UVs */
- GPUIndexBuf *edituv_loops_points; /* verts */
- GPUIndexBuf *edituv_loops_line_strips; /* edges */
- GPUIndexBuf *edituv_loops_tri_fans; /* faces */
- } ibo;
-
- struct {
- /* Surfaces / Render */
- GPUBatch *surface;
- GPUBatch *surface_weights;
- /* Edit mode */
- GPUBatch *edit_triangles;
- GPUBatch *edit_vertices;
- GPUBatch *edit_edges;
- GPUBatch *edit_lnor;
- GPUBatch *edit_facedots;
- GPUBatch *edit_mesh_analysis;
- /* Edit UVs */
- GPUBatch *edituv_faces_strech_area;
- GPUBatch *edituv_faces_strech_angle;
- GPUBatch *edituv_faces;
- GPUBatch *edituv_edges;
- GPUBatch *edituv_verts;
- GPUBatch *edituv_facedots;
- /* Edit selection */
- GPUBatch *edit_selection_verts;
- GPUBatch *edit_selection_edges;
- GPUBatch *edit_selection_faces;
- GPUBatch *edit_selection_facedots;
- /* Common display / Other */
- GPUBatch *all_verts;
- GPUBatch *all_edges;
- GPUBatch *loose_edges;
- GPUBatch *edge_detection;
- GPUBatch *wire_edges; /* Individual edges with face normals. */
- GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */
- GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */
- } batch;
-
- GPUIndexBuf **surf_per_mat_tris;
- GPUBatch **surf_per_mat;
-
- /* arrays of bool uniform names (and value) that will be use to
- * set srgb conversion for auto attributes.*/
- char *auto_layer_names;
- int *auto_layer_is_srgb;
- int auto_layer_len;
-
- DRWBatchFlag batch_requested;
- DRWBatchFlag batch_ready;
-
- /* settings to determine if cache is invalid */
- int edge_len;
- int tri_len;
- int poly_len;
- int vert_len;
- int mat_len;
- bool is_dirty; /* Instantly invalidates cache, skipping mesh check */
- bool is_editmode;
- bool is_uvsyncsel;
-
- struct DRW_MeshWeightState weight_state;
-
- DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time;
-
- int lastmatch;
-
- /* Valid only if edge_detection is up to date. */
- bool is_manifold;
-
- bool no_loose_wire;
-} MeshBatchCache;
-
BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag new_flag)
{
atomic_fetch_and_or_uint32((uint32_t *)(&cache->batch_requested), *(uint32_t *)&new_flag);
@@ -2171,16 +410,14 @@ static void mesh_batch_cache_init(Mesh *me)
cache->is_editmode = me->edit_mesh != 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->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->mat_len = mesh_render_mat_len_get(me);
- cache->surf_per_mat_tris = MEM_callocN(sizeof(*cache->surf_per_mat_tris) * cache->mat_len,
- __func__);
- cache->surf_per_mat = MEM_callocN(sizeof(*cache->surf_per_mat) * cache->mat_len, __func__);
+ cache->surface_per_mat = MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__);
cache->is_dirty = false;
cache->batch_ready = 0;
@@ -2206,8 +443,11 @@ static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache,
const struct DRW_MeshWeightState *wstate)
{
if (!drw_mesh_weight_state_compare(&cache->weight_state, wstate)) {
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.weights);
+ }
GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights);
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.weights);
cache->batch_ready &= ~MBC_SURFACE_WEIGHTS;
@@ -2217,23 +457,20 @@ static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache,
static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
{
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_pos_nor);
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_uv_tan);
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_vcol);
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_orco);
-
- if (cache->surf_per_mat_tris) {
- for (int i = 0; i < cache->mat_len; i++) {
- GPU_INDEXBUF_DISCARD_SAFE(cache->surf_per_mat_tris[i]);
- }
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.uv_tan);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.vcol);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.orco);
}
- MEM_SAFE_FREE(cache->surf_per_mat_tris);
- if (cache->surf_per_mat) {
+
+ if (cache->surface_per_mat) {
for (int i = 0; i < cache->mat_len; i++) {
- GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]);
+ GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]);
}
}
- MEM_SAFE_FREE(cache->surf_per_mat);
+ MEM_SAFE_FREE(cache->surface_per_mat);
cache->batch_ready &= ~MBC_SURF_PER_MAT;
@@ -2247,21 +484,26 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache)
{
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_stretch_angle);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_stretch_area);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv_data);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_uv);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_uv_data);
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_tri_fans);
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_line_strips);
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_points);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.stretch_angle);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.stretch_area);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.uv_tan);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_uv);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data);
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_tris);
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_lines);
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_points);
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_fdots);
+ }
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_area);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_angle);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_facedots);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops_uvs);
cache->batch_ready &= ~MBC_EDITUV;
}
@@ -2274,31 +516,41 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
}
switch (mode) {
case BKE_MESH_BATCH_DIRTY_SELECT:
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_data);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_pos_nor_data);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edit_data);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_nor);
+ }
GPU_BATCH_DISCARD_SAFE(cache->batch.edit_triangles);
GPU_BATCH_DISCARD_SAFE(cache->batch.edit_vertices);
GPU_BATCH_DISCARD_SAFE(cache->batch.edit_edges);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_facedots);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_facedots);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edit_fdots);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_verts);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_edges);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_faces);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_fdots);
GPU_BATCH_DISCARD_SAFE(cache->batch.edit_mesh_analysis);
cache->batch_ready &= ~(MBC_EDIT_TRIANGLES | MBC_EDIT_VERTICES | MBC_EDIT_EDGES |
MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS |
- MBC_EDIT_MESH_ANALYSIS);
+ MBC_EDIT_SELECTION_FACES | MBC_EDIT_SELECTION_EDGES |
+ MBC_EDIT_SELECTION_VERTS | MBC_EDIT_MESH_ANALYSIS);
/* Because visible UVs depends on edit mode selection, discard everything. */
mesh_batch_cache_discard_uvedit(cache);
break;
case BKE_MESH_BATCH_DIRTY_SELECT_PAINT:
/* Paint mode selection flag is packed inside the nor attrib.
* Note that it can be slow if auto smooth is enabled. (see T63946) */
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.loops_lines_paint_mask);
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_pos_nor);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.lines_paint_mask);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor);
+ }
GPU_BATCH_DISCARD_SAFE(cache->batch.surface);
GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops);
GPU_BATCH_DISCARD_SAFE(cache->batch.wire_edges);
- if (cache->surf_per_mat) {
+ if (cache->surface_per_mat) {
for (int i = 0; i < cache->mat_len; i++) {
- GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]);
+ GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]);
}
}
cache->batch_ready &= ~(MBC_SURFACE | MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SURF_PER_MAT);
@@ -2314,14 +566,17 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
mesh_batch_cache_discard_uvedit(cache);
break;
case BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT:
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv_data);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_uv_data);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data);
+ }
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_area);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_angle);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_facedots);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots);
cache->batch_ready &= ~MBC_EDITUV;
break;
default:
@@ -2335,18 +590,16 @@ static void mesh_batch_cache_clear(Mesh *me)
if (!cache) {
return;
}
-
- for (int i = 0; i < sizeof(cache->ordered) / sizeof(void *); ++i) {
- GPUVertBuf **vbo = (GPUVertBuf **)&cache->ordered;
- GPU_VERTBUF_DISCARD_SAFE(vbo[i]);
- }
- for (int i = 0; i < sizeof(cache->edit) / sizeof(void *); ++i) {
- GPUVertBuf **vbo = (GPUVertBuf **)&cache->edit;
- GPU_VERTBUF_DISCARD_SAFE(vbo[i]);
- }
- for (int i = 0; i < sizeof(cache->ibo) / sizeof(void *); ++i) {
- GPUIndexBuf **ibo = (GPUIndexBuf **)&cache->ibo;
- GPU_INDEXBUF_DISCARD_SAFE(ibo[i]);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPUVertBuf **vbos = (GPUVertBuf **)&mbufcache->vbo;
+ GPUIndexBuf **ibos = (GPUIndexBuf **)&mbufcache->ibo;
+ for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); ++i) {
+ GPU_VERTBUF_DISCARD_SAFE(vbos[i]);
+ }
+ for (int i = 0; i < sizeof(mbufcache->ibo) / sizeof(void *); ++i) {
+ GPU_INDEXBUF_DISCARD_SAFE(ibos[i]);
+ }
}
for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
GPUBatch **batch = (GPUBatch **)&cache->batch;
@@ -2368,2074 +621,6 @@ void DRW_mesh_batch_cache_free(Mesh *me)
MEM_SAFE_FREE(me->runtime.batch_cache);
}
-/* GPUBatch cache usage. */
-
-static void mesh_create_edit_vertex_loops(MeshRenderData *rdata,
- GPUVertBuf *vbo_pos_nor,
- GPUVertBuf *vbo_lnor,
- GPUVertBuf *vbo_uv,
- GPUVertBuf *vbo_data,
- GPUVertBuf *vbo_verts,
- GPUVertBuf *vbo_edges,
- GPUVertBuf *vbo_faces)
-{
-#if 0
- const int vert_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- const int edge_len = mesh_render_data_edges_len_get_maybe_mapped(rdata);
-#endif
- const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata);
- const int lvert_len = mesh_render_data_loose_verts_len_get_maybe_mapped(rdata);
- const int ledge_len = mesh_render_data_loose_edges_len_get_maybe_mapped(rdata);
- const int loop_len = mesh_render_data_loops_len_get_maybe_mapped(rdata);
- const int tot_loop_len = loop_len + ledge_len * 2 + lvert_len;
- float(*lnors)[3] = rdata->loop_normals;
- uchar fflag;
-
- /* Static formats */
- static struct {
- GPUVertFormat sel_id, pos_nor, lnor, flag, uv;
- } format = {{0}};
- static struct {
- uint sel_id, pos, nor, lnor, data, uvs;
- } attr_id;
- if (format.sel_id.attr_len == 0) {
- attr_id.sel_id = GPU_vertformat_attr_add(
- &format.sel_id, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
- attr_id.pos = GPU_vertformat_attr_add(
- &format.pos_nor, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- attr_id.nor = GPU_vertformat_attr_add(
- &format.pos_nor, "vnor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- attr_id.lnor = GPU_vertformat_attr_add(
- &format.lnor, "lnor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- attr_id.data = GPU_vertformat_attr_add(&format.flag, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
- attr_id.uvs = GPU_vertformat_attr_add(&format.uv, "u", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- GPU_vertformat_alias_add(&format.uv, "pos");
- GPU_vertformat_alias_add(&format.flag, "flag");
- }
-
- GPUVertBufRaw raw_verts, raw_edges, raw_faces, raw_pos, raw_nor, raw_lnor, raw_uv, raw_data;
- if (DRW_TEST_ASSIGN_VBO(vbo_pos_nor)) {
- GPU_vertbuf_init_with_format(vbo_pos_nor, &format.pos_nor);
- GPU_vertbuf_data_alloc(vbo_pos_nor, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_pos_nor, attr_id.pos, &raw_pos);
- GPU_vertbuf_attr_get_raw_data(vbo_pos_nor, attr_id.nor, &raw_nor);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_lnor)) {
- GPU_vertbuf_init_with_format(vbo_lnor, &format.lnor);
- GPU_vertbuf_data_alloc(vbo_lnor, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_lnor, attr_id.lnor, &raw_lnor);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_data)) {
- GPU_vertbuf_init_with_format(vbo_data, &format.flag);
- GPU_vertbuf_data_alloc(vbo_data, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_data, attr_id.data, &raw_data);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_uv)) {
- GPU_vertbuf_init_with_format(vbo_uv, &format.uv);
- GPU_vertbuf_data_alloc(vbo_uv, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_uv, attr_id.uvs, &raw_uv);
- }
- /* Select Idx */
- if (DRW_TEST_ASSIGN_VBO(vbo_verts)) {
- GPU_vertbuf_init_with_format(vbo_verts, &format.sel_id);
- GPU_vertbuf_data_alloc(vbo_verts, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_verts, attr_id.sel_id, &raw_verts);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_edges)) {
- GPU_vertbuf_init_with_format(vbo_edges, &format.sel_id);
- GPU_vertbuf_data_alloc(vbo_edges, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_edges, attr_id.sel_id, &raw_edges);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_faces)) {
- GPU_vertbuf_init_with_format(vbo_faces, &format.sel_id);
- GPU_vertbuf_data_alloc(vbo_faces, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_faces, attr_id.sel_id, &raw_faces);
- }
-
- if (rdata->edit_bmesh && rdata->mapped.use == false) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop, iter_vert;
- BMFace *efa;
- BMEdge *eed;
- BMVert *eve;
- BMLoop *loop;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- /* Face Loops */
- BM_ITER_MESH (efa, &iter_efa, bm, BM_FACES_OF_MESH) {
- int fidx = BM_elem_index_get(efa);
- if (vbo_data) {
- fflag = mesh_render_data_face_flag(rdata, efa, cd_loop_uv_offset);
- }
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- if (vbo_pos_nor) {
- GPUPackedNormal *vnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor);
- *vnor = GPU_normal_convert_i10_v3(loop->v->no);
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), loop->v->co);
- }
- if (vbo_lnor) {
- const float *nor = (lnors) ? lnors[BM_elem_index_get(loop)] : efa->no;
- GPUPackedNormal *lnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_lnor);
- *lnor = GPU_normal_convert_i10_v3(nor);
- }
- if (vbo_data) {
- EdgeDrawAttr eattr = {.v_flag = fflag};
- mesh_render_data_edge_flag(rdata, loop->e, &eattr);
- mesh_render_data_vert_flag(rdata, loop->v, &eattr);
- mesh_render_data_loop_flag(rdata, loop, cd_loop_uv_offset, &eattr);
- memcpy(GPU_vertbuf_raw_step(&raw_data), &eattr, sizeof(EdgeDrawAttr));
- }
- if (vbo_uv) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_loop_uv_offset);
- copy_v2_v2(GPU_vertbuf_raw_step(&raw_uv), luv->uv);
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = BM_elem_index_get(loop->v);
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- if (vbo_edges) {
- int eidx = BM_elem_index_get(loop->e);
- *((uint *)GPU_vertbuf_raw_step(&raw_edges)) = eidx;
- }
- if (vbo_faces) {
- *((uint *)GPU_vertbuf_raw_step(&raw_faces)) = fidx;
- }
- }
- }
- /* Loose edges */
- for (int e = 0; e < ledge_len; e++) {
- eed = BM_edge_at_index(bm, rdata->loose_edges[e]);
- BM_ITER_ELEM (eve, &iter_vert, eed, BM_VERTS_OF_EDGE) {
- if (vbo_pos_nor) {
- GPUPackedNormal *vnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor);
- *vnor = GPU_normal_convert_i10_v3(eve->no);
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), eve->co);
- }
- if (vbo_data) {
- EdgeDrawAttr eattr = {0};
- mesh_render_data_edge_flag(rdata, eed, &eattr);
- mesh_render_data_vert_flag(rdata, eve, &eattr);
- memcpy(GPU_vertbuf_raw_step(&raw_data), &eattr, sizeof(EdgeDrawAttr));
- }
- if (vbo_lnor) {
- memset(GPU_vertbuf_raw_step(&raw_lnor), 0, sizeof(GPUPackedNormal));
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = BM_elem_index_get(eve);
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- if (vbo_edges) {
- int eidx = BM_elem_index_get(eed);
- *((uint *)GPU_vertbuf_raw_step(&raw_edges)) = eidx;
- }
- }
- }
- /* Loose verts */
- for (int e = 0; e < lvert_len; e++) {
- eve = BM_vert_at_index(bm, rdata->loose_verts[e]);
- if (vbo_pos_nor) {
- GPUPackedNormal *vnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor);
- *vnor = GPU_normal_convert_i10_v3(eve->no);
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), eve->co);
- }
- if (vbo_lnor) {
- memset(GPU_vertbuf_raw_step(&raw_lnor), 0, sizeof(GPUPackedNormal));
- }
- if (vbo_data) {
- EdgeDrawAttr eattr = {0};
- mesh_render_data_vert_flag(rdata, eve, &eattr);
- memcpy(GPU_vertbuf_raw_step(&raw_data), &eattr, sizeof(EdgeDrawAttr));
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = BM_elem_index_get(eve);
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- }
- }
- else if (rdata->mapped.use == true) {
- BMesh *bm = rdata->edit_bmesh->bm;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- const MPoly *mpoly = rdata->mapped.me_cage->mpoly;
- const MEdge *medge = rdata->mapped.me_cage->medge;
- const MVert *mvert = rdata->mapped.me_cage->mvert;
- const MLoop *mloop = rdata->mapped.me_cage->mloop;
-
- const int *v_origindex = rdata->mapped.v_origindex;
- const int *e_origindex = rdata->mapped.e_origindex;
- const int *p_origindex = rdata->mapped.p_origindex;
-
- /* Face Loops */
- for (int poly = 0; poly < poly_len; poly++, mpoly++) {
- const MLoop *l = &mloop[mpoly->loopstart];
- int fidx = p_origindex[poly];
- BMFace *efa = NULL;
- if (vbo_data) {
- fflag = 0;
- if (fidx != ORIGINDEX_NONE) {
- efa = BM_face_at_index(bm, fidx);
- fflag = mesh_render_data_face_flag(rdata, efa, cd_loop_uv_offset);
- }
- }
- for (int i = 0; i < mpoly->totloop; i++, l++) {
- if (vbo_pos_nor) {
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), mvert[l->v].co);
- }
- if (vbo_lnor || vbo_pos_nor) {
- GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[l->v].no);
- if (vbo_pos_nor) {
- *(GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor) = vnor;
- }
- if (vbo_lnor) {
- /* Mapped does not support lnors yet. */
- *(GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_lnor) = vnor;
- }
- }
- if (vbo_data) {
- EdgeDrawAttr eattr = {.v_flag = fflag};
- int vidx = v_origindex[l->v];
- int eidx = e_origindex[l->e];
- if (vidx != ORIGINDEX_NONE) {
- BMVert *eve = BM_vert_at_index(bm, vidx);
- mesh_render_data_vert_flag(rdata, eve, &eattr);
- }
- if (eidx != ORIGINDEX_NONE) {
- BMEdge *eed = BM_edge_at_index(bm, eidx);
- mesh_render_data_edge_flag(rdata, eed, &eattr);
- if (efa) {
- BMLoop *loop = BM_face_edge_share_loop(efa, eed);
- if (loop) {
- mesh_render_data_loop_flag(rdata, loop, cd_loop_uv_offset, &eattr);
- }
- }
- }
- memcpy(GPU_vertbuf_raw_step(&raw_data), &eattr, sizeof(EdgeDrawAttr));
- }
- if (vbo_uv) {
- MLoopUV *luv = &rdata->mloopuv[mpoly->loopstart + i];
- copy_v2_v2(GPU_vertbuf_raw_step(&raw_uv), luv->uv);
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = v_origindex[l->v];
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- if (vbo_edges) {
- int eidx = e_origindex[l->e];
- *((uint *)GPU_vertbuf_raw_step(&raw_edges)) = eidx;
- }
- if (vbo_faces) {
- *((uint *)GPU_vertbuf_raw_step(&raw_faces)) = fidx;
- }
- }
- }
- /* Loose edges */
- for (int j = 0; j < ledge_len; j++) {
- const int e = rdata->mapped.loose_edges[j];
- for (int i = 0; i < 2; ++i) {
- int v = (i == 0) ? medge[e].v1 : medge[e].v2;
- if (vbo_pos_nor) {
- GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[v].no);
- *(GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor) = vnor;
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), mvert[v].co);
- }
- if (vbo_lnor) {
- memset(GPU_vertbuf_raw_step(&raw_lnor), 0, sizeof(GPUPackedNormal));
- }
- if (vbo_data) {
- EdgeDrawAttr eattr = {0};
- int vidx = v_origindex[v];
- int eidx = e_origindex[e];
- if (vidx != ORIGINDEX_NONE) {
- BMVert *eve = BM_vert_at_index(bm, vidx);
- mesh_render_data_vert_flag(rdata, eve, &eattr);
- }
- if (eidx != ORIGINDEX_NONE) {
- BMEdge *eed = BM_edge_at_index(bm, eidx);
- mesh_render_data_edge_flag(rdata, eed, &eattr);
- }
- memcpy(GPU_vertbuf_raw_step(&raw_data), &eattr, sizeof(EdgeDrawAttr));
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = v_origindex[v];
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- if (vbo_edges) {
- int eidx = e_origindex[e];
- *((uint *)GPU_vertbuf_raw_step(&raw_edges)) = eidx;
- }
- }
- }
- /* Loose verts */
- for (int i = 0; i < lvert_len; i++) {
- const int v = rdata->mapped.loose_verts[i];
- if (vbo_pos_nor) {
- GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[v].no);
- *(GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor) = vnor;
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), mvert[v].co);
- }
- if (vbo_lnor) {
- memset(GPU_vertbuf_raw_step(&raw_lnor), 0, sizeof(GPUPackedNormal));
- }
- if (vbo_data) {
- EdgeDrawAttr eattr = {0};
- int vidx = v_origindex[v];
- if (vidx != ORIGINDEX_NONE) {
- BMVert *eve = BM_vert_at_index(bm, vidx);
- mesh_render_data_vert_flag(rdata, eve, &eattr);
- }
- memcpy(GPU_vertbuf_raw_step(&raw_data), &eattr, sizeof(EdgeDrawAttr));
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = v_origindex[v];
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- }
- }
- else {
- const MPoly *mpoly = rdata->mpoly;
- const MVert *mvert = rdata->mvert;
- const MLoop *mloop = rdata->mloop;
-
- const int *v_origindex = CustomData_get_layer(&rdata->me->vdata, CD_ORIGINDEX);
- const int *e_origindex = CustomData_get_layer(&rdata->me->edata, CD_ORIGINDEX);
- const int *p_origindex = CustomData_get_layer(&rdata->me->pdata, CD_ORIGINDEX);
-
- /* Face Loops */
- for (int poly = 0; poly < poly_len; poly++, mpoly++) {
- const MLoop *l = &mloop[mpoly->loopstart];
- int fidx = p_origindex ? p_origindex[poly] : poly;
- for (int i = 0; i < mpoly->totloop; i++, l++) {
- if (vbo_pos_nor) {
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), mvert[l->v].co);
- }
- if (vbo_lnor || vbo_pos_nor) {
- GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[l->v].no);
- if (vbo_pos_nor) {
- *(GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor) = vnor;
- }
- if (vbo_lnor) {
- /* Mapped does not support lnors yet. */
- *(GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_lnor) = vnor;
- }
- }
- if (vbo_uv) {
- MLoopUV *luv = &rdata->mloopuv[mpoly->loopstart + i];
- copy_v2_v2(GPU_vertbuf_raw_step(&raw_uv), luv->uv);
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = v_origindex ? v_origindex[l->v] : l->v;
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- if (vbo_edges) {
- int eidx = e_origindex ? e_origindex[l->e] : l->e;
- *((uint *)GPU_vertbuf_raw_step(&raw_edges)) = eidx;
- }
- if (vbo_faces) {
- *((uint *)GPU_vertbuf_raw_step(&raw_faces)) = fidx;
- }
- }
- }
- /* TODO(fclem): Until we find a way to detect
- * loose verts easily outside of edit mode, this
- * will remain disabled. */
-#if 0
- /* Loose edges */
- for (int e = 0; e < edge_len; e++, medge++) {
- int eidx = e_origindex[e];
- if (eidx != ORIGINDEX_NONE && (medge->flag & ME_LOOSEEDGE)) {
- for (int i = 0; i < 2; ++i) {
- int vidx = (i == 0) ? medge->v1 : medge->v2;
- if (vbo_pos) {
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), mvert[vidx].co);
- }
- if (vbo_verts) {
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- if (vbo_edges) {
- *((uint *)GPU_vertbuf_raw_step(&raw_edges)) = eidx;
- }
- }
- }
- }
- /* Loose verts */
- for (int v = 0; v < vert_len; v++, mvert++) {
- int vidx = v_origindex[v];
- if (vidx != ORIGINDEX_NONE) {
- MVert *eve = BM_vert_at_index(bm, vidx);
- if (eve->e == NULL) {
- if (vbo_pos) {
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), mvert->co);
- }
- if (vbo_verts) {
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- }
- }
- }
-#endif
- }
- /* Don't resize */
-}
-
-/* TODO: We could use gl_PrimitiveID as index instead of using another VBO. */
-static void mesh_create_edit_facedots_select_id(MeshRenderData *rdata,
- GPUVertBuf *vbo,
- Scene *scene,
- Object *ob)
-{
- const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata);
-
- static GPUVertFormat format = {0};
- static struct {
- uint idx;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.idx = GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
- }
-
- GPUVertBufRaw idx_step;
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, poly_len);
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id.idx, &idx_step);
-
- /* Keep in sync with mesh_create_edit_facedots(). */
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- for (int poly = 0; poly < poly_len; poly++) {
- const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, poly);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- *((uint *)GPU_vertbuf_raw_step(&idx_step)) = poly;
- }
- }
- }
- else {
- for (int poly = 0; poly < poly_len; poly++) {
- *((uint *)GPU_vertbuf_raw_step(&idx_step)) = poly;
- }
- }
- }
- else {
- const int *p_origindex = rdata->mapped.p_origindex;
- if (modifiers_usesSubsurfFacedots(scene, ob)) {
- Mesh *me_cage = rdata->mapped.me_cage;
- const MPoly *mpoly = me_cage->mpoly;
- for (int p = 0; p < poly_len; p++, mpoly++) {
- const int p_orig = p_origindex[p];
- if (p_orig != ORIGINDEX_NONE) {
- const MLoop *mloop = me_cage->mloop + mpoly->loopstart;
- for (int l = 0; l < mpoly->totloop; l++, mloop++) {
- if (me_cage->mvert[mloop->v].flag & ME_VERT_FACEDOT) {
- const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, p_orig);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- *((uint *)GPU_vertbuf_raw_step(&idx_step)) = p_orig;
- }
- }
- }
- }
- }
- }
- else {
- for (int poly = 0; poly < poly_len; poly++) {
- const int p_orig = p_origindex[poly];
- if (p_orig != ORIGINDEX_NONE) {
- const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, p_orig);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- *((uint *)GPU_vertbuf_raw_step(&idx_step)) = p_orig;
- }
- }
- }
- }
- }
-
- /* Resize & Finish */
- int facedot_len_used = GPU_vertbuf_raw_used(&idx_step);
- if (facedot_len_used != poly_len) {
- GPU_vertbuf_data_resize(vbo, facedot_len_used);
- }
-}
-
-static void mesh_create_pos_and_nor(MeshRenderData *rdata, GPUVertBuf *vbo)
-{
- static GPUVertFormat format = {0};
- static struct {
- uint pos, nor;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- attr_id.nor = GPU_vertformat_attr_add(
- &format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
-
- GPU_vertbuf_init_with_format(vbo, &format);
- const int vbo_len_capacity = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter;
- BMVert *eve;
- uint i;
-
- mesh_render_data_ensure_vert_normals_pack(rdata);
- GPUPackedNormal *vnor = rdata->vert_normals_pack;
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i, eve->co);
- GPU_vertbuf_attr_set(vbo, attr_id.nor, i, &vnor[i]);
- }
- BLI_assert(i == vbo_len_capacity);
- }
- else {
- for (int i = 0; i < vbo_len_capacity; i++) {
- const MVert *mv = &rdata->mvert[i];
- GPUPackedNormal vnor_pack = GPU_normal_convert_i10_s3(mv->no);
- vnor_pack.w = (mv->flag & ME_HIDE) ? -1 : ((mv->flag & SELECT) ? 1 : 0);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i, rdata->mvert[i].co);
- GPU_vertbuf_attr_set(vbo, attr_id.nor, i, &vnor_pack);
- }
- }
- }
- else {
- const MVert *mvert = rdata->mapped.me_cage->mvert;
- const int *v_origindex = rdata->mapped.v_origindex;
- for (int i = 0; i < vbo_len_capacity; i++) {
- const int v_orig = v_origindex[i];
- if (v_orig != ORIGINDEX_NONE) {
- const MVert *mv = &mvert[i];
- GPUPackedNormal vnor_pack = GPU_normal_convert_i10_s3(mv->no);
- vnor_pack.w = (mv->flag & ME_HIDE) ? -1 : ((mv->flag & SELECT) ? 1 : 0);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i, mv->co);
- GPU_vertbuf_attr_set(vbo, attr_id.nor, i, &vnor_pack);
- }
- }
- }
-}
-
-static void mesh_create_weights(MeshRenderData *rdata,
- GPUVertBuf *vbo,
- DRW_MeshWeightState *wstate)
-{
- static GPUVertFormat format = {0};
- static struct {
- uint weight;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.weight = GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- }
-
- const int vbo_len_capacity = mesh_render_data_verts_len_get_maybe_mapped(rdata);
-
- mesh_render_data_ensure_vert_weight(rdata, wstate);
- const float *vert_weight = rdata->vert_weight;
-
- GPU_vertbuf_init_with_format(vbo, &format);
- /* Meh, another allocation / copy for no benefit.
- * Needed because rdata->vert_weight is freed afterwards and
- * GPU module don't have a GPU_vertbuf_data_from_memory or similar. */
- /* TODO get rid of the extra allocation/copy. */
- GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
- GPU_vertbuf_attr_fill(vbo, attr_id.weight, vert_weight);
-}
-
-static float mesh_loop_edge_factor_get(const float f_no[3],
- const float v_co[3],
- const float v_no[3],
- const float v_next_co[3])
-{
- float enor[3], evec[3];
- sub_v3_v3v3(evec, v_next_co, v_co);
- cross_v3_v3v3(enor, v_no, evec);
- normalize_v3(enor);
- float d = fabsf(dot_v3v3(enor, f_no));
- /* Rescale to the slider range. */
- d *= (1.0f / 0.065f);
- CLAMP(d, 0.0f, 1.0f);
- return d;
-}
-
-static void vertbuf_raw_step_u8(GPUVertBufRaw *wd_step, const uchar wiredata)
-{
- *((uchar *)GPU_vertbuf_raw_step(wd_step)) = wiredata;
-}
-
-static void vertbuf_raw_step_u8_to_f32(GPUVertBufRaw *wd_step, const uchar wiredata)
-{
- *((float *)GPU_vertbuf_raw_step(wd_step)) = wiredata / 255.0f;
-}
-
-static void mesh_create_loop_edge_fac(MeshRenderData *rdata, GPUVertBuf *vbo)
-{
- static GPUVertFormat format = {0};
- static struct {
- uint wd;
- } attr_id;
- static union {
- float f;
- uchar u;
- } data;
- static void (*vertbuf_raw_step)(GPUVertBufRaw *, const uchar);
- if (format.attr_len == 0) {
- if (!GPU_crappy_amd_driver()) {
- /* Some AMD drivers strangely crash with a vbo with this format. */
- attr_id.wd = GPU_vertformat_attr_add(
- &format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
- vertbuf_raw_step = vertbuf_raw_step_u8;
- data.u = UCHAR_MAX;
- }
- else {
- attr_id.wd = GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- vertbuf_raw_step = vertbuf_raw_step_u8_to_f32;
- data.f = 1.0f;
- }
- }
- const int poly_len = mesh_render_data_polys_len_get(rdata);
- const int loop_len = mesh_render_data_loops_len_get(rdata);
- const int edge_len = mesh_render_data_edges_len_get(rdata);
-
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, loop_len);
-
- GPUVertBufRaw wd_step;
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id.wd, &wd_step);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop;
- BMFace *efa;
- BMLoop *loop;
- uint f;
-
- BM_ITER_MESH_INDEX (efa, &iter_efa, bm, BM_FACES_OF_MESH, f) {
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- float ratio = mesh_loop_edge_factor_get(
- efa->no, loop->v->co, loop->v->no, loop->next->v->co);
- vertbuf_raw_step(&wd_step, ratio * 253 + 1);
- }
- }
- BLI_assert(GPU_vertbuf_raw_used(&wd_step) == loop_len);
- }
- else {
- const MVert *mvert = rdata->mvert;
- const MPoly *mpoly = rdata->mpoly;
- const MLoop *mloop = rdata->mloop;
- MEdge *medge = (MEdge *)rdata->medge;
- bool use_edge_render = false;
-
- /* TODO(fclem) We don't need them to be packed. But we need rdata->poly_normals */
- mesh_render_data_ensure_poly_normals_pack(rdata);
-
- /* Reset flag */
- for (int edge = 0; edge < edge_len; ++edge) {
- /* NOTE: not thread safe. */
- medge[edge].flag &= ~ME_EDGE_TMP_TAG;
-
- /* HACK(fclem) Feels like a hack. Detecting the need for edge render. */
- if ((medge[edge].flag & ME_EDGERENDER) == 0) {
- use_edge_render = true;
- }
- }
-
- for (int a = 0; a < poly_len; a++, mpoly++) {
- const float *fnor = rdata->poly_normals[a];
- for (int b = 0; b < mpoly->totloop; b++) {
- const MLoop *ml1 = &mloop[mpoly->loopstart + b];
- const MLoop *ml2 = &mloop[mpoly->loopstart + (b + 1) % mpoly->totloop];
-
- /* Will only work for edges that have an odd number of faces connected. */
- MEdge *ed = (MEdge *)rdata->medge + ml1->e;
- ed->flag ^= ME_EDGE_TMP_TAG;
-
- if (use_edge_render) {
- vertbuf_raw_step(&wd_step, (ed->flag & ME_EDGERENDER) ? 255 : 0);
- }
- else {
- float vnor_f[3];
- normal_short_to_float_v3(vnor_f, mvert[ml1->v].no);
- float ratio = mesh_loop_edge_factor_get(
- fnor, mvert[ml1->v].co, vnor_f, mvert[ml2->v].co);
- vertbuf_raw_step(&wd_step, ratio * 253 + 1);
- }
- }
- }
- /* Gather non-manifold edges. */
- for (int l = 0; l < loop_len; l++, mloop++) {
- MEdge *ed = (MEdge *)rdata->medge + mloop->e;
- if (ed->flag & ME_EDGE_TMP_TAG) {
- GPU_vertbuf_attr_set(vbo, attr_id.wd, l, &data);
- }
- }
-
- BLI_assert(loop_len == GPU_vertbuf_raw_used(&wd_step));
- }
- }
- else {
- BLI_assert(0);
- }
-}
-
-static void mesh_create_loop_pos_and_nor(MeshRenderData *rdata, GPUVertBuf *vbo)
-{
- /* TODO deduplicate format creation*/
- static GPUVertFormat format = {0};
- static struct {
- uint pos, nor;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- attr_id.nor = GPU_vertformat_attr_add(
- &format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
- const int poly_len = mesh_render_data_polys_len_get(rdata);
- const int loop_len = mesh_render_data_loops_len_get(rdata);
-
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, loop_len);
-
- GPUVertBufRaw pos_step, nor_step;
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id.nor, &nor_step);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- const GPUPackedNormal *vnor, *pnor;
- const float(*lnors)[3] = rdata->loop_normals;
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop;
- BMFace *efa;
- BMLoop *loop;
- uint f;
-
- if (rdata->loop_normals == NULL) {
- mesh_render_data_ensure_poly_normals_pack(rdata);
- mesh_render_data_ensure_vert_normals_pack(rdata);
- vnor = rdata->vert_normals_pack;
- pnor = rdata->poly_normals_pack;
- }
-
- BM_ITER_MESH_INDEX (efa, &iter_efa, bm, BM_FACES_OF_MESH, f) {
- const bool face_smooth = BM_elem_flag_test(efa, BM_ELEM_SMOOTH);
-
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- BLI_assert(GPU_vertbuf_raw_used(&pos_step) == BM_elem_index_get(loop));
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), loop->v->co);
-
- if (lnors) {
- GPUPackedNormal plnor = GPU_normal_convert_i10_v3(lnors[BM_elem_index_get(loop)]);
- *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = plnor;
- }
- else if (!face_smooth) {
- *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = pnor[f];
- }
- else {
- *((GPUPackedNormal *)GPU_vertbuf_raw_step(
- &nor_step)) = vnor[BM_elem_index_get(loop->v)];
- }
- }
- }
- BLI_assert(GPU_vertbuf_raw_used(&pos_step) == loop_len);
- }
- else {
- const MVert *mvert = rdata->mvert;
- const MPoly *mpoly = rdata->mpoly;
-
- if (rdata->loop_normals == NULL) {
- mesh_render_data_ensure_poly_normals_pack(rdata);
- }
-
- for (int a = 0; a < poly_len; a++, mpoly++) {
- const MLoop *mloop = rdata->mloop + mpoly->loopstart;
- const float(*lnors)[3] = (rdata->loop_normals) ? &rdata->loop_normals[mpoly->loopstart] :
- NULL;
- const GPUPackedNormal *fnor = (mpoly->flag & ME_SMOOTH) ? NULL :
- &rdata->poly_normals_pack[a];
- const int hide_select_flag = (mpoly->flag & ME_HIDE) ?
- -1 :
- ((mpoly->flag & ME_FACE_SEL) ? 1 : 0);
- for (int b = 0; b < mpoly->totloop; b++, mloop++) {
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop->v].co);
- GPUPackedNormal *pnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step);
- if (lnors) {
- *pnor = GPU_normal_convert_i10_v3(lnors[b]);
- }
- else if (fnor) {
- *pnor = *fnor;
- }
- else {
- *pnor = GPU_normal_convert_i10_s3(mvert[mloop->v].no);
- }
- pnor->w = hide_select_flag;
- }
- }
-
- BLI_assert(loop_len == GPU_vertbuf_raw_used(&pos_step));
- }
- }
- else {
- const int *p_origindex = rdata->mapped.p_origindex;
- const MVert *mvert = rdata->mvert;
- const MPoly *mpoly = rdata->mpoly;
-
- if (rdata->loop_normals == NULL) {
- mesh_render_data_ensure_poly_normals_pack(rdata);
- }
-
- for (int a = 0; a < poly_len; a++, mpoly++) {
- const MLoop *mloop = rdata->mloop + mpoly->loopstart;
- const float(*lnors)[3] = (rdata->loop_normals) ? &rdata->loop_normals[mpoly->loopstart] :
- NULL;
- const GPUPackedNormal *fnor = (mpoly->flag & ME_SMOOTH) ? NULL :
- &rdata->poly_normals_pack[a];
- if (p_origindex[a] == ORIGINDEX_NONE) {
- continue;
- }
- for (int b = 0; b < mpoly->totloop; b++, mloop++) {
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop->v].co);
- GPUPackedNormal *pnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step);
- if (lnors) {
- *pnor = GPU_normal_convert_i10_v3(lnors[b]);
- }
- else if (fnor) {
- *pnor = *fnor;
- }
- else {
- *pnor = GPU_normal_convert_i10_s3(mvert[mloop->v].no);
- }
- }
- }
- }
-
- int vbo_len_used = GPU_vertbuf_raw_used(&pos_step);
- if (vbo_len_used < loop_len) {
- GPU_vertbuf_data_resize(vbo, vbo_len_used);
- }
-}
-
-static void mesh_create_loop_orco(MeshRenderData *rdata, GPUVertBuf *vbo)
-{
- const uint loops_len = mesh_render_data_loops_len_get(rdata);
-
- /* initialize vertex format */
- GPUVertFormat format = {0};
- GPUVertBufRaw vbo_step;
-
- /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex attribs.
- * This is a substential waste of Vram and should be done another way. Unfortunately,
- * at the time of writing, I did not found any other "non disruptive" alternative. */
- uint attr_id = GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, loops_len);
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id, &vbo_step);
-
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop;
- BMFace *efa;
- BMLoop *loop;
-
- BM_ITER_MESH (efa, &iter_efa, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- float *data = (float *)GPU_vertbuf_raw_step(&vbo_step);
- copy_v3_v3(data, rdata->orco[BM_elem_index_get(loop->v)]);
- data[3] = 0.0; /* Tag as not a generic attrib */
- }
- }
- }
- else {
- for (uint l = 0; l < loops_len; l++) {
- float *data = (float *)GPU_vertbuf_raw_step(&vbo_step);
- copy_v3_v3(data, rdata->orco[rdata->mloop[l].v]);
- data[3] = 0.0; /* Tag as not a generic attrib */
- }
- }
-}
-
-static void mesh_create_loop_uv_and_tan(MeshRenderData *rdata, GPUVertBuf *vbo)
-{
- const uint loops_len = mesh_render_data_loops_len_get(rdata);
- const uint uv_len = rdata->cd.layers.uv_len;
- const uint tangent_len = rdata->cd.layers.tangent_len;
- const uint layers_combined_len = uv_len + tangent_len;
-
- GPUVertBufRaw *layers_combined_step = BLI_array_alloca(layers_combined_step,
- layers_combined_len);
- GPUVertBufRaw *uv_step = layers_combined_step;
- GPUVertBufRaw *tangent_step = uv_step + uv_len;
-
- uint *layers_combined_id = BLI_array_alloca(layers_combined_id, layers_combined_len);
- uint *uv_id = layers_combined_id;
- uint *tangent_id = uv_id + uv_len;
-
- /* initialize vertex format */
- GPUVertFormat format = {0};
-
- for (uint i = 0; i < uv_len; i++) {
- const char *attr_name = mesh_render_data_uv_layer_uuid_get(rdata, i);
-#if 0 /* these are clamped. Maybe use them as an option in the future */
- uv_id[i] = GPU_vertformat_attr_add(
- &format, attr_name, GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT);
-#else
- uv_id[i] = GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-#endif
- /* Auto Name */
- attr_name = mesh_render_data_uv_auto_layer_uuid_get(rdata, i);
- GPU_vertformat_alias_add(&format, attr_name);
-
- if (i == rdata->cd.layers.uv_render) {
- GPU_vertformat_alias_add(&format, "u");
- }
- if (i == rdata->cd.layers.uv_active) {
- GPU_vertformat_alias_add(&format, "au");
- }
- if (i == rdata->cd.layers.uv_mask_active) {
- GPU_vertformat_alias_add(&format, "mu");
- }
- }
-
- for (uint i = 0; i < tangent_len; i++) {
- const char *attr_name = mesh_render_data_tangent_layer_uuid_get(rdata, i);
-#ifdef USE_COMP_MESH_DATA
- tangent_id[i] = GPU_vertformat_attr_add(
- &format, attr_name, GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
-#else
- tangent_id[i] = GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-#endif
- if (i == rdata->cd.layers.tangent_render) {
- GPU_vertformat_alias_add(&format, "t");
- }
- if (i == rdata->cd.layers.tangent_active) {
- GPU_vertformat_alias_add(&format, "at");
- }
- }
-
- /* HACK: Create a dummy attribute in case there is no valid UV/tangent layer. */
- if (layers_combined_len == 0) {
- GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
-
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, loops_len);
-
- for (uint i = 0; i < uv_len; i++) {
- GPU_vertbuf_attr_get_raw_data(vbo, uv_id[i], &uv_step[i]);
- }
- for (uint i = 0; i < tangent_len; i++) {
- GPU_vertbuf_attr_get_raw_data(vbo, tangent_id[i], &tangent_step[i]);
- }
-
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop;
- BMFace *efa;
- BMLoop *loop;
-
- BM_ITER_MESH (efa, &iter_efa, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- /* UVs */
- for (uint j = 0; j < uv_len; j++) {
- const uint layer_offset = rdata->cd.offset.uv[j];
- const float *elem = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(loop, layer_offset))->uv;
- copy_v2_v2(GPU_vertbuf_raw_step(&uv_step[j]), elem);
- }
- /* TANGENTs */
- for (uint j = 0; j < tangent_len; j++) {
- float(*layer_data)[4] = rdata->cd.layers.tangent[j];
- const float *elem = layer_data[BM_elem_index_get(loop)];
-#ifdef USE_COMP_MESH_DATA
- normal_float_to_short_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem);
-#else
- copy_v4_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem);
-#endif
- }
- }
- }
- }
- else {
- for (uint loop = 0; loop < loops_len; loop++) {
- /* UVs */
- for (uint j = 0; j < uv_len; j++) {
- const MLoopUV *layer_data = rdata->cd.layers.uv[j];
- const float *elem = layer_data[loop].uv;
- copy_v2_v2(GPU_vertbuf_raw_step(&uv_step[j]), elem);
- }
- /* TANGENTs */
- for (uint j = 0; j < tangent_len; j++) {
- float(*layer_data)[4] = rdata->cd.layers.tangent[j];
- const float *elem = layer_data[loop];
-#ifdef USE_COMP_MESH_DATA
- normal_float_to_short_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem);
-#else
- copy_v4_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem);
-#endif
- }
- }
- }
-
-#ifndef NDEBUG
- /* Check all layers are write aligned. */
- if (layers_combined_len > 0) {
- int vbo_len_used = GPU_vertbuf_raw_used(&layers_combined_step[0]);
- for (uint i = 0; i < layers_combined_len; i++) {
- BLI_assert(vbo_len_used == GPU_vertbuf_raw_used(&layers_combined_step[i]));
- }
- }
-#endif
-
-#undef USE_COMP_MESH_DATA
-}
-
-static void mesh_create_loop_vcol(MeshRenderData *rdata, GPUVertBuf *vbo)
-{
- const uint loops_len = mesh_render_data_loops_len_get(rdata);
- const uint vcol_len = rdata->cd.layers.vcol_len;
-
- GPUVertBufRaw *vcol_step = BLI_array_alloca(vcol_step, vcol_len);
- uint *vcol_id = BLI_array_alloca(vcol_id, vcol_len);
-
- /* initialize vertex format */
- GPUVertFormat format = {0};
-
- for (uint i = 0; i < vcol_len; i++) {
- const char *attr_name = mesh_render_data_vcol_layer_uuid_get(rdata, i);
- vcol_id[i] = GPU_vertformat_attr_add(
- &format, attr_name, GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- /* Auto layer */
- if (rdata->cd.layers.auto_vcol[i]) {
- attr_name = mesh_render_data_vcol_auto_layer_uuid_get(rdata, i);
- GPU_vertformat_alias_add(&format, attr_name);
- }
- if (i == rdata->cd.layers.vcol_render) {
- GPU_vertformat_alias_add(&format, "c");
- }
- if (i == rdata->cd.layers.vcol_active) {
- GPU_vertformat_alias_add(&format, "ac");
- }
- }
-
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, loops_len);
-
- for (uint i = 0; i < vcol_len; i++) {
- GPU_vertbuf_attr_get_raw_data(vbo, vcol_id[i], &vcol_step[i]);
- }
-
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop;
- BMFace *efa;
- BMLoop *loop;
-
- BM_ITER_MESH (efa, &iter_efa, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- for (uint j = 0; j < vcol_len; j++) {
- const uint layer_offset = rdata->cd.offset.vcol[j];
- const uchar *elem = &((MLoopCol *)BM_ELEM_CD_GET_VOID_P(loop, layer_offset))->r;
- copy_v3_v3_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem);
- }
- }
- }
- }
- else {
- for (uint loop = 0; loop < loops_len; loop++) {
- for (uint j = 0; j < vcol_len; j++) {
- const MLoopCol *layer_data = rdata->cd.layers.vcol[j];
- const uchar *elem = &layer_data[loop].r;
- copy_v3_v3_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem);
- }
- }
- }
-
-#ifndef NDEBUG
- /* Check all layers are write aligned. */
- if (vcol_len > 0) {
- int vbo_len_used = GPU_vertbuf_raw_used(&vcol_step[0]);
- for (uint i = 0; i < vcol_len; i++) {
- BLI_assert(vbo_len_used == GPU_vertbuf_raw_used(&vcol_step[i]));
- }
- }
-#endif
-
-#undef USE_COMP_MESH_DATA
-}
-
-static void mesh_create_edit_facedots(MeshRenderData *rdata,
- GPUVertBuf *vbo_facedots_pos_nor_data,
- Scene *scene,
- Object *ob)
-{
- const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata);
- const int verts_facedot_len = poly_len;
- int facedot_len_used = 0;
-
- static struct {
- uint fdot_pos, fdot_nor_flag;
- } attr_id;
- static GPUVertFormat facedot_format = {0};
- if (facedot_format.attr_len == 0) {
- attr_id.fdot_pos = GPU_vertformat_attr_add(
- &facedot_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- attr_id.fdot_nor_flag = GPU_vertformat_attr_add(
- &facedot_format, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
-
- if (DRW_TEST_ASSIGN_VBO(vbo_facedots_pos_nor_data)) {
- GPU_vertbuf_init_with_format(vbo_facedots_pos_nor_data, &facedot_format);
- GPU_vertbuf_data_alloc(vbo_facedots_pos_nor_data, verts_facedot_len);
- /* TODO(fclem): Maybe move data generation to mesh_render_data_create() */
- if (rdata->edit_bmesh) {
- if (rdata->edit_data && rdata->edit_data->vertexCos != NULL) {
- BKE_editmesh_cache_ensure_poly_normals(rdata->edit_bmesh, rdata->edit_data);
- BKE_editmesh_cache_ensure_poly_centers(rdata->edit_bmesh, rdata->edit_data);
- }
- }
- }
-
- if (rdata->mapped.use == false) {
- for (int i = 0; i < poly_len; i++) {
- if (add_edit_facedot(rdata,
- vbo_facedots_pos_nor_data,
- attr_id.fdot_pos,
- attr_id.fdot_nor_flag,
- i,
- facedot_len_used)) {
- facedot_len_used += 1;
- }
- }
- }
- else {
- if (modifiers_usesSubsurfFacedots(scene, ob)) {
- /* Facedots that follow surbsurf face center. */
- Mesh *me_cage = rdata->mapped.me_cage;
- const MPoly *mpoly = me_cage->mpoly;
- for (int p = 0; p < poly_len; p++, mpoly++) {
- const MLoop *mloop = me_cage->mloop + mpoly->loopstart;
- for (int l = 0; l < mpoly->totloop; l++, mloop++) {
- if (me_cage->mvert[mloop->v].flag & ME_VERT_FACEDOT) {
- if (add_edit_facedot_subdiv(rdata,
- vbo_facedots_pos_nor_data,
- attr_id.fdot_pos,
- attr_id.fdot_nor_flag,
- mloop->v,
- p,
- facedot_len_used)) {
- facedot_len_used += 1;
- }
- }
- }
- }
- }
- else {
- for (int i = 0; i < poly_len; i++) {
- if (add_edit_facedot_mapped(rdata,
- vbo_facedots_pos_nor_data,
- attr_id.fdot_pos,
- attr_id.fdot_nor_flag,
- i,
- facedot_len_used)) {
- facedot_len_used += 1;
- }
- }
- }
- }
-
- /* Resize & Finish */
- if (facedot_len_used != verts_facedot_len) {
- if (vbo_facedots_pos_nor_data != NULL) {
- GPU_vertbuf_data_resize(vbo_facedots_pos_nor_data, facedot_len_used);
- }
- }
-}
-
-static void mesh_create_edit_mesh_analysis(MeshRenderData *rdata, GPUVertBuf *vbo_mesh_analysis)
-{
- const MeshStatVis *mesh_stat_vis = &rdata->toolsettings->statvis;
-
- int mesh_analysis_len_used = 0;
-
- const uint loops_len = mesh_render_data_loops_len_get(rdata);
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop;
- BMFace *efa;
- BMLoop *loop;
-
- static struct {
- uint weight;
- } attr_id;
- static GPUVertFormat mesh_analysis_format = {0};
- if (mesh_analysis_format.attr_len == 0) {
- attr_id.weight = GPU_vertformat_attr_add(
- &mesh_analysis_format, "weight_color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
-
- /* TODO(jbakker): Maybe move data generation to mesh_render_data_create() */
- BKE_editmesh_statvis_calc(rdata->edit_bmesh, rdata->edit_data, mesh_stat_vis);
-
- if (DRW_TEST_ASSIGN_VBO(vbo_mesh_analysis)) {
- GPU_vertbuf_init_with_format(vbo_mesh_analysis, &mesh_analysis_format);
- GPU_vertbuf_data_alloc(vbo_mesh_analysis, loops_len);
- }
-
- const bool is_vertex_data = mesh_stat_vis->type == SCE_STATVIS_SHARP;
- if (is_vertex_data) {
- BM_ITER_MESH (efa, &iter_efa, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- uint vertex_index = BM_elem_index_get(loop->v);
- GPU_vertbuf_attr_set(vbo_mesh_analysis,
- attr_id.weight,
- mesh_analysis_len_used,
- &rdata->edit_bmesh->derivedVertColor[vertex_index]);
- mesh_analysis_len_used += 1;
- }
- }
- }
- else {
- uint face_index;
- BM_ITER_MESH_INDEX (efa, &iter_efa, bm, BM_FACES_OF_MESH, face_index) {
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- GPU_vertbuf_attr_set(vbo_mesh_analysis,
- attr_id.weight,
- mesh_analysis_len_used,
- &rdata->edit_bmesh->derivedFaceColor[face_index]);
- mesh_analysis_len_used += 1;
- }
- }
- }
-
- // Free temp data in edit bmesh
- BKE_editmesh_color_free(rdata->edit_bmesh);
-
- /* Resize & Finish */
- if (mesh_analysis_len_used != loops_len) {
- if (vbo_mesh_analysis != NULL) {
- GPU_vertbuf_data_resize(vbo_mesh_analysis, mesh_analysis_len_used);
- }
- }
-}
-/* Indices */
-
-#define NO_EDGE INT_MAX
-static void mesh_create_edges_adjacency_lines(MeshRenderData *rdata,
- GPUIndexBuf *ibo,
- bool *r_is_manifold,
- const bool use_hide)
-{
- const MLoopTri *mlooptri;
- const int vert_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- const int tri_len = mesh_render_data_looptri_len_get_maybe_mapped(rdata);
-
- *r_is_manifold = true;
-
- /* Allocate max but only used indices are sent to GPU. */
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init(&elb, GPU_PRIM_LINES_ADJ, tri_len * 3, vert_len);
-
- if (rdata->mapped.use) {
- Mesh *me_cage = rdata->mapped.me_cage;
- mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage);
- }
- else {
- mlooptri = rdata->mlooptri;
- }
-
- EdgeHash *eh = BLI_edgehash_new_ex(__func__, tri_len * 3);
- /* Create edges for each pair of triangles sharing an edge. */
- for (int i = 0; i < tri_len; i++) {
- for (int e = 0; e < 3; e++) {
- uint v0, v1, v2;
- if (rdata->mapped.use) {
- const MLoop *mloop = rdata->mloop;
- const MLoopTri *mlt = mlooptri + i;
- const int p_orig = rdata->mapped.p_origindex[mlt->poly];
- if (p_orig != ORIGINDEX_NONE) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMFace *efa = BM_face_at_index(bm, p_orig);
- /* Assume 'use_hide' */
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- break;
- }
- }
- v0 = mloop[mlt->tri[e]].v;
- v1 = mloop[mlt->tri[(e + 1) % 3]].v;
- v2 = mloop[mlt->tri[(e + 2) % 3]].v;
- }
- else if (rdata->edit_bmesh) {
- const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
- if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) {
- break;
- }
- v0 = BM_elem_index_get(bm_looptri[e]->v);
- v1 = BM_elem_index_get(bm_looptri[(e + 1) % 3]->v);
- v2 = BM_elem_index_get(bm_looptri[(e + 2) % 3]->v);
- }
- else {
- const MLoop *mloop = rdata->mloop;
- const MLoopTri *mlt = mlooptri + i;
- const MPoly *mp = &rdata->mpoly[mlt->poly];
- if (use_hide && (mp->flag & ME_HIDE)) {
- break;
- }
- v0 = mloop[mlt->tri[e]].v;
- v1 = mloop[mlt->tri[(e + 1) % 3]].v;
- v2 = mloop[mlt->tri[(e + 2) % 3]].v;
- }
- bool inv_indices = (v1 > v2);
- void **pval;
- bool value_is_init = BLI_edgehash_ensure_p(eh, v1, v2, &pval);
- int v_data = POINTER_AS_INT(*pval);
- if (!value_is_init || v_data == NO_EDGE) {
- /* Save the winding order inside the sign bit. Because the
- * edgehash sort the keys and we need to compare winding later. */
- int value = (int)v0 + 1; /* Int 0 bm_looptricannot be signed */
- *pval = POINTER_FROM_INT((inv_indices) ? -value : value);
- }
- else {
- /* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
- *pval = POINTER_FROM_INT(NO_EDGE);
- bool inv_opposite = (v_data < 0);
- uint v_opposite = (uint)abs(v_data) - 1;
-
- if (inv_opposite == inv_indices) {
- /* Don't share edge if triangles have non matching winding. */
- GPU_indexbuf_add_line_adj_verts(&elb, v0, v1, v2, v0);
- GPU_indexbuf_add_line_adj_verts(&elb, v_opposite, v1, v2, v_opposite);
- *r_is_manifold = false;
- }
- else {
- GPU_indexbuf_add_line_adj_verts(&elb, v0, v1, v2, v_opposite);
- }
- }
- }
- }
- /* Create edges for remaining non manifold edges. */
- EdgeHashIterator *ehi;
- for (ehi = BLI_edgehashIterator_new(eh); BLI_edgehashIterator_isDone(ehi) == false;
- BLI_edgehashIterator_step(ehi)) {
- uint v1, v2;
- int v_data = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
- if (v_data == NO_EDGE) {
- continue;
- }
- BLI_edgehashIterator_getKey(ehi, &v1, &v2);
- uint v0 = (uint)abs(v_data) - 1;
- if (v_data < 0) { /* inv_opposite */
- SWAP(uint, v1, v2);
- }
- GPU_indexbuf_add_line_adj_verts(&elb, v0, v1, v2, v0);
- *r_is_manifold = false;
- }
- BLI_edgehashIterator_free(ehi);
- BLI_edgehash_free(eh, NULL);
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-#undef NO_EDGE
-
-static void mesh_create_edges_lines(MeshRenderData *rdata, GPUIndexBuf *ibo, const bool use_hide)
-{
- const int verts_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- const int edges_len = mesh_render_data_edges_len_get_maybe_mapped(rdata);
-
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edges_len, verts_len);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter;
- BMEdge *eed;
-
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- /* use_hide always for edit-mode */
- if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- continue;
- }
- GPU_indexbuf_add_line_verts(&elb, BM_elem_index_get(eed->v1), BM_elem_index_get(eed->v2));
- }
- }
- else {
- const MEdge *ed = rdata->medge;
- for (int i = 0; i < edges_len; i++, ed++) {
- if ((ed->flag & ME_EDGERENDER) == 0) {
- continue;
- }
- if (!(use_hide && (ed->flag & ME_HIDE))) {
- GPU_indexbuf_add_line_verts(&elb, ed->v1, ed->v2);
- }
- }
- }
- }
- else {
- BMesh *bm = rdata->edit_bmesh->bm;
- const MEdge *edge = rdata->medge;
- for (int i = 0; i < edges_len; i++, edge++) {
- const int p_orig = rdata->mapped.e_origindex[i];
- if (p_orig != ORIGINDEX_NONE) {
- BMEdge *eed = BM_edge_at_index(bm, p_orig);
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- GPU_indexbuf_add_line_verts(&elb, edge->v1, edge->v2);
- }
- }
- }
- }
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
-static void mesh_create_surf_tris(MeshRenderData *rdata, GPUIndexBuf *ibo, const bool use_hide)
-{
- const int vert_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- const int tri_len = mesh_render_data_looptri_len_get(rdata);
-
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len * 3);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- for (int i = 0; i < tri_len; i++) {
- const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
- const BMFace *bm_face = bm_looptri[0]->f;
- /* use_hide always for edit-mode */
- if (BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) {
- continue;
- }
- GPU_indexbuf_add_tri_verts(&elb,
- BM_elem_index_get(bm_looptri[0]->v),
- BM_elem_index_get(bm_looptri[1]->v),
- BM_elem_index_get(bm_looptri[2]->v));
- }
- }
- else {
- const MLoop *loops = rdata->mloop;
- for (int i = 0; i < tri_len; i++) {
- const MLoopTri *mlt = &rdata->mlooptri[i];
- const MPoly *mp = &rdata->mpoly[mlt->poly];
- if (use_hide && (mp->flag & ME_HIDE)) {
- continue;
- }
- GPU_indexbuf_add_tri_verts(
- &elb, loops[mlt->tri[0]].v, loops[mlt->tri[1]].v, loops[mlt->tri[2]].v);
- }
- }
- }
- else {
- /* Note: mapped doesn't support lnors yet. */
- BMesh *bm = rdata->edit_bmesh->bm;
- Mesh *me_cage = rdata->mapped.me_cage;
-
- const MLoop *loops = rdata->mloop;
- const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage);
- for (int i = 0; i < tri_len; i++) {
- const MLoopTri *mlt = &mlooptri[i];
- const int p_orig = rdata->mapped.p_origindex[mlt->poly];
- if (p_orig != ORIGINDEX_NONE) {
- /* Assume 'use_hide' */
- BMFace *efa = BM_face_at_index(bm, p_orig);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- GPU_indexbuf_add_tri_verts(
- &elb, loops[mlt->tri[0]].v, loops[mlt->tri[1]].v, loops[mlt->tri[2]].v);
- }
- }
- }
- }
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
-static void mesh_create_loops_lines(MeshRenderData *rdata, GPUIndexBuf *ibo, const bool use_hide)
-{
- const int edge_len = mesh_render_data_edges_len_get(rdata);
- const int loop_len = mesh_render_data_loops_len_get(rdata);
- const int poly_len = mesh_render_data_polys_len_get(rdata);
-
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, loop_len);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter;
- BMEdge *bm_edge;
-
- BM_ITER_MESH (bm_edge, &iter, bm, BM_EDGES_OF_MESH) {
- /* use_hide always for edit-mode */
- if (!BM_elem_flag_test(bm_edge, BM_ELEM_HIDDEN) && bm_edge->l != NULL) {
- BMLoop *bm_loop1 = bm_vert_find_first_loop_visible_inline(bm_edge->v1);
- BMLoop *bm_loop2 = bm_vert_find_first_loop_visible_inline(bm_edge->v2);
- int v1 = BM_elem_index_get(bm_loop1);
- int v2 = BM_elem_index_get(bm_loop2);
- if (v1 > v2) {
- SWAP(int, v1, v2);
- }
- GPU_indexbuf_add_line_verts(&elb, v1, v2);
- }
- }
- }
- else {
- MLoop *mloop = (MLoop *)rdata->mloop;
- MEdge *medge = (MEdge *)rdata->medge;
-
- /* Reset flag */
- for (int edge = 0; edge < edge_len; ++edge) {
- /* NOTE: not thread safe. */
- medge[edge].flag &= ~ME_EDGE_TMP_TAG;
- }
-
- for (int poly = 0; poly < poly_len; poly++) {
- const MPoly *mp = &rdata->mpoly[poly];
- if (!(use_hide && (mp->flag & ME_HIDE))) {
- for (int j = 0; j < mp->totloop; j++) {
- MEdge *ed = (MEdge *)rdata->medge + mloop[mp->loopstart + j].e;
- if ((ed->flag & ME_EDGE_TMP_TAG) == 0) {
- ed->flag |= ME_EDGE_TMP_TAG;
- int v1 = mp->loopstart + j;
- int v2 = mp->loopstart + (j + 1) % mp->totloop;
- GPU_indexbuf_add_line_verts(&elb, v1, v2);
- }
- }
- }
- }
- }
- }
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
-static void mesh_create_loops_lines_paint_mask(MeshRenderData *rdata, GPUIndexBuf *ibo)
-{
- const int loop_len = mesh_render_data_loops_len_get(rdata);
- const int poly_len = mesh_render_data_polys_len_get(rdata);
- const int edge_len = mesh_render_data_edges_len_get(rdata);
-
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init(&elb, GPU_PRIM_LINES, loop_len, loop_len);
-
- if (rdata->edit_bmesh) {
- /* painting does not use the edit_bmesh */
- BLI_assert(0);
- }
- else {
- if (rdata->me->editflag & ME_EDIT_PAINT_FACE_SEL) {
- /* Each edge has two bits used to count selected edges as 0, 1, 2+. */
- BLI_bitmap *edges_used = BLI_BITMAP_NEW(edge_len * 2, __func__);
-
- /* Fill the edge bitmap table. */
- for (int poly = 0; poly < poly_len; poly++) {
- const MPoly *mpoly = &rdata->mpoly[poly];
-
- /* Do not check faces that are hidden and faces that aren't selected */
- if (mpoly->flag & ME_HIDE || ((mpoly->flag & ME_FACE_SEL) == 0)) {
- continue;
- }
-
- for (int loop_index = mpoly->loopstart, loop_index_end = mpoly->loopstart + mpoly->totloop;
- loop_index < loop_index_end;
- loop_index++) {
- const MLoop *mloop = &rdata->mloop[loop_index];
- const int e_a = mloop->e * 2;
- const int e_b = e_a + 1;
- if (!BLI_BITMAP_TEST(edges_used, e_a)) {
- BLI_BITMAP_ENABLE(edges_used, e_a);
- }
- else {
- BLI_BITMAP_ENABLE(edges_used, e_b);
- }
- }
- }
-
- for (int poly = 0; poly < poly_len; poly++) {
- const MPoly *mpoly = &rdata->mpoly[poly];
- if (!(mpoly->flag & ME_HIDE)) {
-
- for (int loop_index_next = mpoly->loopstart,
- loop_index_end = mpoly->loopstart + mpoly->totloop,
- loop_index_curr = loop_index_end - 1;
- loop_index_next < loop_index_end;
- loop_index_curr = loop_index_next++) {
- const MLoop *mloop = &rdata->mloop[loop_index_curr];
- const int e_a = mloop->e * 2;
- const int e_b = e_a + 1;
-
- /* Draw if a boundary or entirely unselected. */
- if (!BLI_BITMAP_TEST(edges_used, e_b)) {
- GPU_indexbuf_add_line_verts(&elb, loop_index_curr, loop_index_next);
- }
- }
- }
- }
-
- MEM_freeN(edges_used);
- }
- else {
- /* Add edges. */
- for (int poly = 0; poly < poly_len; poly++) {
- const MPoly *mpoly = &rdata->mpoly[poly];
- for (int loop_index_next = mpoly->loopstart,
- loop_index_end = mpoly->loopstart + mpoly->totloop,
- loop_index_curr = loop_index_end - 1;
- loop_index_next < loop_index_end;
- loop_index_curr = loop_index_next++) {
- GPU_indexbuf_add_line_verts(&elb, loop_index_curr, loop_index_next);
- }
- }
- }
- }
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
-static void mesh_create_loops_line_strips(MeshRenderData *rdata,
- GPUIndexBuf *ibo,
- const bool use_hide)
-{
- const int loop_len = mesh_render_data_loops_len_get(rdata);
- const int poly_len = mesh_render_data_polys_len_get(rdata);
-
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, loop_len + poly_len * 2, loop_len);
-
- uint v_index = 0;
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter;
- BMFace *bm_face;
-
- BM_ITER_MESH (bm_face, &iter, bm, BM_FACES_OF_MESH) {
- /* use_hide always for edit-mode */
- if (!BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) {
- for (int i = 0; i < bm_face->len; i++) {
- GPU_indexbuf_add_generic_vert(&elb, v_index + i);
- }
- /* Finish loop and restart primitive. */
- GPU_indexbuf_add_generic_vert(&elb, v_index);
- GPU_indexbuf_add_primitive_restart(&elb);
- }
- v_index += bm_face->len;
- }
- }
- else {
- for (int poly = 0; poly < poly_len; poly++) {
- const MPoly *mp = &rdata->mpoly[poly];
- if (!(use_hide && (mp->flag & ME_HIDE))) {
- const int loopend = mp->loopstart + mp->totloop;
- for (int j = mp->loopstart; j < loopend; j++) {
- GPU_indexbuf_add_generic_vert(&elb, j);
- }
- /* Finish loop and restart primitive. */
- GPU_indexbuf_add_generic_vert(&elb, mp->loopstart);
- GPU_indexbuf_add_primitive_restart(&elb);
- }
- v_index += mp->totloop;
- }
- }
- }
- else {
- /* Implement ... eventually if needed. */
- BLI_assert(0);
- }
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
-static void mesh_create_loose_edges_lines(MeshRenderData *rdata,
- GPUIndexBuf *ibo,
- bool *r_no_loose_wire,
- const bool use_hide)
-{
- const int vert_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- const int edge_len = mesh_render_data_edges_len_get_maybe_mapped(rdata);
-
- /* Alloc max (edge_len) and upload only needed range. */
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- /* No need to support since edit mesh already draw them.
- * But some engines may want them ... */
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter eiter;
- BMEdge *eed;
- BM_ITER_MESH (eed, &eiter, bm, BM_EDGES_OF_MESH) {
- if (bm_edge_is_loose_and_visible(eed)) {
- GPU_indexbuf_add_line_verts(
- &elb, BM_elem_index_get(eed->v1), BM_elem_index_get(eed->v2));
- }
- }
- }
- else {
- for (int i = 0; i < edge_len; i++) {
- const MEdge *medge = &rdata->medge[i];
- if ((medge->flag & ME_LOOSEEDGE) && !(use_hide && (medge->flag & ME_HIDE))) {
- GPU_indexbuf_add_line_verts(&elb, medge->v1, medge->v2);
- }
- }
- }
- }
- else {
- /* Hidden checks are already done when creating the loose edge list. */
- Mesh *me_cage = rdata->mapped.me_cage;
- for (int i_iter = 0; i_iter < rdata->mapped.loose_edge_len; i_iter++) {
- const int i = rdata->mapped.loose_edges[i_iter];
- const MEdge *medge = &me_cage->medge[i];
- GPU_indexbuf_add_line_verts(&elb, medge->v1, medge->v2);
- }
- }
-
- *r_no_loose_wire = (elb.index_len == 0);
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
-static void mesh_create_loops_tris(MeshRenderData *rdata,
- GPUIndexBuf **ibo,
- int ibo_len,
- const bool use_hide)
-{
- const int loop_len = mesh_render_data_loops_len_get(rdata);
- const int tri_len = mesh_render_data_looptri_len_get(rdata);
-
- GPUIndexBufBuilder *elb = BLI_array_alloca(elb, ibo_len);
-
- for (int i = 0; i < ibo_len; ++i) {
- /* TODO alloc minmum necessary. */
- GPU_indexbuf_init(&elb[i], GPU_PRIM_TRIS, tri_len, loop_len * 3);
- }
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- for (int i = 0; i < tri_len; i++) {
- const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
- const BMFace *bm_face = bm_looptri[0]->f;
- /* use_hide always for edit-mode */
- if (BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) {
- continue;
- }
- int mat = min_ii(ibo_len - 1, bm_face->mat_nr);
- GPU_indexbuf_add_tri_verts(&elb[mat],
- BM_elem_index_get(bm_looptri[0]),
- BM_elem_index_get(bm_looptri[1]),
- BM_elem_index_get(bm_looptri[2]));
- }
- }
- else {
- for (int i = 0; i < tri_len; i++) {
- const MLoopTri *mlt = &rdata->mlooptri[i];
- const MPoly *mp = &rdata->mpoly[mlt->poly];
- if (use_hide && (mp->flag & ME_HIDE)) {
- continue;
- }
- int mat = min_ii(ibo_len - 1, mp->mat_nr);
- GPU_indexbuf_add_tri_verts(&elb[mat], mlt->tri[0], mlt->tri[1], mlt->tri[2]);
- }
- }
- }
- else {
- /* Note: mapped doesn't support lnors yet. */
- BMesh *bm = rdata->edit_bmesh->bm;
- Mesh *me_cage = rdata->mapped.me_cage;
-
- const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage);
- for (int i = 0; i < tri_len; i++) {
- const MLoopTri *mlt = &mlooptri[i];
- const int p_orig = rdata->mapped.p_origindex[mlt->poly];
- if (p_orig != ORIGINDEX_NONE) {
- /* Assume 'use_hide' */
- BMFace *efa = BM_face_at_index(bm, p_orig);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- int mat = min_ii(ibo_len - 1, efa->mat_nr);
- GPU_indexbuf_add_tri_verts(&elb[mat], mlt->tri[0], mlt->tri[1], mlt->tri[2]);
- }
- }
- }
- }
-
- for (int i = 0; i < ibo_len; ++i) {
- GPU_indexbuf_build_in_place(&elb[i], ibo[i]);
- }
-}
-
-/* Warning! this function is not thread safe!
- * It writes to MEdge->flag with ME_EDGE_TMP_TAG. */
-static void mesh_create_edit_loops_points_lines(MeshRenderData *rdata,
- GPUIndexBuf *ibo_verts,
- GPUIndexBuf *ibo_edges)
-{
- BMIter iter;
- int i;
-
- const int vert_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- const int edge_len = mesh_render_data_edges_len_get_maybe_mapped(rdata);
- const int loop_len = mesh_render_data_loops_len_get_maybe_mapped(rdata);
- const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata);
- const int lvert_len = mesh_render_data_loose_verts_len_get_maybe_mapped(rdata);
- const int ledge_len = mesh_render_data_loose_edges_len_get_maybe_mapped(rdata);
- const int tot_loop_len = loop_len + ledge_len * 2 + lvert_len;
-
- GPUIndexBufBuilder elb_vert, elb_edge;
- if (DRW_TEST_ASSIGN_IBO(ibo_edges)) {
- GPU_indexbuf_init(&elb_edge, GPU_PRIM_LINES, edge_len, tot_loop_len);
- }
- if (DRW_TEST_ASSIGN_IBO(ibo_verts)) {
- GPU_indexbuf_init(&elb_vert, GPU_PRIM_POINTS, tot_loop_len, tot_loop_len);
- }
-
- int loop_idx = 0;
- if (rdata->edit_bmesh && (rdata->mapped.use == false)) {
- BMesh *bm = rdata->edit_bmesh->bm;
- /* Edges not loose. */
- if (ibo_edges) {
- BMEdge *eed;
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- BMLoop *l = bm_edge_find_first_loop_visible_inline(eed);
- if (l != NULL) {
- int v1 = BM_elem_index_get(eed->l);
- int v2 = BM_elem_index_get(eed->l->next);
- GPU_indexbuf_add_line_verts(&elb_edge, v1, v2);
- }
- }
- }
- }
- /* Face Loops */
- if (ibo_verts) {
- BMVert *eve;
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- BMLoop *l = bm_vert_find_first_loop_visible_inline(eve);
- if (l != NULL) {
- int v = BM_elem_index_get(l);
- GPU_indexbuf_add_generic_vert(&elb_vert, v);
- }
- }
- }
- }
- loop_idx = loop_len;
- /* Loose edges */
- for (i = 0; i < ledge_len; ++i) {
- if (ibo_verts) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + 0);
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + 1);
- }
- if (ibo_edges) {
- GPU_indexbuf_add_line_verts(&elb_edge, loop_idx + 0, loop_idx + 1);
- }
- loop_idx += 2;
- }
- /* Loose verts */
- if (ibo_verts) {
- for (i = 0; i < lvert_len; ++i) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx);
- loop_idx += 1;
- }
- }
- }
- else if (rdata->mapped.use) {
- const MPoly *mpoly = rdata->mapped.me_cage->mpoly;
- MVert *mvert = rdata->mapped.me_cage->mvert;
- MEdge *medge = rdata->mapped.me_cage->medge;
- BMesh *bm = rdata->edit_bmesh->bm;
-
- const int *v_origindex = rdata->mapped.v_origindex;
- const int *e_origindex = rdata->mapped.e_origindex;
- const int *p_origindex = rdata->mapped.p_origindex;
-
- /* Reset flag */
- for (int edge = 0; edge < edge_len; ++edge) {
- /* NOTE: not thread safe. */
- medge[edge].flag &= ~ME_EDGE_TMP_TAG;
- }
- for (int vert = 0; vert < vert_len; ++vert) {
- /* NOTE: not thread safe. */
- mvert[vert].flag &= ~ME_VERT_TMP_TAG;
- }
-
- /* Face Loops */
- for (int poly = 0; poly < poly_len; poly++, mpoly++) {
- int fidx = p_origindex[poly];
- if (fidx != ORIGINDEX_NONE) {
- BMFace *efa = BM_face_at_index(bm, fidx);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- const MLoop *mloop = &rdata->mapped.me_cage->mloop[mpoly->loopstart];
- for (i = 0; i < mpoly->totloop; ++i, ++mloop) {
- if (ibo_verts && (v_origindex[mloop->v] != ORIGINDEX_NONE) &&
- (mvert[mloop->v].flag & ME_VERT_TMP_TAG) == 0) {
- mvert[mloop->v].flag |= ME_VERT_TMP_TAG;
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + i);
- }
- if (ibo_edges && (e_origindex[mloop->e] != ORIGINDEX_NONE) &&
- ((medge[mloop->e].flag & ME_EDGE_TMP_TAG) == 0)) {
- medge[mloop->e].flag |= ME_EDGE_TMP_TAG;
- int v1 = loop_idx + i;
- int v2 = loop_idx + ((i + 1) % mpoly->totloop);
- GPU_indexbuf_add_line_verts(&elb_edge, v1, v2);
- }
- }
- }
- }
- loop_idx += mpoly->totloop;
- }
- /* Loose edges */
- for (i = 0; i < ledge_len; ++i) {
- int eidx = e_origindex[rdata->mapped.loose_edges[i]];
- if (eidx != ORIGINDEX_NONE) {
- if (ibo_verts) {
- const MEdge *ed = &medge[rdata->mapped.loose_edges[i]];
- if (v_origindex[ed->v1] != ORIGINDEX_NONE) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + 0);
- }
- if (v_origindex[ed->v2] != ORIGINDEX_NONE) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + 1);
- }
- }
- if (ibo_edges) {
- GPU_indexbuf_add_line_verts(&elb_edge, loop_idx + 0, loop_idx + 1);
- }
- }
- loop_idx += 2;
- }
- /* Loose verts */
- if (ibo_verts) {
- for (i = 0; i < lvert_len; ++i) {
- int vidx = v_origindex[rdata->mapped.loose_verts[i]];
- if (vidx != ORIGINDEX_NONE) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx);
- }
- loop_idx += 1;
- }
- }
- }
- else {
- const MPoly *mpoly = rdata->mpoly;
-
- /* Face Loops */
- for (int poly = 0; poly < poly_len; poly++, mpoly++) {
- if ((mpoly->flag & ME_HIDE) == 0) {
- for (i = 0; i < mpoly->totloop; ++i) {
- if (ibo_verts) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + i);
- }
- if (ibo_edges) {
- int v1 = loop_idx + i;
- int v2 = loop_idx + ((i + 1) % mpoly->totloop);
- GPU_indexbuf_add_line_verts(&elb_edge, v1, v2);
- }
- }
- }
- loop_idx += mpoly->totloop;
- }
- /* TODO(fclem): Until we find a way to detect
- * loose verts easily outside of edit mode, this
- * will remain disabled. */
-#if 0
- /* Loose edges */
- for (int e = 0; e < edge_len; e++, medge++) {
- if (medge->flag & ME_LOOSEEDGE) {
- int eidx = e_origindex[e];
- if (eidx != ORIGINDEX_NONE) {
- if ((medge->flag & ME_HIDE) == 0) {
- for (int j = 0; j < 2; ++j) {
- if (ibo_verts) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + j);
- }
- if (ibo_edges) {
- GPU_indexbuf_add_generic_vert(&elb_edge, loop_idx + j);
- }
- }
- }
- }
- loop_idx += 2;
- }
- }
- /* Loose verts */
- for (int v = 0; v < vert_len; v++, mvert++) {
- int vidx = v_origindex[v];
- if (vidx != ORIGINDEX_NONE) {
- if ((mvert->flag & ME_HIDE) == 0) {
- if (ibo_verts) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx);
- }
- if (ibo_edges) {
- GPU_indexbuf_add_generic_vert(&elb_edge, loop_idx);
- }
- }
- loop_idx += 1;
- }
- }
-#endif
- }
-
- if (ibo_verts) {
- GPU_indexbuf_build_in_place(&elb_vert, ibo_verts);
- }
- if (ibo_edges) {
- GPU_indexbuf_build_in_place(&elb_edge, ibo_edges);
- }
-}
-
-static void mesh_create_edit_loops_tris(MeshRenderData *rdata, GPUIndexBuf *ibo)
-{
- const int loop_len = mesh_render_data_loops_len_get_maybe_mapped(rdata);
- const int tri_len = mesh_render_data_looptri_len_get_maybe_mapped(rdata);
-
- GPUIndexBufBuilder elb;
- /* TODO alloc minmum necessary. */
- GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, loop_len * 3);
-
- if (rdata->edit_bmesh && (rdata->mapped.use == false)) {
- for (int i = 0; i < tri_len; i++) {
- const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
- const BMFace *bm_face = bm_looptri[0]->f;
- /* use_hide always for edit-mode */
- if (BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) {
- continue;
- }
- GPU_indexbuf_add_tri_verts(&elb,
- BM_elem_index_get(bm_looptri[0]),
- BM_elem_index_get(bm_looptri[1]),
- BM_elem_index_get(bm_looptri[2]));
- }
- }
- else if (rdata->mapped.use == true) {
- BMesh *bm = rdata->edit_bmesh->bm;
- Mesh *me_cage = rdata->mapped.me_cage;
-
- const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage);
- for (int i = 0; i < tri_len; i++) {
- const MLoopTri *mlt = &mlooptri[i];
- const int p_orig = rdata->mapped.p_origindex[mlt->poly];
- if (p_orig != ORIGINDEX_NONE) {
- /* Assume 'use_hide' */
- BMFace *efa = BM_face_at_index(bm, p_orig);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- GPU_indexbuf_add_tri_verts(&elb, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
- }
- }
- }
- }
- else {
- const MLoopTri *mlt = rdata->mlooptri;
- for (int i = 0; i < tri_len; i++, mlt++) {
- const MPoly *mpoly = &rdata->mpoly[mlt->poly];
- /* Assume 'use_hide' */
- if ((mpoly->flag & ME_HIDE) == 0) {
- GPU_indexbuf_add_tri_verts(&elb, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
- }
- }
- }
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
/** \} */
/* ---------------------------------------------------------------------- */
@@ -4563,9 +748,9 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
*auto_layer_count = cache->auto_layer_len;
}
for (int i = 0; i < cache->mat_len; ++i) {
- DRW_batch_request(&cache->surf_per_mat[i]);
+ DRW_batch_request(&cache->surface_per_mat[i]);
}
- return cache->surf_per_mat;
+ return cache->surface_per_mat;
}
GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me)
@@ -4574,9 +759,9 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me)
mesh_batch_cache_add_request(cache, MBC_SURF_PER_MAT);
texpaint_request_active_uv(cache, me);
for (int i = 0; i < cache->mat_len; ++i) {
- DRW_batch_request(&cache->surf_per_mat[i]);
+ DRW_batch_request(&cache->surface_per_mat[i]);
}
- return cache->surf_per_mat;
+ return cache->surface_per_mat;
}
GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Mesh *me)
@@ -4622,6 +807,13 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(Mesh *me)
return DRW_batch_request(&cache->batch.edit_vertices);
}
+GPUBatch *DRW_mesh_batch_cache_get_edit_vnors(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+ mesh_batch_cache_add_request(cache, MBC_EDIT_VNOR);
+ return DRW_batch_request(&cache->batch.edit_vnor);
+}
+
GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
@@ -4633,7 +825,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
mesh_batch_cache_add_request(cache, MBC_EDIT_FACEDOTS);
- return DRW_batch_request(&cache->batch.edit_facedots);
+ return DRW_batch_request(&cache->batch.edit_fdots);
}
/** \} */
@@ -4653,7 +845,7 @@ GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_FACEDOTS);
- return DRW_batch_request(&cache->batch.edit_selection_facedots);
+ return DRW_batch_request(&cache->batch.edit_selection_fdots);
}
GPUBatch *DRW_mesh_batch_cache_get_edges_with_select_id(Mesh *me)
@@ -4679,6 +871,7 @@ GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_area(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ texpaint_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRECH_AREA);
return DRW_batch_request(&cache->batch.edituv_faces_strech_area);
}
@@ -4686,6 +879,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_area(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_angle(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ texpaint_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRECH_ANGLE);
return DRW_batch_request(&cache->batch.edituv_faces_strech_angle);
}
@@ -4693,6 +887,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_angle(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ texpaint_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES);
return DRW_batch_request(&cache->batch.edituv_faces);
}
@@ -4700,6 +895,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ texpaint_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_EDGES);
return DRW_batch_request(&cache->batch.edituv_edges);
}
@@ -4707,6 +903,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ texpaint_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_VERTS);
return DRW_batch_request(&cache->batch.edituv_verts);
}
@@ -4714,8 +911,9 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ texpaint_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACEDOTS);
- return DRW_batch_request(&cache->batch.edituv_facedots);
+ return DRW_batch_request(&cache->batch.edituv_fdots);
}
GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Mesh *me)
@@ -4729,356 +927,11 @@ GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ texpaint_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS);
return DRW_batch_request(&cache->batch.wire_loops);
}
-/* Compute 3D & 2D areas and their sum. */
-BLI_INLINE void edit_uv_preprocess_stretch_area(BMFace *efa,
- const int cd_loop_uv_offset,
- uint fidx,
- float *totarea,
- float *totuvarea,
- float (*faces_areas)[2])
-{
- faces_areas[fidx][0] = BM_face_calc_area(efa);
- faces_areas[fidx][1] = BM_face_calc_area_uv(efa, cd_loop_uv_offset);
-
- *totarea += faces_areas[fidx][0];
- *totuvarea += faces_areas[fidx][1];
-}
-
-BLI_INLINE float edit_uv_get_stretch_area(float area, float uvarea)
-{
- if (area < FLT_EPSILON || uvarea < FLT_EPSILON) {
- return 1.0f;
- }
- else if (area > uvarea) {
- return 1.0f - (uvarea / area);
- }
- else {
- return 1.0f - (area / uvarea);
- }
-}
-
-/* Compute face's normalized contour vectors. */
-BLI_INLINE void edit_uv_preprocess_stretch_angle(float (*auv)[2],
- float (*av)[3],
- const int cd_loop_uv_offset,
- BMFace *efa)
-{
- BMLoop *l;
- BMIter liter;
- int i;
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
-
- sub_v2_v2v2(auv[i], luv_prev->uv, luv->uv);
- normalize_v2(auv[i]);
-
- sub_v3_v3v3(av[i], l->prev->v->co, l->v->co);
- normalize_v3(av[i]);
- }
-}
-
-#if 0 /* here for reference, this is done in shader now. */
-BLI_INLINE float edit_uv_get_loop_stretch_angle(const float auv0[2],
- const float auv1[2],
- const float av0[3],
- const float av1[3])
-{
- float uvang = angle_normalized_v2v2(auv0, auv1);
- float ang = angle_normalized_v3v3(av0, av1);
- float stretch = fabsf(uvang - ang) / (float)M_PI;
- return 1.0f - pow2f(1.0f - stretch);
-}
-#endif
-
-static struct EditUVFormatIndex {
- uint area, angle, uv_adj, flag, fdots_uvs, fdots_flag;
-} uv_attr_id = {0};
-
-static void uvedit_fill_buffer_data(MeshRenderData *rdata,
- GPUVertBuf *vbo_area,
- GPUVertBuf *vbo_angle,
- GPUVertBuf *vbo_fdots_pos,
- GPUVertBuf *vbo_fdots_data,
- GPUIndexBufBuilder *elb_vert,
- GPUIndexBufBuilder *elb_edge,
- GPUIndexBufBuilder *elb_face)
-{
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter, liter;
- BMFace *efa;
- uint vidx, fidx, fdot_idx, i;
- const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata);
- float(*faces_areas)[2] = NULL;
- float totarea = 0.0f, totuvarea = 0.0f;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- BLI_buffer_declare_static(vec3f, vec3_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_buffer_declare_static(vec2f, vec2_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
-
- if (vbo_area) {
- faces_areas = MEM_mallocN(sizeof(float) * 2 * bm->totface, "EDITUV faces areas");
- }
-
- /* Preprocess */
- fidx = 0;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- /* Tag hidden faces */
- BM_elem_flag_set(efa, BM_ELEM_TAG, uvedit_face_visible_nolocal_ex(rdata->toolsettings, efa));
-
- if (vbo_area) {
- edit_uv_preprocess_stretch_area(
- efa, cd_loop_uv_offset, fidx++, &totarea, &totuvarea, faces_areas);
- }
- }
-
- vidx = 0;
- fidx = 0;
- fdot_idx = 0;
- if (rdata->mapped.use == false && rdata->edit_bmesh) {
- BMLoop *l;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- const bool face_visible = BM_elem_flag_test(efa, BM_ELEM_TAG);
- const int efa_len = efa->len;
- float fdot[2] = {0.0f, 0.0f};
- float(*av)[3], (*auv)[2];
- ushort area_stretch;
-
- /* Face preprocess */
- if (vbo_area) {
- area_stretch = edit_uv_get_stretch_area(faces_areas[fidx][0] / totarea,
- faces_areas[fidx][1] / totuvarea) *
- 65534.0f;
- }
- if (vbo_angle) {
- av = (float(*)[3])BLI_buffer_reinit_data(&vec3_buf, vec3f, efa_len);
- auv = (float(*)[2])BLI_buffer_reinit_data(&vec2_buf, vec2f, efa_len);
- edit_uv_preprocess_stretch_angle(auv, av, cd_loop_uv_offset, efa);
- }
-
- /* Skip hidden faces. */
- if (face_visible) {
- if (elb_face) {
- for (i = 0; i < efa->len; ++i) {
- GPU_indexbuf_add_generic_vert(elb_face, vidx + i);
- }
- }
- if (elb_vert) {
- for (i = 0; i < efa->len; ++i) {
- GPU_indexbuf_add_generic_vert(elb_vert, vidx + i);
- }
- }
- if (elb_edge) {
- for (i = 0; i < efa->len; ++i) {
- GPU_indexbuf_add_line_verts(elb_edge, vidx + i, vidx + (i + 1) % efa->len);
- }
- }
- }
-
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (vbo_area) {
- GPU_vertbuf_attr_set(vbo_area, uv_attr_id.area, vidx, &area_stretch);
- }
- if (vbo_angle) {
- int i_next = (i + 1) % efa_len;
- short suv[4];
- /* Send uvs to the shader and let it compute the aspect corrected angle. */
- normal_float_to_short_v2(&suv[0], auv[i]);
- normal_float_to_short_v2(&suv[2], auv[i_next]);
- GPU_vertbuf_attr_set(vbo_angle, uv_attr_id.uv_adj, vidx, suv);
- /* Compute 3D angle here */
- short angle = 32767.0f * angle_normalized_v3v3(av[i], av[i_next]) / (float)M_PI;
- GPU_vertbuf_attr_set(vbo_angle, uv_attr_id.angle, vidx, &angle);
- }
- if (vbo_fdots_pos) {
- add_v2_v2(fdot, luv->uv);
- }
- vidx++;
- }
-
- if (elb_face && face_visible) {
- GPU_indexbuf_add_generic_vert(elb_face, vidx - efa->len);
- GPU_indexbuf_add_primitive_restart(elb_face);
- }
- if (vbo_fdots_pos && face_visible) {
- mul_v2_fl(fdot, 1.0f / (float)efa->len);
- GPU_vertbuf_attr_set(vbo_fdots_pos, uv_attr_id.fdots_uvs, fdot_idx, fdot);
- }
- if (vbo_fdots_data && face_visible) {
- uchar face_flag = mesh_render_data_face_flag(rdata, efa, cd_loop_uv_offset);
- GPU_vertbuf_attr_set(vbo_fdots_data, uv_attr_id.fdots_flag, fdot_idx, &face_flag);
- }
- fdot_idx += face_visible ? 1 : 0;
- fidx++;
- }
- }
- else {
- const MPoly *mpoly = rdata->mapped.me_cage->mpoly;
- // const MEdge *medge = rdata->mapped.me_cage->medge;
- // const MVert *mvert = rdata->mapped.me_cage->mvert;
- const MLoop *mloop = rdata->mapped.me_cage->mloop;
-
- const int *v_origindex = rdata->mapped.v_origindex;
- const int *e_origindex = rdata->mapped.e_origindex;
- const int *p_origindex = rdata->mapped.p_origindex;
-
- /* Face Loops */
- for (int poly = 0; poly < poly_len; poly++, mpoly++) {
- float fdot[2] = {0.0f, 0.0f};
- const MLoop *l = &mloop[mpoly->loopstart];
- int fidx_ori = p_origindex[poly];
- efa = (fidx_ori != ORIGINDEX_NONE) ? BM_face_at_index(bm, fidx_ori) : NULL;
- const bool face_visible = efa != NULL && BM_elem_flag_test(efa, BM_ELEM_TAG);
- if (efa && vbo_fdots_data) {
- uchar face_flag = mesh_render_data_face_flag(rdata, efa, cd_loop_uv_offset);
- GPU_vertbuf_attr_set(vbo_fdots_data, uv_attr_id.fdots_flag, fdot_idx, &face_flag);
- }
- /* Skip hidden faces. */
- if (face_visible) {
- if (elb_face) {
- for (i = 0; i < mpoly->totloop; ++i) {
- GPU_indexbuf_add_generic_vert(elb_face, vidx + i);
- }
- GPU_indexbuf_add_generic_vert(elb_face, vidx);
- GPU_indexbuf_add_primitive_restart(elb_face);
- }
- if (elb_edge) {
- for (i = 0; i < mpoly->totloop; ++i) {
- if (e_origindex[l[i].e] != ORIGINDEX_NONE) {
- GPU_indexbuf_add_line_verts(elb_edge, vidx + i, vidx + (i + 1) % mpoly->totloop);
- }
- }
- }
- if (elb_vert) {
- for (i = 0; i < mpoly->totloop; ++i) {
- if (v_origindex[l[i].v] != ORIGINDEX_NONE) {
- GPU_indexbuf_add_generic_vert(elb_vert, vidx + i);
- }
- }
- }
- }
- for (i = 0; i < mpoly->totloop; i++, l++) {
- /* TODO support stretch. */
- if (vbo_fdots_pos) {
- MLoopUV *luv = &rdata->mloopuv[mpoly->loopstart + i];
- add_v2_v2(fdot, luv->uv);
- }
- vidx++;
- }
- if (vbo_fdots_pos && face_visible) {
- mul_v2_fl(fdot, 1.0f / mpoly->totloop);
- GPU_vertbuf_attr_set(vbo_fdots_pos, uv_attr_id.fdots_uvs, fdot_idx, fdot);
- }
- fidx++;
- fdot_idx += face_visible ? 1 : 0;
- }
- }
-
- if (faces_areas) {
- MEM_freeN(faces_areas);
- }
-
- BLI_buffer_free(&vec3_buf);
- BLI_buffer_free(&vec2_buf);
-
- if (fdot_idx < poly_len) {
- if (vbo_fdots_pos) {
- GPU_vertbuf_data_resize(vbo_fdots_pos, fdot_idx);
- }
- if (vbo_fdots_data) {
- GPU_vertbuf_data_resize(vbo_fdots_data, fdot_idx);
- }
- }
-}
-
-static void mesh_create_uvedit_buffers(MeshRenderData *rdata,
- GPUVertBuf *vbo_area,
- GPUVertBuf *vbo_angle,
- GPUVertBuf *vbo_fdots_pos,
- GPUVertBuf *vbo_fdots_data,
- GPUIndexBuf *ibo_vert,
- GPUIndexBuf *ibo_edge,
- GPUIndexBuf *ibo_face)
-{
- static GPUVertFormat format_area = {0};
- static GPUVertFormat format_angle = {0};
- static GPUVertFormat format_fdots_pos = {0};
- static GPUVertFormat format_fdots_flag = {0};
-
- if (format_area.attr_len == 0) {
- uv_attr_id.area = GPU_vertformat_attr_add(
- &format_area, "stretch", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
- uv_attr_id.angle = GPU_vertformat_attr_add(
- &format_angle, "angle", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
- uv_attr_id.uv_adj = GPU_vertformat_attr_add(
- &format_angle, "uv_adj", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
-
- uv_attr_id.fdots_flag = GPU_vertformat_attr_add(
- &format_fdots_flag, "flag", GPU_COMP_U8, 1, GPU_FETCH_INT);
- uv_attr_id.fdots_uvs = GPU_vertformat_attr_add(
- &format_fdots_pos, "u", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- GPU_vertformat_alias_add(&format_fdots_pos, "pos");
- }
-
- const int loop_len = mesh_render_data_loops_len_get_maybe_mapped(rdata);
- const int face_len = mesh_render_data_polys_len_get_maybe_mapped(rdata);
- const int idx_len = loop_len + face_len * 2;
-
- if (DRW_TEST_ASSIGN_VBO(vbo_area)) {
- GPU_vertbuf_init_with_format(vbo_area, &format_area);
- GPU_vertbuf_data_alloc(vbo_area, loop_len);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_angle)) {
- GPU_vertbuf_init_with_format(vbo_angle, &format_angle);
- GPU_vertbuf_data_alloc(vbo_angle, loop_len);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_fdots_pos)) {
- GPU_vertbuf_init_with_format(vbo_fdots_pos, &format_fdots_pos);
- GPU_vertbuf_data_alloc(vbo_fdots_pos, face_len);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_fdots_data)) {
- GPU_vertbuf_init_with_format(vbo_fdots_data, &format_fdots_flag);
- GPU_vertbuf_data_alloc(vbo_fdots_data, face_len);
- }
-
- GPUIndexBufBuilder elb_vert, elb_edge, elb_face;
- if (DRW_TEST_ASSIGN_IBO(ibo_vert)) {
- GPU_indexbuf_init_ex(&elb_vert, GPU_PRIM_POINTS, loop_len, loop_len);
- }
- if (DRW_TEST_ASSIGN_IBO(ibo_edge)) {
- GPU_indexbuf_init_ex(&elb_edge, GPU_PRIM_LINES, loop_len * 2, loop_len);
- }
- if (DRW_TEST_ASSIGN_IBO(ibo_face)) {
- GPU_indexbuf_init_ex(&elb_face, GPU_PRIM_TRI_FAN, idx_len, loop_len);
- }
-
- uvedit_fill_buffer_data(rdata,
- vbo_area,
- vbo_angle,
- vbo_fdots_pos,
- vbo_fdots_data,
- ibo_vert ? &elb_vert : NULL,
- ibo_edge ? &elb_edge : NULL,
- ibo_face ? &elb_face : NULL);
-
- if (ibo_vert) {
- GPU_indexbuf_build_in_place(&elb_vert, ibo_vert);
- }
-
- if (ibo_edge) {
- GPU_indexbuf_build_in_place(&elb_edge, ibo_edge);
- }
-
- if (ibo_face) {
- GPU_indexbuf_build_in_place(&elb_face, ibo_face);
- }
-}
-
/** \} */
/* ---------------------------------------------------------------------- */
@@ -5109,8 +962,9 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
/* Can be called for any surface type. Mesh *me is the final mesh. */
void DRW_mesh_batch_cache_create_requested(
- Object *ob, Mesh *me, const ToolSettings *ts, const bool is_paint_mode, const bool use_hide)
+ Object *ob, Mesh *me, const Scene *scene, const bool is_paint_mode, const bool use_hide)
{
+ const ToolSettings *ts = scene->toolsettings;
MeshBatchCache *cache = mesh_batch_cache_get(me);
/* Early out */
@@ -5136,15 +990,13 @@ void DRW_mesh_batch_cache_create_requested(
}
}
- if (batch_requested & (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS)) {
+ if (batch_requested &
+ (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRECH_AREA |
+ MBC_EDITUV_FACES_STRECH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) {
/* Modifiers will only generate an orco layer if the mesh is deformed. */
if (cache->cd_needed.orco != 0) {
- if (CustomData_get_layer(&me->vdata, CD_ORCO) != NULL) {
- /* Orco layer is needed. */
- }
- else if (cache->cd_needed.tan_orco == 0) {
- /* Skip orco calculation if not needed by tangent generation.
- */
+ if (CustomData_get_layer(&me->vdata, CD_ORCO) == NULL) {
+ /* Skip orco calculation */
cache->cd_needed.orco = 0;
}
}
@@ -5155,21 +1007,24 @@ void DRW_mesh_batch_cache_create_requested(
* material. */
bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed);
if (cd_overlap == false) {
- if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv ||
- (cache->cd_used.tan & cache->cd_needed.tan) != cache->cd_needed.tan ||
- cache->cd_used.tan_orco != cache->cd_needed.tan_orco) {
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_uv_tan);
- }
- if (cache->cd_used.orco != cache->cd_needed.orco) {
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_orco);
- }
- if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) {
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_vcol);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache)
+ {
+ if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv ||
+ (cache->cd_used.tan & cache->cd_needed.tan) != cache->cd_needed.tan ||
+ cache->cd_used.tan_orco != cache->cd_needed.tan_orco) {
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.uv_tan);
+ }
+ if (cache->cd_used.orco != cache->cd_needed.orco) {
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.orco);
+ }
+ if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) {
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.vcol);
+ }
}
/* We can't discard batches at this point as they have been
* referenced for drawing. Just clear them in place. */
for (int i = 0; i < cache->mat_len; ++i) {
- GPU_BATCH_CLEAR_SAFE(cache->surf_per_mat[i]);
+ GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]);
}
GPU_BATCH_CLEAR_SAFE(cache->batch.surface);
cache->batch_ready &= ~(MBC_SURFACE | MBC_SURF_PER_MAT);
@@ -5186,22 +1041,26 @@ void DRW_mesh_batch_cache_create_requested(
const bool is_uvsyncsel = (ts->uv_flag & UV_SYNC_SELECTION);
if (cache->is_uvsyncsel != is_uvsyncsel) {
cache->is_uvsyncsel = is_uvsyncsel;
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv_data);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_stretch_angle);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_stretch_area);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_uv);
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_tri_fans);
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_line_strips);
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_points);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.edituv_data);
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.stretch_angle);
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.stretch_area);
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.uv_tan);
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.fdots_uv);
+ GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_tris);
+ GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_lines);
+ GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_points);
+ }
/* We only clear the batches as they may already have been
* referenced. */
+ GPU_BATCH_CLEAR_SAFE(cache->batch.wire_loops_uvs);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_strech_area);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_strech_angle);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_edges);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_verts);
- GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_facedots);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_fdots);
cache->batch_ready &= ~MBC_EDITUV;
}
}
@@ -5217,410 +1076,224 @@ void DRW_mesh_batch_cache_create_requested(
cache->batch_ready |= batch_requested;
+ const bool do_cage = (me->edit_mesh &&
+ (me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage));
+
+ const bool do_uvcage = me->edit_mesh && !me->edit_mesh->mesh_eval_final->runtime.is_original;
+
+ MeshBufferCache *mbufcache = &cache->final;
+
/* Init batches and request VBOs & IBOs */
if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.surface, &cache->ibo.loops_tris);
- DRW_vbo_request(cache->batch.surface, &cache->ordered.loop_pos_nor);
- /* For paint overlay. Active layer should have been queried. */
+ DRW_ibo_request(cache->batch.surface, &mbufcache->ibo.tris);
+ /* Order matters. First ones override latest vbos' attribs. */
+ DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.lnor);
+ DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.pos_nor);
if (cache->cd_used.uv != 0) {
- DRW_vbo_request(cache->batch.surface, &cache->ordered.loop_uv_tan);
+ DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.uv_tan);
}
if (cache->cd_used.vcol != 0) {
- DRW_vbo_request(cache->batch.surface, &cache->ordered.loop_vcol);
+ DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.vcol);
}
}
if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) {
- DRW_vbo_request(cache->batch.all_verts, &cache->ordered.pos_nor);
+ DRW_vbo_request(cache->batch.all_verts, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.all_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.all_edges, &cache->ibo.edges_lines);
- DRW_vbo_request(cache->batch.all_edges, &cache->ordered.pos_nor);
+ DRW_ibo_request(cache->batch.all_edges, &mbufcache->ibo.lines);
+ DRW_vbo_request(cache->batch.all_edges, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.loose_edges, &cache->ibo.loose_edges_lines);
- DRW_vbo_request(cache->batch.loose_edges, &cache->ordered.pos_nor);
+ DRW_ibo_request(cache->batch.loose_edges, &mbufcache->ibo.lines);
+ DRW_vbo_request(cache->batch.loose_edges, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) {
- DRW_ibo_request(cache->batch.edge_detection, &cache->ibo.edges_adj_lines);
- DRW_vbo_request(cache->batch.edge_detection, &cache->ordered.pos_nor);
+ DRW_ibo_request(cache->batch.edge_detection, &mbufcache->ibo.lines_adjacency);
+ DRW_vbo_request(cache->batch.edge_detection, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.surface_weights, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.surface_weights, &cache->ibo.surf_tris);
- DRW_vbo_request(cache->batch.surface_weights, &cache->ordered.pos_nor);
- DRW_vbo_request(cache->batch.surface_weights, &cache->ordered.weights);
+ DRW_ibo_request(cache->batch.surface_weights, &mbufcache->ibo.tris);
+ DRW_vbo_request(cache->batch.surface_weights, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.surface_weights, &mbufcache->vbo.weights);
}
if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.wire_loops, &cache->ibo.loops_lines_paint_mask);
- DRW_vbo_request(cache->batch.wire_loops, &cache->ordered.loop_pos_nor);
+ DRW_ibo_request(cache->batch.wire_loops, &mbufcache->ibo.lines_paint_mask);
+ DRW_vbo_request(cache->batch.wire_loops, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.wire_edges, &cache->ibo.loops_lines);
- DRW_vbo_request(cache->batch.wire_edges, &cache->ordered.loop_pos_nor);
- DRW_vbo_request(cache->batch.wire_edges, &cache->ordered.loop_edge_fac);
+ DRW_ibo_request(cache->batch.wire_edges, &mbufcache->ibo.lines);
+ DRW_vbo_request(cache->batch.wire_edges, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.wire_edges, &mbufcache->vbo.edge_fac);
}
- if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINE_STRIP)) {
- DRW_ibo_request(cache->batch.wire_loops_uvs, &cache->ibo.loops_line_strips);
+ if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINES)) {
+ DRW_ibo_request(cache->batch.wire_loops_uvs, &mbufcache->ibo.edituv_lines);
/* For paint overlay. Active layer should have been queried. */
if (cache->cd_used.uv != 0) {
- DRW_vbo_request(cache->batch.wire_loops_uvs, &cache->ordered.loop_uv_tan);
+ DRW_vbo_request(cache->batch.wire_loops_uvs, &mbufcache->vbo.uv_tan);
}
}
-
- /* Edit Mesh */
- if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.edit_triangles, &cache->ibo.edit_loops_tris);
- DRW_vbo_request(cache->batch.edit_triangles, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_triangles, &cache->edit.loop_data);
- }
- if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) {
- DRW_ibo_request(cache->batch.edit_vertices, &cache->ibo.edit_loops_points);
- DRW_vbo_request(cache->batch.edit_vertices, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_vertices, &cache->edit.loop_data);
- }
- if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.edit_edges, &cache->ibo.edit_loops_lines);
- DRW_vbo_request(cache->batch.edit_edges, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_edges, &cache->edit.loop_data);
- }
- if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) {
- DRW_ibo_request(cache->batch.edit_lnor, &cache->ibo.edit_loops_tris);
- DRW_vbo_request(cache->batch.edit_lnor, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_lnor, &cache->edit.loop_lnor);
- }
- if (DRW_batch_requested(cache->batch.edit_facedots, GPU_PRIM_POINTS)) {
- DRW_vbo_request(cache->batch.edit_facedots, &cache->edit.facedots_pos_nor_data);
- }
-
- /* Mesh Analysis */
if (DRW_batch_requested(cache->batch.edit_mesh_analysis, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.edit_mesh_analysis, &cache->ibo.edit_loops_tris);
- DRW_vbo_request(cache->batch.edit_mesh_analysis, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_mesh_analysis, &cache->edit.loop_mesh_analysis);
- }
-
- /* Edit UV */
- if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRI_FAN)) {
- DRW_ibo_request(cache->batch.edituv_faces, &cache->ibo.edituv_loops_tri_fans);
- DRW_vbo_request(cache->batch.edituv_faces, &cache->edit.loop_uv);
- DRW_vbo_request(cache->batch.edituv_faces, &cache->edit.loop_uv_data);
- }
- if (DRW_batch_requested(cache->batch.edituv_faces_strech_area, GPU_PRIM_TRI_FAN)) {
- DRW_ibo_request(cache->batch.edituv_faces_strech_area, &cache->ibo.edituv_loops_tri_fans);
- DRW_vbo_request(cache->batch.edituv_faces_strech_area, &cache->edit.loop_uv);
- DRW_vbo_request(cache->batch.edituv_faces_strech_area, &cache->edit.loop_uv_data);
- DRW_vbo_request(cache->batch.edituv_faces_strech_area, &cache->edit.loop_stretch_area);
- }
- if (DRW_batch_requested(cache->batch.edituv_faces_strech_angle, GPU_PRIM_TRI_FAN)) {
- DRW_ibo_request(cache->batch.edituv_faces_strech_angle, &cache->ibo.edituv_loops_tri_fans);
- DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &cache->edit.loop_uv);
- DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &cache->edit.loop_uv_data);
- DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &cache->edit.loop_stretch_angle);
- }
- if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.edituv_edges, &cache->ibo.edituv_loops_line_strips);
- DRW_vbo_request(cache->batch.edituv_edges, &cache->edit.loop_uv);
- DRW_vbo_request(cache->batch.edituv_edges, &cache->edit.loop_uv_data);
- }
- if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) {
- DRW_ibo_request(cache->batch.edituv_verts, &cache->ibo.edituv_loops_points);
- DRW_vbo_request(cache->batch.edituv_verts, &cache->edit.loop_uv);
- DRW_vbo_request(cache->batch.edituv_verts, &cache->edit.loop_uv_data);
- }
- if (DRW_batch_requested(cache->batch.edituv_facedots, GPU_PRIM_POINTS)) {
- DRW_vbo_request(cache->batch.edituv_facedots, &cache->edit.facedots_uv);
- DRW_vbo_request(cache->batch.edituv_facedots, &cache->edit.facedots_uv_data);
- }
-
- /* Selection */
- /* TODO reuse ordered.loop_pos_nor if possible. */
- if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) {
- DRW_ibo_request(cache->batch.edit_selection_verts, &cache->ibo.edit_loops_points);
- DRW_vbo_request(cache->batch.edit_selection_verts, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_selection_verts, &cache->edit.loop_vert_idx);
- }
- if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.edit_selection_edges, &cache->ibo.edit_loops_lines);
- DRW_vbo_request(cache->batch.edit_selection_edges, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_selection_edges, &cache->edit.loop_edge_idx);
- }
- if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.edit_selection_faces, &cache->ibo.edit_loops_tris);
- DRW_vbo_request(cache->batch.edit_selection_faces, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_selection_faces, &cache->edit.loop_face_idx);
- }
- if (DRW_batch_requested(cache->batch.edit_selection_facedots, GPU_PRIM_POINTS)) {
- DRW_vbo_request(cache->batch.edit_selection_facedots, &cache->edit.facedots_pos_nor_data);
- DRW_vbo_request(cache->batch.edit_selection_facedots, &cache->edit.facedots_idx);
+ DRW_ibo_request(cache->batch.edit_mesh_analysis, &mbufcache->ibo.tris);
+ DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbufcache->vbo.mesh_analysis);
}
/* Per Material */
for (int i = 0; i < cache->mat_len; ++i) {
- if (DRW_batch_requested(cache->surf_per_mat[i], GPU_PRIM_TRIS)) {
- if (cache->mat_len > 1) {
- DRW_ibo_request(cache->surf_per_mat[i], &cache->surf_per_mat_tris[i]);
- }
- else {
- DRW_ibo_request(cache->surf_per_mat[i], &cache->ibo.loops_tris);
- }
- DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_pos_nor);
+ if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->surface_per_mat[i], &mbufcache->ibo.tris);
+ /* Order matters. First ones override latest vbos' attribs. */
+ DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.lnor);
+ DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.pos_nor);
if ((cache->cd_used.uv != 0) || (cache->cd_used.tan != 0) ||
(cache->cd_used.tan_orco != 0)) {
- DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_uv_tan);
+ DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.uv_tan);
}
if (cache->cd_used.vcol != 0) {
- DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_vcol);
+ DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.vcol);
}
if (cache->cd_used.orco != 0) {
- DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_orco);
+ DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.orco);
}
}
}
-#ifdef DRW_DEBUG_MESH_CACHE_REQUEST
- printf("-- %s %s --\n", __func__, ob->id.name + 2);
-#endif
+ mbufcache = (do_cage) ? &cache->cage : &cache->final;
- /* Generate MeshRenderData flags */
- eMRDataType mr_flag = 0, mr_edit_flag = 0;
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.pos_nor, MR_DATATYPE_VERT /* A comment to wrap the line ;) */);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.weights, MR_DATATYPE_VERT | MR_DATATYPE_DVERT);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.loop_pos_nor, MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_LOOP_NORMALS);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.loop_uv_tan, MR_DATATYPE_VERT_LOOP_TRI_POLY | MR_DATATYPE_SHADING);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.loop_orco, MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_SHADING);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.loop_vcol, MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_SHADING);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.loop_edge_fac, MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_EDGE);
-
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.surf_tris, MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_LOOPTRI);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.loops_tris, MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPTRI);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.loops_lines, MR_DATATYPE_LOOP | MR_DATATYPE_EDGE | MR_DATATYPE_POLY);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag,
- cache->ibo.loops_lines_paint_mask,
- MR_DATATYPE_LOOP | MR_DATATYPE_EDGE | MR_DATATYPE_POLY);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.loops_line_strips, MR_DATATYPE_LOOP | MR_DATATYPE_POLY);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.edges_lines, MR_DATATYPE_VERT | MR_DATATYPE_EDGE);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.edges_adj_lines, MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_LOOPTRI);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.loose_edges_lines, MR_DATATYPE_VERT | MR_DATATYPE_EDGE);
- for (int i = 0; i < cache->mat_len; ++i) {
- int combined_flag = MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPTRI;
- DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->surf_per_mat_tris[i], combined_flag);
- }
-
- int combined_edit_flag = MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_EDGE |
- MR_DATATYPE_LOOSE_VERT_EGDE;
- int combined_edit_with_lnor_flag = combined_edit_flag | MR_DATATYPE_LOOP_NORMALS;
- int combined_edituv_flag = combined_edit_flag | MR_DATATYPE_LOOPUV;
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_pos_nor, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_lnor, combined_edit_with_lnor_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_data, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_uv_data, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_uv, combined_edituv_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_stretch_angle, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_stretch_area, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_mesh_analysis, MR_DATATYPE_VERT_LOOP_POLY);
-
- DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.loop_vert_idx, combined_edit_flag);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.loop_edge_idx, combined_edit_flag);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.loop_face_idx, combined_edit_flag);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.facedots_idx, MR_DATATYPE_POLY);
-
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.facedots_pos_nor_data, MR_DATATYPE_POLY | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.facedots_uv, combined_edituv_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.facedots_uv_data, combined_edit_flag | MR_DATATYPE_OVERLAY);
-
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_edit_flag, cache->ibo.edituv_loops_points, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_edit_flag, cache->ibo.edituv_loops_line_strips, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_edit_flag, cache->ibo.edituv_loops_tri_fans, combined_edit_flag | MR_DATATYPE_OVERLAY);
-
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_edit_flag, cache->ibo.edit_loops_points, combined_edit_flag | MR_DATATYPE_LOOPTRI);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_edit_flag, cache->ibo.edit_loops_lines, combined_edit_flag | MR_DATATYPE_LOOPTRI);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_edit_flag, cache->ibo.edit_loops_tris, combined_edit_flag | MR_DATATYPE_LOOPTRI);
-
- Mesh *me_original = me;
- MBC_GET_FINAL_MESH(me);
-
-#ifdef DRW_DEBUG_MESH_CACHE_REQUEST
- printf(" mr_flag %u, mr_edit_flag %u\n\n", mr_flag, mr_edit_flag);
-#endif
-
- if (me_original == me) {
- mr_flag |= mr_edit_flag;
- }
-
- MeshRenderData *rdata = NULL;
-
- if (mr_flag != 0) {
- rdata = mesh_render_data_create_ex(me, mr_flag, &cache->cd_used, ts);
- }
-
- /* Generate VBOs */
- if (DRW_vbo_requested(cache->ordered.pos_nor)) {
- mesh_create_pos_and_nor(rdata, cache->ordered.pos_nor);
- }
- if (DRW_vbo_requested(cache->ordered.weights)) {
- mesh_create_weights(rdata, cache->ordered.weights, &cache->weight_state);
- }
- if (DRW_vbo_requested(cache->ordered.loop_pos_nor)) {
- mesh_create_loop_pos_and_nor(rdata, cache->ordered.loop_pos_nor);
- }
- if (DRW_vbo_requested(cache->ordered.loop_edge_fac)) {
- mesh_create_loop_edge_fac(rdata, cache->ordered.loop_edge_fac);
- }
- if (DRW_vbo_requested(cache->ordered.loop_uv_tan)) {
- mesh_create_loop_uv_and_tan(rdata, cache->ordered.loop_uv_tan);
- }
- if (DRW_vbo_requested(cache->ordered.loop_orco)) {
- mesh_create_loop_orco(rdata, cache->ordered.loop_orco);
- }
- if (DRW_vbo_requested(cache->ordered.loop_vcol)) {
- mesh_create_loop_vcol(rdata, cache->ordered.loop_vcol);
- }
- if (DRW_ibo_requested(cache->ibo.edges_lines)) {
- mesh_create_edges_lines(rdata, cache->ibo.edges_lines, use_hide);
- }
- if (DRW_ibo_requested(cache->ibo.edges_adj_lines)) {
- mesh_create_edges_adjacency_lines(
- rdata, cache->ibo.edges_adj_lines, &cache->is_manifold, use_hide);
- }
- if (DRW_ibo_requested(cache->ibo.loose_edges_lines)) {
- mesh_create_loose_edges_lines(
- rdata, cache->ibo.loose_edges_lines, &cache->no_loose_wire, use_hide);
- }
- if (DRW_ibo_requested(cache->ibo.surf_tris)) {
- mesh_create_surf_tris(rdata, cache->ibo.surf_tris, use_hide);
- }
- if (DRW_ibo_requested(cache->ibo.loops_lines)) {
- mesh_create_loops_lines(rdata, cache->ibo.loops_lines, use_hide);
- }
- if (DRW_ibo_requested(cache->ibo.loops_lines_paint_mask)) {
- mesh_create_loops_lines_paint_mask(rdata, cache->ibo.loops_lines_paint_mask);
+ /* Edit Mesh */
+ if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.edit_triangles, &mbufcache->ibo.tris);
+ DRW_vbo_request(cache->batch.edit_triangles, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_triangles, &mbufcache->vbo.edit_data);
}
- if (DRW_ibo_requested(cache->ibo.loops_line_strips)) {
- mesh_create_loops_line_strips(rdata, cache->ibo.loops_line_strips, use_hide);
+ if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edit_vertices, &mbufcache->ibo.points);
+ DRW_vbo_request(cache->batch.edit_vertices, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_vertices, &mbufcache->vbo.edit_data);
}
- if (DRW_ibo_requested(cache->ibo.loops_tris)) {
- mesh_create_loops_tris(rdata, &cache->ibo.loops_tris, 1, use_hide);
+ if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) {
+ DRW_ibo_request(cache->batch.edit_edges, &mbufcache->ibo.lines);
+ DRW_vbo_request(cache->batch.edit_edges, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_edges, &mbufcache->vbo.edit_data);
}
- if (DRW_ibo_requested(cache->surf_per_mat_tris[0])) {
- mesh_create_loops_tris(rdata, cache->surf_per_mat_tris, cache->mat_len, use_hide);
+ if (DRW_batch_requested(cache->batch.edit_vnor, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edit_vnor, &mbufcache->ibo.points);
+ DRW_vbo_request(cache->batch.edit_vnor, &mbufcache->vbo.pos_nor);
}
-
- /* Use original Mesh* to have the correct edit cage. */
- if (me_original != me && mr_edit_flag != 0) {
- if (rdata) {
- mesh_render_data_free(rdata);
- }
- rdata = mesh_render_data_create_ex(me_original, mr_edit_flag, NULL, ts);
+ if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edit_lnor, &mbufcache->ibo.tris);
+ DRW_vbo_request(cache->batch.edit_lnor, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_lnor, &mbufcache->vbo.lnor);
}
-
- if (rdata && rdata->mapped.supported) {
- rdata->mapped.use = true;
+ if (DRW_batch_requested(cache->batch.edit_fdots, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edit_fdots, &mbufcache->ibo.fdots);
+ DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_pos);
+ DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_nor);
}
- if (DRW_vbo_requested(cache->edit.loop_pos_nor) || DRW_vbo_requested(cache->edit.loop_lnor) ||
- DRW_vbo_requested(cache->edit.loop_data) || DRW_vbo_requested(cache->edit.loop_vert_idx) ||
- DRW_vbo_requested(cache->edit.loop_edge_idx) ||
- DRW_vbo_requested(cache->edit.loop_face_idx)) {
- mesh_create_edit_vertex_loops(rdata,
- cache->edit.loop_pos_nor,
- cache->edit.loop_lnor,
- NULL,
- cache->edit.loop_data,
- cache->edit.loop_vert_idx,
- cache->edit.loop_edge_idx,
- cache->edit.loop_face_idx);
- }
- if (DRW_vbo_requested(cache->edit.facedots_pos_nor_data)) {
- Scene *scene = DRW_context_state_get()->scene;
- mesh_create_edit_facedots(rdata, cache->edit.facedots_pos_nor_data, scene, ob);
- }
- if (DRW_vbo_requested(cache->edit.facedots_idx)) {
- Scene *scene = DRW_context_state_get()->scene;
- mesh_create_edit_facedots_select_id(rdata, cache->edit.facedots_idx, scene, ob);
+ /* Selection */
+ if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edit_selection_verts, &mbufcache->ibo.points);
+ DRW_vbo_request(cache->batch.edit_selection_verts, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_selection_verts, &mbufcache->vbo.vert_idx);
}
- if (DRW_ibo_requested(cache->ibo.edit_loops_points) ||
- DRW_ibo_requested(cache->ibo.edit_loops_lines)) {
- mesh_create_edit_loops_points_lines(
- rdata, cache->ibo.edit_loops_points, cache->ibo.edit_loops_lines);
+ if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) {
+ DRW_ibo_request(cache->batch.edit_selection_edges, &mbufcache->ibo.lines);
+ DRW_vbo_request(cache->batch.edit_selection_edges, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_selection_edges, &mbufcache->vbo.edge_idx);
}
- if (DRW_ibo_requested(cache->ibo.edit_loops_tris)) {
- mesh_create_edit_loops_tris(rdata, cache->ibo.edit_loops_tris);
+ if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.edit_selection_faces, &mbufcache->ibo.tris);
+ DRW_vbo_request(cache->batch.edit_selection_faces, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_selection_faces, &mbufcache->vbo.poly_idx);
}
- if (DRW_vbo_requested(cache->edit.loop_mesh_analysis)) {
- mesh_create_edit_mesh_analysis(rdata, cache->edit.loop_mesh_analysis);
+ if (DRW_batch_requested(cache->batch.edit_selection_fdots, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edit_selection_fdots, &mbufcache->ibo.fdots);
+ DRW_vbo_request(cache->batch.edit_selection_fdots, &mbufcache->vbo.fdots_pos);
+ DRW_vbo_request(cache->batch.edit_selection_fdots, &mbufcache->vbo.fdot_idx);
}
- /* UV editor */
/**
* TODO: The code and data structure is ready to support modified UV display
* but the selection code for UVs needs to support it first. So for now, only
* display the cage in all cases.
*/
- if (rdata && rdata->mapped.supported) {
- rdata->mapped.use = false;
- }
+ mbufcache = (do_uvcage) ? &cache->uv_cage : &cache->final;
- if (DRW_vbo_requested(cache->edit.loop_uv_data) || DRW_vbo_requested(cache->edit.loop_uv)) {
- mesh_create_edit_vertex_loops(
- rdata, NULL, NULL, cache->edit.loop_uv, cache->edit.loop_uv_data, NULL, NULL, NULL);
+ /* Edit UV */
+ if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.edituv_faces, &mbufcache->ibo.edituv_tris);
+ DRW_vbo_request(cache->batch.edituv_faces, &mbufcache->vbo.uv_tan);
+ DRW_vbo_request(cache->batch.edituv_faces, &mbufcache->vbo.edituv_data);
+ }
+ if (DRW_batch_requested(cache->batch.edituv_faces_strech_area, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.edituv_faces_strech_area, &mbufcache->ibo.edituv_tris);
+ DRW_vbo_request(cache->batch.edituv_faces_strech_area, &mbufcache->vbo.uv_tan);
+ DRW_vbo_request(cache->batch.edituv_faces_strech_area, &mbufcache->vbo.edituv_data);
+ DRW_vbo_request(cache->batch.edituv_faces_strech_area, &mbufcache->vbo.stretch_area);
+ }
+ if (DRW_batch_requested(cache->batch.edituv_faces_strech_angle, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->ibo.edituv_tris);
+ DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->vbo.uv_tan);
+ DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->vbo.edituv_data);
+ DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->vbo.stretch_angle);
}
- if (DRW_vbo_requested(cache->edit.loop_stretch_angle) ||
- DRW_vbo_requested(cache->edit.loop_stretch_area) ||
- DRW_vbo_requested(cache->edit.facedots_uv) ||
- DRW_vbo_requested(cache->edit.facedots_uv_data) ||
- DRW_ibo_requested(cache->ibo.edituv_loops_points) ||
- DRW_ibo_requested(cache->ibo.edituv_loops_line_strips) ||
- DRW_ibo_requested(cache->ibo.edituv_loops_tri_fans)) {
- mesh_create_uvedit_buffers(rdata,
- cache->edit.loop_stretch_area,
- cache->edit.loop_stretch_angle,
- cache->edit.facedots_uv,
- cache->edit.facedots_uv_data,
- cache->ibo.edituv_loops_points,
- cache->ibo.edituv_loops_line_strips,
- cache->ibo.edituv_loops_tri_fans);
+ if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) {
+ DRW_ibo_request(cache->batch.edituv_edges, &mbufcache->ibo.edituv_lines);
+ DRW_vbo_request(cache->batch.edituv_edges, &mbufcache->vbo.uv_tan);
+ DRW_vbo_request(cache->batch.edituv_edges, &mbufcache->vbo.edituv_data);
+ }
+ if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edituv_verts, &mbufcache->ibo.edituv_points);
+ DRW_vbo_request(cache->batch.edituv_verts, &mbufcache->vbo.uv_tan);
+ DRW_vbo_request(cache->batch.edituv_verts, &mbufcache->vbo.edituv_data);
}
+ if (DRW_batch_requested(cache->batch.edituv_fdots, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edituv_fdots, &mbufcache->ibo.edituv_fdots);
+ DRW_vbo_request(cache->batch.edituv_fdots, &mbufcache->vbo.fdots_uv);
+ DRW_vbo_request(cache->batch.edituv_fdots, &mbufcache->vbo.fdots_edituv_data);
+ }
+
+ /* Meh loose Scene const correctness here. */
+ const bool use_subsurf_fdots = scene ? modifiers_usesSubsurfFacedots((Scene *)scene, ob) : false;
- if (rdata) {
- mesh_render_data_free(rdata);
+ if (do_uvcage) {
+ mesh_buffer_cache_create_requested(
+ cache, cache->uv_cage, me, false, true, false, &cache->cd_used, ts, true);
}
+ if (do_cage) {
+ mesh_buffer_cache_create_requested(
+ cache, cache->cage, me, false, false, use_subsurf_fdots, &cache->cd_used, ts, true);
+ }
+
+ mesh_buffer_cache_create_requested(
+ cache, cache->final, me, true, false, use_subsurf_fdots, &cache->cd_used, ts, use_hide);
+
#ifdef DEBUG
check:
/* Make sure all requested batches have been setup. */
for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0));
}
+ for (int i = 0; i < sizeof(cache->final.vbo) / sizeof(void *); ++i) {
+ BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.vbo)[i]));
+ }
+ for (int i = 0; i < sizeof(cache->final.ibo) / sizeof(void *); ++i) {
+ BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->final.ibo)[i]));
+ }
+ for (int i = 0; i < sizeof(cache->cage.vbo) / sizeof(void *); ++i) {
+ BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.vbo)[i]));
+ }
+ for (int i = 0; i < sizeof(cache->cage.ibo) / sizeof(void *); ++i) {
+ BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->cage.ibo)[i]));
+ }
+ for (int i = 0; i < sizeof(cache->uv_cage.vbo) / sizeof(void *); ++i) {
+ BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.vbo)[i]));
+ }
+ for (int i = 0; i < sizeof(cache->uv_cage.ibo) / sizeof(void *); ++i) {
+ BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->uv_cage.ibo)[i]));
+ }
#endif
}
diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c
index f0e35e47a66..f8247d7929e 100644
--- a/source/blender/draw/modes/edit_mesh_mode.c
+++ b/source/blender/draw/modes/edit_mesh_mode.c
@@ -128,8 +128,7 @@ typedef struct EDIT_MESH_Shaders {
GPUShader *depth;
/* Mesh analysis shader */
- GPUShader *mesh_analysis_face;
- GPUShader *mesh_analysis_vertex;
+ GPUShader *mesh_analysis;
} EDIT_MESH_Shaders;
/* *********** STATIC *********** */
@@ -307,15 +306,9 @@ static void EDIT_MESH_engine_init(void *vedata)
});
/* Mesh Analysis */
- sh_data->mesh_analysis_face = GPU_shader_create_from_arrays({
+ sh_data->mesh_analysis = GPU_shader_create_from_arrays({
.vert = (const char *[]){lib, datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl, NULL},
.frag = (const char *[]){datatoc_edit_mesh_overlay_mesh_analysis_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define FACE_COLOR\n", NULL},
- });
- sh_data->mesh_analysis_vertex = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_edit_mesh_overlay_mesh_analysis_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define VERTEX_COLOR\n", NULL},
});
MEM_freeN(lib);
@@ -548,10 +541,9 @@ static void EDIT_MESH_cache_init(void *vedata)
/* Mesh Analysis Pass */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
psl->mesh_analysis_pass = DRW_pass_create("Mesh Analysis", state);
- const bool is_vertex_color = scene->toolsettings->statvis.type == SCE_STATVIS_SHARP;
- g_data->mesh_analysis_shgrp = DRW_shgroup_create(
- is_vertex_color ? sh_data->mesh_analysis_vertex : sh_data->mesh_analysis_face,
- psl->mesh_analysis_pass);
+ g_data->mesh_analysis_shgrp = DRW_shgroup_create(sh_data->mesh_analysis,
+ psl->mesh_analysis_pass);
+ DRW_shgroup_uniform_texture(g_data->mesh_analysis_shgrp, "weightTex", G_draw.weight_ramp);
if (rv3d->rflag & RV3D_CLIPPING) {
DRW_shgroup_state_enable(g_data->mesh_analysis_shgrp, DRW_STATE_CLIP_PLANES);
}
@@ -704,17 +696,10 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob)
geom = DRW_cache_mesh_surface_weights_get(ob);
DRW_shgroup_call_no_cull(g_data->fweights_shgrp, geom, ob);
}
-
- if (do_show_mesh_analysis && !XRAY_ACTIVE(v3d)) {
- Mesh *me = (Mesh *)ob->data;
- BMEditMesh *embm = me->edit_mesh;
- const bool is_original = embm->mesh_eval_final &&
- (embm->mesh_eval_final->runtime.is_original == true);
- if (is_original) {
- geom = DRW_cache_mesh_surface_mesh_analysis_get(ob);
- if (geom) {
- DRW_shgroup_call_no_cull(g_data->mesh_analysis_shgrp, geom, ob);
- }
+ else if (do_show_mesh_analysis && !XRAY_ACTIVE(v3d)) {
+ geom = DRW_cache_mesh_surface_mesh_analysis_get(ob);
+ if (geom) {
+ DRW_shgroup_call_no_cull(g_data->mesh_analysis_shgrp, geom, ob);
}
}
@@ -727,7 +712,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob)
}
if (vnormals_do) {
- geom = DRW_mesh_batch_cache_get_edit_vertices(ob->data);
+ geom = DRW_mesh_batch_cache_get_edit_vnors(ob->data);
DRW_shgroup_call_no_cull(g_data->vnormals_shgrp, geom, ob);
}
if (lnormals_do) {
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl
index 8581453e810..8d96c0e418f 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl
@@ -1,12 +1,6 @@
out vec4 fragColor;
-#ifdef FACE_COLOR
-flat in vec4 weightColor;
-#endif
-
-#ifdef VERTEX_COLOR
in vec4 weightColor;
-#endif
void main()
{
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl
index 7065ce3df7c..b89a3f407f9 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl
@@ -1,14 +1,25 @@
in vec3 pos;
-in vec4 weight_color;
+in float weight;
-#ifdef FACE_COLOR
-flat out vec4 weightColor;
-#endif
+uniform sampler1D weightTex;
-#ifdef VERTEX_COLOR
out vec4 weightColor;
-#endif
+
+vec3 weight_to_rgb(float t)
+{
+ if (t < 0.0) {
+ /* Minimum color, grey */
+ return vec3(0.25, 0.25, 0.25);
+ }
+ else if (t > 1.0) {
+ /* Error color */
+ return vec3(1.0, 0.0, 1.0);
+ }
+ else {
+ return texture(weightTex, t).rgb;
+ }
+}
void main()
{
@@ -16,7 +27,7 @@ void main()
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
- weightColor = vec4(weight_color.rgb, 1.0);
+ weightColor = vec4(weight_to_rgb(weight), 1.0);
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index ed8178d1908..d97714061c0 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -163,13 +163,13 @@ void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
static void uvedit_get_batches(Object *ob,
SpaceImage *sima,
- const ToolSettings *ts,
+ const Scene *scene,
GPUBatch **faces,
GPUBatch **edges,
GPUBatch **verts,
GPUBatch **facedots)
{
- int drawfaces = draw_uvs_face_check(ts);
+ int drawfaces = draw_uvs_face_check(scene->toolsettings);
const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0;
@@ -197,7 +197,7 @@ static void uvedit_get_batches(Object *ob,
*faces = NULL;
}
- DRW_mesh_batch_cache_create_requested(ob, ob->data, ts, false, false);
+ DRW_mesh_batch_cache_create_requested(ob, ob->data, scene, false, false);
}
static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
@@ -212,7 +212,7 @@ static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
DRW_mesh_batch_cache_validate(me);
GPUBatch *edges = DRW_mesh_batch_cache_get_uv_edges(me);
- DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false);
+ DRW_mesh_batch_cache_create_requested(eval_ob, me, scene, false, false);
if (edges) {
GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UV_UNIFORM_COLOR);
@@ -235,7 +235,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
DRW_mesh_batch_cache_validate(me);
GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(me);
- DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false);
+ DRW_mesh_batch_cache_create_requested(eval_ob, me, scene, false, false);
GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_UV_UNIFORM_COLOR);
GPU_batch_uniform_4fv(geom, "color", col);
@@ -300,7 +300,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
}
}
- uvedit_get_batches(eval_ob, sima, ts, &faces, &edges, &verts, &facedots);
+ uvedit_get_batches(eval_ob, sima, scene, &faces, &edges, &verts, &facedots);
bool interpedges;
bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 365dd89a006..c65ca5d905e 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -40,7 +40,7 @@ typedef enum {
GPU_BATCH_READY_TO_DRAW,
} GPUBatchPhase;
-#define GPU_BATCH_VBO_MAX_LEN 4
+#define GPU_BATCH_VBO_MAX_LEN 5
#define GPU_BATCH_VAO_STATIC_LEN 3
#define GPU_BATCH_VAO_DYN_ALLOC_COUNT 16
@@ -115,6 +115,7 @@ void GPU_batch_vao_cache_clear(GPUBatch *);
void GPU_batch_callback_free_set(GPUBatch *, void (*callback)(GPUBatch *, void *), void *);
void GPU_batch_instbuf_set(GPUBatch *, GPUVertBuf *, bool own_vbo); /* Instancing */
+void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo);
int GPU_batch_vertbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
diff --git a/source/blender/gpu/GPU_element.h b/source/blender/gpu/GPU_element.h
index 4ac89d2658b..75caf4cbd6a 100644
--- a/source/blender/gpu/GPU_element.h
+++ b/source/blender/gpu/GPU_element.h
@@ -36,14 +36,19 @@ typedef enum {
} GPUIndexBufType;
typedef struct GPUIndexBuf {
+ uint index_start;
uint index_len;
+ bool is_subrange;
#if GPU_TRACK_INDEX_RANGE
GPUIndexBufType index_type;
uint32_t gl_index_type;
uint base_index;
#endif
uint32_t ibo_id; /* 0 indicates not yet sent to VRAM */
- void *data; /* non-NULL indicates not yet sent to VRAM */
+ union {
+ void *data; /* non-NULL indicates not yet sent to VRAM */
+ struct GPUIndexBuf *src; /* if is_subrange is true, this is the source buffer. */
+ };
} GPUIndexBuf;
void GPU_indexbuf_use(GPUIndexBuf *);
@@ -71,9 +76,21 @@ void GPU_indexbuf_add_line_verts(GPUIndexBufBuilder *, uint v1, uint v2);
void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3);
void GPU_indexbuf_add_line_adj_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3, uint v4);
+void GPU_indexbuf_set_point_vert(GPUIndexBufBuilder *builder, uint elem, uint v1);
+void GPU_indexbuf_set_line_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2);
+void GPU_indexbuf_set_tri_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2, uint v3);
+
+/* Skip primitive rendering at the given index. */
+void GPU_indexbuf_set_point_restart(GPUIndexBufBuilder *builder, uint elem);
+void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem);
+void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem);
+
GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *);
void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, GPUIndexBuf *);
+/* Create a subrange of an existing indexbuffer. */
+GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *ibo, uint start, uint length);
+
void GPU_indexbuf_discard(GPUIndexBuf *);
int GPU_indexbuf_primitive_len(GPUPrimType prim_type);
diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h
index 68608a98a79..dc60c52122c 100644
--- a/source/blender/gpu/GPU_vertex_format.h
+++ b/source/blender/gpu/GPU_vertex_format.h
@@ -31,7 +31,7 @@
#include "BLI_assert.h"
#define GPU_VERT_ATTR_MAX_LEN 16
-#define GPU_VERT_ATTR_MAX_NAMES 5
+#define GPU_VERT_ATTR_MAX_NAMES 6
#define GPU_VERT_ATTR_NAME_AVERAGE_LEN 11
#define GPU_VERT_ATTR_NAMES_BUF_LEN ((GPU_VERT_ATTR_NAME_AVERAGE_LEN + 1) * GPU_VERT_ATTR_MAX_LEN)
@@ -88,6 +88,8 @@ typedef struct GPUVertFormat {
uint packed : 1;
/** Current offset in names[]. */
uint name_offset : 8;
+ /** Store each attrib in one contiguous buffer region. */
+ uint deinterleaved : 1;
GPUVertAttr attrs[GPU_VERT_ATTR_MAX_LEN];
char names[GPU_VERT_ATTR_NAMES_BUF_LEN];
@@ -104,6 +106,8 @@ uint GPU_vertformat_attr_add(
GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode);
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias);
+void GPU_vertformat_deinterleave(GPUVertFormat *format);
+
int GPU_vertformat_attr_id_get(const GPUVertFormat *, const char *name);
BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format,
@@ -122,7 +126,59 @@ typedef struct GPUPackedNormal {
int w : 2; /* 0 by default, can manually set to { -2, -1, 0, 1 } */
} GPUPackedNormal;
-GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3]);
-GPUPackedNormal GPU_normal_convert_i10_s3(const short data[3]);
+/* OpenGL ES packs in a different order as desktop GL but component conversion is the same.
+ * Of the code here, only struct GPUPackedNormal needs to change. */
+
+#define SIGNED_INT_10_MAX 511
+#define SIGNED_INT_10_MIN -512
+
+BLI_INLINE int clampi(int x, int min_allowed, int max_allowed)
+{
+#if TRUST_NO_ONE
+ assert(min_allowed <= max_allowed);
+#endif
+ if (x < min_allowed) {
+ return min_allowed;
+ }
+ else if (x > max_allowed) {
+ return max_allowed;
+ }
+ else {
+ return x;
+ }
+}
+
+BLI_INLINE int gpu_convert_normalized_f32_to_i10(float x)
+{
+ int qx = x * 511.0f;
+ return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX);
+}
+
+BLI_INLINE int gpu_convert_i16_to_i10(short x)
+{
+ /* 16-bit signed --> 10-bit signed */
+ /* TODO: round? */
+ return x >> 6;
+}
+
+BLI_INLINE GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3])
+{
+ GPUPackedNormal n = {
+ .x = gpu_convert_normalized_f32_to_i10(data[0]),
+ .y = gpu_convert_normalized_f32_to_i10(data[1]),
+ .z = gpu_convert_normalized_f32_to_i10(data[2]),
+ };
+ return n;
+}
+
+BLI_INLINE GPUPackedNormal GPU_normal_convert_i10_s3(const short data[3])
+{
+ GPUPackedNormal n = {
+ .x = gpu_convert_i16_to_i10(data[0]),
+ .y = gpu_convert_i16_to_i10(data[1]),
+ .z = gpu_convert_i16_to_i10(data[2]),
+ };
+ return n;
+}
#endif /* __GPU_VERTEX_FORMAT_H__ */
diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c
index 11b487f7be4..583551e3e58 100644
--- a/source/blender/gpu/intern/gpu_batch.c
+++ b/source/blender/gpu/intern/gpu_batch.c
@@ -182,6 +182,25 @@ void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo)
}
}
+void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo)
+{
+ BLI_assert(elem != NULL);
+ /* redo the bindings */
+ GPU_batch_vao_cache_clear(batch);
+
+ if (batch->elem != NULL && (batch->owns_flag & GPU_BATCH_OWNS_INDEX)) {
+ GPU_indexbuf_discard(batch->elem);
+ }
+ batch->elem = elem;
+
+ if (own_ibo) {
+ batch->owns_flag |= GPU_BATCH_OWNS_INDEX;
+ }
+ else {
+ batch->owns_flag &= ~GPU_BATCH_OWNS_INDEX;
+ }
+}
+
/* Returns the index of verts in the batch. */
int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
{
@@ -362,13 +381,23 @@ static void create_bindings(GPUVertBuf *verts,
const GPUVertFormat *format = &verts->format;
const uint attr_len = format->attr_len;
- const uint stride = format->stride;
+ uint stride = format->stride;
+ uint offset = 0;
GPU_vertbuf_use(verts);
for (uint a_idx = 0; a_idx < attr_len; ++a_idx) {
const GPUVertAttr *a = &format->attrs[a_idx];
- const GLvoid *pointer = (const GLubyte *)0 + a->offset + v_first * stride;
+
+ if (format->deinterleaved) {
+ offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].sz) * verts->vertex_len;
+ stride = a->sz;
+ }
+ else {
+ offset = a->offset;
+ }
+
+ const GLvoid *pointer = (const GLubyte *)0 + offset + v_first * stride;
for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) {
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
@@ -419,8 +448,11 @@ static void create_bindings(GPUVertBuf *verts,
static void batch_update_program_bindings(GPUBatch *batch, uint v_first)
{
- for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN && batch->verts[v] != NULL; ++v) {
- create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false);
+ /* Reverse order so first vbos have more prevalence (in term of attrib override). */
+ for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; --v) {
+ if (batch->verts[v] != NULL) {
+ create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false);
+ }
}
if (batch->inst) {
create_bindings(batch->inst, batch->interface, v_first, true);
@@ -550,10 +582,10 @@ static void *elem_offset(const GPUIndexBuf *el, int v_first)
{
#if GPU_TRACK_INDEX_RANGE
if (el->index_type == GPU_INDEX_U16) {
- return (GLushort *)0 + v_first;
+ return (GLushort *)0 + v_first + el->index_start;
}
#endif
- return (GLuint *)0 + v_first;
+ return (GLuint *)0 + v_first + el->index_start;
}
/* Use when drawing with GPU_batch_draw_advanced */
diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.c
index 50e7df96503..6c9331b4903 100644
--- a/source/blender/gpu/intern/gpu_element.c
+++ b/source/blender/gpu/intern/gpu_element.c
@@ -162,6 +162,100 @@ void GPU_indexbuf_add_line_adj_verts(
GPU_indexbuf_add_generic_vert(builder, v4);
}
+void GPU_indexbuf_set_point_vert(GPUIndexBufBuilder *builder, uint elem, uint v1)
+{
+ BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
+ BLI_assert(elem < builder->max_index_len);
+ builder->data[elem++] = v1;
+ if (builder->index_len < elem) {
+ builder->index_len = elem;
+ }
+}
+
+void GPU_indexbuf_set_line_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2)
+{
+ BLI_assert(builder->prim_type == GPU_PRIM_LINES);
+ BLI_assert(v1 != v2);
+ BLI_assert(v1 <= builder->max_allowed_index);
+ BLI_assert(v2 <= builder->max_allowed_index);
+ BLI_assert((elem + 1) * 2 <= builder->max_index_len);
+ uint idx = elem * 2;
+ builder->data[idx++] = v1;
+ builder->data[idx++] = v2;
+ if (builder->index_len < idx) {
+ builder->index_len = idx;
+ }
+}
+
+void GPU_indexbuf_set_tri_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2, uint v3)
+{
+ BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
+ BLI_assert(v1 != v2 && v2 != v3 && v3 != v1);
+ BLI_assert(v1 <= builder->max_allowed_index);
+ BLI_assert(v2 <= builder->max_allowed_index);
+ BLI_assert(v3 <= builder->max_allowed_index);
+ BLI_assert((elem + 1) * 3 <= builder->max_index_len);
+ uint idx = elem * 3;
+ builder->data[idx++] = v1;
+ builder->data[idx++] = v2;
+ builder->data[idx++] = v3;
+ if (builder->index_len < idx) {
+ builder->index_len = idx;
+ }
+}
+
+void GPU_indexbuf_set_point_restart(GPUIndexBufBuilder *builder, uint elem)
+{
+ BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
+ BLI_assert(elem < builder->max_index_len);
+ builder->data[elem++] = RESTART_INDEX;
+ if (builder->index_len < elem) {
+ builder->index_len = elem;
+ }
+}
+
+void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem)
+{
+ BLI_assert(builder->prim_type == GPU_PRIM_LINES);
+ BLI_assert((elem + 1) * 2 <= builder->max_index_len);
+ uint idx = elem * 2;
+ builder->data[idx++] = RESTART_INDEX;
+ builder->data[idx++] = RESTART_INDEX;
+ if (builder->index_len < idx) {
+ builder->index_len = idx;
+ }
+}
+
+void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem)
+{
+ BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
+ BLI_assert((elem + 1) * 3 <= builder->max_index_len);
+ uint idx = elem * 3;
+ builder->data[idx++] = RESTART_INDEX;
+ builder->data[idx++] = RESTART_INDEX;
+ builder->data[idx++] = RESTART_INDEX;
+ if (builder->index_len < idx) {
+ builder->index_len = idx;
+ }
+}
+
+GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length)
+{
+ GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
+ BLI_assert(elem_src && !elem_src->is_subrange);
+ BLI_assert(start + length <= elem_src->index_len);
+#if GPU_TRACK_INDEX_RANGE
+ elem->index_type = elem_src->index_type;
+ elem->gl_index_type = elem_src->gl_index_type;
+ elem->base_index = elem_src->base_index;
+#endif
+ elem->is_subrange = true;
+ elem->src = elem_src;
+ elem->index_start = start;
+ elem->index_len = length;
+ return elem;
+}
+
#if GPU_TRACK_INDEX_RANGE
/* Everything remains 32 bit while building to keep things simple.
* Find min/max after, then convert to smallest index type possible. */
@@ -271,6 +365,10 @@ static void indexbuf_upload_data(GPUIndexBuf *elem)
void GPU_indexbuf_use(GPUIndexBuf *elem)
{
+ if (elem->is_subrange) {
+ GPU_indexbuf_use(elem->src);
+ return;
+ }
if (elem->ibo_id == 0) {
elem->ibo_id = GPU_buf_alloc();
}
@@ -285,7 +383,7 @@ void GPU_indexbuf_discard(GPUIndexBuf *elem)
if (elem->ibo_id) {
GPU_buf_free(elem->ibo_id);
}
- if (elem->data) {
+ if (!elem->is_subrange && elem->data) {
MEM_freeN(elem->data);
}
MEM_freeN(elem);
diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c
index 493c6d3ec59..f672d350afa 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.c
+++ b/source/blender/gpu/intern/gpu_vertex_format.c
@@ -218,6 +218,29 @@ int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name)
return -1;
}
+/* Make attribute layout non-interleaved.
+ * Warning! This does not change data layout!
+ * Use direct buffer access to fill the data.
+ * This is for advanced usage.
+ *
+ * Deinterleaved data means all attrib data for each attrib
+ * is stored continuously like this :
+ * 000011112222
+ * instead of :
+ * 012012012012
+ *
+ * Note this is per attrib deinterleaving, NOT per component.
+ * */
+void GPU_vertformat_deinterleave(GPUVertFormat *format)
+{
+ /* Ideally we should change the stride and offset here. This would allow
+ * us to use GPU_vertbuf_attr_set / GPU_vertbuf_attr_fill. But since
+ * we use only 11 bits for attr->offset this limits the size of the
+ * buffer considerably. So instead we do the conversion when creating
+ * bindings in create_bindings(). */
+ format->deinterleaved = true;
+}
+
uint padding(uint offset, uint alignment)
{
const uint mod = offset % alignment;
@@ -391,58 +414,3 @@ void GPU_vertformat_from_interface(GPUVertFormat *format, const GPUShaderInterfa
}
}
}
-
-/* OpenGL ES packs in a different order as desktop GL but component conversion is the same.
- * Of the code here, only struct GPUPackedNormal needs to change. */
-
-#define SIGNED_INT_10_MAX 511
-#define SIGNED_INT_10_MIN -512
-
-static int clampi(int x, int min_allowed, int max_allowed)
-{
-#if TRUST_NO_ONE
- assert(min_allowed <= max_allowed);
-#endif
- if (x < min_allowed) {
- return min_allowed;
- }
- else if (x > max_allowed) {
- return max_allowed;
- }
- else {
- return x;
- }
-}
-
-static int quantize(float x)
-{
- int qx = x * 511.0f;
- return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX);
-}
-
-static int convert_i16(short x)
-{
- /* 16-bit signed --> 10-bit signed */
- /* TODO: round? */
- return x >> 6;
-}
-
-GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3])
-{
- GPUPackedNormal n = {
- .x = quantize(data[0]),
- .y = quantize(data[1]),
- .z = quantize(data[2]),
- };
- return n;
-}
-
-GPUPackedNormal GPU_normal_convert_i10_s3(const short data[3])
-{
- GPUPackedNormal n = {
- .x = convert_i16(data[0]),
- .y = convert_i16(data[1]),
- .z = convert_i16(data[2]),
- };
- return n;
-}
diff --git a/source/blender/gpu/intern/gpu_vertex_format_private.h b/source/blender/gpu/intern/gpu_vertex_format_private.h
index a850d17a1dd..13459101669 100644
--- a/source/blender/gpu/intern/gpu_vertex_format_private.h
+++ b/source/blender/gpu/intern/gpu_vertex_format_private.h
@@ -27,6 +27,7 @@
#define __GPU_VERTEX_FORMAT_PRIVATE_H__
void VertexFormat_pack(GPUVertFormat *format);
+void VertexFormat_deinterleave(GPUVertFormat *format, uint vertex_len);
uint padding(uint offset, uint alignment);
uint vertex_buffer_size(const GPUVertFormat *format, uint vertex_len);
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
index 810784e2fbc..0ce5504dfa8 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
@@ -8,7 +8,7 @@ in vec2 pos;
in float stretch;
#else
-in vec4 uv_adj;
+in vec2 uv_angles;
in float angle;
#endif
@@ -52,6 +52,11 @@ vec3 weight_to_rgb(float weight)
#define M_PI 3.1415926535897932
+vec2 angle_to_v2(float angle)
+{
+ return vec2(cos(angle), sin(angle));
+}
+
/* Adapted from BLI_math_vector.h */
float angle_normalized_v2v2(vec2 v1, vec2 v2)
{
@@ -69,7 +74,9 @@ void main()
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
#ifdef STRETCH_ANGLE
- float uv_angle = angle_normalized_v2v2(uv_adj.xy, uv_adj.zw) / M_PI;
+ vec2 v1 = angle_to_v2(uv_angles.x * M_PI);
+ vec2 v2 = angle_to_v2(uv_angles.y * M_PI);
+ float uv_angle = angle_normalized_v2v2(v1, v2) / M_PI;
float stretch = 1.0 - abs(uv_angle - angle);
stretch = stretch;
stretch = 1.0 - stretch * stretch;
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 531ff27798d..4da67f837c1 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -3467,7 +3467,7 @@ static void rna_def_statvis(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "overhang_min");
RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
- RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 0.001, 3);
+ RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Overhang Min", "Minimum angle to display");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");