diff options
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"); |