2019-07-14 16:49:44 +02:00
|
|
|
/*
|
|
|
|
* 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"
|
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_alloca.h"
|
2019-07-14 16:49:44 +02:00
|
|
|
#include "BLI_bitmap.h"
|
|
|
|
#include "BLI_buffer.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_edgehash.h"
|
|
|
|
#include "BLI_jitter_2d.h"
|
2019-07-14 16:49:44 +02:00
|
|
|
#include "BLI_math_bits.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_math_vector.h"
|
2019-07-14 16:49:44 +02:00
|
|
|
#include "BLI_string.h"
|
|
|
|
#include "BLI_task.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_utildefines.h"
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
#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"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BKE_editmesh_bvh.h"
|
2019-07-14 16:49:44 +02:00
|
|
|
#include "BKE_editmesh_cache.h"
|
|
|
|
#include "BKE_editmesh_tangent.h"
|
|
|
|
#include "BKE_mesh.h"
|
|
|
|
#include "BKE_mesh_runtime.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BKE_mesh_tangent.h"
|
2019-07-14 16:49:44 +02:00
|
|
|
#include "BKE_modifier.h"
|
|
|
|
#include "BKE_object_deform.h"
|
2020-09-18 19:30:02 +02:00
|
|
|
#include "BKE_paint.h"
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
#include "atomic_ops.h"
|
|
|
|
|
|
|
|
#include "bmesh.h"
|
|
|
|
|
|
|
|
#include "GPU_batch.h"
|
2020-09-07 19:35:56 +02:00
|
|
|
#include "GPU_capabilities.h"
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
#include "DRW_render.h"
|
|
|
|
|
|
|
|
#include "ED_mesh.h"
|
|
|
|
#include "ED_uvedit.h"
|
|
|
|
|
|
|
|
#include "draw_cache_impl.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "draw_cache_inline.h"
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
#include "draw_cache_extract.h"
|
|
|
|
|
|
|
|
// #define DEBUG_TIME
|
|
|
|
|
|
|
|
#ifdef DEBUG_TIME
|
|
|
|
# include "PIL_time_utildefines.h"
|
|
|
|
#endif
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
#define CHUNK_SIZE 8192
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Max number of extractions types.
|
|
|
|
*/
|
|
|
|
#define M_EXTRACT_LEN 38
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \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;
|
|
|
|
|
2020-01-07 04:06:33 +01:00
|
|
|
/** Use for #MeshStatVis calculation which use world-space coords. */
|
|
|
|
float obmat[4][4];
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
const ToolSettings *toolsettings;
|
|
|
|
/** Edit Mesh */
|
2020-03-23 18:18:36 +01:00
|
|
|
BMEditMesh *edit_bmesh;
|
2019-07-14 16:49:44 +02:00
|
|
|
BMesh *bm;
|
|
|
|
EditMeshData *edit_data;
|
2020-05-25 12:16:42 +02:00
|
|
|
|
|
|
|
/* For deformed edit-mesh data. */
|
|
|
|
/* Use for #ME_WRAPPER_TYPE_BMESH. */
|
|
|
|
const float (*bm_vert_coords)[3];
|
|
|
|
const float (*bm_vert_normals)[3];
|
|
|
|
const float (*bm_poly_normals)[3];
|
|
|
|
const float (*bm_poly_centers)[3];
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
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;
|
2020-06-25 08:56:49 +02:00
|
|
|
/* Data created on-demand (usually not for #BMesh based data). */
|
2019-07-14 16:49:44 +02:00
|
|
|
MLoopTri *mlooptri;
|
|
|
|
float (*loop_normals)[3];
|
|
|
|
float (*poly_normals)[3];
|
|
|
|
int *lverts, *ledges;
|
|
|
|
} MeshRenderData;
|
2020-06-15 15:25:25 +02:00
|
|
|
|
2021-05-31 09:32:37 +02:00
|
|
|
static void mesh_render_data_loose_geom_load(MeshRenderData *mr, MeshBufferExtractionCache *cache)
|
2020-06-15 15:25:25 +02:00
|
|
|
{
|
2021-05-31 09:32:37 +02:00
|
|
|
mr->ledges = cache->ledges;
|
|
|
|
mr->lverts = cache->lverts;
|
|
|
|
mr->vert_loose_len = cache->vert_loose_len;
|
|
|
|
mr->edge_loose_len = cache->edge_loose_len;
|
|
|
|
|
|
|
|
mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_render_data_loose_geom_ensure(const MeshRenderData *mr,
|
|
|
|
MeshBufferExtractionCache *cache)
|
|
|
|
{
|
|
|
|
/* Early exit: Are loose geometry already available. Only checking for loose verts as loose edges
|
|
|
|
* and verts are calculated at the same time.*/
|
|
|
|
if (cache->lverts) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cache->vert_loose_len = 0;
|
|
|
|
cache->edge_loose_len = 0;
|
|
|
|
|
2020-06-15 15:25:25 +02:00
|
|
|
if (mr->extract_type != MR_EXTRACT_BMESH) {
|
|
|
|
/* Mesh */
|
|
|
|
|
2021-05-31 09:32:37 +02:00
|
|
|
BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
|
2020-06-15 15:25:25 +02:00
|
|
|
|
2021-05-31 09:32:37 +02:00
|
|
|
cache->ledges = MEM_mallocN(mr->edge_len * sizeof(*cache->ledges), __func__);
|
|
|
|
const MEdge *med = mr->medge;
|
|
|
|
for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) {
|
|
|
|
if (med->flag & ME_LOOSEEDGE) {
|
|
|
|
cache->ledges[cache->edge_loose_len++] = med_index;
|
2020-06-15 15:25:25 +02:00
|
|
|
}
|
2021-05-31 09:32:37 +02:00
|
|
|
/* Tag verts as not loose. */
|
|
|
|
BLI_BITMAP_ENABLE(lvert_map, med->v1);
|
|
|
|
BLI_BITMAP_ENABLE(lvert_map, med->v2);
|
|
|
|
}
|
|
|
|
if (cache->edge_loose_len < mr->edge_len) {
|
|
|
|
cache->ledges = MEM_reallocN(cache->ledges, cache->edge_loose_len * sizeof(*cache->ledges));
|
|
|
|
}
|
2020-06-15 15:25:25 +02:00
|
|
|
|
2021-05-31 09:32:37 +02:00
|
|
|
cache->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)) {
|
|
|
|
cache->lverts[cache->vert_loose_len++] = v;
|
2020-06-15 15:25:25 +02:00
|
|
|
}
|
|
|
|
}
|
2021-05-31 09:32:37 +02:00
|
|
|
if (cache->vert_loose_len < mr->vert_len) {
|
|
|
|
cache->lverts = MEM_reallocN(cache->lverts, cache->vert_loose_len * sizeof(*cache->lverts));
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(lvert_map);
|
2020-06-15 15:25:25 +02:00
|
|
|
}
|
|
|
|
else {
|
2020-06-25 08:56:49 +02:00
|
|
|
/* #BMesh */
|
2020-06-15 15:25:25 +02:00
|
|
|
BMesh *bm = mr->bm;
|
2021-05-31 09:32:37 +02:00
|
|
|
int elem_id;
|
|
|
|
BMIter iter;
|
|
|
|
BMVert *eve;
|
|
|
|
BMEdge *ede;
|
2020-06-15 15:25:25 +02:00
|
|
|
|
2021-05-31 09:32:37 +02:00
|
|
|
cache->lverts = MEM_mallocN(mr->vert_len * sizeof(*cache->lverts), __func__);
|
|
|
|
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
|
|
|
|
if (eve->e == NULL) {
|
|
|
|
cache->lverts[cache->vert_loose_len++] = elem_id;
|
2020-06-15 15:25:25 +02:00
|
|
|
}
|
2021-05-31 09:32:37 +02:00
|
|
|
}
|
|
|
|
if (cache->vert_loose_len < mr->vert_len) {
|
|
|
|
cache->lverts = MEM_reallocN(cache->lverts, cache->vert_loose_len * sizeof(*cache->lverts));
|
|
|
|
}
|
2020-06-15 15:25:25 +02:00
|
|
|
|
2021-05-31 09:32:37 +02:00
|
|
|
cache->ledges = MEM_mallocN(mr->edge_len * sizeof(*cache->ledges), __func__);
|
|
|
|
BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
|
|
|
|
if (ede->l == NULL) {
|
|
|
|
cache->ledges[cache->edge_loose_len++] = elem_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cache->edge_loose_len < mr->edge_len) {
|
|
|
|
cache->ledges = MEM_reallocN(cache->ledges, cache->edge_loose_len * sizeof(*cache->ledges));
|
2020-06-15 15:25:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 08:56:49 +02:00
|
|
|
/**
|
|
|
|
* Part of the creation of the #MeshRenderData that happens in a thread.
|
|
|
|
*/
|
2020-06-15 15:25:25 +02:00
|
|
|
static void mesh_render_data_update_looptris(MeshRenderData *mr,
|
|
|
|
const eMRIterType iter_type,
|
|
|
|
const eMRDataType data_flag)
|
|
|
|
{
|
|
|
|
Mesh *me = mr->me;
|
|
|
|
if (mr->extract_type != MR_EXTRACT_BMESH) {
|
|
|
|
/* Mesh */
|
|
|
|
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(
|
|
|
|
me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mr->mlooptri);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-06-25 08:56:49 +02:00
|
|
|
/* #BMesh */
|
2020-06-15 15:25:25 +02:00
|
|
|
if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
|
|
|
|
/* Edit mode ensures this is valid, no need to calculate. */
|
|
|
|
BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_render_data_update_normals(MeshRenderData *mr,
|
|
|
|
const eMRIterType UNUSED(iter_type),
|
|
|
|
const eMRDataType data_flag)
|
|
|
|
{
|
|
|
|
Mesh *me = mr->me;
|
|
|
|
const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
|
|
|
|
const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI;
|
|
|
|
|
|
|
|
if (mr->extract_type != MR_EXTRACT_BMESH) {
|
|
|
|
/* Mesh */
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-06-25 08:56:49 +02:00
|
|
|
/* #BMesh */
|
2020-06-15 15:25:25 +02:00
|
|
|
if (data_flag & MR_DATA_POLY_NOR) {
|
2020-06-25 08:56:49 +02:00
|
|
|
/* Use #BMFace.no instead. */
|
2020-06-15 15:25:25 +02:00
|
|
|
}
|
|
|
|
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
|
|
|
|
|
|
|
|
const float(*vert_coords)[3] = NULL;
|
|
|
|
const float(*vert_normals)[3] = NULL;
|
|
|
|
const float(*poly_normals)[3] = NULL;
|
|
|
|
|
|
|
|
if (mr->edit_data && mr->edit_data->vertexCos) {
|
|
|
|
vert_coords = mr->bm_vert_coords;
|
|
|
|
vert_normals = mr->bm_vert_normals;
|
|
|
|
poly_normals = mr->bm_poly_normals;
|
|
|
|
}
|
|
|
|
|
|
|
|
mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
|
2020-06-30 16:13:39 +02:00
|
|
|
const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL);
|
2020-06-15 15:25:25 +02:00
|
|
|
BM_loops_calc_normal_vcos(mr->bm,
|
|
|
|
vert_coords,
|
|
|
|
vert_normals,
|
|
|
|
poly_normals,
|
|
|
|
is_auto_smooth,
|
|
|
|
split_angle,
|
|
|
|
mr->loop_normals,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
clnors_offset,
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-25 15:49:55 +02:00
|
|
|
/**
|
|
|
|
* \param is_mode_active: When true, use the modifiers from the edit-data,
|
|
|
|
* otherwise don't use modifiers as they are not from this object.
|
|
|
|
*/
|
2019-07-14 16:49:44 +02:00
|
|
|
static MeshRenderData *mesh_render_data_create(Mesh *me,
|
2021-05-31 09:32:37 +02:00
|
|
|
MeshBufferExtractionCache *cache,
|
2020-01-08 12:20:45 +01:00
|
|
|
const bool is_editmode,
|
2020-04-04 11:14:45 +02:00
|
|
|
const bool is_paint_mode,
|
2020-08-25 15:49:55 +02:00
|
|
|
const bool is_mode_active,
|
2020-01-07 04:06:33 +01:00
|
|
|
const float obmat[4][4],
|
2019-07-14 16:49:44 +02:00
|
|
|
const bool do_final,
|
|
|
|
const bool do_uvedit,
|
|
|
|
const DRW_MeshCDMask *UNUSED(cd_used),
|
2020-06-15 15:25:25 +02:00
|
|
|
const ToolSettings *ts,
|
2021-05-31 09:32:37 +02:00
|
|
|
const eMRIterType iter_type)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
|
|
|
|
mr->toolsettings = ts;
|
|
|
|
mr->mat_len = mesh_render_mat_len_get(me);
|
|
|
|
|
2020-01-07 04:06:33 +01:00
|
|
|
copy_m4_m4(mr->obmat, obmat);
|
|
|
|
|
2020-01-08 12:20:45 +01:00
|
|
|
if (is_editmode) {
|
2019-07-14 16:49:44 +02:00
|
|
|
BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final);
|
|
|
|
mr->bm = me->edit_mesh->bm;
|
2020-03-23 18:18:36 +01:00
|
|
|
mr->edit_bmesh = me->edit_mesh;
|
2019-07-14 16:49:44 +02:00
|
|
|
mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage;
|
2020-08-25 15:49:55 +02:00
|
|
|
mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL;
|
2020-05-25 12:16:42 +02:00
|
|
|
|
|
|
|
if (mr->edit_data) {
|
|
|
|
EditMeshData *emd = mr->edit_data;
|
|
|
|
if (emd->vertexCos) {
|
|
|
|
BKE_editmesh_cache_ensure_vert_normals(mr->edit_bmesh, emd);
|
|
|
|
BKE_editmesh_cache_ensure_poly_normals(mr->edit_bmesh, emd);
|
|
|
|
}
|
|
|
|
|
|
|
|
mr->bm_vert_coords = mr->edit_data->vertexCos;
|
|
|
|
mr->bm_vert_normals = mr->edit_data->vertexNos;
|
|
|
|
mr->bm_poly_normals = mr->edit_data->polyNos;
|
|
|
|
mr->bm_poly_centers = mr->edit_data->polyCos;
|
|
|
|
}
|
|
|
|
|
2020-08-25 15:49:55 +02:00
|
|
|
bool has_mdata = is_mode_active && (mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA);
|
|
|
|
bool use_mapped = is_mode_active &&
|
|
|
|
(has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2020-03-23 18:18:36 +01:00
|
|
|
mr->efa_act_uv = EDBM_uv_active_face_get(mr->edit_bmesh, false, false);
|
2019-07-14 16:49:44 +02:00
|
|
|
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. */
|
2020-05-25 12:16:42 +02:00
|
|
|
if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
|
2019-07-14 16:49:44 +02:00
|
|
|
// mr->edit_bmesh = NULL;
|
|
|
|
mr->extract_type = MR_EXTRACT_MESH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mr->me = me;
|
2020-03-23 18:18:36 +01:00
|
|
|
mr->edit_bmesh = NULL;
|
2020-03-30 11:20:29 +02:00
|
|
|
|
2020-04-04 11:14:45 +02:00
|
|
|
bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original;
|
2020-03-30 11:20:29 +02:00
|
|
|
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_MESH;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2020-06-02 15:07:17 +02:00
|
|
|
}
|
|
|
|
else {
|
2020-06-25 08:56:49 +02:00
|
|
|
/* #BMesh */
|
2020-06-02 15:07:17 +02:00
|
|
|
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);
|
|
|
|
}
|
2021-05-31 09:32:37 +02:00
|
|
|
|
|
|
|
if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
|
|
|
|
mesh_render_data_loose_geom_ensure(mr, cache);
|
|
|
|
mesh_render_data_loose_geom_load(mr, cache);
|
|
|
|
}
|
2020-06-02 15:07:17 +02:00
|
|
|
|
|
|
|
return mr;
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2021-05-31 09:32:37 +02:00
|
|
|
/* Loose geometry are owned by MeshBufferExtractionCache. */
|
|
|
|
mr->ledges = NULL;
|
|
|
|
mr->lverts = NULL;
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-05-25 12:16:42 +02:00
|
|
|
BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve)
|
|
|
|
{
|
|
|
|
const float(*vert_coords)[3] = mr->bm_vert_coords;
|
|
|
|
if (vert_coords != NULL) {
|
|
|
|
return vert_coords[BM_elem_index_get(eve)];
|
|
|
|
}
|
2020-08-07 11:49:59 +02:00
|
|
|
|
|
|
|
UNUSED_VARS(mr);
|
|
|
|
return eve->co;
|
2020-05-25 12:16:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve)
|
|
|
|
{
|
|
|
|
const float(*vert_normals)[3] = mr->bm_vert_normals;
|
|
|
|
if (vert_normals != NULL) {
|
|
|
|
return vert_normals[BM_elem_index_get(eve)];
|
|
|
|
}
|
2020-08-07 11:49:59 +02:00
|
|
|
|
|
|
|
UNUSED_VARS(mr);
|
|
|
|
return eve->no;
|
2020-05-25 12:16:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa)
|
|
|
|
{
|
|
|
|
const float(*poly_normals)[3] = mr->bm_poly_normals;
|
|
|
|
if (poly_normals != NULL) {
|
|
|
|
return poly_normals[BM_elem_index_get(efa)];
|
|
|
|
}
|
2020-08-07 11:49:59 +02:00
|
|
|
|
|
|
|
UNUSED_VARS(mr);
|
|
|
|
return efa->no;
|
2020-05-25 12:16:42 +02:00
|
|
|
}
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
2020-06-30 16:13:39 +02:00
|
|
|
/** \name Mesh Elements Extract: Loop Triangles
|
2019-07-14 16:49:44 +02:00
|
|
|
* \{ */
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
typedef struct ExtractTriBMesh_Params {
|
|
|
|
BMLoop *(*looptris)[3];
|
|
|
|
int tri_range[2];
|
|
|
|
} ExtractTriBMesh_Params;
|
2020-06-29 07:09:43 +02:00
|
|
|
typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop **elt,
|
|
|
|
const int elt_index,
|
2020-06-29 07:09:43 +02:00
|
|
|
void *data);
|
2020-06-30 16:13:39 +02:00
|
|
|
|
|
|
|
#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elem_tri, index_tri, params) \
|
|
|
|
CHECK_TYPE(params, const ExtractTriBMesh_Params *); \
|
|
|
|
{ \
|
|
|
|
const int _tri_index_end = (params)->tri_range[1]; \
|
|
|
|
BMLoop **elem_tri = (params)->looptris[(params)->tri_range[0]]; \
|
|
|
|
for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
|
|
|
|
index_tri += 1, elem_tri += 3)
|
|
|
|
#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END }
|
|
|
|
|
|
|
|
typedef struct ExtractTriMesh_Params {
|
|
|
|
const MLoopTri *mlooptri;
|
|
|
|
int tri_range[2];
|
|
|
|
} ExtractTriMesh_Params;
|
2020-06-29 07:09:43 +02:00
|
|
|
typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoopTri *mlt,
|
|
|
|
const int elt_index,
|
2020-06-29 07:09:43 +02:00
|
|
|
void *data);
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(elem_tri, index_tri, params) \
|
|
|
|
CHECK_TYPE(params, const ExtractTriMesh_Params *); \
|
|
|
|
{ \
|
|
|
|
const int _tri_index_end = (params)->tri_range[1]; \
|
|
|
|
const MLoopTri *elem_tri = &(params)->mlooptri[(params)->tri_range[0]]; \
|
|
|
|
for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
|
|
|
|
index_tri += 1, elem_tri += 1)
|
|
|
|
#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END }
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Mesh Elements Extract: Polygons, Loops
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct ExtractPolyBMesh_Params {
|
|
|
|
BMLoop *(*looptris)[3];
|
|
|
|
int poly_range[2];
|
|
|
|
} ExtractPolyBMesh_Params;
|
|
|
|
typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMFace *f,
|
|
|
|
const int f_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data);
|
|
|
|
|
|
|
|
#define EXTRACT_POLY_FOREACH_BM_BEGIN(elem_poly, index_poly, params, mr) \
|
|
|
|
CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
|
|
|
|
{ \
|
|
|
|
BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
|
|
|
|
BMFace **_ftable = mr->bm->ftable; \
|
|
|
|
const int _poly_index_end = (params)->poly_range[1]; \
|
|
|
|
for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
|
|
|
|
index_poly += 1) { \
|
|
|
|
BMFace *elem_poly = _ftable[index_poly]; \
|
|
|
|
(void)elem_poly;
|
|
|
|
|
|
|
|
#define EXTRACT_POLY_FOREACH_BM_END \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Iterate over polygon and loop. */
|
|
|
|
#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(elem_loop, index_loop, params, mr) \
|
|
|
|
CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
|
|
|
|
{ \
|
|
|
|
BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
|
|
|
|
BMFace **_ftable = mr->bm->ftable; \
|
|
|
|
const int _poly_index_end = (params)->poly_range[1]; \
|
|
|
|
for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
|
|
|
|
index_poly += 1) { \
|
|
|
|
BMFace *elem_face = _ftable[index_poly]; \
|
|
|
|
BMLoop *elem_loop, *l_first; \
|
|
|
|
elem_loop = l_first = BM_FACE_FIRST_LOOP(elem_face); \
|
|
|
|
do { \
|
|
|
|
const int index_loop = BM_elem_index_get(elem_loop); \
|
|
|
|
(void)index_loop; /* Quiet warning when unused. */
|
|
|
|
|
|
|
|
#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(elem_loop) \
|
|
|
|
} \
|
|
|
|
while ((elem_loop = elem_loop->next) != l_first) \
|
|
|
|
; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct ExtractPolyMesh_Params {
|
|
|
|
int poly_range[2];
|
|
|
|
} ExtractPolyMesh_Params;
|
|
|
|
typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int mp_index,
|
2020-06-29 07:09:43 +02:00
|
|
|
void *data);
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
#define EXTRACT_POLY_FOREACH_MESH_BEGIN(elem_poly, index_poly, params, mr) \
|
|
|
|
CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
|
|
|
|
{ \
|
|
|
|
const MPoly *_mpoly = mr->mpoly; \
|
|
|
|
const int _poly_index_end = (params)->poly_range[1]; \
|
|
|
|
for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
|
|
|
|
index_poly += 1) { \
|
|
|
|
const MPoly *elem_poly = &_mpoly[index_poly]; \
|
|
|
|
(void)elem_poly;
|
|
|
|
|
|
|
|
#define EXTRACT_POLY_FOREACH_MESH_END \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Iterate over polygon and loop. */
|
|
|
|
#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN( \
|
|
|
|
elem_poly, index_poly, elem_loop, index_loop, params, mr) \
|
|
|
|
CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
|
|
|
|
{ \
|
|
|
|
const MPoly *_mpoly = mr->mpoly; \
|
|
|
|
const MLoop *_mloop = mr->mloop; \
|
|
|
|
const int _poly_index_end = (params)->poly_range[1]; \
|
|
|
|
for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
|
|
|
|
index_poly += 1) { \
|
|
|
|
const MPoly *elem_poly = &_mpoly[index_poly]; \
|
|
|
|
const int _index_end = elem_poly->loopstart + elem_poly->totloop; \
|
|
|
|
for (int index_loop = elem_poly->loopstart; index_loop < _index_end; index_loop += 1) { \
|
|
|
|
const MLoop *elem_loop = &_mloop[index_loop]; \
|
|
|
|
(void)elem_loop;
|
|
|
|
|
|
|
|
#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Mesh Elements Extract: Loose Edges
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct ExtractLEdgeBMesh_Params {
|
|
|
|
const int *ledge;
|
|
|
|
int ledge_range[2];
|
|
|
|
} ExtractLEdgeBMesh_Params;
|
2020-06-29 07:09:43 +02:00
|
|
|
typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMEdge *eed,
|
|
|
|
const int ledge_index,
|
2020-06-29 07:09:43 +02:00
|
|
|
void *data);
|
2020-06-30 16:13:39 +02:00
|
|
|
|
|
|
|
#define EXTRACT_LEDGE_FOREACH_BM_BEGIN(elem_edge, index_ledge, params) \
|
|
|
|
CHECK_TYPE(params, const ExtractLEdgeBMesh_Params *); \
|
|
|
|
{ \
|
|
|
|
BLI_assert((mr->bm->elem_table_dirty & BM_EDGE) == 0); \
|
|
|
|
BMEdge **_etable = mr->bm->etable; \
|
|
|
|
const int *_ledge = (params)->ledge; \
|
|
|
|
const int _ledge_index_end = (params)->ledge_range[1]; \
|
|
|
|
for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
|
|
|
|
index_ledge += 1) { \
|
|
|
|
BMEdge *elem_edge = _etable[_ledge[index_ledge]]; \
|
|
|
|
(void)elem_edge; /* Quiet warning when unused. */ \
|
|
|
|
{
|
|
|
|
#define EXTRACT_LEDGE_FOREACH_BM_END \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct ExtractLEdgeMesh_Params {
|
|
|
|
const int *ledge;
|
|
|
|
int ledge_range[2];
|
|
|
|
} ExtractLEdgeMesh_Params;
|
2020-06-29 07:09:43 +02:00
|
|
|
typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MEdge *med,
|
|
|
|
const uint ledge_index,
|
2020-06-29 07:09:43 +02:00
|
|
|
void *data);
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
#define EXTRACT_LEDGE_FOREACH_MESH_BEGIN(elem_edge, index_ledge, params, mr) \
|
|
|
|
CHECK_TYPE(params, const ExtractLEdgeMesh_Params *); \
|
|
|
|
{ \
|
|
|
|
const MEdge *_medge = mr->medge; \
|
|
|
|
const int *_ledge = (params)->ledge; \
|
|
|
|
const int _ledge_index_end = (params)->ledge_range[1]; \
|
|
|
|
for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
|
|
|
|
index_ledge += 1) { \
|
|
|
|
const MEdge *elem_edge = &_medge[_ledge[index_ledge]]; \
|
|
|
|
(void)elem_edge; /* Quiet warning when unused. */ \
|
|
|
|
{
|
|
|
|
#define EXTRACT_LEDGE_FOREACH_MESH_END \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Mesh Elements Extract: Loose Vertices
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct ExtractLVertBMesh_Params {
|
|
|
|
const int *lvert;
|
|
|
|
int lvert_range[2];
|
|
|
|
} ExtractLVertBMesh_Params;
|
2020-06-29 07:09:43 +02:00
|
|
|
typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMVert *eve,
|
|
|
|
const int lvert_index,
|
2020-06-29 07:09:43 +02:00
|
|
|
void *data);
|
2020-06-30 16:13:39 +02:00
|
|
|
|
|
|
|
#define EXTRACT_LVERT_FOREACH_BM_BEGIN(elem_vert, index_lvert, params) \
|
|
|
|
CHECK_TYPE(params, const ExtractLVertBMesh_Params *); \
|
|
|
|
{ \
|
|
|
|
BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
|
|
|
|
BMVert **vtable = mr->bm->vtable; \
|
|
|
|
const int *lverts = (params)->lvert; \
|
|
|
|
const int _lvert_index_end = (params)->lvert_range[1]; \
|
|
|
|
for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
|
|
|
|
index_lvert += 1) { \
|
|
|
|
BMVert *elem_vert = vtable[lverts[index_lvert]]; \
|
|
|
|
(void)elem_vert; /* Quiet warning when unused. */ \
|
|
|
|
{
|
|
|
|
#define EXTRACT_LVERT_FOREACH_BM_END \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct ExtractLVertMesh_Params {
|
|
|
|
const int *lvert;
|
|
|
|
int lvert_range[2];
|
|
|
|
} ExtractLVertMesh_Params;
|
2020-06-29 13:03:42 +02:00
|
|
|
typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MVert *mv,
|
|
|
|
const int lvert_index,
|
2020-06-29 13:03:42 +02:00
|
|
|
void *data);
|
2020-06-30 16:13:39 +02:00
|
|
|
|
|
|
|
#define EXTRACT_LVERT_FOREACH_MESH_BEGIN(elem, index_lvert, params, mr) \
|
|
|
|
CHECK_TYPE(params, const ExtractLVertMesh_Params *); \
|
|
|
|
{ \
|
|
|
|
const MVert *mvert = mr->mvert; \
|
|
|
|
const int *lverts = (params)->lvert; \
|
|
|
|
const int _lvert_index_end = (params)->lvert_range[1]; \
|
|
|
|
for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
|
|
|
|
index_lvert += 1) { \
|
|
|
|
const MVert *elem = &mvert[lverts[index_lvert]]; \
|
|
|
|
(void)elem; /* Quiet warning when unused. */ \
|
|
|
|
{
|
|
|
|
#define EXTRACT_LVERT_FOREACH_MESH_END \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Mesh Elements Extract Struct
|
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
typedef void *(ExtractInitFn)(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *cache,
|
|
|
|
void *buffer);
|
|
|
|
typedef void(ExtractFinishFn)(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *cache,
|
|
|
|
void *buffer,
|
|
|
|
void *data);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
typedef struct MeshExtract {
|
2020-06-25 08:56:49 +02:00
|
|
|
/** Executed on main thread and return user data for iteration functions. */
|
2019-07-14 16:49:44 +02:00
|
|
|
ExtractInitFn *init;
|
|
|
|
/** Executed on one (or more if use_threading) worker thread(s). */
|
2020-06-29 07:09:43 +02:00
|
|
|
ExtractTriBMeshFn *iter_looptri_bm;
|
|
|
|
ExtractTriMeshFn *iter_looptri_mesh;
|
2020-06-30 16:13:39 +02:00
|
|
|
ExtractPolyBMeshFn *iter_poly_bm;
|
|
|
|
ExtractPolyMeshFn *iter_poly_mesh;
|
2020-06-29 07:09:43 +02:00
|
|
|
ExtractLEdgeBMeshFn *iter_ledge_bm;
|
|
|
|
ExtractLEdgeMeshFn *iter_ledge_mesh;
|
|
|
|
ExtractLVertBMeshFn *iter_lvert_bm;
|
2020-06-29 13:03:42 +02:00
|
|
|
ExtractLVertMeshFn *iter_lvert_mesh;
|
2019-07-14 16:49:44 +02:00
|
|
|
/** Executed on one worker thread after all elements iterations. */
|
|
|
|
ExtractFinishFn *finish;
|
|
|
|
/** Used to request common data. */
|
|
|
|
const eMRDataType data_flag;
|
2020-06-25 08:56:49 +02:00
|
|
|
/** Used to know if the element callbacks are thread-safe and can be parallelized. */
|
2019-07-14 16:49:44 +02:00
|
|
|
const bool use_threading;
|
2021-05-31 17:11:01 +02:00
|
|
|
/**
|
|
|
|
* Offset in bytes of the buffer inside a MeshBufferCache instance. Points to a vertex or index
|
|
|
|
* buffer.
|
|
|
|
*/
|
|
|
|
const size_t mesh_buffer_offset;
|
2019-07-14 16:49:44 +02:00
|
|
|
} MeshExtract;
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferCache *mbc)
|
|
|
|
{
|
|
|
|
/* NOTE: POINTER_OFFSET on windows platforms casts internally to `void *`, but on GCC/CLANG to
|
|
|
|
* `MeshBufferCache *`. What shows a different usage versus intent. */
|
|
|
|
void **buffer_ptr = (void **)POINTER_OFFSET(mbc, extractor->mesh_buffer_offset);
|
|
|
|
void *buffer = *buffer_ptr;
|
|
|
|
BLI_assert(buffer);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct MeshExtractRunData {
|
|
|
|
const MeshExtract *extractor;
|
|
|
|
void *buffer;
|
|
|
|
void *user_data;
|
|
|
|
} MeshExtractRunData;
|
|
|
|
|
|
|
|
typedef struct MeshExtractRunDataArray {
|
|
|
|
int len;
|
|
|
|
MeshExtractRunData items[M_EXTRACT_LEN];
|
|
|
|
} MeshExtractRunDataArray;
|
|
|
|
|
|
|
|
static void mesh_extract_run_data_array_init(MeshExtractRunDataArray *array)
|
|
|
|
{
|
|
|
|
array->len = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_extract_run_data_array_add_ex(MeshExtractRunDataArray *array,
|
|
|
|
const MeshExtractRunData *run_data)
|
|
|
|
{
|
|
|
|
array->items[array->len] = *run_data;
|
|
|
|
array->len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_extract_run_data_array_add(MeshExtractRunDataArray *array,
|
|
|
|
const MeshExtract *extractor)
|
|
|
|
{
|
|
|
|
MeshExtractRunData run_data;
|
|
|
|
run_data.extractor = extractor;
|
|
|
|
run_data.buffer = NULL;
|
|
|
|
run_data.user_data = NULL;
|
|
|
|
mesh_extract_run_data_array_add_ex(array, &run_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_extract_run_data_array_filter_iter_type(const MeshExtractRunDataArray *src,
|
|
|
|
MeshExtractRunDataArray *dst,
|
|
|
|
eMRIterType iter_type)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < src->len; i++) {
|
|
|
|
|
|
|
|
const MeshExtractRunData *data = &src->items[i];
|
|
|
|
const MeshExtract *extractor = data->extractor;
|
|
|
|
if ((iter_type & MR_ITER_LOOPTRI) && extractor->iter_looptri_bm) {
|
|
|
|
BLI_assert(extractor->iter_looptri_mesh);
|
|
|
|
mesh_extract_run_data_array_add_ex(dst, data);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((iter_type & MR_ITER_POLY) && extractor->iter_poly_bm) {
|
|
|
|
BLI_assert(extractor->iter_poly_mesh);
|
|
|
|
mesh_extract_run_data_array_add_ex(dst, data);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((iter_type & MR_ITER_LEDGE) && extractor->iter_ledge_bm) {
|
|
|
|
BLI_assert(extractor->iter_ledge_mesh);
|
|
|
|
mesh_extract_run_data_array_add_ex(dst, data);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((iter_type & MR_ITER_LVERT) && extractor->iter_lvert_bm) {
|
|
|
|
BLI_assert(extractor->iter_lvert_mesh);
|
|
|
|
mesh_extract_run_data_array_add_ex(dst, data);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_extract_run_data_array_filter_threading(
|
|
|
|
const MeshExtractRunDataArray *src, MeshExtractRunDataArray *dst_multi_threaded)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < src->len; i++) {
|
|
|
|
const MeshExtract *extractor = src->items[i].extractor;
|
|
|
|
if (extractor->use_threading) {
|
|
|
|
mesh_extract_run_data_array_add(dst_multi_threaded, extractor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
BLI_INLINE eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
|
|
|
|
{
|
|
|
|
eMRIterType type = 0;
|
2020-06-29 07:09:43 +02:00
|
|
|
SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI);
|
2020-06-30 16:13:39 +02:00
|
|
|
SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY);
|
2020-06-29 07:09:43 +02:00
|
|
|
SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE);
|
|
|
|
SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert_mesh), MR_ITER_LVERT);
|
2019-07-14 16:49:44 +02:00
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Triangles Indices
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct MeshExtract_Tri_Data {
|
|
|
|
GPUIndexBufBuilder elb;
|
|
|
|
int *tri_mat_start;
|
|
|
|
int *tri_mat_end;
|
|
|
|
} MeshExtract_Tri_Data;
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_tris_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *UNUSED(ibo))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
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)) {
|
2019-08-18 22:40:47 +02:00
|
|
|
int mat = min_ii(efa->mat_nr, mr->mat_len - 1);
|
|
|
|
mat_tri_len[mat] += efa->len - 2;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-06-30 16:13:39 +02:00
|
|
|
const MPoly *mp = mr->mpoly;
|
|
|
|
for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
|
|
|
|
if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
|
|
|
|
int mat = min_ii(mp->mat_nr, mr->mat_len - 1);
|
|
|
|
mat_tri_len[mat] += mp->totloop - 2;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-06-25 08:56:49 +02:00
|
|
|
/* Accumulate triangle lengths per material to have correct offsets. */
|
2019-07-14 16:49:44 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_tris_iter_looptri_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop **elt,
|
|
|
|
const int UNUSED(elt_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_Tri_Data *data = _data;
|
|
|
|
const int mat_last = mr->mat_len - 1;
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
|
|
|
|
int *mat_tri_ofs = data->tri_mat_end;
|
|
|
|
const int mat = min_ii(elt[0]->f->mat_nr, mat_last);
|
|
|
|
GPU_indexbuf_set_tri_verts(&data->elb,
|
|
|
|
mat_tri_ofs[mat]++,
|
|
|
|
BM_elem_index_get(elt[0]),
|
|
|
|
BM_elem_index_get(elt[1]),
|
|
|
|
BM_elem_index_get(elt[2]));
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_tris_iter_looptri_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoopTri *mlt,
|
|
|
|
const int UNUSED(elt_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_Tri_Data *data = _data;
|
|
|
|
const int mat_last = mr->mat_len - 1;
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp = &mr->mpoly[mlt->poly];
|
|
|
|
if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
|
|
|
|
int *mat_tri_ofs = data->tri_mat_end;
|
|
|
|
const int mat = min_ii(mp->mat_nr, mat_last);
|
|
|
|
GPU_indexbuf_set_tri_verts(
|
|
|
|
&data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_tris_finish(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *cache,
|
2021-05-31 17:11:01 +02:00
|
|
|
void *buf,
|
2020-08-21 09:19:25 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUIndexBuf *ibo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
MeshExtract_Tri_Data *data = _data;
|
|
|
|
GPU_indexbuf_build_in_place(&data->elb, ibo);
|
2020-10-19 08:08:49 +02:00
|
|
|
|
2020-11-03 10:55:18 +01:00
|
|
|
/* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch
|
|
|
|
* is created before the surfaces-per-material. */
|
|
|
|
if (mr->use_final_mesh && cache->final.tris_per_mat) {
|
2021-05-31 17:11:01 +02:00
|
|
|
MeshBufferCache *mbc_final = &cache->final;
|
2019-09-07 16:12:26 +02:00
|
|
|
for (int i = 0; i < mr->mat_len; i++) {
|
2021-02-06 04:07:03 +01:00
|
|
|
/* These IBOs have not been queried yet but we create them just in case they are needed
|
2020-11-03 10:55:18 +01:00
|
|
|
* later since they are not tracked by mesh_buffer_cache_create_requested(). */
|
2021-05-31 17:11:01 +02:00
|
|
|
if (mbc_final->tris_per_mat[i] == NULL) {
|
|
|
|
mbc_final->tris_per_mat[i] = GPU_indexbuf_calloc();
|
2020-11-03 10:55:18 +01:00
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
/* Multiply by 3 because these are triangle indices. */
|
2020-07-17 13:47:10 +02:00
|
|
|
const int mat_start = data->tri_mat_start[i];
|
|
|
|
const int mat_end = data->tri_mat_end[i];
|
|
|
|
const int start = mat_start * 3;
|
|
|
|
const int len = (mat_end - mat_start) * 3;
|
2021-05-31 17:11:01 +02:00
|
|
|
GPU_indexbuf_create_subrange_in_place(mbc_final->tris_per_mat[i], ibo, start, len);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
MEM_freeN(data->tri_mat_start);
|
|
|
|
MEM_freeN(data->tri_mat_end);
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_tris = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_tris_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_looptri_bm = extract_tris_iter_looptri_bm,
|
|
|
|
.iter_looptri_mesh = extract_tris_iter_looptri_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_tris_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Edges Indices
|
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_lines_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *UNUSED(buf))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_lines_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *elb)
|
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
/* Use #BMLoop.prev to match mesh order (to avoid minor differences in data extraction). */
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f)->prev;
|
|
|
|
do {
|
|
|
|
if (!BM_elem_flag_test(l_iter->e, BM_ELEM_HIDDEN)) {
|
|
|
|
GPU_indexbuf_set_line_verts(elb,
|
|
|
|
BM_elem_index_get(l_iter->e),
|
|
|
|
BM_elem_index_get(l_iter),
|
|
|
|
BM_elem_index_get(l_iter->next));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(l_iter->e));
|
|
|
|
}
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_lines_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int UNUSED(mp_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
/* Using poly & loop iterator would complicate accessing the adjacent loop. */
|
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const MEdge *medge = mr->medge;
|
|
|
|
if (mr->use_hide || (mr->extract_type == MR_EXTRACT_MAPPED) || (mr->e_origindex != NULL)) {
|
2021-05-31 17:11:01 +02:00
|
|
|
const int ml_index_last = mp->loopstart + (mp->totloop - 1);
|
|
|
|
int ml_index = ml_index_last, ml_index_next = mp->loopstart;
|
|
|
|
do {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
const MEdge *med = &medge[ml->e];
|
|
|
|
if (!((mr->use_hide && (med->flag & ME_HIDE)) ||
|
|
|
|
((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
|
|
|
|
(mr->e_origindex[ml->e] == ORIGINDEX_NONE)))) {
|
|
|
|
GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
GPU_indexbuf_set_line_restart(elb, ml->e);
|
|
|
|
}
|
|
|
|
} while ((ml_index = ml_index_next++) != ml_index_last);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
else {
|
2021-05-31 17:11:01 +02:00
|
|
|
const int ml_index_last = mp->loopstart + (mp->totloop - 1);
|
|
|
|
int ml_index = ml_index_last, ml_index_next = mp->loopstart;
|
|
|
|
do {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next);
|
|
|
|
} while ((ml_index = ml_index_next++) != ml_index_last);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_lines_iter_ledge_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMEdge *eed,
|
|
|
|
const int ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const int l_index_offset = mr->edge_len + ledge_index;
|
|
|
|
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
|
|
|
|
const int l_index = mr->loop_len + ledge_index * 2;
|
|
|
|
GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
else {
|
|
|
|
GPU_indexbuf_set_line_restart(elb, l_index_offset);
|
|
|
|
}
|
|
|
|
/* Don't render the edge twice. */
|
|
|
|
GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed));
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_lines_iter_ledge_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MEdge *med,
|
|
|
|
const uint ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const int l_index_offset = mr->edge_len + ledge_index;
|
|
|
|
const int e_index = mr->ledges[ledge_index];
|
|
|
|
if (!((mr->use_hide && (med->flag & ME_HIDE)) ||
|
|
|
|
((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
|
|
|
|
(mr->e_origindex[e_index] == ORIGINDEX_NONE)))) {
|
|
|
|
const int l_index = mr->loop_len + ledge_index * 2;
|
|
|
|
GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
else {
|
|
|
|
GPU_indexbuf_set_line_restart(elb, l_index_offset);
|
|
|
|
}
|
|
|
|
/* Don't render the edge twice. */
|
|
|
|
GPU_indexbuf_set_line_restart(elb, e_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2021-05-31 17:11:01 +02:00
|
|
|
void *buf,
|
2020-08-21 09:19:25 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUIndexBuf *ibo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_indexbuf_build_in_place(elb, ibo);
|
|
|
|
MEM_freeN(elb);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_lines = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_lines_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_lines_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_lines_iter_poly_mesh,
|
|
|
|
.iter_ledge_bm = extract_lines_iter_ledge_bm,
|
|
|
|
.iter_ledge_mesh = extract_lines_iter_ledge_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_lines_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines)};
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
/** \} */
|
|
|
|
|
2019-12-03 08:27:55 +01:00
|
|
|
/* ---------------------------------------------------------------------- */
|
2020-06-02 15:07:17 +02:00
|
|
|
/** \name Extract Loose Edges Sub Buffer
|
2019-12-03 08:27:55 +01:00
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshBatchCache *cache)
|
2019-12-03 08:27:55 +01:00
|
|
|
{
|
2020-08-21 09:19:25 +02:00
|
|
|
BLI_assert(cache->final.ibo.lines);
|
2019-12-03 08:27:55 +01:00
|
|
|
/* Multiply by 2 because these are edges indices. */
|
|
|
|
const int start = mr->edge_len * 2;
|
|
|
|
const int len = mr->edge_loose_len * 2;
|
|
|
|
GPU_indexbuf_create_subrange_in_place(
|
2020-08-21 09:19:25 +02:00
|
|
|
cache->final.ibo.lines_loose, cache->final.ibo.lines, start, len);
|
|
|
|
cache->no_loose_wire = (len == 0);
|
2019-12-03 08:27:55 +01:00
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *cache,
|
2021-05-31 17:11:01 +02:00
|
|
|
void *buf,
|
2020-08-21 09:19:25 +02:00
|
|
|
void *elb)
|
2020-06-02 15:07:17 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUIndexBuf *ibo = buf;
|
2020-06-02 15:07:17 +02:00
|
|
|
GPU_indexbuf_build_in_place(elb, ibo);
|
2020-08-21 09:19:25 +02:00
|
|
|
extract_lines_loose_subbuffer(mr, cache);
|
2020-06-02 15:07:17 +02:00
|
|
|
MEM_freeN(elb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MeshExtract extract_lines_with_lines_loose = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_lines_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_lines_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_lines_iter_poly_mesh,
|
|
|
|
.iter_ledge_bm = extract_lines_iter_ledge_bm,
|
|
|
|
.iter_ledge_mesh = extract_lines_iter_ledge_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_lines_with_lines_loose_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines)};
|
2019-12-03 08:27:55 +01:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Point Indices
|
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_points_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *UNUSED(buf))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
BLI_INLINE void vert_set_bm(GPUIndexBufBuilder *elb, BMVert *eve, int l_index)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
const int v_index = BM_elem_index_get(eve);
|
2019-07-14 16:49:44 +02:00
|
|
|
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
|
2020-06-30 16:13:39 +02:00
|
|
|
GPU_indexbuf_set_point_vert(elb, v_index, l_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
else {
|
2020-06-30 16:13:39 +02:00
|
|
|
GPU_indexbuf_set_point_restart(elb, v_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb,
|
|
|
|
const MeshRenderData *mr,
|
2020-06-30 16:13:39 +02:00
|
|
|
const int v_index,
|
|
|
|
const int l_index)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
const MVert *mv = &mr->mvert[v_index];
|
|
|
|
if (!((mr->use_hide && (mv->flag & ME_HIDE)) ||
|
2020-03-31 16:05:19 +02:00
|
|
|
((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) &&
|
2020-06-30 16:13:39 +02:00
|
|
|
(mr->v_origindex[v_index] == ORIGINDEX_NONE)))) {
|
|
|
|
GPU_indexbuf_set_point_vert(elb, v_index, l_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
else {
|
2020-06-30 16:13:39 +02:00
|
|
|
GPU_indexbuf_set_point_restart(elb, v_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_points_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
|
|
|
|
|
|
|
vert_set_bm(elb, l_iter->v, l_index);
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_points_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int UNUSED(mp_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
2020-06-30 16:13:39 +02:00
|
|
|
vert_set_mesh(elb, mr, ml->v, ml_index);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_points_iter_ledge_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMEdge *eed,
|
|
|
|
const int ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
vert_set_bm(elb, eed->v1, mr->loop_len + (ledge_index * 2));
|
|
|
|
vert_set_bm(elb, eed->v2, mr->loop_len + (ledge_index * 2) + 1);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_points_iter_ledge_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MEdge *med,
|
|
|
|
const uint ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
vert_set_mesh(elb, mr, med->v1, mr->loop_len + (ledge_index * 2));
|
|
|
|
vert_set_mesh(elb, mr, med->v2, mr->loop_len + (ledge_index * 2) + 1);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_points_iter_lvert_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMVert *eve,
|
|
|
|
const int lvert_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
|
2021-05-31 17:11:01 +02:00
|
|
|
vert_set_bm(elb, eve, offset + lvert_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_points_iter_lvert_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MVert *UNUSED(mv),
|
|
|
|
const int lvert_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
vert_set_mesh(elb, mr, mr->lverts[lvert_index], offset + lvert_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_points_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2021-05-31 17:11:01 +02:00
|
|
|
void *buf,
|
2020-08-21 09:19:25 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUIndexBuf *ibo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_indexbuf_build_in_place(elb, ibo);
|
|
|
|
MEM_freeN(elb);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_points = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_points_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_points_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_points_iter_poly_mesh,
|
|
|
|
.iter_ledge_bm = extract_points_iter_ledge_bm,
|
|
|
|
.iter_ledge_mesh = extract_points_iter_ledge_mesh,
|
|
|
|
.iter_lvert_bm = extract_points_iter_lvert_bm,
|
|
|
|
.iter_lvert_mesh = extract_points_iter_lvert_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_points_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.points)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Facedots Indices
|
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_fdots_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *UNUSED(buf))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
|
|
|
|
GPU_indexbuf_init(elb, GPU_PRIM_POINTS, mr->poly_len, mr->poly_len);
|
|
|
|
return elb;
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_fdots_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *f,
|
|
|
|
const int f_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
|
|
|
GPU_indexbuf_set_point_vert(elb, f_index, f_index);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
GPU_indexbuf_set_point_restart(elb, f_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int mp_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
if (mr->use_subsurf_fdots) {
|
|
|
|
/* Check #ME_VERT_FACEDOT. */
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
2020-06-30 16:13:39 +02:00
|
|
|
const MVert *mv = &mr->mvert[ml->v];
|
|
|
|
if ((mv->flag & ME_VERT_FACEDOT) && !(mr->use_hide && (mp->flag & ME_HIDE))) {
|
|
|
|
GPU_indexbuf_set_point_vert(elb, mp_index, mp_index);
|
2021-05-31 17:11:01 +02:00
|
|
|
return;
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
GPU_indexbuf_set_point_restart(elb, mp_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
else {
|
2021-05-31 17:11:01 +02:00
|
|
|
if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
|
|
|
|
GPU_indexbuf_set_point_vert(elb, mp_index, mp_index);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
GPU_indexbuf_set_point_restart(elb, mp_index);
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_fdots_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2021-05-31 17:11:01 +02:00
|
|
|
void *buf,
|
2020-08-21 09:19:25 +02:00
|
|
|
void *elb)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUIndexBuf *ibo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_indexbuf_build_in_place(elb, ibo);
|
|
|
|
MEM_freeN(elb);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_fdots = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_fdots_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_fdots_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_fdots_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_fdots_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.fdots)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \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;
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_lines_paint_mask_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2021-05-31 17:11:01 +02:00
|
|
|
void *UNUSED(ibo))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int UNUSED(mp_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
|
|
|
{
|
|
|
|
MeshExtract_LinePaintMask_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
const int e_index = ml->e;
|
|
|
|
const MEdge *me = &mr->medge[e_index];
|
|
|
|
if (!((mr->use_hide && (me->flag & ME_HIDE)) ||
|
|
|
|
((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
|
|
|
|
(mr->e_origindex[e_index] == ORIGINDEX_NONE)))) {
|
|
|
|
|
|
|
|
const int ml_index_last = mp->totloop + mp->loopstart - 1;
|
|
|
|
const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1);
|
|
|
|
if (mp->flag & ME_FACE_SEL) {
|
|
|
|
if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, e_index)) {
|
|
|
|
/* Hide edge as it has more than 2 selected loop. */
|
|
|
|
GPU_indexbuf_set_line_restart(&data->elb, e_index);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* First selected loop. Set edge visible, overwriting any unselected loop. */
|
|
|
|
GPU_indexbuf_set_line_verts(&data->elb, e_index, ml_index, ml_index_other);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
else {
|
2021-02-06 04:07:03 +01:00
|
|
|
/* Set these unselected loop only if this edge has no other selected loop. */
|
2020-06-30 16:13:39 +02:00
|
|
|
if (!BLI_BITMAP_TEST(data->select_map, e_index)) {
|
|
|
|
GPU_indexbuf_set_line_verts(&data->elb, e_index, ml_index, ml_index_other);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-06-30 16:13:39 +02:00
|
|
|
GPU_indexbuf_set_line_restart(&data->elb, e_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
|
2020-08-21 09:19:25 +02:00
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2021-05-31 17:11:01 +02:00
|
|
|
void *buf,
|
2019-07-14 16:49:44 +02:00
|
|
|
void *_data)
|
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUIndexBuf *ibo = buf;
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_LinePaintMask_Data *data = _data;
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_indexbuf_build_in_place(&data->elb, ibo);
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_lines_paint_mask = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_lines_paint_mask_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_mesh = extract_lines_paint_mask_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_lines_paint_mask_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_paint_mask)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \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;
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_lines_adjacency_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *UNUSED(buf))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
/* Similar to poly_to_tri_count().
|
2020-06-25 08:56:49 +02:00
|
|
|
* There is always (loop + triangle - 1) edges inside a polygon.
|
2019-08-16 16:54:22 +02:00
|
|
|
* Accumulate for all polys and you get : */
|
2019-07-14 16:49:44 +02:00
|
|
|
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;
|
2020-06-25 08:56:49 +02:00
|
|
|
/* Iterate around the triangle's edges. */
|
2019-07-14 16:49:44 +02:00
|
|
|
for (int e = 0; e < 3; e++) {
|
2019-09-21 03:34:39 +02:00
|
|
|
SHIFT3(uint, v3, v2, v1);
|
|
|
|
SHIFT3(uint, l3, l2, l1);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
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
|
2020-06-25 08:56:49 +02:00
|
|
|
* Edge-hash sort the keys and we need to compare winding later. */
|
2019-07-14 16:49:44 +02:00
|
|
|
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;
|
2020-06-25 08:56:49 +02:00
|
|
|
/* TODO Make this part thread-safe. */
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_lines_adjacency_iter_looptri_bm(const MeshRenderData *UNUSED(mr),
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop **elt,
|
|
|
|
const int UNUSED(elt_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
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);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoopTri *mlt,
|
|
|
|
const int UNUSED(elt_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp = &mr->mpoly[mlt->poly];
|
|
|
|
if (!(mr->use_hide && (mp->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);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *cache,
|
2021-05-31 17:11:01 +02:00
|
|
|
void *buf,
|
2020-08-21 09:19:25 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUIndexBuf *ibo = buf;
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_LineAdjacency_Data *data = _data;
|
2019-07-14 16:49:44 +02:00
|
|
|
/* 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);
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
cache->is_manifold = data->is_manifold;
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
GPU_indexbuf_build_in_place(&data->elb, ibo);
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef NO_EDGE
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_lines_adjacency = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_lines_adjacency_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm,
|
|
|
|
.iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_lines_adjacency_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_adjacency)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Edit UV Triangles Indices
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct MeshExtract_EditUvElem_Data {
|
|
|
|
GPUIndexBufBuilder elb;
|
|
|
|
bool sync_selection;
|
|
|
|
} MeshExtract_EditUvElem_Data;
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_edituv_tris_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *UNUSED(ibo))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edituv_tris_iter_looptri_bm(const MeshRenderData *UNUSED(mr),
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop **elt,
|
|
|
|
const int UNUSED(elt_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
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]));
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoopTri *mlt,
|
|
|
|
const int UNUSED(elt_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp = &mr->mpoly[mlt->poly];
|
|
|
|
edituv_tri_add(data,
|
|
|
|
(mp->flag & ME_HIDE) != 0,
|
|
|
|
(mp->flag & ME_FACE_SEL) != 0,
|
|
|
|
mlt->tri[0],
|
|
|
|
mlt->tri[1],
|
|
|
|
mlt->tri[2]);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2021-05-31 17:11:01 +02:00
|
|
|
void *buf,
|
2020-08-21 09:19:25 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUIndexBuf *ibo = buf;
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_EditUvElem_Data *extract_data = data;
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
|
|
|
|
MEM_freeN(extract_data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_edituv_tris = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_edituv_tris_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_looptri_bm = extract_edituv_tris_iter_looptri_bm,
|
|
|
|
.iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_edituv_tris_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_tris)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Edit UV Line Indices around faces
|
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_edituv_lines_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *UNUSED(ibo))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
edituv_edge_add(data,
|
2021-05-31 17:11:01 +02:00
|
|
|
BM_elem_flag_test_bool(f, BM_ELEM_HIDDEN),
|
|
|
|
BM_elem_flag_test_bool(f, BM_ELEM_SELECT),
|
2020-06-30 16:13:39 +02:00
|
|
|
l_index,
|
2021-05-31 17:11:01 +02:00
|
|
|
BM_elem_index_get(l_iter->next));
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int UNUSED(mp_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
const int ml_index_last = mp->totloop + mp->loopstart - 1;
|
|
|
|
const int ml_index_next = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1);
|
|
|
|
const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[ml->e] != ORIGINDEX_NONE);
|
|
|
|
edituv_edge_add(data,
|
|
|
|
(mp->flag & ME_HIDE) != 0 || !real_edge,
|
|
|
|
(mp->flag & ME_FACE_SEL) != 0,
|
|
|
|
ml_index,
|
|
|
|
ml_index_next);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2021-05-31 17:11:01 +02:00
|
|
|
void *buf,
|
2020-08-21 09:19:25 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUIndexBuf *ibo = buf;
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_EditUvElem_Data *extract_data = data;
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
|
|
|
|
MEM_freeN(extract_data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_edituv_lines = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_edituv_lines_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_edituv_lines_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_edituv_lines_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_edituv_lines_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_lines)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Edit UV Points Indices
|
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_edituv_points_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *UNUSED(ibo))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_edituv_points_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
|
|
|
|
|
|
|
edituv_point_add(
|
|
|
|
data, BM_elem_flag_test(f, BM_ELEM_HIDDEN), BM_elem_flag_test(f, BM_ELEM_SELECT), l_index);
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int UNUSED(mp_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
|
|
|
|
mr->v_origindex[ml->v] != ORIGINDEX_NONE);
|
|
|
|
edituv_point_add(
|
|
|
|
data, ((mp->flag & ME_HIDE) != 0) || !real_vert, (mp->flag & ME_FACE_SEL) != 0, ml_index);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2021-05-31 17:11:01 +02:00
|
|
|
void *buf,
|
2020-08-21 09:19:25 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUIndexBuf *ibo = buf;
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_EditUvElem_Data *extract_data = data;
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
|
|
|
|
MEM_freeN(extract_data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_edituv_points = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_edituv_points_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_edituv_points_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_edituv_points_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_edituv_points_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_points)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Edit UV Facedots Indices
|
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_edituv_fdots_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *UNUSED(ibo))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
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,
|
2020-06-30 16:13:39 +02:00
|
|
|
int face_index)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
if (!hidden && (data->sync_selection || selected)) {
|
2020-06-30 16:13:39 +02:00
|
|
|
GPU_indexbuf_set_point_vert(&data->elb, face_index, face_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
else {
|
2020-06-30 16:13:39 +02:00
|
|
|
GPU_indexbuf_set_point_restart(&data->elb, face_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_edituv_fdots_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *f,
|
|
|
|
const int f_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
edituv_facedot_add(data,
|
|
|
|
BM_elem_flag_test_bool(f, BM_ELEM_HIDDEN),
|
|
|
|
BM_elem_flag_test_bool(f, BM_ELEM_SELECT),
|
|
|
|
f_index);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int mp_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
if (mr->use_subsurf_fdots) {
|
|
|
|
/* Check #ME_VERT_FACEDOT. */
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
|
|
|
|
mr->p_origindex[mp_index] != ORIGINDEX_NONE);
|
|
|
|
const bool subd_fdot = (!mr->use_subsurf_fdots ||
|
|
|
|
(mr->mvert[ml->v].flag & ME_VERT_FACEDOT) != 0);
|
|
|
|
edituv_facedot_add(data,
|
|
|
|
((mp->flag & ME_HIDE) != 0) || !real_fdot || !subd_fdot,
|
|
|
|
(mp->flag & ME_FACE_SEL) != 0,
|
|
|
|
mp_index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2021-05-31 17:11:01 +02:00
|
|
|
const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
|
|
|
|
mr->p_origindex[mp_index] != ORIGINDEX_NONE);
|
|
|
|
edituv_facedot_add(
|
|
|
|
data, ((mp->flag & ME_HIDE) != 0) || !real_fdot, (mp->flag & ME_FACE_SEL) != 0, mp_index);
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2021-05-31 17:11:01 +02:00
|
|
|
void *buf,
|
2020-08-21 09:19:25 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUIndexBuf *ibo = buf;
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_EditUvElem_Data *data = _data;
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_indexbuf_build_in_place(&data->elb, ibo);
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_edituv_fdots = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_edituv_fdots_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_edituv_fdots_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_edituv_fdots_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_edituv_fdots_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_fdots)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Position and Vertex Normal
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct PosNorLoop {
|
|
|
|
float pos[3];
|
|
|
|
GPUPackedNormal nor;
|
|
|
|
} PosNorLoop;
|
|
|
|
|
|
|
|
typedef struct MeshExtract_PosNor_Data {
|
|
|
|
PosNorLoop *vbo_data;
|
2021-01-11 08:44:53 +01:00
|
|
|
GPUNormal normals[];
|
2019-07-14 16:49:44 +02:00
|
|
|
} MeshExtract_PosNor_Data;
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_pos_nor_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
2020-06-25 08:56:49 +02:00
|
|
|
/* WARNING Adjust #PosNorLoop struct accordingly. */
|
2019-07-14 16:49:44 +02:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
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. */
|
2021-01-11 08:44:53 +01:00
|
|
|
size_t packed_nor_len = sizeof(GPUNormal) * mr->vert_len;
|
2019-07-14 16:49:44 +02:00
|
|
|
MeshExtract_PosNor_Data *data = MEM_mallocN(sizeof(*data) + packed_nor_len, __func__);
|
2020-09-06 16:40:07 +02:00
|
|
|
data->vbo_data = (PosNorLoop *)GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/* 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) {
|
2021-01-11 08:44:53 +01:00
|
|
|
data->normals[v].low = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, eve));
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-06-30 16:13:39 +02:00
|
|
|
const MVert *mv = mr->mvert;
|
|
|
|
for (int v = 0; v < mr->vert_len; v++, mv++) {
|
2021-01-11 08:44:53 +01:00
|
|
|
data->normals[v].low = GPU_normal_convert_i10_s3(mv->no);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_pos_nor_iter_poly_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MeshExtract_PosNor_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
2020-06-30 16:13:39 +02:00
|
|
|
PosNorLoop *vert = &data->vbo_data[l_index];
|
2021-05-31 17:11:01 +02:00
|
|
|
copy_v3_v3(vert->pos, bm_vert_co_get(mr, l_iter->v));
|
|
|
|
vert->nor = data->normals[BM_elem_index_get(l_iter->v)].low;
|
|
|
|
vert->nor.w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0;
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int UNUSED(mp_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MeshExtract_PosNor_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
PosNorLoop *vert = &data->vbo_data[ml_index];
|
|
|
|
const MVert *mv = &mr->mvert[ml->v];
|
|
|
|
copy_v3_v3(vert->pos, mv->co);
|
2021-01-11 08:44:53 +01:00
|
|
|
vert->nor = data->normals[ml->v].low;
|
2020-06-30 16:13:39 +02:00
|
|
|
/* Flag for paint mode overlay. */
|
|
|
|
if (mp->flag & ME_HIDE || mv->flag & ME_HIDE ||
|
|
|
|
((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) &&
|
|
|
|
(mr->v_origindex[ml->v] == ORIGINDEX_NONE))) {
|
|
|
|
vert->nor.w = -1;
|
|
|
|
}
|
|
|
|
else if (mv->flag & SELECT) {
|
|
|
|
vert->nor.w = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
vert->nor.w = 0;
|
|
|
|
}
|
2019-08-27 05:45:26 +02:00
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_pos_nor_iter_ledge_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMEdge *eed,
|
|
|
|
const int ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MeshExtract_PosNor_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
int l_index = mr->loop_len + ledge_index * 2;
|
|
|
|
PosNorLoop *vert = &data->vbo_data[l_index];
|
|
|
|
copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
|
|
|
|
copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
|
|
|
|
vert[0].nor = data->normals[BM_elem_index_get(eed->v1)].low;
|
|
|
|
vert[1].nor = data->normals[BM_elem_index_get(eed->v2)].low;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_pos_nor_iter_ledge_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MEdge *med,
|
|
|
|
const uint ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MeshExtract_PosNor_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
const int ml_index = mr->loop_len + ledge_index * 2;
|
|
|
|
PosNorLoop *vert = &data->vbo_data[ml_index];
|
|
|
|
copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co);
|
|
|
|
copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co);
|
|
|
|
vert[0].nor = data->normals[med->v1].low;
|
|
|
|
vert[1].nor = data->normals[med->v2].low;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_pos_nor_iter_lvert_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMVert *eve,
|
|
|
|
const int lvert_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MeshExtract_PosNor_Data *data = _data;
|
2020-06-30 16:13:39 +02:00
|
|
|
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
const int l_index = offset + lvert_index;
|
|
|
|
PosNorLoop *vert = &data->vbo_data[l_index];
|
|
|
|
copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
|
|
|
|
vert->nor = data->normals[BM_elem_index_get(eve)].low;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MVert *mv,
|
|
|
|
const int lvert_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MeshExtract_PosNor_Data *data = _data;
|
2020-06-30 16:13:39 +02:00
|
|
|
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
const int ml_index = offset + lvert_index;
|
|
|
|
const int v_index = mr->lverts[lvert_index];
|
|
|
|
PosNorLoop *vert = &data->vbo_data[ml_index];
|
|
|
|
copy_v3_v3(vert->pos, mv->co);
|
|
|
|
vert->nor = data->normals[v_index].low;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2021-05-31 17:11:01 +02:00
|
|
|
void *UNUSED(buf),
|
2020-08-21 09:19:25 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_pos_nor = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_pos_nor_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_pos_nor_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_pos_nor_iter_poly_mesh,
|
|
|
|
.iter_ledge_bm = extract_pos_nor_iter_ledge_bm,
|
|
|
|
.iter_ledge_mesh = extract_pos_nor_iter_ledge_mesh,
|
|
|
|
.iter_lvert_bm = extract_pos_nor_iter_lvert_bm,
|
|
|
|
.iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_pos_nor_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor)};
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
/** \} */
|
|
|
|
|
2021-01-11 08:44:53 +01:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Position and High Quality Vertex Normal
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct PosNorHQLoop {
|
|
|
|
float pos[3];
|
|
|
|
short nor[4];
|
|
|
|
} PosNorHQLoop;
|
|
|
|
|
|
|
|
typedef struct MeshExtract_PosNorHQ_Data {
|
|
|
|
PosNorHQLoop *vbo_data;
|
|
|
|
GPUNormal normals[];
|
|
|
|
} MeshExtract_PosNorHQ_Data;
|
|
|
|
|
|
|
|
static void *extract_pos_nor_hq_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2021-01-11 08:44:53 +01:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
|
|
|
/* WARNING Adjust #PosNorHQLoop struct accordingly. */
|
|
|
|
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
|
|
|
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
|
|
|
GPU_vertformat_alias_add(&format, "vnor");
|
|
|
|
}
|
|
|
|
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(GPUNormal) * mr->vert_len;
|
|
|
|
MeshExtract_PosNorHQ_Data *data = MEM_mallocN(sizeof(*data) + packed_nor_len, __func__);
|
|
|
|
data->vbo_data = (PosNorHQLoop *)GPU_vertbuf_get_data(vbo);
|
|
|
|
|
|
|
|
/* 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) {
|
|
|
|
normal_float_to_short_v3(data->normals[v].high, bm_vert_no_get(mr, eve));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const MVert *mv = mr->mvert;
|
|
|
|
for (int v = 0; v < mr->vert_len; v++, mv++) {
|
|
|
|
copy_v3_v3_short(data->normals[v].high, mv->no);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_pos_nor_hq_iter_poly_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2021-01-11 08:44:53 +01:00
|
|
|
void *_data)
|
|
|
|
{
|
|
|
|
MeshExtract_PosNorHQ_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
2021-01-11 08:44:53 +01:00
|
|
|
PosNorHQLoop *vert = &data->vbo_data[l_index];
|
2021-05-31 17:11:01 +02:00
|
|
|
copy_v3_v3(vert->pos, bm_vert_co_get(mr, l_iter->v));
|
|
|
|
copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(l_iter->v)].high);
|
2021-01-11 08:44:53 +01:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
BMFace *efa = l_iter->f;
|
2021-01-11 08:44:53 +01:00
|
|
|
vert->nor[3] = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
|
2021-05-31 17:11:01 +02:00
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2021-01-11 08:44:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_pos_nor_hq_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int UNUSED(mp_index),
|
2021-01-11 08:44:53 +01:00
|
|
|
void *_data)
|
|
|
|
{
|
|
|
|
MeshExtract_PosNorHQ_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
|
2021-01-11 08:44:53 +01:00
|
|
|
PosNorHQLoop *vert = &data->vbo_data[ml_index];
|
|
|
|
const MVert *mv = &mr->mvert[ml->v];
|
|
|
|
copy_v3_v3(vert->pos, mv->co);
|
|
|
|
copy_v3_v3_short(vert->nor, data->normals[ml->v].high);
|
|
|
|
|
|
|
|
/* Flag for paint mode overlay. */
|
|
|
|
if (mp->flag & ME_HIDE || mv->flag & ME_HIDE ||
|
|
|
|
((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) &&
|
|
|
|
(mr->v_origindex[ml->v] == ORIGINDEX_NONE))) {
|
|
|
|
vert->nor[3] = -1;
|
|
|
|
}
|
|
|
|
else if (mv->flag & SELECT) {
|
|
|
|
vert->nor[3] = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
vert->nor[3] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_pos_nor_hq_iter_ledge_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMEdge *eed,
|
|
|
|
const int ledge_index,
|
2021-01-11 08:44:53 +01:00
|
|
|
void *_data)
|
|
|
|
{
|
|
|
|
MeshExtract_PosNorHQ_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
int l_index = mr->loop_len + ledge_index * 2;
|
|
|
|
PosNorHQLoop *vert = &data->vbo_data[l_index];
|
|
|
|
copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
|
|
|
|
copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
|
|
|
|
copy_v3_v3_short(vert[0].nor, data->normals[BM_elem_index_get(eed->v1)].high);
|
|
|
|
vert[0].nor[3] = 0;
|
|
|
|
copy_v3_v3_short(vert[1].nor, data->normals[BM_elem_index_get(eed->v2)].high);
|
|
|
|
vert[1].nor[3] = 0;
|
2021-01-11 08:44:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_pos_nor_hq_iter_ledge_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MEdge *med,
|
|
|
|
const uint ledge_index,
|
2021-01-11 08:44:53 +01:00
|
|
|
void *_data)
|
|
|
|
{
|
|
|
|
MeshExtract_PosNorHQ_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
const int ml_index = mr->loop_len + ledge_index * 2;
|
|
|
|
PosNorHQLoop *vert = &data->vbo_data[ml_index];
|
|
|
|
copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co);
|
|
|
|
copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co);
|
|
|
|
copy_v3_v3_short(vert[0].nor, data->normals[med->v1].high);
|
|
|
|
vert[0].nor[3] = 0;
|
|
|
|
copy_v3_v3_short(vert[1].nor, data->normals[med->v2].high);
|
|
|
|
vert[1].nor[3] = 0;
|
2021-01-11 08:44:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_pos_nor_hq_iter_lvert_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMVert *eve,
|
|
|
|
const int lvert_index,
|
2021-01-11 08:44:53 +01:00
|
|
|
void *_data)
|
|
|
|
{
|
|
|
|
MeshExtract_PosNorHQ_Data *data = _data;
|
|
|
|
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
const int l_index = offset + lvert_index;
|
|
|
|
PosNorHQLoop *vert = &data->vbo_data[l_index];
|
|
|
|
copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
|
|
|
|
copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(eve)].high);
|
|
|
|
vert->nor[3] = 0;
|
2021-01-11 08:44:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_pos_nor_hq_iter_lvert_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MVert *mv,
|
|
|
|
const int lvert_index,
|
2021-01-11 08:44:53 +01:00
|
|
|
void *_data)
|
|
|
|
{
|
|
|
|
MeshExtract_PosNorHQ_Data *data = _data;
|
|
|
|
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
const int ml_index = offset + lvert_index;
|
|
|
|
const int v_index = mr->lverts[lvert_index];
|
|
|
|
PosNorHQLoop *vert = &data->vbo_data[ml_index];
|
|
|
|
copy_v3_v3(vert->pos, mv->co);
|
|
|
|
copy_v3_v3_short(vert->nor, data->normals[v_index].high);
|
|
|
|
vert->nor[3] = 0;
|
2021-01-11 08:44:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_pos_nor_hq_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2021-05-31 17:11:01 +02:00
|
|
|
void *UNUSED(buf),
|
2021-01-11 08:44:53 +01:00
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MeshExtract extract_pos_nor_hq = {
|
|
|
|
.init = extract_pos_nor_hq_init,
|
|
|
|
.iter_poly_bm = extract_pos_nor_hq_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_pos_nor_hq_iter_poly_mesh,
|
|
|
|
.iter_ledge_bm = extract_pos_nor_hq_iter_ledge_bm,
|
|
|
|
.iter_ledge_mesh = extract_pos_nor_hq_iter_ledge_mesh,
|
|
|
|
.iter_lvert_bm = extract_pos_nor_hq_iter_lvert_bm,
|
|
|
|
.iter_lvert_mesh = extract_pos_nor_hq_iter_lvert_mesh,
|
|
|
|
.finish = extract_pos_nor_hq_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor)};
|
2021-01-11 08:44:53 +01:00
|
|
|
|
|
|
|
/** \} */
|
2020-02-19 01:44:52 +01:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract HQ Loop Normal
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct gpuHQNor {
|
|
|
|
short x, y, z, w;
|
|
|
|
} gpuHQNor;
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_lnor_hq_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2020-02-19 01:44:52 +01:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2020-02-19 01:44:52 +01:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
|
|
|
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
|
|
|
GPU_vertformat_alias_add(&format, "lnor");
|
|
|
|
}
|
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
|
|
|
|
|
2020-09-06 16:40:07 +02:00
|
|
|
return GPU_vertbuf_get_data(vbo);
|
2020-02-19 01:44:52 +01:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2020-02-19 01:44:52 +01:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
|
|
|
if (mr->loop_normals) {
|
2020-06-30 16:13:39 +02:00
|
|
|
normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, mr->loop_normals[l_index]);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
else {
|
|
|
|
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
|
|
|
|
normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_vert_no_get(mr, l_iter->v));
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
|
|
|
else {
|
2021-05-31 17:11:01 +02:00
|
|
|
normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_face_no_get(mr, f));
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2020-02-19 01:44:52 +01:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int mp_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2020-02-19 01:44:52 +01:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
2020-06-30 16:13:39 +02:00
|
|
|
gpuHQNor *lnor_data = &((gpuHQNor *)data)[ml_index];
|
|
|
|
if (mr->loop_normals) {
|
|
|
|
normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]);
|
|
|
|
}
|
|
|
|
else if (mp->flag & ME_SMOOTH) {
|
|
|
|
copy_v3_v3_short(&lnor_data->x, mr->mvert[ml->v].no);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]);
|
|
|
|
}
|
2020-03-30 14:03:28 +02:00
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
/* Flag for paint mode overlay.
|
|
|
|
* Only use #MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals.
|
|
|
|
* In paint mode it will use the un-mapped data to draw the wire-frame. */
|
|
|
|
if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED &&
|
|
|
|
(mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) {
|
|
|
|
lnor_data->w = -1;
|
|
|
|
}
|
|
|
|
else if (mp->flag & ME_FACE_SEL) {
|
|
|
|
lnor_data->w = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lnor_data->w = 0;
|
|
|
|
}
|
2020-02-19 01:44:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MeshExtract extract_lnor_hq = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_lnor_hq_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_lnor_hq_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_lnor_hq_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.data_flag = MR_DATA_LOOP_NOR,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor)};
|
2020-02-19 01:44:52 +01:00
|
|
|
|
|
|
|
/** \} */
|
2019-07-14 16:49:44 +02:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Loop Normal
|
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_lnor_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
2019-08-26 18:43:46 +02:00
|
|
|
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_vertformat_alias_add(&format, "lnor");
|
|
|
|
}
|
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
|
|
|
|
|
2020-09-06 16:40:07 +02:00
|
|
|
return GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_lnor_iter_poly_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
|
|
|
if (mr->loop_normals) {
|
2020-06-30 16:13:39 +02:00
|
|
|
((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
else {
|
|
|
|
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
|
|
|
|
((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(
|
|
|
|
bm_vert_no_get(mr, l_iter->v));
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
|
|
|
else {
|
2021-05-31 17:11:01 +02:00
|
|
|
((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, f));
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0;
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int mp_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
2020-06-30 16:13:39 +02:00
|
|
|
GPUPackedNormal *lnor_data = &((GPUPackedNormal *)data)[ml_index];
|
|
|
|
if (mr->loop_normals) {
|
|
|
|
*lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]);
|
|
|
|
}
|
|
|
|
else if (mp->flag & ME_SMOOTH) {
|
|
|
|
*lnor_data = GPU_normal_convert_i10_s3(mr->mvert[ml->v].no);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]);
|
|
|
|
}
|
2020-03-30 14:03:28 +02:00
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
/* Flag for paint mode overlay.
|
|
|
|
* Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals.
|
|
|
|
* In paint mode it will use the un-mapped data to draw the wire-frame. */
|
|
|
|
if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED &&
|
|
|
|
(mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) {
|
|
|
|
lnor_data->w = -1;
|
|
|
|
}
|
|
|
|
else if (mp->flag & ME_FACE_SEL) {
|
|
|
|
lnor_data->w = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lnor_data->w = 0;
|
|
|
|
}
|
2019-08-27 05:45:26 +02:00
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_lnor = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_lnor_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_lnor_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_lnor_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.data_flag = MR_DATA_LOOP_NOR,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
2019-08-14 22:43:44 +02:00
|
|
|
/** \name Extract UV layers
|
2019-07-14 16:49:44 +02:00
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_uv_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
GPUVertFormat format = {0};
|
|
|
|
GPU_vertformat_deinterleave(&format);
|
|
|
|
|
|
|
|
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
|
2020-08-21 09:19:25 +02:00
|
|
|
uint32_t uv_layers = cache->cd_used.uv;
|
2019-10-08 18:35:57 +02:00
|
|
|
/* HACK to fix T68857 */
|
2020-08-21 09:19:25 +02:00
|
|
|
if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) {
|
2019-10-08 18:35:57 +02:00
|
|
|
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
|
|
|
|
if (layer != -1) {
|
|
|
|
uv_layers |= (1 << layer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
for (int i = 0; i < MAX_MTFACE; i++) {
|
|
|
|
if (uv_layers & (1 << i)) {
|
2020-04-03 07:59:34 +02:00
|
|
|
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
|
2019-07-14 16:49:44 +02:00
|
|
|
const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
|
2019-08-14 22:18:47 +02:00
|
|
|
|
2020-04-03 07:59:34 +02:00
|
|
|
GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
|
2019-07-14 16:49:44 +02:00
|
|
|
/* UV layer name. */
|
2019-08-14 22:18:47 +02:00
|
|
|
BLI_snprintf(attr_name, sizeof(attr_name), "u%s", attr_safe_name);
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
|
|
|
/* Auto layer name. */
|
2019-08-14 22:18:47 +02:00
|
|
|
BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
|
2019-07-14 16:49:44 +02:00
|
|
|
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");
|
2020-06-25 08:56:49 +02:00
|
|
|
/* Alias to `pos` for edit uvs. */
|
2019-07-14 16:49:44 +02:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-14 22:43:44 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, v_len);
|
|
|
|
|
2020-09-06 16:40:07 +02:00
|
|
|
float(*uv_data)[2] = (float(*)[2])GPU_vertbuf_get_data(vbo);
|
2019-08-14 22:43:44 +02:00
|
|
|
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);
|
2020-06-25 08:44:36 +02:00
|
|
|
BMIter f_iter;
|
2019-08-14 22:43:44 +02:00
|
|
|
BMFace *efa;
|
|
|
|
BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
|
2020-06-25 08:44:36 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
|
|
|
|
do {
|
|
|
|
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs);
|
2019-08-14 22:43:44 +02:00
|
|
|
memcpy(uv_data, luv->uv, sizeof(*uv_data));
|
|
|
|
uv_data++;
|
2020-06-25 08:44:36 +02:00
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-08-14 22:43:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
MLoopUV *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, uv_data++, layer_data++) {
|
2019-08-14 22:43:44 +02:00
|
|
|
memcpy(uv_data, layer_data->uv, sizeof(*uv_data));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static const MeshExtract extract_uv = {.init = extract_uv_init,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.uv)};
|
2019-08-22 18:22:23 +02:00
|
|
|
|
2019-08-14 22:43:44 +02:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Tangent layers
|
|
|
|
* \{ */
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_tan_ex_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *cache,
|
|
|
|
GPUVertBuf *vbo,
|
|
|
|
const bool do_hq)
|
2019-08-14 22:43:44 +02:00
|
|
|
{
|
2020-02-20 00:13:48 +01:00
|
|
|
GPUVertCompType comp_type = do_hq ? GPU_COMP_I16 : GPU_COMP_I10;
|
|
|
|
GPUVertFetchMode fetch_mode = GPU_FETCH_INT_TO_FLOAT_UNIT;
|
2020-02-19 01:44:52 +01:00
|
|
|
|
2019-08-14 22:43:44 +02:00
|
|
|
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;
|
2020-08-21 09:19:25 +02:00
|
|
|
uint32_t tan_layers = cache->cd_used.tan;
|
2019-08-14 22:43:44 +02:00
|
|
|
float(*orco)[3] = CustomData_get_layer(cd_vdata, CD_ORCO);
|
|
|
|
bool orco_allocated = false;
|
2020-08-21 09:19:25 +02:00
|
|
|
const bool use_orco_tan = cache->cd_used.tan_orco != 0;
|
2019-08-14 22:43:44 +02:00
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
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)) {
|
2020-04-03 07:59:34 +02:00
|
|
|
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
|
2019-07-14 16:49:44 +02:00
|
|
|
const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
|
2020-04-03 07:59:34 +02:00
|
|
|
GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
|
2019-07-14 16:49:44 +02:00
|
|
|
/* Tangent layer name. */
|
2019-08-14 22:18:47 +02:00
|
|
|
BLI_snprintf(attr_name, sizeof(attr_name), "t%s", attr_safe_name);
|
2020-02-19 01:44:52 +01:00
|
|
|
GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode);
|
2019-07-14 16:49:44 +02:00
|
|
|
/* 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) {
|
2020-06-25 08:56:49 +02:00
|
|
|
/* If `orco` is not available compute it ourselves */
|
2019-07-14 16:49:44 +02:00
|
|
|
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++) {
|
2020-05-25 12:16:42 +02:00
|
|
|
const BMVert *eve = BM_vert_at_index(bm, v);
|
|
|
|
/* Exceptional case where #bm_vert_co_get can be avoided, as we want the original coords.
|
|
|
|
* not the distorted ones. */
|
|
|
|
copy_v3_v3(orco[v], eve->co);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-06-30 16:13:39 +02:00
|
|
|
const MVert *mv = mr->mvert;
|
|
|
|
for (int v = 0; v < mr->vert_len; v++, mv++) {
|
|
|
|
copy_v3_v3(orco[v], mv->co);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
BKE_mesh_orco_verts_transform(mr->me, orco, mr->vert_len, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start Fresh */
|
2020-06-23 14:28:08 +02:00
|
|
|
CustomData loop_data;
|
|
|
|
CustomData_reset(&loop_data);
|
2019-07-14 16:49:44 +02:00
|
|
|
if (tan_len != 0 || use_orco_tan) {
|
|
|
|
short tangent_mask = 0;
|
|
|
|
bool calc_active_tangent = false;
|
|
|
|
if (mr->extract_type == MR_EXTRACT_BMESH) {
|
2020-03-23 18:18:36 +01:00
|
|
|
BKE_editmesh_loop_tangent_calc(mr->edit_bmesh,
|
2019-07-14 16:49:44 +02:00
|
|
|
calc_active_tangent,
|
|
|
|
tangent_names,
|
|
|
|
tan_len,
|
|
|
|
mr->poly_normals,
|
|
|
|
mr->loop_normals,
|
|
|
|
orco,
|
2020-07-02 11:28:25 +02:00
|
|
|
&loop_data,
|
2019-07-14 16:49:44 +02:00
|
|
|
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,
|
2020-06-23 14:28:08 +02:00
|
|
|
&loop_data,
|
2019-07-14 16:49:44 +02:00
|
|
|
mr->loop_len,
|
|
|
|
&tangent_mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (use_orco_tan) {
|
2020-04-03 07:59:34 +02:00
|
|
|
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
|
2020-07-02 11:28:25 +02:00
|
|
|
const char *layer_name = CustomData_get_layer_name(&loop_data, CD_TANGENT, 0);
|
2020-04-03 07:59:34 +02:00
|
|
|
GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
|
2019-08-14 22:18:47 +02:00
|
|
|
BLI_snprintf(attr_name, sizeof(*attr_name), "t%s", attr_safe_name);
|
2020-02-19 01:44:52 +01:00
|
|
|
GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode);
|
2019-07-14 16:49:44 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, v_len);
|
|
|
|
|
2020-02-19 01:44:52 +01:00
|
|
|
if (do_hq) {
|
2020-09-06 16:40:07 +02:00
|
|
|
short(*tan_data)[4] = (short(*)[4])GPU_vertbuf_get_data(vbo);
|
2020-02-19 01:44:52 +01:00
|
|
|
for (int i = 0; i < tan_len; i++) {
|
|
|
|
const char *name = tangent_names[i];
|
2020-07-02 11:28:25 +02:00
|
|
|
float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(
|
|
|
|
&loop_data, CD_TANGENT, name);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
|
|
|
|
normal_float_to_short_v3(*tan_data, layer_data[ml_index]);
|
|
|
|
(*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
|
2020-02-19 01:44:52 +01:00
|
|
|
tan_data++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (use_orco_tan) {
|
2020-07-02 11:28:25 +02:00
|
|
|
float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
|
|
|
|
normal_float_to_short_v3(*tan_data, layer_data[ml_index]);
|
|
|
|
(*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
|
2020-02-19 01:44:52 +01:00
|
|
|
tan_data++;
|
|
|
|
}
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
2020-02-19 01:44:52 +01:00
|
|
|
else {
|
2020-09-06 16:40:07 +02:00
|
|
|
GPUPackedNormal *tan_data = (GPUPackedNormal *)GPU_vertbuf_get_data(vbo);
|
2020-02-19 01:44:52 +01:00
|
|
|
for (int i = 0; i < tan_len; i++) {
|
|
|
|
const char *name = tangent_names[i];
|
2020-07-02 11:28:25 +02:00
|
|
|
float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(
|
|
|
|
&loop_data, CD_TANGENT, name);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
|
|
|
|
*tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]);
|
|
|
|
tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2;
|
2020-02-19 01:44:52 +01:00
|
|
|
tan_data++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (use_orco_tan) {
|
2020-07-02 11:28:25 +02:00
|
|
|
float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
|
|
|
|
*tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]);
|
|
|
|
tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2;
|
2020-02-19 01:44:52 +01:00
|
|
|
tan_data++;
|
|
|
|
}
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-23 14:28:08 +02:00
|
|
|
CustomData_free(&loop_data, mr->loop_len);
|
2020-02-19 01:44:52 +01:00
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_tan_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
|
2020-02-19 01:44:52 +01:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_tan_ex_init(mr, cache, buf, false);
|
2019-07-14 16:49:44 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static const MeshExtract extract_tan = {.init = extract_tan_init,
|
|
|
|
.data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR |
|
|
|
|
MR_DATA_LOOPTRI,
|
|
|
|
.use_threading = false,
|
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.tan)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2020-02-19 01:44:52 +01:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract HQ Tangent layers
|
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_tan_hq_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
|
2020-02-19 01:44:52 +01:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_tan_ex_init(mr, cache, buf, true);
|
2020-02-19 01:44:52 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MeshExtract extract_tan_hq = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_tan_hq_init,
|
|
|
|
.data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI,
|
|
|
|
.use_threading = false,
|
2020-02-19 01:44:52 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2020-09-18 19:30:02 +02:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Sculpt Data
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
static void *extract_sculpt_data_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2020-09-18 19:30:02 +02:00
|
|
|
GPUVertFormat format = {0};
|
|
|
|
|
|
|
|
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;
|
|
|
|
CustomData *cd_pdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata;
|
|
|
|
|
|
|
|
float *cd_mask = CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
|
|
|
|
int *cd_face_set = CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
|
|
|
|
|
|
|
|
if (format.attr_len == 0) {
|
|
|
|
GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
|
|
|
GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
|
|
|
}
|
|
|
|
|
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
|
|
|
|
|
|
|
|
typedef struct gpuSculptData {
|
|
|
|
uint8_t face_set_color[4];
|
|
|
|
float mask;
|
|
|
|
} gpuSculptData;
|
|
|
|
|
|
|
|
gpuSculptData *vbo_data = (gpuSculptData *)GPU_vertbuf_get_data(vbo);
|
|
|
|
MLoop *loops = CustomData_get_layer(cd_ldata, CD_MLOOP);
|
|
|
|
|
|
|
|
if (mr->extract_type == MR_EXTRACT_BMESH) {
|
|
|
|
int cd_mask_ofs = CustomData_get_offset(cd_vdata, CD_PAINT_MASK);
|
|
|
|
int cd_face_set_ofs = CustomData_get_offset(cd_pdata, CD_SCULPT_FACE_SETS);
|
|
|
|
BMIter f_iter;
|
|
|
|
BMFace *efa;
|
|
|
|
BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
|
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
|
|
|
|
do {
|
|
|
|
float v_mask = 0.0f;
|
|
|
|
if (cd_mask) {
|
|
|
|
v_mask = BM_ELEM_CD_GET_FLOAT(l_iter->v, cd_mask_ofs);
|
|
|
|
}
|
|
|
|
vbo_data->mask = v_mask;
|
|
|
|
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
|
|
|
|
if (cd_face_set) {
|
|
|
|
const int face_set_id = BM_ELEM_CD_GET_INT(l_iter->f, cd_face_set_ofs);
|
|
|
|
if (face_set_id != mr->me->face_sets_color_default) {
|
|
|
|
BKE_paint_face_set_overlay_color_get(
|
|
|
|
face_set_id, mr->me->face_sets_color_seed, face_set_color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
copy_v3_v3_uchar(vbo_data->face_set_color, face_set_color);
|
|
|
|
vbo_data++;
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int mp_loop = 0;
|
|
|
|
for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) {
|
|
|
|
const MPoly *p = &mr->mpoly[mp_index];
|
|
|
|
for (int l = 0; l < p->totloop; l++) {
|
|
|
|
float v_mask = 0.0f;
|
|
|
|
if (cd_mask) {
|
|
|
|
v_mask = cd_mask[loops[mp_loop].v];
|
|
|
|
}
|
|
|
|
vbo_data->mask = v_mask;
|
|
|
|
|
|
|
|
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
|
|
|
|
if (cd_face_set) {
|
|
|
|
const int face_set_id = cd_face_set[mp_index];
|
|
|
|
/* Skip for the default color Face Set to render it white. */
|
|
|
|
if (face_set_id != mr->me->face_sets_color_default) {
|
|
|
|
BKE_paint_face_set_overlay_color_get(
|
|
|
|
face_set_id, mr->me->face_sets_color_seed, face_set_color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
copy_v3_v3_uchar(vbo_data->face_set_color, face_set_color);
|
|
|
|
mp_loop++;
|
|
|
|
vbo_data++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MeshExtract extract_sculpt_data = {
|
|
|
|
.init = extract_sculpt_data_init,
|
|
|
|
.data_flag = 0,
|
|
|
|
/* TODO: enable threading. */
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.sculpt_data)};
|
2020-09-18 19:30:02 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract VCol
|
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_vcol_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
GPUVertFormat format = {0};
|
|
|
|
GPU_vertformat_deinterleave(&format);
|
|
|
|
|
2020-06-03 17:52:33 +02:00
|
|
|
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
|
2020-08-21 09:19:25 +02:00
|
|
|
uint32_t vcol_layers = cache->cd_used.vcol;
|
|
|
|
uint32_t svcol_layers = cache->cd_used.sculpt_vcol;
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2020-06-04 04:40:17 +02:00
|
|
|
for (int i = 0; i < MAX_MCOL; i++) {
|
2019-07-14 16:49:44 +02:00
|
|
|
if (vcol_layers & (1 << i)) {
|
2020-04-03 07:59:34 +02:00
|
|
|
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
|
2019-07-14 16:49:44 +02:00
|
|
|
const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i);
|
2020-04-03 07:59:34 +02:00
|
|
|
GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2019-08-14 22:18:47 +02:00
|
|
|
BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
|
2020-01-17 16:05:19 +01:00
|
|
|
GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
|
|
|
|
/* Gather number of auto layers. */
|
2020-06-25 08:56:49 +02:00
|
|
|
/* We only do `vcols` that are not overridden by `uvs` and sculpt vertex colors. */
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1 &&
|
|
|
|
CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, layer_name) == -1) {
|
|
|
|
BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
|
|
|
|
GPU_vertformat_alias_add(&format, attr_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sculpt Vertex Colors */
|
2020-07-09 17:16:24 +02:00
|
|
|
if (U.experimental.use_sculpt_vertex_colors) {
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
|
|
if (svcol_layers & (1 << i)) {
|
|
|
|
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
|
|
|
|
const char *layer_name = CustomData_get_layer_name(cd_vdata, CD_PROP_COLOR, i);
|
|
|
|
GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
|
|
|
|
|
|
|
|
BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
|
|
|
|
GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
|
|
|
|
|
|
|
if (i == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) {
|
|
|
|
GPU_vertformat_alias_add(&format, "c");
|
|
|
|
}
|
|
|
|
if (i == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) {
|
|
|
|
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%s", attr_safe_name);
|
|
|
|
GPU_vertformat_alias_add(&format, attr_name);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
|
|
|
|
|
2020-01-17 16:05:19 +01:00
|
|
|
typedef struct gpuMeshVcol {
|
|
|
|
ushort r, g, b, a;
|
|
|
|
} gpuMeshVcol;
|
|
|
|
|
2020-09-06 16:40:07 +02:00
|
|
|
gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo);
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
MLoop *loops = CustomData_get_layer(cd_ldata, CD_MLOOP);
|
|
|
|
|
2020-06-04 04:40:17 +02:00
|
|
|
for (int i = 0; i < MAX_MCOL; i++) {
|
2019-07-14 16:49:44 +02:00
|
|
|
if (vcol_layers & (1 << i)) {
|
2020-06-03 17:52:33 +02:00
|
|
|
if (mr->extract_type == MR_EXTRACT_BMESH) {
|
|
|
|
int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPCOL, i);
|
2020-06-25 08:44:36 +02:00
|
|
|
BMIter f_iter;
|
2020-06-03 17:52:33 +02:00
|
|
|
BMFace *efa;
|
|
|
|
BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
|
2020-06-25 08:44:36 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
|
|
|
|
do {
|
|
|
|
const MLoopCol *mloopcol = BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs);
|
2020-06-03 17:52:33 +02:00
|
|
|
vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
|
|
|
|
vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
|
|
|
|
vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
|
|
|
|
vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
|
|
|
|
vcol_data++;
|
2020-06-25 08:44:36 +02:00
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2020-06-03 17:52:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, mloopcol++, vcol_data++) {
|
2020-06-03 17:52:33 +02:00
|
|
|
vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
|
|
|
|
vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
|
|
|
|
vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
|
|
|
|
vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
|
|
|
|
}
|
2020-01-17 16:05:19 +01:00
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
|
2020-07-09 17:16:24 +02:00
|
|
|
if (svcol_layers & (1 << i) && U.experimental.use_sculpt_vertex_colors) {
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
if (mr->extract_type == MR_EXTRACT_BMESH) {
|
|
|
|
int cd_ofs = CustomData_get_n_offset(cd_vdata, CD_PROP_COLOR, i);
|
2020-06-25 08:44:36 +02:00
|
|
|
BMIter f_iter;
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
BMFace *efa;
|
|
|
|
BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
|
2020-06-25 08:44:36 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
|
|
|
|
do {
|
|
|
|
const MPropCol *prop_col = BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs);
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
vcol_data->r = unit_float_to_ushort_clamp(prop_col->color[0]);
|
|
|
|
vcol_data->g = unit_float_to_ushort_clamp(prop_col->color[1]);
|
|
|
|
vcol_data->b = unit_float_to_ushort_clamp(prop_col->color[2]);
|
|
|
|
vcol_data->a = unit_float_to_ushort_clamp(prop_col->color[3]);
|
|
|
|
vcol_data++;
|
2020-06-25 08:44:36 +02:00
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
MPropCol *vcol = CustomData_get_layer_n(cd_vdata, CD_PROP_COLOR, i);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vcol_data++) {
|
|
|
|
vcol_data->r = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[0]);
|
|
|
|
vcol_data->g = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[1]);
|
|
|
|
vcol_data->b = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[2]);
|
|
|
|
vcol_data->a = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[3]);
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_vcol = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_vcol_init,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vcol)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
/** \} */
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Orco
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct MeshExtract_Orco_Data {
|
|
|
|
float (*vbo_data)[4];
|
|
|
|
float (*orco)[3];
|
|
|
|
} MeshExtract_Orco_Data;
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_orco_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
|
|
|
/* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
|
2020-06-25 08:56:49 +02:00
|
|
|
* attributes. This is a substantial waste of video-ram and should be done another way.
|
2019-08-16 16:54:22 +02:00
|
|
|
* Unfortunately, at the time of writing, I did not found any other "non disruptive"
|
2019-07-14 16:49:44 +02:00
|
|
|
* alternative. */
|
|
|
|
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, mr->loop_len);
|
|
|
|
|
|
|
|
CustomData *cd_vdata = &mr->me->vdata;
|
|
|
|
|
|
|
|
MeshExtract_Orco_Data *data = MEM_mallocN(sizeof(*data), __func__);
|
2020-09-06 16:40:07 +02:00
|
|
|
data->vbo_data = (float(*)[4])GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
data->orco = CustomData_get_layer(cd_vdata, CD_ORCO);
|
2020-06-25 08:56:49 +02:00
|
|
|
/* Make sure `orco` layer was requested only if needed! */
|
2019-07-14 16:49:44 +02:00
|
|
|
BLI_assert(data->orco);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_orco_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data;
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
2020-06-30 16:13:39 +02:00
|
|
|
float *loop_orco = orco_data->vbo_data[l_index];
|
2021-05-31 17:11:01 +02:00
|
|
|
copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(l_iter->v)]);
|
2020-06-30 16:13:39 +02:00
|
|
|
loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
|
2021-05-31 17:11:01 +02:00
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_orco_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int UNUSED(mp_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data;
|
|
|
|
float *loop_orco = orco_data->vbo_data[ml_index];
|
|
|
|
copy_v3_v3(loop_orco, orco_data->orco[ml->v]);
|
|
|
|
loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_orco_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *UNUSED(buf),
|
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_orco = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_orco_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_orco_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_orco_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_orco_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.orco)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \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));
|
2020-06-25 08:56:49 +02:00
|
|
|
/* Re-scale to the slider range. */
|
2019-07-14 16:49:44 +02:00
|
|
|
d *= (1.0f / 0.065f);
|
|
|
|
CLAMP(d, 0.0f, 1.0f);
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_edge_fac_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
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. */
|
2020-06-30 16:13:39 +02:00
|
|
|
const MEdge *med = mr->medge;
|
|
|
|
for (int e_index = 0; e_index < mr->edge_len; e_index++, med++) {
|
|
|
|
if ((med->flag & ME_EDGERENDER) == 0) {
|
2019-07-14 16:49:44 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-09-06 16:40:07 +02:00
|
|
|
data->vbo_data = GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_EdgeFac_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
|
|
|
|
|
|
|
if (BM_edge_is_manifold(l_iter->e)) {
|
|
|
|
float ratio = loop_edge_factor_get(bm_face_no_get(mr, f),
|
|
|
|
bm_vert_co_get(mr, l_iter->v),
|
|
|
|
bm_vert_no_get(mr, l_iter->v),
|
|
|
|
bm_vert_co_get(mr, l_iter->next->v));
|
2020-06-30 16:13:39 +02:00
|
|
|
data->vbo_data[l_index] = ratio * 253 + 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
data->vbo_data[l_index] = 255;
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int mp_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
|
2020-06-30 16:13:39 +02:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
|
|
|
|
if (data->use_edge_render) {
|
2020-06-30 16:13:39 +02:00
|
|
|
const MEdge *med = &mr->medge[ml->e];
|
|
|
|
data->vbo_data[ml_index] = (med->flag & ME_EDGERENDER) ? 255 : 0;
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
else {
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
/* Count loop per edge to detect non-manifold. */
|
|
|
|
if (data->edge_loop_count[ml->e] < 3) {
|
|
|
|
data->edge_loop_count[ml->e]++;
|
|
|
|
}
|
|
|
|
if (data->edge_loop_count[ml->e] == 2) {
|
|
|
|
/* Manifold */
|
|
|
|
const int ml_index_last = mp->totloop + mp->loopstart - 1;
|
|
|
|
const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1);
|
|
|
|
const MLoop *ml_next = &mr->mloop[ml_index_other];
|
|
|
|
const MVert *v1 = &mr->mvert[ml->v];
|
|
|
|
const MVert *v2 = &mr->mvert[ml_next->v];
|
|
|
|
float vnor_f[3];
|
|
|
|
normal_short_to_float_v3(vnor_f, v1->no);
|
|
|
|
float ratio = loop_edge_factor_get(mr->poly_normals[mp_index], v1->co, vnor_f, v2->co);
|
|
|
|
data->vbo_data[ml_index] = ratio * 253 + 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Non-manifold */
|
|
|
|
data->vbo_data[ml_index] = 255;
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edge_fac_iter_ledge_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMEdge *UNUSED(eed),
|
|
|
|
const int ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_EdgeFac_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255;
|
|
|
|
data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MEdge *UNUSED(med),
|
|
|
|
const uint ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_EdgeFac_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255;
|
|
|
|
data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_edge_fac_finish(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf,
|
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_EdgeFac_Data *data = _data;
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
if (GPU_crappy_amd_driver()) {
|
2020-06-25 08:56:49 +02:00
|
|
|
/* Some AMD drivers strangely crash with VBO's with a one byte format.
|
|
|
|
* To workaround we reinitialize the VBO with another format and convert
|
2019-07-14 16:49:44 +02:00
|
|
|
* 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. */
|
2020-09-06 16:40:07 +02:00
|
|
|
data->vbo_data = GPU_vertbuf_steal_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
|
|
|
|
2020-09-06 16:40:07 +02:00
|
|
|
float *fdata = (float *)GPU_vertbuf_get_data(vbo);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int ml_index = 0; ml_index < buf_len; ml_index++, fdata++) {
|
|
|
|
*fdata = data->vbo_data[ml_index] / 255.0f;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
/* Free old byte data. */
|
|
|
|
MEM_freeN(data->vbo_data);
|
|
|
|
}
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_edge_fac = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_edge_fac_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_edge_fac_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_edge_fac_iter_poly_mesh,
|
|
|
|
.iter_ledge_bm = extract_edge_fac_iter_ledge_bm,
|
|
|
|
.iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_edge_fac_finish,
|
|
|
|
.data_flag = MR_DATA_POLY_NOR,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_fac)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Vertex Weight
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct MeshExtract_Weight_Data {
|
|
|
|
float *vbo_data;
|
|
|
|
const DRW_MeshWeightState *wstate;
|
2020-06-25 08:56:49 +02:00
|
|
|
const MDeformVert *dvert; /* For #Mesh. */
|
|
|
|
int cd_ofs; /* For #BMesh. */
|
2019-07-14 16:49:44 +02:00
|
|
|
} 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;
|
|
|
|
}
|
2020-08-07 11:49:59 +02:00
|
|
|
if (dvert == NULL) {
|
2019-07-14 16:49:44 +02:00
|
|
|
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 */
|
2018-10-07 17:25:51 +02:00
|
|
|
bool is_normalized = (wstate->flags & (DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE |
|
|
|
|
DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE));
|
|
|
|
input = BKE_defvert_multipaint_collective_weight(dvert,
|
|
|
|
wstate->defgroup_len,
|
|
|
|
wstate->defgroup_sel,
|
|
|
|
wstate->defgroup_sel_count,
|
|
|
|
is_normalized);
|
2019-07-14 16:49:44 +02:00
|
|
|
/* 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 */
|
2020-03-06 02:50:56 +01:00
|
|
|
input = BKE_defvert_find_weight(dvert, wstate->defgroup_active);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
if (input == 0.0f) {
|
|
|
|
switch (wstate->alert_mode) {
|
|
|
|
case OB_DRAW_GROUPUSER_ACTIVE:
|
|
|
|
return -1.0f;
|
|
|
|
break;
|
|
|
|
case OB_DRAW_GROUPUSER_ALL:
|
2020-03-06 02:50:56 +01:00
|
|
|
if (BKE_defvert_is_weight_zero(dvert, wstate->defgroup_len)) {
|
2019-07-14 16:49:44 +02:00
|
|
|
return -1.0f;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-10-07 17:25:51 +02:00
|
|
|
|
|
|
|
/* Lock-Relative: display the fraction of current weight vs total unlocked weight. */
|
|
|
|
if (wstate->flags & DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE) {
|
|
|
|
input = BKE_defvert_lock_relative_weight(
|
|
|
|
input, dvert, wstate->defgroup_len, wstate->defgroup_locked, wstate->defgroup_unlocked);
|
|
|
|
}
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
CLAMP(input, 0.0f, 1.0f);
|
|
|
|
return input;
|
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_weights_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *cache,
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
|
|
|
GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
|
|
|
}
|
|
|
|
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__);
|
2020-09-06 16:40:07 +02:00
|
|
|
data->vbo_data = (float *)GPU_vertbuf_get_data(vbo);
|
2020-08-21 09:19:25 +02:00
|
|
|
data->wstate = &cache->weight_state;
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_weights_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_Weight_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
|
|
|
if (data->cd_ofs != -1) {
|
|
|
|
const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(l_iter->v, data->cd_ofs);
|
2020-06-30 16:13:39 +02:00
|
|
|
data->vbo_data[l_index] = evaluate_vertex_weight(dvert, data->wstate);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
else {
|
2020-06-30 16:13:39 +02:00
|
|
|
data->vbo_data[l_index] = evaluate_vertex_weight(NULL, data->wstate);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_weights_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int UNUSED(mp_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_Weight_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
if (data->dvert != NULL) {
|
2020-06-30 16:13:39 +02:00
|
|
|
const MDeformVert *dvert = &data->dvert[ml->v];
|
|
|
|
data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
else {
|
|
|
|
const MDeformVert *dvert = NULL;
|
2020-06-30 16:13:39 +02:00
|
|
|
data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate);
|
|
|
|
}
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_weights_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *UNUSED(buf),
|
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_weights = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_weights_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_weights_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_weights_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_weights_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.weights)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \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 than 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,
|
2020-06-30 16:13:39 +02:00
|
|
|
BMLoop *l,
|
2019-07-14 16:49:44 +02:00
|
|
|
const int cd_ofs,
|
|
|
|
EditLoopData *eattr)
|
|
|
|
{
|
|
|
|
if (cd_ofs == -1) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-30 16:13:39 +02:00
|
|
|
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_ofs);
|
2019-07-14 16:49:44 +02:00
|
|
|
if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) {
|
|
|
|
eattr->v_flag |= VFLAG_VERT_UV_PINNED;
|
|
|
|
}
|
2020-06-30 16:13:39 +02:00
|
|
|
if (uvedit_uv_select_test_ex(mr->toolsettings, l, cd_ofs)) {
|
2019-07-14 16:49:44 +02:00
|
|
|
eattr->v_flag |= VFLAG_VERT_UV_SELECT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_render_data_loop_edge_flag(const MeshRenderData *mr,
|
2020-06-30 16:13:39 +02:00
|
|
|
BMLoop *l,
|
2019-07-14 16:49:44 +02:00
|
|
|
const int cd_ofs,
|
|
|
|
EditLoopData *eattr)
|
|
|
|
{
|
|
|
|
if (cd_ofs == -1) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-30 16:13:39 +02:00
|
|
|
if (uvedit_edge_select_test_ex(mr->toolsettings, l, cd_ofs)) {
|
2019-07-14 16:49:44 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_edit_data_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
2020-06-25 08:56:49 +02:00
|
|
|
/* WARNING: Adjust #EditLoopData struct accordingly. */
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
|
|
|
|
GPU_vertformat_alias_add(&format, "flag");
|
|
|
|
}
|
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
|
2020-09-06 16:40:07 +02:00
|
|
|
return GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edit_data_iter_poly_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
EditLoopData *data = (EditLoopData *)_data + l_index;
|
|
|
|
memset(data, 0x0, sizeof(*data));
|
2021-05-31 17:11:01 +02:00
|
|
|
mesh_render_data_face_flag(mr, f, -1, data);
|
|
|
|
mesh_render_data_edge_flag(mr, l_iter->e, data);
|
|
|
|
mesh_render_data_vert_flag(mr, l_iter->v, data);
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int mp_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
2020-06-30 16:13:39 +02:00
|
|
|
EditLoopData *data = (EditLoopData *)_data + ml_index;
|
|
|
|
memset(data, 0x0, sizeof(*data));
|
|
|
|
BMFace *efa = bm_original_face_get(mr, mp_index);
|
|
|
|
BMEdge *eed = bm_original_edge_get(mr, ml->e);
|
|
|
|
BMVert *eve = bm_original_vert_get(mr, ml->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);
|
|
|
|
}
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edit_data_iter_ledge_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMEdge *eed,
|
|
|
|
const int ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
EditLoopData *data = (EditLoopData *)_data + mr->loop_len + (ledge_index * 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]);
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_edit_data_iter_ledge_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MEdge *med,
|
|
|
|
const uint ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
EditLoopData *data = (EditLoopData *)_data + mr->loop_len + ledge_index * 2;
|
|
|
|
memset(data, 0x0, sizeof(*data) * 2);
|
|
|
|
const int e_index = mr->ledges[ledge_index];
|
|
|
|
BMEdge *eed = bm_original_edge_get(mr, e_index);
|
|
|
|
BMVert *eve1 = bm_original_vert_get(mr, med->v1);
|
|
|
|
BMVert *eve2 = bm_original_vert_get(mr, med->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]);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edit_data_iter_lvert_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMVert *eve,
|
|
|
|
const int lvert_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
|
2021-05-31 17:11:01 +02:00
|
|
|
EditLoopData *data = (EditLoopData *)_data + offset + lvert_index;
|
|
|
|
memset(data, 0x0, sizeof(*data));
|
|
|
|
mesh_render_data_vert_flag(mr, eve, data);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MVert *UNUSED(mv),
|
|
|
|
const int lvert_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
EditLoopData *data = (EditLoopData *)_data + offset + lvert_index;
|
|
|
|
memset(data, 0x0, sizeof(*data));
|
|
|
|
const int v_index = mr->lverts[lvert_index];
|
|
|
|
BMVert *eve = bm_original_vert_get(mr, v_index);
|
|
|
|
if (eve) {
|
|
|
|
mesh_render_data_vert_flag(mr, eve, data);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_edit_data = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_edit_data_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_edit_data_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_edit_data_iter_poly_mesh,
|
|
|
|
.iter_ledge_bm = extract_edit_data_iter_ledge_bm,
|
|
|
|
.iter_ledge_mesh = extract_edit_data_iter_ledge_mesh,
|
|
|
|
.iter_lvert_bm = extract_edit_data_iter_lvert_bm,
|
|
|
|
.iter_lvert_mesh = extract_edit_data_iter_lvert_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edit_data)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Edit UV Data / Flags
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct MeshExtract_EditUVData_Data {
|
|
|
|
EditLoopData *vbo_data;
|
|
|
|
int cd_ofs;
|
|
|
|
} MeshExtract_EditUVData_Data;
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_edituv_data_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
2020-06-25 08:56:49 +02:00
|
|
|
/* WARNING: Adjust #EditLoopData struct accordingly. */
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
|
|
|
|
GPU_vertformat_alias_add(&format, "flag");
|
|
|
|
}
|
|
|
|
|
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
|
|
|
|
|
2019-08-26 16:28:32 +02:00
|
|
|
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
MeshExtract_EditUVData_Data *data = MEM_callocN(sizeof(*data), __func__);
|
2020-09-06 16:40:07 +02:00
|
|
|
data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_EditUVData_Data *data = _data;
|
|
|
|
EditLoopData *eldata = &data->vbo_data[l_index];
|
|
|
|
memset(eldata, 0x0, sizeof(*eldata));
|
2021-05-31 17:11:01 +02:00
|
|
|
mesh_render_data_loop_flag(mr, l_iter, data->cd_ofs, eldata);
|
|
|
|
mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata);
|
|
|
|
mesh_render_data_loop_edge_flag(mr, l_iter, data->cd_ofs, eldata);
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int mp_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
|
|
|
{
|
|
|
|
MeshExtract_EditUVData_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
EditLoopData *eldata = &data->vbo_data[ml_index];
|
|
|
|
memset(eldata, 0x0, sizeof(*eldata));
|
|
|
|
BMFace *efa = bm_original_face_get(mr, mp_index);
|
|
|
|
if (efa) {
|
|
|
|
BMEdge *eed = bm_original_edge_get(mr, ml->e);
|
|
|
|
BMVert *eve = bm_original_vert_get(mr, ml->v);
|
|
|
|
if (eed && eve) {
|
|
|
|
/* Loop on an edge endpoint. */
|
|
|
|
BMLoop *l = BM_face_edge_share_loop(efa, eed);
|
|
|
|
mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata);
|
|
|
|
mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
2020-06-30 16:13:39 +02:00
|
|
|
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. */
|
|
|
|
const int ml_index_last = mp->loopstart + mp->totloop - 1;
|
|
|
|
const int l_prev = (ml_index == mp->loopstart) ? ml_index_last : (ml_index - 1);
|
|
|
|
const MLoop *ml_prev = &mr->mloop[l_prev];
|
|
|
|
eed = bm_original_edge_get(mr, ml_prev->e);
|
|
|
|
}
|
|
|
|
if (eed) {
|
|
|
|
/* Mapped points on an edge between two edit verts. */
|
|
|
|
BMLoop *l = BM_face_edge_share_loop(efa, eed);
|
|
|
|
mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr),
|
2020-08-21 09:19:25 +02:00
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2019-07-14 16:49:44 +02:00
|
|
|
void *UNUSED(buf),
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_edituv_data = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_edituv_data_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_edituv_data_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_edituv_data_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_edituv_data_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_data)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Edit UV area stretch
|
|
|
|
* \{ */
|
|
|
|
|
2021-02-17 05:36:18 +01:00
|
|
|
static void *extract_edituv_stretch_area_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
2019-12-18 16:10:01 +01:00
|
|
|
GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *cache,
|
|
|
|
void *buf,
|
|
|
|
void *UNUSED(data))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-09-03 13:42:11 +02:00
|
|
|
float tot_area = 0.0f, tot_uv_area = 0.0f;
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
2019-09-03 13:42:11 +02:00
|
|
|
tot_area += area;
|
|
|
|
tot_uv_area += uvarea;
|
2019-07-14 16:49:44 +02:00
|
|
|
area_ratio[f] = area_ratio_get(area, uvarea);
|
|
|
|
}
|
|
|
|
}
|
2021-02-17 05:12:39 +01:00
|
|
|
else {
|
|
|
|
BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH));
|
2019-07-14 16:49:44 +02:00
|
|
|
const MLoopUV *uv_data = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
|
2020-06-30 16:13:39 +02:00
|
|
|
const MPoly *mp = mr->mpoly;
|
|
|
|
for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
|
|
|
|
float area = BKE_mesh_calc_poly_area(mp, &mr->mloop[mp->loopstart], mr->mvert);
|
|
|
|
float uvarea = BKE_mesh_calc_poly_uv_area(mp, uv_data);
|
2019-09-03 13:42:11 +02:00
|
|
|
tot_area += area;
|
|
|
|
tot_uv_area += uvarea;
|
2020-06-30 16:13:39 +02:00
|
|
|
area_ratio[mp_index] = area_ratio_get(area, uvarea);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
cache->tot_area = tot_area;
|
|
|
|
cache->tot_uv_area = tot_uv_area;
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/* Convert in place to avoid an extra allocation */
|
|
|
|
uint16_t *poly_stretch = (uint16_t *)area_ratio;
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) {
|
|
|
|
poly_stretch[mp_index] = area_ratio[mp_index] * SHRT_MAX;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy face data for each loop. */
|
2020-09-06 16:40:07 +02:00
|
|
|
uint16_t *loop_stretch = (uint16_t *)GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
if (mr->extract_type == MR_EXTRACT_BMESH) {
|
|
|
|
BMFace *efa;
|
|
|
|
BMIter f_iter;
|
2020-06-30 16:13:39 +02:00
|
|
|
int f, l_index = 0;
|
2019-07-14 16:49:44 +02:00
|
|
|
BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) {
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int i = 0; i < efa->len; i++, l_index++) {
|
|
|
|
loop_stretch[l_index] = poly_stretch[f];
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-17 05:12:39 +01:00
|
|
|
else {
|
|
|
|
BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH));
|
2020-06-30 16:13:39 +02:00
|
|
|
const MPoly *mp = mr->mpoly;
|
|
|
|
for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
|
|
|
|
for (int i = 0; i < mp->totloop; i++, l_index++) {
|
|
|
|
loop_stretch[l_index] = poly_stretch[mp_index];
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(area_ratio);
|
|
|
|
}
|
|
|
|
|
2021-02-17 05:36:18 +01:00
|
|
|
static const MeshExtract extract_edituv_stretch_area = {
|
|
|
|
.init = extract_edituv_stretch_area_init,
|
2021-05-31 17:11:01 +02:00
|
|
|
.finish = extract_edituv_stretch_area_finish,
|
2020-06-29 07:09:43 +02:00
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_area)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \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],
|
2019-08-30 16:14:59 +02:00
|
|
|
const float co[3],
|
|
|
|
const float co_prev[3])
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
/* 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]);
|
|
|
|
}
|
|
|
|
|
2020-08-07 14:56:13 +02:00
|
|
|
static short v2_to_short_angle(const float v[2])
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
return atan2f(v[1], v[0]) * (float)M_1_PI * SHRT_MAX;
|
|
|
|
}
|
|
|
|
|
2021-02-17 05:36:18 +01:00
|
|
|
static void edituv_get_edituv_stretch_angle(float auv[2][2],
|
|
|
|
const float av[2][3],
|
|
|
|
UVStretchAngle *r_stretch)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-25 08:56:49 +02:00
|
|
|
/* Send UV's to the shader and let it compute the aspect corrected angle. */
|
2019-07-14 16:49:44 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-02-17 05:36:18 +01:00
|
|
|
static void *extract_edituv_stretch_angle_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
2020-06-25 08:56:49 +02:00
|
|
|
/* Waning: adjust #UVStretchAngle struct accordingly. */
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
|
|
|
|
|
|
|
|
MeshExtract_StretchAngle_Data *data = MEM_callocN(sizeof(*data), __func__);
|
2020-09-06 16:40:07 +02:00
|
|
|
data->vbo_data = (UVStretchAngle *)GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2020-06-25 08:56:49 +02:00
|
|
|
/* Special iterator needed to save about half of the computing cost. */
|
2019-07-14 16:49:44 +02:00
|
|
|
if (mr->extract_type == MR_EXTRACT_BMESH) {
|
|
|
|
data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
|
|
|
|
}
|
|
|
|
else {
|
2021-02-17 05:12:39 +01:00
|
|
|
BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH));
|
|
|
|
data->luv = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2021-02-17 05:36:18 +01:00
|
|
|
static void extract_edituv_stretch_angle_iter_poly_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2021-02-17 05:36:18 +01:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_StretchAngle_Data *data = _data;
|
2019-07-14 16:49:44 +02:00
|
|
|
float(*auv)[2] = data->auv, *last_auv = data->last_auv;
|
|
|
|
float(*av)[3] = data->av, *last_av = data->last_av;
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
const MLoopUV *luv, *luv_next;
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_next = l_iter->next;
|
|
|
|
if (l_iter == BM_FACE_FIRST_LOOP(f)) {
|
2020-06-30 16:13:39 +02:00
|
|
|
/* First loop in face. */
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_tmp = l_iter->prev;
|
|
|
|
BMLoop *l_next_tmp = l_iter;
|
2020-06-30 16:13:39 +02:00
|
|
|
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,
|
|
|
|
bm_vert_co_get(mr, l_tmp->v),
|
|
|
|
bm_vert_co_get(mr, l_next_tmp->v));
|
|
|
|
/* Save last edge. */
|
|
|
|
copy_v2_v2(last_auv, auv[1]);
|
|
|
|
copy_v3_v3(last_av, av[1]);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
if (l_next == BM_FACE_FIRST_LOOP(f)) {
|
2020-06-30 16:13:39 +02:00
|
|
|
/* 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 {
|
2021-05-31 17:11:01 +02:00
|
|
|
luv = BM_ELEM_CD_GET_VOID_P(l_iter, data->cd_ofs);
|
2020-06-30 16:13:39 +02:00
|
|
|
luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs);
|
2021-05-31 17:11:01 +02:00
|
|
|
compute_normalize_edge_vectors(auv,
|
|
|
|
av,
|
|
|
|
luv->uv,
|
|
|
|
luv_next->uv,
|
|
|
|
bm_vert_co_get(mr, l_iter->v),
|
|
|
|
bm_vert_co_get(mr, l_next->v));
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
2021-02-17 05:36:18 +01:00
|
|
|
edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[l_index]);
|
2021-05-31 17:11:01 +02:00
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
|
|
|
|
2021-02-17 05:36:18 +01:00
|
|
|
static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int UNUSED(mp_index),
|
2021-02-17 05:36:18 +01:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_StretchAngle_Data *data = _data;
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
2020-06-30 16:13:39 +02:00
|
|
|
float(*auv)[2] = data->auv, *last_auv = data->last_auv;
|
|
|
|
float(*av)[3] = data->av, *last_av = data->last_av;
|
2021-05-31 17:11:01 +02:00
|
|
|
int l_next = ml_index + 1;
|
2020-06-30 16:13:39 +02:00
|
|
|
const MVert *v, *v_next;
|
|
|
|
if (ml_index == mp->loopstart) {
|
|
|
|
/* First loop in face. */
|
|
|
|
const int ml_index_last = ml_index_end - 1;
|
|
|
|
const int l_next_tmp = mp->loopstart;
|
|
|
|
v = &mr->mvert[mr->mloop[ml_index_last].v];
|
|
|
|
v_next = &mr->mvert[mr->mloop[l_next_tmp].v];
|
|
|
|
compute_normalize_edge_vectors(
|
|
|
|
auv, av, data->luv[ml_index_last].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 == ml_index_end) {
|
|
|
|
l_next = mp->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[ml_index].v];
|
|
|
|
v_next = &mr->mvert[mr->mloop[l_next].v];
|
|
|
|
compute_normalize_edge_vectors(
|
|
|
|
auv, av, data->luv[ml_index].uv, data->luv[l_next].uv, v->co, v_next->co);
|
|
|
|
}
|
2021-02-17 05:36:18 +01:00
|
|
|
edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[ml_index]);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-17 05:36:18 +01:00
|
|
|
static void extract_edituv_stretch_angle_finish(const MeshRenderData *UNUSED(mr),
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *UNUSED(buf),
|
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
2021-02-17 05:36:18 +01:00
|
|
|
static const MeshExtract extract_edituv_stretch_angle = {
|
|
|
|
.init = extract_edituv_stretch_angle_init,
|
|
|
|
.iter_poly_bm = extract_edituv_stretch_angle_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_edituv_stretch_angle_iter_poly_mesh,
|
|
|
|
.finish = extract_edituv_stretch_angle_finish,
|
2020-06-29 07:09:43 +02:00
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_angle)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
2020-03-18 12:28:54 +01:00
|
|
|
/** \name Extract Edit Mesh Analysis Colors
|
2019-07-14 16:49:44 +02:00
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_mesh_analysis_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
|
|
|
GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2020-03-23 18:18:36 +01:00
|
|
|
BMEditMesh *em = mr->edit_bmesh;
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
|
|
|
|
2020-01-07 04:06:33 +01:00
|
|
|
/* now convert into global space */
|
|
|
|
mul_transposed_mat3_m4_v3(mr->obmat, dir);
|
|
|
|
normalize_v3(dir);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
if (mr->extract_type == MR_EXTRACT_BMESH) {
|
2020-06-30 16:13:39 +02:00
|
|
|
int l_index = 0;
|
2019-07-14 16:49:44 +02:00
|
|
|
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
2020-05-25 12:16:42 +02:00
|
|
|
float fac = angle_normalized_v3v3(bm_face_no_get(mr, f), dir) / (float)M_PI;
|
2019-07-14 16:49:44 +02:00
|
|
|
fac = overhang_remap(fac, min, max, minmax_irange);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int i = 0; i < f->len; i++, l_index++) {
|
|
|
|
r_overhang[l_index] = fac;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-06-30 16:13:39 +02:00
|
|
|
const MPoly *mp = mr->mpoly;
|
|
|
|
for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
|
|
|
|
float fac = angle_normalized_v3v3(mr->poly_normals[mp_index], dir) / (float)M_PI;
|
2019-07-14 16:49:44 +02:00
|
|
|
fac = overhang_remap(fac, min, max, minmax_irange);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int i = 0; i < mp->totloop; i++, l_index++) {
|
|
|
|
r_overhang[l_index] = fac;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 08:56:49 +02:00
|
|
|
/**
|
|
|
|
* Needed so we can use jitter values for face interpolation.
|
|
|
|
*/
|
2019-07-14 16:49:44 +02:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
2020-03-04 01:31:51 +01:00
|
|
|
clamp_v2(uv, 0.0f, 1.0f);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2020-03-23 18:18:36 +01:00
|
|
|
BMEditMesh *em = mr->edit_bmesh;
|
2020-01-07 04:06:33 +01:00
|
|
|
const float scale = 1.0f / mat4_to_scale(mr->obmat);
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
2020-05-25 12:16:42 +02:00
|
|
|
const float *cos[3] = {
|
|
|
|
bm_vert_co_get(mr, ltri[0]->v),
|
|
|
|
bm_vert_co_get(mr, ltri[1]->v),
|
|
|
|
bm_vert_co_get(mr, ltri[2]->v),
|
|
|
|
};
|
2019-07-14 16:49:44 +02:00
|
|
|
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]) {
|
2020-05-25 12:16:42 +02:00
|
|
|
float angle_fac = fabsf(
|
|
|
|
dot_v3v3(bm_face_no_get(mr, ltri[0]->f), bm_face_no_get(mr, f_hit)));
|
2019-07-14 16:49:44 +02:00
|
|
|
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;
|
2020-06-30 16:13:39 +02:00
|
|
|
int l_index = 0;
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int i = 0; i < f->len; i++, l_index++) {
|
|
|
|
r_thickness[l_index] = fac;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
const MPoly *mp = mr->mpoly;
|
|
|
|
for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
|
|
|
|
float fac = face_dists[mp_index];
|
2019-07-14 16:49:44 +02:00
|
|
|
fac = thickness_remap(fac, min, max, minmax_irange);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int i = 0; i < mp->totloop; i++, l_index++) {
|
|
|
|
r_thickness[l_index] = fac;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-08-10 17:05:37 +02:00
|
|
|
return (isect_tri_tri_v3(UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1]) &&
|
2019-07-14 16:49:44 +02:00
|
|
|
/* 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)
|
|
|
|
{
|
2020-03-23 18:18:36 +01:00
|
|
|
BMEditMesh *em = mr->edit_bmesh;
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int l_index = 0; l_index < mr->loop_len; l_index++) {
|
|
|
|
r_intersect[l_index] = -1.0f;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2020-09-22 16:00:06 +02:00
|
|
|
BVHTreeOverlap *overlap = BKE_bmbvh_overlap_self(bmtree, &overlap_len);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
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);
|
2020-06-30 16:13:39 +02:00
|
|
|
int l_index = BM_elem_index_get(l_first);
|
|
|
|
for (int k = 0; k < f_hit->len; k++, l_index++) {
|
|
|
|
r_intersect[l_index] = 1.0f;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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];
|
2020-06-30 16:13:39 +02:00
|
|
|
int l_index = f_hit->loopstart;
|
|
|
|
for (int k = 0; k < f_hit->totloop; k++, l_index++) {
|
|
|
|
r_intersect[l_index] = 1.0f;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2020-03-23 18:18:36 +01:00
|
|
|
BMEditMesh *em = mr->edit_bmesh;
|
2019-07-14 16:49:44 +02:00
|
|
|
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;
|
|
|
|
|
2020-05-25 12:16:42 +02:00
|
|
|
if (mr->bm_vert_coords != NULL) {
|
|
|
|
BKE_editmesh_cache_ensure_poly_normals(em, mr->edit_data);
|
|
|
|
|
|
|
|
/* Most likely this is already valid, ensure just in case.
|
|
|
|
* Needed for #BM_loop_calc_face_normal_safe_vcos. */
|
|
|
|
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
int l_index = 0;
|
|
|
|
int f_index = 0;
|
|
|
|
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, f_index) {
|
2019-07-14 16:49:44 +02:00
|
|
|
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 {
|
2020-05-25 12:16:42 +02:00
|
|
|
const float *no_face;
|
2019-07-14 16:49:44 +02:00
|
|
|
float no_corner[3];
|
2020-05-25 12:16:42 +02:00
|
|
|
if (mr->bm_vert_coords != NULL) {
|
2020-06-30 16:13:39 +02:00
|
|
|
no_face = mr->bm_poly_normals[f_index];
|
2020-05-25 12:16:42 +02:00
|
|
|
BM_loop_calc_face_normal_safe_vcos(l_iter, no_face, mr->bm_vert_coords, no_corner);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
no_face = f->no;
|
|
|
|
BM_loop_calc_face_normal_safe(l_iter, no_corner);
|
|
|
|
}
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
/* simple way to detect (what is most likely) concave */
|
2020-05-25 12:16:42 +02:00
|
|
|
if (dot_v3v3(no_face, no_corner) < 0.0f) {
|
2019-07-14 16:49:44 +02:00
|
|
|
negate_v3(no_corner);
|
|
|
|
}
|
2020-05-25 12:16:42 +02:00
|
|
|
fac = max_ff(fac, angle_normalized_v3v3(no_face, no_corner));
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
|
|
|
fac *= 2.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
fac = distort_remap(fac, min, max, minmax_irange);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int i = 0; i < f->len; i++, l_index++) {
|
|
|
|
r_distort[l_index] = fac;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-06-30 16:13:39 +02:00
|
|
|
const MPoly *mp = mr->mpoly;
|
|
|
|
for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
|
2019-07-14 16:49:44 +02:00
|
|
|
float fac = -1.0f;
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
if (mp->totloop > 3) {
|
|
|
|
float *f_no = mr->poly_normals[mp_index];
|
2019-07-14 16:49:44 +02:00
|
|
|
fac = 0.0f;
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int i = 1; i <= mp->totloop; i++) {
|
|
|
|
const MLoop *l_prev = &mr->mloop[mp->loopstart + (i - 1) % mp->totloop];
|
|
|
|
const MLoop *l_curr = &mr->mloop[mp->loopstart + (i + 0) % mp->totloop];
|
|
|
|
const MLoop *l_next = &mr->mloop[mp->loopstart + (i + 1) % mp->totloop];
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int i = 0; i < mp->totloop; i++, l_index++) {
|
|
|
|
r_distort[l_index] = fac;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2020-03-23 18:18:36 +01:00
|
|
|
BMEditMesh *em = mr->edit_bmesh;
|
2019-07-14 16:49:44 +02:00
|
|
|
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) {
|
2020-06-25 08:44:36 +02:00
|
|
|
BMIter iter;
|
2019-07-14 16:49:44 +02:00
|
|
|
BMesh *bm = em->bm;
|
|
|
|
BMFace *efa;
|
|
|
|
BMEdge *e;
|
|
|
|
/* 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) {
|
2020-06-25 08:44:36 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
|
|
|
|
do {
|
2020-06-30 16:13:39 +02:00
|
|
|
int l_index = BM_elem_index_get(l_iter);
|
|
|
|
int v_index = BM_elem_index_get(l_iter->v);
|
|
|
|
r_sharp[l_index] = sharp_remap(vert_angles[v_index], min, max, minmax_irange);
|
2020-06-25 08:44:36 +02:00
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* first assign float values to verts */
|
2020-06-30 16:13:39 +02:00
|
|
|
const MPoly *mp = mr->mpoly;
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
EdgeHash *eh = BLI_edgehash_new_ex(__func__, mr->edge_len);
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
|
|
|
|
for (int i = 0; i < mp->totloop; i++) {
|
|
|
|
const MLoop *l_curr = &mr->mloop[mp->loopstart + (i + 0) % mp->totloop];
|
|
|
|
const MLoop *l_next = &mr->mloop[mp->loopstart + (i + 1) % mp->totloop];
|
2019-07-14 16:49:44 +02:00
|
|
|
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) {
|
2020-06-30 16:13:39 +02:00
|
|
|
*pval = mr->poly_normals[mp_index];
|
2019-07-14 16:49:44 +02:00
|
|
|
/* non-manifold edge, yet... */
|
|
|
|
continue;
|
|
|
|
}
|
2020-08-07 11:49:59 +02:00
|
|
|
if (*pval != NULL) {
|
2020-06-30 16:13:39 +02:00
|
|
|
const float *f1_no = mr->poly_normals[mp_index];
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
const MLoop *ml = mr->mloop;
|
|
|
|
for (int l_index = 0; l_index < mr->loop_len; l_index++, ml++) {
|
|
|
|
r_sharp[l_index] = sharp_remap(vert_angles[ml->v], min, max, minmax_irange);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(vert_angles);
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_analysis_iter_finish_mesh(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf,
|
|
|
|
void *UNUSED(data))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2020-03-23 18:18:36 +01:00
|
|
|
BLI_assert(mr->edit_bmesh);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2020-09-06 16:40:07 +02:00
|
|
|
float *l_weight = (float *)GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_mesh_analysis = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_mesh_analysis_init,
|
2021-05-31 17:11:01 +02:00
|
|
|
.finish = extract_analysis_iter_finish_mesh,
|
2020-06-25 08:56:49 +02:00
|
|
|
/* This is not needed for all visualization types.
|
2020-06-29 07:09:43 +02:00
|
|
|
* * Maybe split into different extract. */
|
|
|
|
.data_flag = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.mesh_analysis)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Facedots positions
|
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_fdots_pos_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
|
|
|
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
|
2020-09-06 16:40:07 +02:00
|
|
|
return GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_fdots_pos_iter_poly_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMFace *f,
|
|
|
|
const int f_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
float(*center)[3] = data;
|
2020-07-10 04:38:28 +02:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
float *co = center[f_index];
|
|
|
|
zero_v3(co);
|
2020-07-10 04:38:28 +02:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
add_v3_v3(co, bm_vert_co_get(mr, l_iter->v));
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
|
|
|
mul_v3_fl(co, 1.0f / (float)f->len);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int mp_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
float(*center)[3] = (float(*)[3])data;
|
2021-05-31 17:11:01 +02:00
|
|
|
float *co = center[mp_index];
|
|
|
|
zero_v3(co);
|
|
|
|
|
2020-07-10 04:38:28 +02:00
|
|
|
const MVert *mvert = mr->mvert;
|
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
if (mr->use_subsurf_fdots) {
|
2020-07-10 04:38:28 +02:00
|
|
|
const MVert *mv = &mr->mvert[ml->v];
|
2020-06-30 16:13:39 +02:00
|
|
|
if (mv->flag & ME_VERT_FACEDOT) {
|
|
|
|
copy_v3_v3(center[mp_index], mv->co);
|
2021-05-31 17:11:01 +02:00
|
|
|
break;
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
else {
|
|
|
|
const MVert *mv = &mvert[ml->v];
|
|
|
|
add_v3_v3(center[mp_index], mv->co);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!mr->use_subsurf_fdots) {
|
|
|
|
mul_v3_fl(co, 1.0f / (float)mp->totloop);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_fdots_pos = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_fdots_pos_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_fdots_pos_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_fdots_pos_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_pos)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Facedots Normal and edit flag
|
|
|
|
* \{ */
|
2020-02-10 15:29:16 +01:00
|
|
|
#define NOR_AND_FLAG_DEFAULT 0
|
|
|
|
#define NOR_AND_FLAG_SELECT 1
|
|
|
|
#define NOR_AND_FLAG_ACTIVE -1
|
|
|
|
#define NOR_AND_FLAG_HIDDEN -2
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_fdots_nor_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void extract_fdots_nor_finish(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf,
|
|
|
|
void *UNUSED(data))
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
GPUVertBuf *vbo = buf;
|
2021-05-31 17:11:01 +02:00
|
|
|
static float invalid_normal[3] = {0.0f, 0.0f, 0.0f};
|
2020-09-06 16:40:07 +02:00
|
|
|
GPUPackedNormal *nor = (GPUPackedNormal *)GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
2020-02-10 15:29:16 +01:00
|
|
|
const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
|
2020-03-31 16:05:19 +02:00
|
|
|
if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
|
|
|
|
mr->p_origindex[f] == ORIGINDEX_NONE)) {
|
2020-02-10 15:29:16 +01:00
|
|
|
nor[f] = GPU_normal_convert_i10_v3(invalid_normal);
|
|
|
|
nor[f].w = NOR_AND_FLAG_HIDDEN;
|
|
|
|
}
|
|
|
|
else {
|
2020-05-25 12:16:42 +02:00
|
|
|
nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa));
|
2020-02-10 15:29:16 +01:00
|
|
|
/* Select / Active Flag. */
|
|
|
|
nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
|
|
|
|
((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
|
|
|
|
NOR_AND_FLAG_DEFAULT);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (int f = 0; f < mr->poly_len; f++) {
|
2020-02-10 15:29:16 +01:00
|
|
|
efa = bm_original_face_get(mr, f);
|
2020-03-30 14:39:16 +02:00
|
|
|
const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
|
2020-03-31 16:05:19 +02:00
|
|
|
if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
|
|
|
|
mr->p_origindex[f] == ORIGINDEX_NONE)) {
|
2020-02-10 15:29:16 +01:00
|
|
|
nor[f] = GPU_normal_convert_i10_v3(invalid_normal);
|
|
|
|
nor[f].w = NOR_AND_FLAG_HIDDEN;
|
|
|
|
}
|
|
|
|
else {
|
2020-05-25 12:16:42 +02:00
|
|
|
nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa));
|
2019-07-14 16:49:44 +02:00
|
|
|
/* Select / Active Flag. */
|
2020-02-10 15:29:16 +01:00
|
|
|
nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
|
|
|
|
((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
|
|
|
|
NOR_AND_FLAG_DEFAULT);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_fdots_nor = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_fdots_nor_init,
|
|
|
|
.finish = extract_fdots_nor_finish,
|
|
|
|
.data_flag = MR_DATA_POLY_NOR,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2021-01-11 09:48:42 +01:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Facedots High Quality Normal and edit flag
|
|
|
|
* \{ */
|
|
|
|
static void *extract_fdots_nor_hq_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2021-01-11 09:48:42 +01:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
|
|
|
GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
|
2021-01-11 09:48:42 +01:00
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_fdots_nor_hq_finish(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf,
|
|
|
|
void *UNUSED(data))
|
|
|
|
{
|
|
|
|
GPUVertBuf *vbo = buf;
|
2021-05-31 17:11:01 +02:00
|
|
|
static float invalid_normal[3] = {0.0f, 0.0f, 0.0f};
|
2021-01-11 09:48:42 +01:00
|
|
|
short *nor = (short *)GPU_vertbuf_get_data(vbo);
|
|
|
|
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);
|
|
|
|
const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
|
|
|
|
if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
|
|
|
|
mr->p_origindex[f] == ORIGINDEX_NONE)) {
|
|
|
|
normal_float_to_short_v3(&nor[f * 4], invalid_normal);
|
|
|
|
nor[f * 4 + 3] = NOR_AND_FLAG_HIDDEN;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
normal_float_to_short_v3(&nor[f * 4], bm_face_no_get(mr, efa));
|
|
|
|
/* Select / Active Flag. */
|
|
|
|
nor[f * 4 + 3] = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
|
|
|
|
((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
|
|
|
|
NOR_AND_FLAG_DEFAULT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (int f = 0; f < mr->poly_len; f++) {
|
|
|
|
efa = bm_original_face_get(mr, f);
|
|
|
|
const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
|
|
|
|
if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
|
|
|
|
mr->p_origindex[f] == ORIGINDEX_NONE)) {
|
|
|
|
normal_float_to_short_v3(&nor[f * 4], invalid_normal);
|
|
|
|
nor[f * 4 + 3] = NOR_AND_FLAG_HIDDEN;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
normal_float_to_short_v3(&nor[f * 4], bm_face_no_get(mr, efa));
|
|
|
|
/* Select / Active Flag. */
|
|
|
|
nor[f * 4 + 3] = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
|
|
|
|
((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
|
|
|
|
NOR_AND_FLAG_DEFAULT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MeshExtract extract_fdots_nor_hq = {
|
|
|
|
.init = extract_fdots_nor_hq_init,
|
|
|
|
.finish = extract_fdots_nor_hq_finish,
|
|
|
|
.data_flag = MR_DATA_POLY_NOR,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor)};
|
2021-01-11 09:48:42 +01:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
/* ---------------------------------------------------------------------- */
|
2021-01-11 09:05:34 +01:00
|
|
|
/** \name Extract Facedots UV
|
2019-07-14 16:49:44 +02:00
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct MeshExtract_FdotUV_Data {
|
|
|
|
float (*vbo_data)[2];
|
|
|
|
MLoopUV *uv_data;
|
2019-11-08 12:16:25 +01:00
|
|
|
int cd_ofs;
|
2019-07-14 16:49:44 +02:00
|
|
|
} MeshExtract_FdotUV_Data;
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_fdots_uv_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
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");
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
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. */
|
2020-09-06 16:40:07 +02:00
|
|
|
memset(GPU_vertbuf_get_data(vbo), 0x0, mr->poly_len * GPU_vertbuf_get_format(vbo)->stride);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
MeshExtract_FdotUV_Data *data = MEM_callocN(sizeof(*data), __func__);
|
2020-09-06 16:40:07 +02:00
|
|
|
data->vbo_data = (float(*)[2])GPU_vertbuf_get_data(vbo);
|
2019-11-08 12:16:25 +01:00
|
|
|
|
|
|
|
if (mr->extract_type == MR_EXTRACT_BMESH) {
|
|
|
|
data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
data->uv_data = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_fdots_uv_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_FdotUV_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
float w = 1.0f / (float)f->len;
|
|
|
|
const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, data->cd_ofs);
|
|
|
|
madd_v2_v2fl(data->vbo_data[BM_elem_index_get(f)], luv->uv, w);
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int mp_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_FdotUV_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
|
|
|
if (mr->use_subsurf_fdots) {
|
2020-06-30 16:13:39 +02:00
|
|
|
const MVert *mv = &mr->mvert[ml->v];
|
|
|
|
if (mv->flag & ME_VERT_FACEDOT) {
|
|
|
|
copy_v2_v2(data->vbo_data[mp_index], data->uv_data[ml_index].uv);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
else {
|
2020-06-30 16:13:39 +02:00
|
|
|
float w = 1.0f / (float)mp->totloop;
|
|
|
|
madd_v2_v2fl(data->vbo_data[mp_index], data->uv_data[ml_index].uv, w);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_fdots_uv_finish(const MeshRenderData *UNUSED(mr),
|
2020-08-21 09:19:25 +02:00
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2019-07-14 16:49:44 +02:00
|
|
|
void *UNUSED(buf),
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_fdots_uv = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_fdots_uv_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_fdots_uv_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_fdots_uv_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_fdots_uv_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_uv)};
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Facedots Edit UV flag
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct MeshExtract_EditUVFdotData_Data {
|
|
|
|
EditLoopData *vbo_data;
|
|
|
|
int cd_ofs;
|
|
|
|
} MeshExtract_EditUVFdotData_Data;
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_fdots_edituv_data_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
|
|
|
GPU_vertformat_attr_add(&format, "flag", GPU_COMP_U8, 4, GPU_FETCH_INT);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
|
|
|
|
|
|
|
|
MeshExtract_EditUVFdotData_Data *data = MEM_callocN(sizeof(*data), __func__);
|
2020-09-06 16:40:07 +02:00
|
|
|
data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_fdots_edituv_data_iter_poly_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_EditUVFdotData_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
EditLoopData *eldata = &data->vbo_data[BM_elem_index_get(f)];
|
|
|
|
memset(eldata, 0x0, sizeof(*eldata));
|
|
|
|
mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_fdots_edituv_data_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *UNUSED(mp),
|
|
|
|
const int mp_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *_data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
MeshExtract_EditUVFdotData_Data *data = _data;
|
2021-05-31 17:11:01 +02:00
|
|
|
EditLoopData *eldata = &data->vbo_data[mp_index];
|
|
|
|
memset(eldata, 0x0, sizeof(*eldata));
|
|
|
|
BMFace *efa = bm_original_face_get(mr, mp_index);
|
|
|
|
if (efa) {
|
|
|
|
mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr),
|
2020-08-21 09:19:25 +02:00
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
2019-07-14 16:49:44 +02:00
|
|
|
void *UNUSED(buf),
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_fdots_edituv_data = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_fdots_edituv_data_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_fdots_edituv_data_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_fdots_edituv_data_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.finish = extract_fdots_edituv_data_finish,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_edituv_data)};
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
/** \} */
|
|
|
|
|
2019-10-15 01:49:53 +02:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Skin Modifier Roots
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
typedef struct SkinRootData {
|
|
|
|
float size;
|
|
|
|
float local_pos[3];
|
|
|
|
} SkinRootData;
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_skin_roots_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-10-15 01:49:53 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-10-15 01:49:53 +02:00
|
|
|
/* Exclusively for edit mode. */
|
|
|
|
BLI_assert(mr->bm);
|
|
|
|
|
|
|
|
static GPUVertFormat format = {0};
|
|
|
|
if (format.attr_len == 0) {
|
|
|
|
GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
|
|
|
GPU_vertformat_attr_add(&format, "local_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
|
2019-10-15 01:49:53 +02:00
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->bm->totvert);
|
|
|
|
|
2020-09-06 16:40:07 +02:00
|
|
|
SkinRootData *vbo_data = (SkinRootData *)GPU_vertbuf_get_data(vbo);
|
2019-10-15 01:49:53 +02:00
|
|
|
|
|
|
|
int root_len = 0;
|
|
|
|
int cd_ofs = CustomData_get_offset(&mr->bm->vdata, CD_MVERT_SKIN);
|
|
|
|
|
|
|
|
BMIter iter;
|
|
|
|
BMVert *eve;
|
|
|
|
BM_ITER_MESH (eve, &iter, mr->bm, BM_VERTS_OF_MESH) {
|
|
|
|
const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_ofs);
|
|
|
|
if (vs->flag & MVERT_SKIN_ROOT) {
|
|
|
|
vbo_data->size = (vs->radius[0] + vs->radius[1]) * 0.5f;
|
2020-05-25 12:16:42 +02:00
|
|
|
copy_v3_v3(vbo_data->local_pos, bm_vert_co_get(mr, eve));
|
2019-10-15 01:49:53 +02:00
|
|
|
vbo_data++;
|
|
|
|
root_len++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-06 04:07:03 +01:00
|
|
|
/* It's really unlikely that all verts will be roots. Resize to avoid losing VRAM. */
|
2019-10-15 01:49:53 +02:00
|
|
|
GPU_vertbuf_data_len_set(vbo, root_len);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MeshExtract extract_skin_roots = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_skin_roots_init,
|
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = false,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.skin_roots)};
|
2019-10-15 01:49:53 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Selection Index
|
|
|
|
* \{ */
|
|
|
|
|
2020-08-21 09:19:25 +02:00
|
|
|
static void *extract_select_idx_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
|
2020-09-06 16:40:07 +02:00
|
|
|
return GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-25 08:56:49 +02:00
|
|
|
/* TODO Use #glVertexID to get loop index and use the data structure on the CPU to retrieve the
|
2020-02-10 15:29:16 +01:00
|
|
|
* select element associated with this loop ID. This would remove the need for this separate
|
2020-06-25 08:56:49 +02:00
|
|
|
* index VBO's. We could upload the p/e/v_origindex as a buffer texture and sample it inside the
|
2020-02-10 15:29:16 +01:00
|
|
|
* shader to output original index. */
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_poly_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *f,
|
|
|
|
const int f_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
|
|
|
((uint32_t *)data)[l_index] = f_index;
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_edge_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
|
|
|
((uint32_t *)data)[l_index] = BM_elem_index_get(l_iter->e);
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_vert_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *f,
|
|
|
|
const int UNUSED(f_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
do {
|
|
|
|
const int l_index = BM_elem_index_get(l_iter);
|
|
|
|
((uint32_t *)data)[l_index] = BM_elem_index_get(l_iter->v);
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edge_idx_iter_ledge_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMEdge *eed,
|
|
|
|
const int ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed);
|
|
|
|
((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_vert_idx_iter_ledge_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMEdge *eed,
|
|
|
|
const int ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed->v1);
|
|
|
|
((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed->v2);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_vert_idx_iter_lvert_bm(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
BMVert *eve,
|
|
|
|
const int lvert_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
((uint32_t *)data)[offset + lvert_index] = BM_elem_index_get(eve);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_poly_idx_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int mp_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
2020-06-30 16:13:39 +02:00
|
|
|
((uint32_t *)data)[ml_index] = (mr->p_origindex) ? mr->p_origindex[mp_index] : mp_index;
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edge_idx_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int UNUSED(mp_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
2020-06-30 16:13:39 +02:00
|
|
|
((uint32_t *)data)[ml_index] = (mr->e_origindex) ? mr->e_origindex[ml->e] : ml->e;
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_vert_idx_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *mp,
|
|
|
|
const int UNUSED(mp_index),
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const MLoop *mloop = mr->mloop;
|
|
|
|
const int ml_index_end = mp->loopstart + mp->totloop;
|
|
|
|
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
|
|
|
const MLoop *ml = &mloop[ml_index];
|
2020-06-30 16:13:39 +02:00
|
|
|
((uint32_t *)data)[ml_index] = (mr->v_origindex) ? mr->v_origindex[ml->v] : ml->v;
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_edge_idx_iter_ledge_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MEdge *UNUSED(med),
|
|
|
|
const uint ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
const int e_index = mr->ledges[ledge_index];
|
|
|
|
const int e_orig = (mr->e_origindex) ? mr->e_origindex[e_index] : e_index;
|
|
|
|
((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = e_orig;
|
|
|
|
((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = e_orig;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_vert_idx_iter_ledge_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MEdge *med,
|
|
|
|
const uint ledge_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
int v1_orig = (mr->v_origindex) ? mr->v_origindex[med->v1] : med->v1;
|
|
|
|
int v2_orig = (mr->v_origindex) ? mr->v_origindex[med->v2] : med->v2;
|
|
|
|
((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = v1_orig;
|
|
|
|
((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = v2_orig;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MVert *UNUSED(mv),
|
|
|
|
const int lvert_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
const int v_index = mr->lverts[lvert_index];
|
|
|
|
const int v_orig = (mr->v_origindex) ? mr->v_origindex[v_index] : v_index;
|
|
|
|
((uint32_t *)data)[offset + lvert_index] = v_orig;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_poly_idx = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_select_idx_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_poly_idx_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_poly_idx_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.poly_idx)};
|
2019-08-22 18:22:23 +02:00
|
|
|
|
|
|
|
static const MeshExtract extract_edge_idx = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_select_idx_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_edge_idx_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_edge_idx_iter_poly_mesh,
|
|
|
|
.iter_ledge_bm = extract_edge_idx_iter_ledge_bm,
|
|
|
|
.iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_idx)};
|
2019-08-22 18:22:23 +02:00
|
|
|
|
|
|
|
static const MeshExtract extract_vert_idx = {
|
2020-06-29 07:09:43 +02:00
|
|
|
.init = extract_select_idx_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_vert_idx_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_vert_idx_iter_poly_mesh,
|
|
|
|
.iter_ledge_bm = extract_vert_idx_iter_ledge_bm,
|
|
|
|
.iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh,
|
|
|
|
.iter_lvert_bm = extract_vert_idx_iter_lvert_bm,
|
|
|
|
.iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vert_idx)};
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void *extract_fdot_idx_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *UNUSED(cache),
|
|
|
|
void *buf)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
GPUVertBuf *vbo = buf;
|
2019-07-14 16:49:44 +02:00
|
|
|
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);
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
GPU_vertbuf_init_with_format(vbo, &format);
|
|
|
|
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
|
2020-09-06 16:40:07 +02:00
|
|
|
return GPU_vertbuf_get_data(vbo);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_fdot_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
|
|
|
|
BMFace *UNUSED(f),
|
|
|
|
const int f_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
((uint32_t *)data)[f_index] = f_index;
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 16:13:39 +02:00
|
|
|
static void extract_fdot_idx_iter_poly_mesh(const MeshRenderData *mr,
|
2021-05-31 17:11:01 +02:00
|
|
|
const MPoly *UNUSED(mp),
|
|
|
|
const int mp_index,
|
2020-06-30 16:13:39 +02:00
|
|
|
void *data)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-30 16:13:39 +02:00
|
|
|
if (mr->p_origindex != NULL) {
|
2021-05-31 17:11:01 +02:00
|
|
|
((uint32_t *)data)[mp_index] = mr->p_origindex[mp_index];
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
|
|
|
else {
|
2021-05-31 17:11:01 +02:00
|
|
|
((uint32_t *)data)[mp_index] = mp_index;
|
2020-06-30 16:13:39 +02:00
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2019-08-22 18:22:23 +02:00
|
|
|
static const MeshExtract extract_fdot_idx = {
|
2021-05-31 17:11:01 +02:00
|
|
|
.init = extract_fdot_idx_init,
|
2020-06-30 16:13:39 +02:00
|
|
|
.iter_poly_bm = extract_fdot_idx_iter_poly_bm,
|
|
|
|
.iter_poly_mesh = extract_fdot_idx_iter_poly_mesh,
|
2020-06-29 07:09:43 +02:00
|
|
|
.data_flag = 0,
|
|
|
|
.use_threading = true,
|
2021-05-31 17:11:01 +02:00
|
|
|
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdot_idx)};
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
static void extracts_flags_get(const MeshExtractRunDataArray *extractors,
|
|
|
|
eMRIterType *r_iter_type,
|
|
|
|
eMRDataType *r_data_flag)
|
|
|
|
{
|
|
|
|
eMRIterType iter_type = 0;
|
|
|
|
eMRDataType data_flag = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < extractors->len; i++) {
|
|
|
|
const MeshExtract *extractor = extractors->items[i].extractor;
|
|
|
|
iter_type |= mesh_extract_iter_type(extractor);
|
|
|
|
data_flag |= extractor->data_flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r_iter_type) {
|
|
|
|
*r_iter_type = iter_type;
|
|
|
|
}
|
|
|
|
if (r_data_flag) {
|
|
|
|
*r_data_flag = data_flag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void extract_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *cache,
|
|
|
|
MeshExtractRunDataArray *extractors,
|
|
|
|
MeshBufferCache *mbc)
|
|
|
|
{
|
|
|
|
/* Multi thread. */
|
|
|
|
for (int i = 0; i < extractors->len; i++) {
|
|
|
|
MeshExtractRunData *run_data = &extractors->items[i];
|
|
|
|
const MeshExtract *extractor = run_data->extractor;
|
|
|
|
run_data->buffer = mesh_extract_buffer_get(extractor, mbc);
|
|
|
|
run_data->user_data = extractor->init(mr, cache, run_data->buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void extract_iter_looptri_bm(const MeshRenderData *mr,
|
|
|
|
const ExtractTriBMesh_Params *params,
|
|
|
|
const MeshExtractRunDataArray *_extractors)
|
|
|
|
{
|
|
|
|
MeshExtractRunDataArray extractors;
|
|
|
|
mesh_extract_run_data_array_init(&extractors);
|
|
|
|
mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_LOOPTRI);
|
|
|
|
|
|
|
|
EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, elt_index, params)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < extractors.len; i++) {
|
|
|
|
MeshExtractRunData *run_data = &extractors.items[i];
|
|
|
|
run_data->extractor->iter_looptri_bm(mr, elt, elt_index, run_data->user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void extract_iter_looptri_mesh(const MeshRenderData *mr,
|
|
|
|
const ExtractTriMesh_Params *params,
|
|
|
|
const MeshExtractRunDataArray *_extractors)
|
|
|
|
{
|
|
|
|
MeshExtractRunDataArray extractors;
|
|
|
|
mesh_extract_run_data_array_init(&extractors);
|
|
|
|
mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_LOOPTRI);
|
|
|
|
|
|
|
|
EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, mlt_index, params)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < extractors.len; i++) {
|
|
|
|
MeshExtractRunData *run_data = &extractors.items[i];
|
|
|
|
run_data->extractor->iter_looptri_mesh(mr, mlt, mlt_index, run_data->user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void extract_iter_poly_bm(const MeshRenderData *mr,
|
|
|
|
const ExtractPolyBMesh_Params *params,
|
|
|
|
const MeshExtractRunDataArray *_extractors)
|
|
|
|
{
|
|
|
|
MeshExtractRunDataArray extractors;
|
|
|
|
mesh_extract_run_data_array_init(&extractors);
|
|
|
|
mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_POLY);
|
|
|
|
|
|
|
|
EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < extractors.len; i++) {
|
|
|
|
MeshExtractRunData *run_data = &extractors.items[i];
|
|
|
|
run_data->extractor->iter_poly_bm(mr, f, f_index, run_data->user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXTRACT_POLY_FOREACH_BM_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void extract_iter_poly_mesh(const MeshRenderData *mr,
|
|
|
|
const ExtractPolyMesh_Params *params,
|
|
|
|
const MeshExtractRunDataArray *_extractors)
|
|
|
|
{
|
|
|
|
MeshExtractRunDataArray extractors;
|
|
|
|
mesh_extract_run_data_array_init(&extractors);
|
|
|
|
mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_POLY);
|
|
|
|
|
|
|
|
EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < extractors.len; i++) {
|
|
|
|
MeshExtractRunData *run_data = &extractors.items[i];
|
|
|
|
run_data->extractor->iter_poly_mesh(mr, mp, mp_index, run_data->user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXTRACT_POLY_FOREACH_MESH_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void extract_iter_ledge_bm(const MeshRenderData *mr,
|
|
|
|
const ExtractLEdgeBMesh_Params *params,
|
|
|
|
const MeshExtractRunDataArray *_extractors)
|
|
|
|
{
|
|
|
|
MeshExtractRunDataArray extractors;
|
|
|
|
mesh_extract_run_data_array_init(&extractors);
|
|
|
|
mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_LEDGE);
|
|
|
|
|
|
|
|
EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < extractors.len; i++) {
|
|
|
|
MeshExtractRunData *run_data = &extractors.items[i];
|
|
|
|
run_data->extractor->iter_ledge_bm(mr, eed, ledge_index, run_data->user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXTRACT_LEDGE_FOREACH_BM_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void extract_iter_ledge_mesh(const MeshRenderData *mr,
|
|
|
|
const ExtractLEdgeMesh_Params *params,
|
|
|
|
const MeshExtractRunDataArray *_extractors)
|
|
|
|
{
|
|
|
|
MeshExtractRunDataArray extractors;
|
|
|
|
mesh_extract_run_data_array_init(&extractors);
|
|
|
|
mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_LEDGE);
|
|
|
|
|
|
|
|
EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < extractors.len; i++) {
|
|
|
|
MeshExtractRunData *run_data = &extractors.items[i];
|
|
|
|
run_data->extractor->iter_ledge_mesh(mr, med, ledge_index, run_data->user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXTRACT_LEDGE_FOREACH_MESH_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void extract_iter_lvert_bm(const MeshRenderData *mr,
|
|
|
|
const ExtractLVertBMesh_Params *params,
|
|
|
|
const MeshExtractRunDataArray *_extractors)
|
|
|
|
{
|
|
|
|
MeshExtractRunDataArray extractors;
|
|
|
|
mesh_extract_run_data_array_init(&extractors);
|
|
|
|
mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_LVERT);
|
|
|
|
|
|
|
|
EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < extractors.len; i++) {
|
|
|
|
MeshExtractRunData *run_data = &extractors.items[i];
|
|
|
|
run_data->extractor->iter_lvert_bm(mr, eve, lvert_index, run_data->user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXTRACT_LVERT_FOREACH_BM_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void extract_iter_lvert_mesh(const MeshRenderData *mr,
|
|
|
|
const ExtractLVertMesh_Params *params,
|
|
|
|
const MeshExtractRunDataArray *_extractors)
|
|
|
|
{
|
|
|
|
MeshExtractRunDataArray extractors;
|
|
|
|
mesh_extract_run_data_array_init(&extractors);
|
|
|
|
mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_LVERT);
|
|
|
|
|
|
|
|
EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < extractors.len; i++) {
|
|
|
|
MeshExtractRunData *run_data = &extractors.items[i];
|
|
|
|
run_data->extractor->iter_lvert_mesh(mr, mv, lvert_index, run_data->user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXTRACT_LVERT_FOREACH_MESH_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void extract_finish(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *cache,
|
|
|
|
const MeshExtractRunDataArray *extractors)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < extractors->len; i++) {
|
|
|
|
const MeshExtractRunData *run_data = &extractors->items[i];
|
|
|
|
const MeshExtract *extractor = run_data->extractor;
|
|
|
|
if (extractor->finish) {
|
|
|
|
extractor->finish(mr, cache, run_data->buffer, run_data->user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Single Thread. */
|
|
|
|
BLI_INLINE void extract_run_and_finish_init(const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *cache,
|
|
|
|
MeshExtractRunDataArray *extractors,
|
|
|
|
eMRIterType iter_type,
|
|
|
|
MeshBufferCache *mbc)
|
|
|
|
{
|
|
|
|
extract_init(mr, cache, extractors, mbc);
|
|
|
|
|
|
|
|
bool is_mesh = mr->extract_type != MR_EXTRACT_BMESH;
|
|
|
|
if (iter_type & MR_ITER_LOOPTRI) {
|
|
|
|
if (is_mesh) {
|
|
|
|
extract_iter_looptri_mesh(mr,
|
|
|
|
&(const ExtractTriMesh_Params){
|
|
|
|
.mlooptri = mr->mlooptri,
|
|
|
|
.tri_range = {0, mr->tri_len},
|
|
|
|
},
|
|
|
|
extractors);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
extract_iter_looptri_bm(mr,
|
|
|
|
&(const ExtractTriBMesh_Params){
|
|
|
|
.looptris = mr->edit_bmesh->looptris,
|
|
|
|
.tri_range = {0, mr->tri_len},
|
|
|
|
},
|
|
|
|
extractors);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (iter_type & MR_ITER_POLY) {
|
|
|
|
if (is_mesh) {
|
|
|
|
extract_iter_poly_mesh(mr,
|
|
|
|
&(const ExtractPolyMesh_Params){
|
|
|
|
.poly_range = {0, mr->poly_len},
|
|
|
|
},
|
|
|
|
extractors);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
extract_iter_poly_bm(mr,
|
|
|
|
&(const ExtractPolyBMesh_Params){
|
|
|
|
.poly_range = {0, mr->poly_len},
|
|
|
|
},
|
|
|
|
extractors);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (iter_type & MR_ITER_LEDGE) {
|
|
|
|
if (is_mesh) {
|
|
|
|
extract_iter_ledge_mesh(mr,
|
|
|
|
&(const ExtractLEdgeMesh_Params){
|
|
|
|
.ledge = mr->ledges,
|
|
|
|
.ledge_range = {0, mr->edge_loose_len},
|
|
|
|
},
|
|
|
|
extractors);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
extract_iter_ledge_bm(mr,
|
|
|
|
&(const ExtractLEdgeBMesh_Params){
|
|
|
|
.ledge = mr->ledges,
|
|
|
|
.ledge_range = {0, mr->edge_loose_len},
|
|
|
|
},
|
|
|
|
extractors);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (iter_type & MR_ITER_LVERT) {
|
|
|
|
if (is_mesh) {
|
|
|
|
extract_iter_lvert_mesh(mr,
|
|
|
|
&(const ExtractLVertMesh_Params){
|
|
|
|
.lvert = mr->lverts,
|
|
|
|
.lvert_range = {0, mr->vert_loose_len},
|
|
|
|
},
|
|
|
|
extractors);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
extract_iter_lvert_bm(mr,
|
|
|
|
&(const ExtractLVertBMesh_Params){
|
|
|
|
.lvert = mr->lverts,
|
|
|
|
.lvert_range = {0, mr->vert_loose_len},
|
|
|
|
},
|
|
|
|
extractors);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
extract_finish(mr, cache, extractors);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
2020-06-02 15:07:17 +02:00
|
|
|
/** \name ExtractTaskData
|
2019-07-14 16:49:44 +02:00
|
|
|
* \{ */
|
|
|
|
typedef struct ExtractTaskData {
|
2020-06-02 15:07:17 +02:00
|
|
|
void *next, *prev;
|
2019-07-14 16:49:44 +02:00
|
|
|
const MeshRenderData *mr;
|
2020-08-21 09:19:25 +02:00
|
|
|
struct MeshBatchCache *cache;
|
2021-05-31 17:11:01 +02:00
|
|
|
MeshExtractRunDataArray *extractors;
|
2019-07-14 16:49:44 +02:00
|
|
|
eMRIterType iter_type;
|
|
|
|
int start, end;
|
|
|
|
/** Decremented each time a task is finished. */
|
|
|
|
int32_t *task_counter;
|
2021-05-31 17:11:01 +02:00
|
|
|
MeshBufferCache *mbc;
|
2019-07-14 16:49:44 +02:00
|
|
|
} ExtractTaskData;
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static ExtractTaskData *extract_extract_iter_task_data_create_mesh(
|
|
|
|
const MeshRenderData *mr,
|
|
|
|
struct MeshBatchCache *cache,
|
|
|
|
MeshExtractRunDataArray *extractors,
|
|
|
|
MeshBufferCache *mbc,
|
|
|
|
int32_t *task_counter)
|
2020-06-15 16:46:56 +02:00
|
|
|
{
|
|
|
|
ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), __func__);
|
|
|
|
taskdata->next = NULL;
|
|
|
|
taskdata->prev = NULL;
|
|
|
|
taskdata->mr = mr;
|
2020-08-21 09:19:25 +02:00
|
|
|
taskdata->cache = cache;
|
2021-05-31 17:11:01 +02:00
|
|
|
taskdata->mbc = mbc;
|
2020-06-15 16:46:56 +02:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
/* #UserData is shared between the iterations as it holds counters to detect if the
|
2020-06-25 08:56:49 +02:00
|
|
|
* extraction is finished. To make sure the duplication of the user_data does not create a new
|
|
|
|
* instance of the counters we allocate the user_data in its own container.
|
2020-06-15 16:46:56 +02:00
|
|
|
*
|
|
|
|
* This structure makes sure that when extract_init is called, that the user data of all
|
|
|
|
* iterations are updated. */
|
2021-05-31 17:11:01 +02:00
|
|
|
taskdata->extractors = extractors;
|
2020-06-15 16:46:56 +02:00
|
|
|
taskdata->task_counter = task_counter;
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
extracts_flags_get(extractors, &taskdata->iter_type, NULL);
|
2020-06-15 16:46:56 +02:00
|
|
|
taskdata->start = 0;
|
|
|
|
taskdata->end = INT_MAX;
|
|
|
|
return taskdata;
|
|
|
|
}
|
|
|
|
|
2020-06-02 15:07:17 +02:00
|
|
|
static void extract_task_data_free(void *data)
|
|
|
|
{
|
|
|
|
ExtractTaskData *task_data = data;
|
2021-05-31 17:11:01 +02:00
|
|
|
MEM_SAFE_FREE(task_data->extractors);
|
2020-06-02 15:07:17 +02:00
|
|
|
MEM_freeN(task_data);
|
|
|
|
}
|
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr,
|
|
|
|
const eMRIterType iter_type,
|
|
|
|
int start,
|
|
|
|
int end,
|
2021-05-31 17:11:01 +02:00
|
|
|
MeshExtractRunDataArray *extractors)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
switch (mr->extract_type) {
|
|
|
|
case MR_EXTRACT_BMESH:
|
|
|
|
if (iter_type & MR_ITER_LOOPTRI) {
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_iter_looptri_bm(mr,
|
|
|
|
&(const ExtractTriBMesh_Params){
|
|
|
|
.looptris = mr->edit_bmesh->looptris,
|
|
|
|
.tri_range = {start, min_ii(mr->tri_len, end)},
|
|
|
|
},
|
|
|
|
extractors);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
2020-06-30 16:13:39 +02:00
|
|
|
if (iter_type & MR_ITER_POLY) {
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_iter_poly_bm(mr,
|
|
|
|
&(const ExtractPolyBMesh_Params){
|
|
|
|
.poly_range = {start, min_ii(mr->poly_len, end)},
|
|
|
|
},
|
|
|
|
extractors);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
if (iter_type & MR_ITER_LEDGE) {
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_iter_ledge_bm(mr,
|
|
|
|
&(const ExtractLEdgeBMesh_Params){
|
|
|
|
.ledge = mr->ledges,
|
|
|
|
.ledge_range = {start, min_ii(mr->edge_loose_len, end)},
|
|
|
|
},
|
|
|
|
extractors);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
if (iter_type & MR_ITER_LVERT) {
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_iter_lvert_bm(mr,
|
|
|
|
&(const ExtractLVertBMesh_Params){
|
|
|
|
.lvert = mr->lverts,
|
|
|
|
.lvert_range = {start, min_ii(mr->vert_loose_len, end)},
|
|
|
|
},
|
|
|
|
extractors);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MR_EXTRACT_MAPPED:
|
|
|
|
case MR_EXTRACT_MESH:
|
|
|
|
if (iter_type & MR_ITER_LOOPTRI) {
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_iter_looptri_mesh(mr,
|
|
|
|
&(const ExtractTriMesh_Params){
|
|
|
|
.mlooptri = mr->mlooptri,
|
|
|
|
.tri_range = {start, min_ii(mr->tri_len, end)},
|
|
|
|
},
|
|
|
|
extractors);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
2020-06-30 16:13:39 +02:00
|
|
|
if (iter_type & MR_ITER_POLY) {
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_iter_poly_mesh(mr,
|
|
|
|
&(const ExtractPolyMesh_Params){
|
|
|
|
.poly_range = {start, min_ii(mr->poly_len, end)},
|
|
|
|
},
|
|
|
|
extractors);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
if (iter_type & MR_ITER_LEDGE) {
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_iter_ledge_mesh(mr,
|
|
|
|
&(const ExtractLEdgeMesh_Params){
|
|
|
|
.ledge = mr->ledges,
|
|
|
|
.ledge_range = {start, min_ii(mr->edge_loose_len, end)},
|
|
|
|
},
|
|
|
|
extractors);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
if (iter_type & MR_ITER_LVERT) {
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_iter_lvert_mesh(mr,
|
|
|
|
&(const ExtractLVertMesh_Params){
|
|
|
|
.lvert = mr->lverts,
|
|
|
|
.lvert_range = {start, min_ii(mr->vert_loose_len, end)},
|
|
|
|
},
|
|
|
|
extractors);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_task_init(ExtractTaskData *data)
|
2020-06-02 15:07:17 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_init(data->mr, data->cache, data->extractors, data->mbc);
|
2020-06-02 15:07:17 +02:00
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_task_run(void *__restrict taskdata)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2020-06-02 15:07:17 +02:00
|
|
|
ExtractTaskData *data = (ExtractTaskData *)taskdata;
|
2021-05-31 17:11:01 +02:00
|
|
|
mesh_extract_iter(data->mr, data->iter_type, data->start, data->end, data->extractors);
|
2020-06-15 16:46:56 +02:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
/* 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) {
|
|
|
|
extract_finish(data->mr, data->cache, data->extractors);
|
2020-06-02 15:07:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_task_init_and_run(void *__restrict taskdata)
|
2020-06-02 15:07:17 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
ExtractTaskData *data = (ExtractTaskData *)taskdata;
|
|
|
|
extract_run_and_finish_init(data->mr, data->cache, data->extractors, data->iter_type, data->mbc);
|
2020-06-02 15:07:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Task Node - Update Mesh Render Data
|
|
|
|
* \{ */
|
|
|
|
typedef struct MeshRenderDataUpdateTaskData {
|
|
|
|
MeshRenderData *mr;
|
|
|
|
eMRIterType iter_type;
|
|
|
|
eMRDataType data_flag;
|
|
|
|
} MeshRenderDataUpdateTaskData;
|
|
|
|
|
|
|
|
static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata)
|
|
|
|
{
|
|
|
|
BLI_assert(taskdata);
|
2020-06-15 16:46:56 +02:00
|
|
|
MeshRenderData *mr = taskdata->mr;
|
|
|
|
mesh_render_data_free(mr);
|
2020-06-02 15:07:17 +02:00
|
|
|
MEM_freeN(taskdata);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_extract_render_data_node_exec(void *__restrict task_data)
|
|
|
|
{
|
|
|
|
MeshRenderDataUpdateTaskData *update_task_data = task_data;
|
2020-06-15 15:25:25 +02:00
|
|
|
MeshRenderData *mr = update_task_data->mr;
|
|
|
|
const eMRIterType iter_type = update_task_data->iter_type;
|
|
|
|
const eMRDataType data_flag = update_task_data->data_flag;
|
|
|
|
|
|
|
|
mesh_render_data_update_normals(mr, iter_type, data_flag);
|
|
|
|
mesh_render_data_update_looptris(mr, iter_type, data_flag);
|
2020-06-02 15:07:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph,
|
|
|
|
MeshRenderData *mr,
|
|
|
|
const eMRIterType iter_type,
|
|
|
|
const eMRDataType data_flag)
|
|
|
|
{
|
|
|
|
MeshRenderDataUpdateTaskData *task_data = MEM_mallocN(sizeof(MeshRenderDataUpdateTaskData),
|
|
|
|
__func__);
|
|
|
|
task_data->mr = mr;
|
|
|
|
task_data->iter_type = iter_type;
|
|
|
|
task_data->data_flag = data_flag;
|
|
|
|
|
|
|
|
struct TaskNode *task_node = BLI_task_graph_node_create(
|
|
|
|
task_graph,
|
|
|
|
mesh_extract_render_data_node_exec,
|
|
|
|
task_data,
|
|
|
|
(TaskGraphNodeFreeFunction)mesh_render_data_update_task_data_free);
|
|
|
|
return task_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Task Node - Extract Single Threaded
|
|
|
|
* \{ */
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static struct TaskNode *extract_single_threaded_task_node_create(struct TaskGraph *task_graph,
|
|
|
|
ExtractTaskData *task_data)
|
2020-06-02 15:07:17 +02:00
|
|
|
{
|
|
|
|
struct TaskNode *task_node = BLI_task_graph_node_create(
|
|
|
|
task_graph,
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_task_init_and_run,
|
2020-06-02 15:07:17 +02:00
|
|
|
task_data,
|
2021-05-31 17:11:01 +02:00
|
|
|
(TaskGraphNodeFreeFunction)extract_task_data_free);
|
2020-06-02 15:07:17 +02:00
|
|
|
return task_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Task Node - UserData Initializer
|
|
|
|
* \{ */
|
|
|
|
typedef struct UserDataInitTaskData {
|
2021-05-31 17:11:01 +02:00
|
|
|
ExtractTaskData *td;
|
|
|
|
int32_t task_counter;
|
2020-06-02 15:07:17 +02:00
|
|
|
|
|
|
|
} UserDataInitTaskData;
|
|
|
|
|
|
|
|
static void user_data_init_task_data_free(UserDataInitTaskData *taskdata)
|
|
|
|
{
|
|
|
|
BLI_assert(taskdata);
|
2021-05-31 17:11:01 +02:00
|
|
|
extract_task_data_free(taskdata->td);
|
2020-06-02 15:07:17 +02:00
|
|
|
MEM_freeN(taskdata);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void user_data_init_task_data_exec(void *__restrict task_data)
|
|
|
|
{
|
|
|
|
UserDataInitTaskData *extract_task_data = task_data;
|
2021-05-31 17:11:01 +02:00
|
|
|
ExtractTaskData *taskdata_base = extract_task_data->td;
|
|
|
|
extract_task_init(taskdata_base);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-02 15:07:17 +02:00
|
|
|
static struct TaskNode *user_data_init_task_node_create(struct TaskGraph *task_graph,
|
|
|
|
UserDataInitTaskData *task_data)
|
|
|
|
{
|
|
|
|
struct TaskNode *task_node = BLI_task_graph_node_create(
|
|
|
|
task_graph,
|
|
|
|
user_data_init_task_data_exec,
|
|
|
|
task_data,
|
|
|
|
(TaskGraphNodeFreeFunction)user_data_init_task_data_free);
|
|
|
|
return task_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
2021-05-31 17:11:01 +02:00
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Override extractors
|
|
|
|
* Extractors can be overridden. When overridden a specialized version is used. The next functions
|
|
|
|
* would check for any needed overrides and usage of the specialized version.
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
static const MeshExtract *mesh_extract_override_hq_normals(const MeshExtract *extractor)
|
|
|
|
{
|
|
|
|
if (extractor == &extract_pos_nor) {
|
|
|
|
return &extract_pos_nor_hq;
|
|
|
|
}
|
|
|
|
if (extractor == &extract_lnor) {
|
|
|
|
return &extract_lnor_hq;
|
|
|
|
}
|
|
|
|
if (extractor == &extract_tan) {
|
|
|
|
return &extract_tan_hq;
|
|
|
|
}
|
|
|
|
if (extractor == &extract_fdots_nor) {
|
|
|
|
return &extract_fdots_nor_hq;
|
|
|
|
}
|
|
|
|
return extractor;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MeshExtract *mesh_extract_override_loose_lines(const MeshExtract *extractor)
|
|
|
|
{
|
|
|
|
if (extractor == &extract_lines) {
|
|
|
|
return &extract_lines_with_lines_loose;
|
|
|
|
}
|
|
|
|
return extractor;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor,
|
|
|
|
const bool do_hq_normals,
|
|
|
|
const bool do_lines_loose_subbuffer)
|
|
|
|
{
|
|
|
|
if (do_hq_normals) {
|
|
|
|
extractor = mesh_extract_override_hq_normals(extractor);
|
|
|
|
}
|
|
|
|
if (do_lines_loose_subbuffer) {
|
|
|
|
extractor = mesh_extract_override_loose_lines(extractor);
|
|
|
|
}
|
|
|
|
return extractor;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2020-06-02 15:07:17 +02:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/** \name Extract Loop
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
static void extract_range_task_create(struct TaskGraph *task_graph,
|
|
|
|
struct TaskNode *task_node_user_data_init,
|
|
|
|
ExtractTaskData *taskdata,
|
|
|
|
const eMRIterType type,
|
|
|
|
int start,
|
|
|
|
int length)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
|
|
|
taskdata = MEM_dupallocN(taskdata);
|
|
|
|
atomic_add_and_fetch_int32(taskdata->task_counter, 1);
|
|
|
|
taskdata->iter_type = type;
|
|
|
|
taskdata->start = start;
|
|
|
|
taskdata->end = start + length;
|
2020-06-02 15:07:17 +02:00
|
|
|
struct TaskNode *task_node = BLI_task_graph_node_create(
|
2021-05-31 17:11:01 +02:00
|
|
|
task_graph, extract_task_run, taskdata, MEM_freeN);
|
2020-06-02 15:07:17 +02:00
|
|
|
BLI_task_graph_edge_create(task_node_user_data_init, task_node);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static int extract_range_task_num_elements_get(const MeshRenderData *mr,
|
|
|
|
const eMRIterType iter_type)
|
2019-07-14 16:49:44 +02:00
|
|
|
{
|
2021-05-31 17:11:01 +02:00
|
|
|
/* Divide task into sensible chunks. */
|
|
|
|
int iter_len = 0;
|
|
|
|
if (iter_type & MR_ITER_LOOPTRI) {
|
|
|
|
iter_len += mr->tri_len;
|
2020-02-19 01:44:52 +01:00
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
if (iter_type & MR_ITER_POLY) {
|
|
|
|
iter_len += mr->poly_len;
|
|
|
|
}
|
|
|
|
if (iter_type & MR_ITER_LEDGE) {
|
|
|
|
iter_len += mr->edge_loose_len;
|
|
|
|
}
|
|
|
|
if (iter_type & MR_ITER_LVERT) {
|
|
|
|
iter_len += mr->vert_loose_len;
|
|
|
|
}
|
|
|
|
return iter_len;
|
|
|
|
}
|
2020-02-19 01:44:52 +01:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static int extract_range_task_chunk_size_get(const MeshRenderData *mr,
|
|
|
|
const eMRIterType iter_type,
|
|
|
|
const int num_threads)
|
|
|
|
{
|
|
|
|
/* Divide task into sensible chunks. */
|
|
|
|
const int num_elements = extract_range_task_num_elements_get(mr, iter_type);
|
|
|
|
int range_len = (num_elements + num_threads) / num_threads;
|
|
|
|
CLAMP_MIN(range_len, CHUNK_SIZE);
|
|
|
|
return range_len;
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
static void extract_task_in_ranges_create(struct TaskGraph *task_graph,
|
|
|
|
struct TaskNode *task_node_user_data_init,
|
|
|
|
ExtractTaskData *taskdata_base,
|
|
|
|
const int num_threads)
|
|
|
|
{
|
|
|
|
const MeshRenderData *mr = taskdata_base->mr;
|
|
|
|
const int range_len = extract_range_task_chunk_size_get(
|
|
|
|
mr, taskdata_base->iter_type, num_threads);
|
|
|
|
|
|
|
|
if (taskdata_base->iter_type & MR_ITER_LOOPTRI) {
|
|
|
|
for (int i = 0; i < mr->tri_len; i += range_len) {
|
|
|
|
extract_range_task_create(
|
|
|
|
task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LOOPTRI, i, range_len);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
}
|
|
|
|
if (taskdata_base->iter_type & MR_ITER_POLY) {
|
|
|
|
for (int i = 0; i < mr->poly_len; i += range_len) {
|
|
|
|
extract_range_task_create(
|
|
|
|
task_graph, task_node_user_data_init, taskdata_base, MR_ITER_POLY, i, range_len);
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
if (taskdata_base->iter_type & MR_ITER_LEDGE) {
|
|
|
|
for (int i = 0; i < mr->edge_loose_len; i += range_len) {
|
|
|
|
extract_range_task_create(
|
|
|
|
task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LEDGE, i, range_len);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
2021-05-31 17:11:01 +02:00
|
|
|
if (taskdata_base->iter_type & MR_ITER_LVERT) {
|
|
|
|
for (int i = 0; i < mr->vert_loose_len; i += range_len) {
|
|
|
|
extract_range_task_create(
|
|
|
|
task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LVERT, i, range_len);
|
|
|
|
}
|
2019-07-14 16:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-02 15:07:17 +02:00
|
|
|
void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
|
|
|
|
MeshBatchCache *cache,
|
2021-05-31 17:11:01 +02:00
|
|
|
MeshBufferCache *mbc,
|
2021-05-31 09:32:37 +02:00
|
|
|
MeshBufferExtractionCache *extraction_cache,
|
2019-07-14 16:49:44 +02:00
|
|
|
Mesh *me,
|
2020-06-02 15:07:17 +02:00
|
|
|
|
2020-01-08 12:20:45 +01:00
|
|
|
const bool is_editmode,
|
2020-04-04 11:14:45 +02:00
|
|
|
const bool is_paint_mode,
|
2020-08-25 15:49:55 +02:00
|
|
|
const bool is_mode_active,
|
2020-01-07 04:06:33 +01:00
|
|
|
const float obmat[4][4],
|
2019-07-14 16:49:44 +02:00
|
|
|
const bool do_final,
|
|
|
|
const bool do_uvedit,
|
|
|
|
const bool use_subsurf_fdots,
|
|
|
|
const DRW_MeshCDMask *cd_layer_used,
|
2020-02-19 01:44:52 +01:00
|
|
|
const Scene *scene,
|
2019-07-14 16:49:44 +02:00
|
|
|
const ToolSettings *ts,
|
|
|
|
const bool use_hide)
|
|
|
|
{
|
2020-06-02 15:07:17 +02:00
|
|
|
/* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph.
|
2021-05-31 17:11:01 +02:00
|
|
|
* This sub-graph starts with an extract_render_data_node. This fills/converts the required
|
|
|
|
* data from Mesh.
|
2020-06-02 15:07:17 +02:00
|
|
|
*
|
|
|
|
* Small extractions and extractions that can't be multi-threaded are grouped in a single
|
|
|
|
* `extract_single_threaded_task_node`.
|
|
|
|
*
|
|
|
|
* Other extractions will create a node for each loop exceeding 8192 items. these nodes are
|
2020-06-25 08:56:49 +02:00
|
|
|
* linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the
|
|
|
|
* user_data needed for the extraction based on the data extracted from the mesh.
|
|
|
|
* counters are used to check if the finalize of a task has to be called.
|
2020-06-02 15:07:17 +02:00
|
|
|
*
|
|
|
|
* Mesh extraction sub graph
|
|
|
|
*
|
|
|
|
* +----------------------+
|
|
|
|
* +-----> | extract_task1_loop_1 |
|
|
|
|
* | +----------------------+
|
|
|
|
* +------------------+ +----------------------+ +----------------------+
|
|
|
|
* | mesh_render_data | --> | | --> | extract_task1_loop_2 |
|
|
|
|
* +------------------+ | | +----------------------+
|
|
|
|
* | | | +----------------------+
|
|
|
|
* | | user_data_init | --> | extract_task2_loop_1 |
|
|
|
|
* v | | +----------------------+
|
|
|
|
* +------------------+ | | +----------------------+
|
|
|
|
* | single_threaded | | | --> | extract_task2_loop_2 |
|
|
|
|
* +------------------+ +----------------------+ +----------------------+
|
|
|
|
* | +----------------------+
|
|
|
|
* +-----> | extract_task2_loop_3 |
|
|
|
|
* +----------------------+
|
|
|
|
*/
|
2021-05-31 17:11:01 +02:00
|
|
|
const bool do_lines_loose_subbuffer = mbc->ibo.lines_loose != NULL;
|
|
|
|
const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
|
|
|
|
GPU_use_hq_normals_workaround();
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
/* Create an array containing all the extractors that needs to be executed. */
|
|
|
|
MeshExtractRunDataArray extractors;
|
|
|
|
mesh_extract_run_data_array_init(&extractors);
|
2020-06-02 15:07:17 +02:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
#define EXTRACT_ADD_REQUESTED(type, type_lowercase, name) \
|
2019-07-14 16:49:44 +02:00
|
|
|
do { \
|
2021-05-31 17:11:01 +02:00
|
|
|
if (DRW_##type_lowercase##_requested(mbc->type_lowercase.name)) { \
|
|
|
|
const MeshExtract *extractor = mesh_extract_override_get( \
|
|
|
|
&extract_##name, do_hq_normals, do_lines_loose_subbuffer); \
|
|
|
|
mesh_extract_run_data_array_add(&extractors, extractor); \
|
2019-07-14 16:49:44 +02:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, pos_nor);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, lnor);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, uv);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, tan);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, vcol);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, sculpt_data);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, orco);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, edge_fac);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, weights);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, edit_data);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_data);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_stretch_area);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_stretch_angle);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, mesh_analysis);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_pos);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_nor);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_uv);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_edituv_data);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, poly_idx);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, edge_idx);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, vert_idx);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, fdot_idx);
|
|
|
|
EXTRACT_ADD_REQUESTED(VBO, vbo, skin_roots);
|
|
|
|
|
|
|
|
EXTRACT_ADD_REQUESTED(IBO, ibo, tris);
|
|
|
|
EXTRACT_ADD_REQUESTED(IBO, ibo, lines);
|
|
|
|
EXTRACT_ADD_REQUESTED(IBO, ibo, points);
|
|
|
|
EXTRACT_ADD_REQUESTED(IBO, ibo, fdots);
|
|
|
|
EXTRACT_ADD_REQUESTED(IBO, ibo, lines_paint_mask);
|
|
|
|
EXTRACT_ADD_REQUESTED(IBO, ibo, lines_adjacency);
|
|
|
|
EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_tris);
|
|
|
|
EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_lines);
|
|
|
|
EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_points);
|
|
|
|
EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_fdots);
|
|
|
|
|
|
|
|
#undef EXTRACT_ADD_REQUESTED
|
|
|
|
|
|
|
|
if (extractors.len == 0) {
|
2021-05-28 16:51:05 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-05-31 21:28:00 +02:00
|
|
|
#ifdef DEBUG_TIME
|
|
|
|
double rdata_start = PIL_check_seconds_timer();
|
|
|
|
#endif
|
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
eMRIterType iter_type;
|
|
|
|
eMRDataType data_flag;
|
|
|
|
extracts_flags_get(&extractors, &iter_type, &data_flag);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2020-06-15 15:25:25 +02:00
|
|
|
MeshRenderData *mr = mesh_render_data_create(me,
|
2021-05-31 09:32:37 +02:00
|
|
|
extraction_cache,
|
2020-06-15 15:25:25 +02:00
|
|
|
is_editmode,
|
|
|
|
is_paint_mode,
|
2020-08-25 15:49:55 +02:00
|
|
|
is_mode_active,
|
2020-06-15 15:25:25 +02:00
|
|
|
obmat,
|
|
|
|
do_final,
|
|
|
|
do_uvedit,
|
|
|
|
cd_layer_used,
|
|
|
|
ts,
|
2021-05-31 17:11:01 +02:00
|
|
|
iter_type);
|
2019-07-14 16:49:44 +02:00
|
|
|
mr->use_hide = use_hide;
|
|
|
|
mr->use_subsurf_fdots = use_subsurf_fdots;
|
|
|
|
mr->use_final_mesh = do_final;
|
|
|
|
|
|
|
|
#ifdef DEBUG_TIME
|
2021-05-31 21:28:00 +02:00
|
|
|
double rdata_end = PIL_check_seconds_timer();
|
2019-07-14 16:49:44 +02:00
|
|
|
#endif
|
|
|
|
|
2020-06-02 15:07:17 +02:00
|
|
|
struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create(
|
2021-05-31 17:11:01 +02:00
|
|
|
task_graph, mr, iter_type, data_flag);
|
2019-07-14 16:49:44 +02:00
|
|
|
|
2021-05-31 17:11:01 +02:00
|
|
|
/* Simple heuristic. */
|
|
|
|
const bool use_thread = (mr->loop_len + mr->loop_loose_len) > CHUNK_SIZE;
|
|
|
|
|
|
|
|
if (use_thread) {
|
|
|
|
uint threads_to_use = 0;
|
|
|
|
|
|
|
|
/* First run the requested extractors that do not support asynchronous ranges. */
|
|
|
|
for (int i = 0; i < extractors.len; i++) {
|
|
|
|
const MeshExtract *extractor = extractors.items[i].extractor;
|
|
|
|
if (!extractor->use_threading) {
|
|
|
|
MeshExtractRunDataArray *single_threaded_extractors = MEM_callocN(
|
|
|
|
sizeof(MeshExtractRunDataArray),
|
|
|
|
"mesh_buffer_cache_create_requested.single_threaded_extractors");
|
|
|
|
mesh_extract_run_data_array_add(single_threaded_extractors, extractor);
|
|
|
|
ExtractTaskData *taskdata = extract_extract_iter_task_data_create_mesh(
|
|
|
|
mr, cache, single_threaded_extractors, mbc, NULL);
|
|
|
|
struct TaskNode *task_node = extract_single_threaded_task_node_create(task_graph,
|
|
|
|
taskdata);
|
|
|
|
BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
|
|
|
|
}
|
|
|
|
threads_to_use++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Distribute the remaining extractors into ranges per core. */
|
|
|
|
MeshExtractRunDataArray *multi_threaded_extractors = MEM_callocN(
|
|
|
|
sizeof(MeshExtractRunDataArray),
|
|
|
|
"mesh_buffer_cache_create_requested.multi_threaded_extractors");
|
|
|
|
mesh_extract_run_data_array_filter_threading(&extractors, multi_threaded_extractors);
|
|
|
|
if (multi_threaded_extractors->len) {
|
|
|
|
/*
|
|
|
|
* Determine the number of thread to use for multithreading.
|
|
|
|
* Thread can be used for single threaded tasks. These typically take longer to execute so
|
|
|
|
* fill the rest of the threads for range operations.
|
|
|
|
*/
|
|
|
|
int num_threads = BLI_task_scheduler_num_threads();
|
|
|
|
if (threads_to_use < num_threads) {
|
|
|
|
num_threads -= threads_to_use;
|
|
|
|
}
|
|
|
|
|
|
|
|
UserDataInitTaskData *user_data_init_task_data = MEM_callocN(
|
|
|
|
sizeof(UserDataInitTaskData),
|
|
|
|
"mesh_buffer_cache_create_requested.user_data_init_task_data");
|
|
|
|
struct TaskNode *task_node_user_data_init = user_data_init_task_node_create(
|
|
|
|
task_graph, user_data_init_task_data);
|
|
|
|
|
|
|
|
user_data_init_task_data->td = extract_extract_iter_task_data_create_mesh(
|
|
|
|
mr, cache, multi_threaded_extractors, mbc, &user_data_init_task_data->task_counter);
|
|
|
|
|
|
|
|
extract_task_in_ranges_create(
|
|
|
|
task_graph, task_node_user_data_init, user_data_init_task_data->td, num_threads);
|
|
|
|
|
|
|
|
BLI_task_graph_edge_create(task_node_mesh_render_data, task_node_user_data_init);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* No tasks created freeing extractors list. */
|
|
|
|
MEM_freeN(multi_threaded_extractors);
|
|
|
|
}
|
2020-06-02 15:07:17 +02:00
|
|
|
}
|
|
|
|
else {
|
2021-05-31 17:11:01 +02:00
|
|
|
/* Run all requests on the same thread. */
|
|
|
|
MeshExtractRunDataArray *extractors_copy = MEM_mallocN(
|
|
|
|
sizeof(MeshExtractRunDataArray), "mesh_buffer_cache_create_requested.extractors_copy");
|
|
|
|
memcpy(extractors_copy, &extractors, sizeof(MeshExtractRunDataArray));
|
|
|
|
ExtractTaskData *taskdata = extract_extract_iter_task_data_create_mesh(
|
|
|
|
mr, cache, extractors_copy, mbc, NULL);
|
|
|
|
|
|
|
|
struct TaskNode *task_node = extract_single_threaded_task_node_create(task_graph, taskdata);
|
|
|
|
BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
|
2020-06-02 15:07:17 +02:00
|
|
|
}
|
2019-12-03 08:27:55 +01:00
|
|
|
|
2020-06-02 15:07:17 +02:00
|
|
|
/* Trigger the sub-graph for this mesh. */
|
|
|
|
BLI_task_graph_node_push_work(task_node_mesh_render_data);
|
2019-12-05 08:14:32 +01:00
|
|
|
|
2019-07-14 16:49:44 +02:00
|
|
|
#ifdef DEBUG_TIME
|
2020-06-02 15:07:17 +02:00
|
|
|
BLI_task_graph_work_and_wait(task_graph);
|
2019-07-14 16:49:44 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|