diff options
Diffstat (limited to 'source/blender/draw/intern')
32 files changed, 3944 insertions, 2090 deletions
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 89dd6fa210c..3551296cfc3 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -198,12 +198,28 @@ void DRW_uniformbuffer_free(struct GPUUniformBuffer *ubo); } while (0) /* Shaders */ + +#ifndef __GPU_MATERIAL_H__ +/* FIXME: Meh avoid including all GPUMaterial. */ +typedef void (*GPUMaterialEvalCallbackFn)(struct GPUMaterial *mat, + int options, + const char **vert_code, + const char **geom_code, + const char **frag_lib, + const char **defines); +#endif + struct GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines); struct GPUShader *DRW_shader_create_with_lib( const char *vert, const char *geom, const char *frag, const char *lib, const char *defines); +struct GPUShader *DRW_shader_create_with_shaderlib(const char *vert, + const char *geom, + const char *frag, + const DRWShaderLibrary *lib, + const char *defines); struct GPUShader *DRW_shader_create_with_transform_feedback(const char *vert, const char *geom, const char *defines, @@ -211,6 +227,9 @@ struct GPUShader *DRW_shader_create_with_transform_feedback(const char *vert, const char **varying_names, const int varying_count); struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines); +struct GPUShader *DRW_shader_create_fullscreen_with_shaderlib(const char *frag, + const DRWShaderLibrary *lib, + const char *defines); struct GPUMaterial *DRW_shader_find_from_world(struct World *wo, const void *engine_type, const int options, @@ -229,7 +248,8 @@ struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, const char *geom, const char *frag_lib, const char *defines, - bool deferred); + bool deferred, + GPUMaterialEvalCallbackFn callback); struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, struct Material *ma, struct bNodeTree *ntree, @@ -240,7 +260,8 @@ struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, const char *geom, const char *frag_lib, const char *defines, - bool deferred); + bool deferred, + GPUMaterialEvalCallbackFn callback); void DRW_shader_free(struct GPUShader *shader); #define DRW_SHADER_FREE_SAFE(shader) \ do { \ @@ -257,7 +278,8 @@ void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const ch #define DRW_SHADER_LIB_ADD(lib, lib_name) \ DRW_shader_library_add_file(lib, datatoc_##lib_name##_glsl, STRINGIFY(lib_name) ".glsl") -char *DRW_shader_library_create_shader_string(DRWShaderLibrary *lib, char *shader_code); +char *DRW_shader_library_create_shader_string(const DRWShaderLibrary *lib, + const char *shader_code); void DRW_shader_library_free(DRWShaderLibrary *lib); #define DRW_SHADER_LIB_FREE_SAFE(lib) \ @@ -462,6 +484,10 @@ void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex, eGPUSamplerState sampler_state); +void DRW_shgroup_uniform_texture_ref_ex(DRWShadingGroup *shgroup, + const char *name, + GPUTexture **tex, + eGPUSamplerState sampler_state); void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex); @@ -569,7 +595,7 @@ void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float w const DRWView *DRW_view_default_get(void); void DRW_view_default_set(DRWView *view); - +void DRW_view_reset(void); void DRW_view_set_active(DRWView *view); void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len); @@ -619,13 +645,15 @@ void DRW_render_object_iter(void *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph)); void DRW_render_instance_buffer_finish(void); -void DRW_render_viewport_size_set(int size[2]); +void DRW_render_viewport_size_set(const int size[2]); void DRW_custom_pipeline(DrawEngineType *draw_engine_type, struct Depsgraph *depsgraph, void (*callback)(void *vedata, void *user_data), void *user_data); +void DRW_cache_restart(void); + /* ViewLayers */ void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type); void **DRW_view_layer_engine_data_ensure_ex(struct ViewLayer *view_layer, diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index c23ea3d7c82..20e346375a7 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -829,7 +829,7 @@ GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob) case OB_HAIR: return NULL; case OB_POINTCLOUD: - return NULL; + return DRW_pointcloud_batch_cache_get_dots(ob); case OB_VOLUME: return DRW_cache_volume_face_wireframe_get(ob); case OB_GPENCIL: { @@ -880,6 +880,32 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob) case OB_HAIR: return NULL; case OB_POINTCLOUD: + return DRW_cache_pointcloud_surface_get(ob); + case OB_VOLUME: + return NULL; + default: + return NULL; + } +} + +/* Returns the vertbuf used by shaded surface batch. */ +GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob) +{ + Mesh *me = BKE_object_get_evaluated_mesh(ob); + short type = (me != NULL) ? OB_MESH : ob->type; + + switch (type) { + case OB_MESH: + return DRW_mesh_batch_cache_pos_vertbuf_get((me != NULL) ? me : ob->data); + case OB_CURVE: + case OB_SURF: + case OB_FONT: + return DRW_curve_batch_cache_pos_vertbuf_get(ob->data); + case OB_MBALL: + return DRW_mball_batch_cache_pos_vertbuf_get(ob); + case OB_HAIR: + return NULL; + case OB_POINTCLOUD: return NULL; case OB_VOLUME: return NULL; @@ -932,7 +958,7 @@ GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob, case OB_HAIR: return NULL; case OB_POINTCLOUD: - return NULL; + return DRW_cache_pointcloud_surface_shaded_get(ob, gpumat_array, gpumat_array_len); case OB_VOLUME: return NULL; default: @@ -2844,6 +2870,12 @@ GPUBatch *DRW_cache_mesh_surface_vertpaint_get(Object *ob) return DRW_mesh_batch_cache_get_surface_vertpaint(ob->data); } +GPUBatch *DRW_cache_mesh_surface_sculptcolors_get(Object *ob) +{ + BLI_assert(ob->type == OB_MESH); + return DRW_mesh_batch_cache_get_surface_sculpt(ob->data); +} + GPUBatch *DRW_cache_mesh_surface_weights_get(Object *ob) { BLI_assert(ob->type == OB_MESH); @@ -3257,9 +3289,16 @@ GPUBatch *DRW_cache_lattice_vert_overlay_get(Object *ob) GPUBatch *DRW_cache_pointcloud_get_dots(Object *object) { + BLI_assert(object->type == OB_POINTCLOUD); return DRW_pointcloud_batch_cache_get_dots(object); } +GPUBatch *DRW_cache_pointcloud_surface_get(Object *object) +{ + BLI_assert(object->type == OB_POINTCLOUD); + return DRW_pointcloud_batch_cache_get_surface(object); +} + /* -------------------------------------------------------------------- */ /** \name Volume * \{ */ @@ -3552,6 +3591,11 @@ void drw_batch_cache_generate_requested(Object *ob) } } +void drw_batch_cache_generate_requested_delayed(Object *ob) +{ + BLI_gset_add(DST.delayed_extraction, ob); +} + void DRW_batch_cache_free_old(Object *ob, int ctime) { struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 221fb89612f..1ea53c91cb3 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -63,6 +63,8 @@ struct GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob, struct GPUBatch *DRW_cache_object_face_wireframe_get(struct Object *ob); int DRW_cache_object_material_count_get(struct Object *ob); +struct GPUVertBuf *DRW_cache_object_pos_vertbuf_get(struct Object *ob); + /* Empties */ struct GPUBatch *DRW_cache_plain_axes_get(void); struct GPUBatch *DRW_cache_single_arrow_get(void); @@ -134,6 +136,7 @@ struct GPUBatch **DRW_cache_mesh_surface_shaded_get(struct Object *ob, struct GPUBatch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_vertpaint_get(struct Object *ob); +struct GPUBatch *DRW_cache_mesh_surface_sculptcolors_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_weights_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_mesh_analysis_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_face_wireframe_get(struct Object *ob); @@ -212,6 +215,7 @@ struct GPUBatch *DRW_cache_hair_edge_detection_get(struct Object *ob, bool *r_is /* PointCloud */ struct GPUBatch *DRW_cache_pointcloud_get_dots(struct Object *obj); +struct GPUBatch *DRW_cache_pointcloud_surface_get(struct Object *obj); /* Volume */ typedef struct DRWVolumeGrid { diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index f203c2ff1ea..4156e2e79d8 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -53,16 +53,21 @@ typedef struct DRW_MeshCDMask { uint32_t uv : 8; uint32_t tan : 8; uint32_t vcol : 8; + uint32_t sculpt_vcol : 8; uint32_t orco : 1; uint32_t tan_orco : 1; /** Edit uv layer is from the base edit mesh as * modifiers could remove it. (see T68857) */ uint32_t edit_uv : 1; } DRW_MeshCDMask; +/* Keep `DRW_MeshCDMask` struct within an `uint64_t`. + * bit-wise and atomic operations are used to compare and update the struct. + * See `mesh_cd_layers_type_*` functions. */ +BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint64_t), "DRW_MeshCDMask exceeds 64 bits") typedef enum eMRIterType { MR_ITER_LOOPTRI = 1 << 0, - MR_ITER_LOOP = 1 << 1, + MR_ITER_POLY = 1 << 1, MR_ITER_LEDGE = 1 << 2, MR_ITER_LVERT = 1 << 3, } eMRIterType; @@ -165,8 +170,7 @@ typedef enum DRWBatchFlag { MBC_WIRE_EDGES = (1 << 23), MBC_WIRE_LOOPS = (1 << 24), MBC_WIRE_LOOPS_UVS = (1 << 25), - MBC_SURF_PER_MAT = (1 << 26), - MBC_SKIN_ROOTS = (1 << 27), + MBC_SKIN_ROOTS = (1 << 26), } DRWBatchFlag; #define MBC_EDITUV \ diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c index 06462d5b9c5..cca8ebcf2a8 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh.c @@ -128,12 +128,191 @@ typedef struct MeshRenderData { BMEdge *eed_act; BMFace *efa_act; BMFace *efa_act_uv; - /* Data created on-demand (usually not for bmesh-based data). */ + /* Data created on-demand (usually not for #BMesh based data). */ MLoopTri *mlooptri; float (*loop_normals)[3]; float (*poly_normals)[3]; int *lverts, *ledges; } MeshRenderData; + +static void mesh_render_data_update_loose_geom(MeshRenderData *mr, + const eMRIterType iter_type, + const eMRDataType UNUSED(data_flag)) +{ + if (mr->extract_type != MR_EXTRACT_BMESH) { + /* Mesh */ + if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) { + mr->vert_loose_len = 0; + mr->edge_loose_len = 0; + + BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__); + + mr->ledges = MEM_mallocN(mr->edge_len * sizeof(int), __func__); + const MEdge *med = mr->medge; + for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) { + if (med->flag & ME_LOOSEEDGE) { + mr->ledges[mr->edge_loose_len++] = med_index; + } + /* Tag verts as not loose. */ + BLI_BITMAP_ENABLE(lvert_map, med->v1); + BLI_BITMAP_ENABLE(lvert_map, med->v2); + } + if (mr->edge_loose_len < mr->edge_len) { + mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges)); + } + + mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__); + for (int v = 0; v < mr->vert_len; v++) { + if (!BLI_BITMAP_TEST(lvert_map, v)) { + mr->lverts[mr->vert_loose_len++] = v; + } + } + if (mr->vert_loose_len < mr->vert_len) { + mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts)); + } + + MEM_freeN(lvert_map); + + mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2); + } + } + else { + /* #BMesh */ + BMesh *bm = mr->bm; + if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) { + int elem_id; + BMIter iter; + BMVert *eve; + BMEdge *ede; + mr->vert_loose_len = 0; + mr->edge_loose_len = 0; + + mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__); + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) { + if (eve->e == NULL) { + mr->lverts[mr->vert_loose_len++] = elem_id; + } + } + if (mr->vert_loose_len < mr->vert_len) { + mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts)); + } + + mr->ledges = MEM_mallocN(mr->edge_len * sizeof(*mr->ledges), __func__); + BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) { + if (ede->l == NULL) { + mr->ledges[mr->edge_loose_len++] = elem_id; + } + } + if (mr->edge_loose_len < mr->edge_len) { + mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges)); + } + + mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2; + } + } +} + +/** + * Part of the creation of the #MeshRenderData that happens in a thread. + */ +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 { + /* #BMesh */ + 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 { + /* #BMesh */ + if (data_flag & MR_DATA_POLY_NOR) { + /* Use #BMFace.no instead. */ + } + if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { + + 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__); + const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); + 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); + } + } +} + static MeshRenderData *mesh_render_data_create(Mesh *me, const bool is_editmode, const bool is_paint_mode, @@ -141,7 +320,9 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const bool do_final, const bool do_uvedit, const DRW_MeshCDMask *UNUSED(cd_used), - const ToolSettings *ts) + const ToolSettings *ts, + const eMRIterType iter_type, + const eMRDataType data_flag) { MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__); mr->toolsettings = ts; @@ -240,7 +421,7 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); } else { - /* BMesh */ + /* #BMesh */ BMesh *bm = mr->bm; mr->vert_len = bm->totvert; @@ -249,165 +430,11 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, mr->poly_len = bm->totface; mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); } + mesh_render_data_update_loose_geom(mr, iter_type, data_flag); return mr; } -/* Part of the creation of the MeshRenderData that happens in a thread. */ -static void mesh_render_data_update(MeshRenderData *mr, - const eMRIterType 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); - } - if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { - mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI"); - BKE_mesh_recalc_looptri(mr->me->mloop, - mr->me->mpoly, - mr->me->mvert, - mr->me->totloop, - mr->me->totpoly, - mr->mlooptri); - } - if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) { - mr->vert_loose_len = 0; - mr->edge_loose_len = 0; - - BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, "lvert map"); - - mr->ledges = MEM_mallocN(mr->edge_len * sizeof(int), __func__); - const MEdge *medge = mr->medge; - for (int e = 0; e < mr->edge_len; e++, medge++) { - if (medge->flag & ME_LOOSEEDGE) { - mr->ledges[mr->edge_loose_len++] = e; - } - /* Tag verts as not loose. */ - BLI_BITMAP_ENABLE(lvert_map, medge->v1); - BLI_BITMAP_ENABLE(lvert_map, medge->v2); - } - if (mr->edge_loose_len < mr->edge_len) { - mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges)); - } - - mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__); - for (int v = 0; v < mr->vert_len; v++) { - if (!BLI_BITMAP_TEST(lvert_map, v)) { - mr->lverts[mr->vert_loose_len++] = v; - } - } - if (mr->vert_loose_len < mr->vert_len) { - mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts)); - } - - MEM_freeN(lvert_map); - - mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2; - } - } - else { - /* BMesh */ - BMesh *bm = mr->bm; - if (data_flag & MR_DATA_POLY_NOR) { - /* Use bmface->no instead. */ - } - if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { - - 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__); - int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); - 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); - } - if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { - /* Edit mode ensures this is valid, no need to calculate. */ - BLI_assert((bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL)); - } - if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) { - int elem_id; - BMIter iter; - BMVert *eve; - BMEdge *ede; - mr->vert_loose_len = 0; - mr->edge_loose_len = 0; - - mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__); - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) { - if (eve->e == NULL) { - mr->lverts[mr->vert_loose_len++] = elem_id; - } - } - if (mr->vert_loose_len < mr->vert_len) { - mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts)); - } - - mr->ledges = MEM_mallocN(mr->edge_len * sizeof(*mr->ledges), __func__); - BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) { - if (ede->l == NULL) { - mr->ledges[mr->edge_loose_len++] = elem_id; - } - } - if (mr->edge_loose_len < mr->edge_len) { - mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges)); - } - - mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2; - } - } -} - static void mesh_render_data_free(MeshRenderData *mr) { MEM_SAFE_FREE(mr->mlooptri); @@ -461,7 +488,7 @@ BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *e } else { UNUSED_VARS(mr); - return eve->co; + return eve->no; } } @@ -480,48 +507,283 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Mesh Elements Extract Iter +/** \name Mesh Elements Extract: Loop Triangles + * \{ */ + +typedef struct ExtractTriBMesh_Params { + BMLoop *(*looptris)[3]; + int tri_range[2]; +} ExtractTriBMesh_Params; +typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, + const ExtractTriBMesh_Params *params, + void *data); + +#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; +typedef void(ExtractTriMeshFn)(const MeshRenderData *mr, + const ExtractTriMesh_Params *params, + void *data); + +#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, + const ExtractPolyBMesh_Params *params, + 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, + const ExtractPolyMesh_Params *params, + void *data); + +#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; +typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *data); + +#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; +typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *data); + +#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; +typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *data); + +#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; +typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *data); + +#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 * \{ */ typedef void *(ExtractInitFn)(const MeshRenderData *mr, void *buffer); -typedef void(ExtractEditTriFn)(const MeshRenderData *mr, int t, BMLoop **e, void *data); -typedef void(ExtractEditLoopFn)(const MeshRenderData *mr, int l, BMLoop *el, void *data); -typedef void(ExtractEditLedgeFn)(const MeshRenderData *mr, int e, BMEdge *ed, void *data); -typedef void(ExtractEditLvertFn)(const MeshRenderData *mr, int v, BMVert *ev, void *data); -typedef void(ExtractTriFn)(const MeshRenderData *mr, int t, const MLoopTri *mlt, void *data); -typedef void(ExtractLoopFn)( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data); -typedef void(ExtractLedgeFn)(const MeshRenderData *mr, int e, const MEdge *medge, void *data); -typedef void(ExtractLvertFn)(const MeshRenderData *mr, int v, const MVert *mvert, void *data); typedef void(ExtractFinishFn)(const MeshRenderData *mr, void *buffer, void *data); typedef struct MeshExtract { - /** Executed on main thread and return user data for iter functions. */ + /** Executed on main thread and return user data for iteration functions. */ ExtractInitFn *init; /** Executed on one (or more if use_threading) worker thread(s). */ - ExtractEditTriFn *iter_looptri_bm; - ExtractTriFn *iter_looptri; - ExtractEditLoopFn *iter_loop_bm; - ExtractLoopFn *iter_loop; - ExtractEditLedgeFn *iter_ledge_bm; - ExtractLedgeFn *iter_ledge; - ExtractEditLvertFn *iter_lvert_bm; - ExtractLvertFn *iter_lvert; + ExtractTriBMeshFn *iter_looptri_bm; + ExtractTriMeshFn *iter_looptri_mesh; + ExtractPolyBMeshFn *iter_poly_bm; + ExtractPolyMeshFn *iter_poly_mesh; + ExtractLEdgeBMeshFn *iter_ledge_bm; + ExtractLEdgeMeshFn *iter_ledge_mesh; + ExtractLVertBMeshFn *iter_lvert_bm; + ExtractLVertMeshFn *iter_lvert_mesh; /** Executed on one worker thread after all elements iterations. */ ExtractFinishFn *finish; /** Used to request common data. */ const eMRDataType data_flag; - /** Used to know if the element callbacks are threadsafe and can be parallelized. */ + /** Used to know if the element callbacks are thread-safe and can be parallelized. */ const bool use_threading; } MeshExtract; BLI_INLINE eMRIterType mesh_extract_iter_type(const MeshExtract *ext) { eMRIterType type = 0; - SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri), MR_ITER_LOOPTRI); - SET_FLAG_FROM_TEST(type, (ext->iter_loop_bm || ext->iter_loop), MR_ITER_LOOP); - SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge), MR_ITER_LEDGE); - SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert), MR_ITER_LVERT); + SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI); + SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY); + 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); return type; } @@ -558,15 +820,15 @@ static void *extract_tris_init(const MeshRenderData *mr, void *UNUSED(ibo)) } } else { - const MPoly *mpoly = mr->mpoly; - for (int p = 0; p < mr->poly_len; p++, mpoly++) { - if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) { - int mat = min_ii(mpoly->mat_nr, mr->mat_len - 1); - mat_tri_len[mat] += mpoly->totloop - 2; + 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; } } } - /* Accumulate tri len per mat to have correct offsets. */ + /* Accumulate triangle lengths per material to have correct offsets. */ int ofs = mat_tri_len[0]; mat_tri_len[0] = 0; for (int i = 1; i < mr->mat_len; i++) { @@ -583,51 +845,62 @@ static void *extract_tris_init(const MeshRenderData *mr, void *UNUSED(ibo)) return data; } -static void extract_tris_looptri_bmesh(const MeshRenderData *mr, - int UNUSED(t), - BMLoop **elt, - void *_data) +static void extract_tris_iter_looptri_bm(const MeshRenderData *mr, + const struct ExtractTriBMesh_Params *params, + void *_data) { - if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { - MeshExtract_Tri_Data *data = _data; - int *mat_tri_ofs = data->tri_mat_end; - int mat = min_ii(elt[0]->f->mat_nr, mr->mat_len - 1); - 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])); + MeshExtract_Tri_Data *data = _data; + const int mat_last = mr->mat_len - 1; + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params) + { + 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])); + } } + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; } -static void extract_tris_looptri_mesh(const MeshRenderData *mr, - int UNUSED(t), - const MLoopTri *mlt, - void *_data) +static void extract_tris_iter_looptri_mesh(const MeshRenderData *mr, + const struct ExtractTriMesh_Params *params, + void *_data) { - const MPoly *mpoly = &mr->mpoly[mlt->poly]; - if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) { - MeshExtract_Tri_Data *data = _data; - int *mat_tri_ofs = data->tri_mat_end; - int mat = min_ii(mpoly->mat_nr, mr->mat_len - 1); - GPU_indexbuf_set_tri_verts( - &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]); + MeshExtract_Tri_Data *data = _data; + const int mat_last = mr->mat_len - 1; + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params) + { + 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]); + } } + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; } static void extract_tris_finish(const MeshRenderData *mr, void *ibo, void *_data) { MeshExtract_Tri_Data *data = _data; GPU_indexbuf_build_in_place(&data->elb, ibo); - /* HACK Create ibo subranges and assign them to each GPUBatch. */ + /* HACK: Create ibo sub-ranges and assign them to each #GPUBatch. */ + /* The `surface_per_mat` tests are there when object shading type is set to Wire or Bounds. In + * these cases there isn't a surface per material. */ if (mr->use_final_mesh && mr->cache->surface_per_mat && mr->cache->surface_per_mat[0]) { - BLI_assert(mr->cache->surface_per_mat[0]->elem == ibo); for (int i = 0; i < mr->mat_len; i++) { /* Multiply by 3 because these are triangle indices. */ - int start = data->tri_mat_start[i] * 3; - int len = data->tri_mat_end[i] * 3 - data->tri_mat_start[i] * 3; + 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; GPUIndexBuf *sub_ibo = GPU_indexbuf_create_subrange(ibo, start, len); - /* WARNING: We modify the GPUBatch here! */ + /* WARNING: We modify the #GPUBatch here! */ GPU_batch_elembuf_set(mr->cache->surface_per_mat[i], sub_ibo, true); } } @@ -637,18 +910,12 @@ static void extract_tris_finish(const MeshRenderData *mr, void *ibo, void *_data } static const MeshExtract extract_tris = { - extract_tris_init, - extract_tris_looptri_bmesh, - extract_tris_looptri_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_tris_finish, - 0, - false, + .init = extract_tris_init, + .iter_looptri_bm = extract_tris_iter_looptri_bm, + .iter_looptri_mesh = extract_tris_iter_looptri_mesh, + .finish = extract_tris_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -666,71 +933,113 @@ static void *extract_lines_init(const MeshRenderData *mr, void *UNUSED(buf)) return elb; } -static void extract_lines_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *elb) -{ - if (!BM_elem_flag_test(loop->e, BM_ELEM_HIDDEN)) { - GPU_indexbuf_set_line_verts(elb, BM_elem_index_get(loop->e), l, BM_elem_index_get(loop->next)); - } - else { - GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(loop->e)); - } -} - -static void extract_lines_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *elb) -{ - const MEdge *medge = &mr->medge[mloop->e]; - if (!((mr->use_hide && (medge->flag & ME_HIDE)) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[mloop->e] == ORIGINDEX_NONE)))) { - int loopend = mpoly->totloop + mpoly->loopstart - 1; - int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1); - GPU_indexbuf_set_line_verts(elb, mloop->e, l, other_loop); +static void extract_lines_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *elb) +{ + /* Using poly & loop iterator would complicate accessing the adjacent loop. */ + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + 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); + } + EXTRACT_POLY_FOREACH_BM_END; +} + +static void extract_lines_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *elb) +{ + /* 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)) { + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + 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); + } + EXTRACT_POLY_FOREACH_MESH_END; } else { - GPU_indexbuf_set_line_restart(elb, mloop->e); + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + 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); + } + EXTRACT_POLY_FOREACH_MESH_END; } } -static void extract_lines_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *elb) +static void extract_lines_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *elb) { - int ledge_idx = mr->edge_len + e; - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - int l = mr->loop_len + e * 2; - GPU_indexbuf_set_line_verts(elb, ledge_idx, l, l + 1); - } - else { - GPU_indexbuf_set_line_restart(elb, ledge_idx); + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + 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); + } + 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)); } - /* Don't render the edge twice. */ - GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed)); + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_lines_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *medge, - void *elb) +static void extract_lines_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *elb) { - int ledge_idx = mr->edge_len + e; - int edge_idx = mr->ledges[e]; - if (!((mr->use_hide && (medge->flag & ME_HIDE)) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[edge_idx] == ORIGINDEX_NONE)))) { - int l = mr->loop_len + e * 2; - GPU_indexbuf_set_line_verts(elb, ledge_idx, l, l + 1); - } - else { - GPU_indexbuf_set_line_restart(elb, ledge_idx); + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + 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); + } + else { + GPU_indexbuf_set_line_restart(elb, l_index_offset); + } + /* Don't render the edge twice. */ + GPU_indexbuf_set_line_restart(elb, e_index); } - /* Don't render the edge twice. */ - GPU_indexbuf_set_line_restart(elb, edge_idx); + EXTRACT_LEDGE_FOREACH_MESH_END; } static void extract_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb) @@ -740,18 +1049,14 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, vo } static const MeshExtract extract_lines = { - extract_lines_init, - NULL, - NULL, - extract_lines_loop_bmesh, - extract_lines_loop_mesh, - extract_lines_ledge_bmesh, - extract_lines_ledge_mesh, - NULL, - NULL, - extract_lines_finish, - 0, - false, + .init = extract_lines_init, + .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, + .finish = extract_lines_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -778,18 +1083,14 @@ static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr, void } static const MeshExtract extract_lines_with_lines_loose = { - extract_lines_init, - NULL, - NULL, - extract_lines_loop_bmesh, - extract_lines_loop_mesh, - extract_lines_ledge_bmesh, - extract_lines_ledge_mesh, - NULL, - NULL, - extract_lines_with_lines_loose_finish, - 0, - false, + .init = extract_lines_init, + .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, + .finish = extract_lines_with_lines_loose_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -805,77 +1106,101 @@ static void *extract_points_init(const MeshRenderData *mr, void *UNUSED(buf)) return elb; } -BLI_INLINE void vert_set_bmesh(GPUIndexBufBuilder *elb, BMVert *eve, int loop) +BLI_INLINE void vert_set_bm(GPUIndexBufBuilder *elb, BMVert *eve, int l_index) { - int vert_idx = BM_elem_index_get(eve); + const int v_index = BM_elem_index_get(eve); if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - GPU_indexbuf_set_point_vert(elb, vert_idx, loop); + GPU_indexbuf_set_point_vert(elb, v_index, l_index); } else { - GPU_indexbuf_set_point_restart(elb, vert_idx); + GPU_indexbuf_set_point_restart(elb, v_index); } } BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb, const MeshRenderData *mr, - int vert_idx, - int loop) + const int v_index, + const int l_index) { - const MVert *mvert = &mr->mvert[vert_idx]; - if (!((mr->use_hide && (mvert->flag & ME_HIDE)) || + const MVert *mv = &mr->mvert[v_index]; + if (!((mr->use_hide && (mv->flag & ME_HIDE)) || ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && - (mr->v_origindex[vert_idx] == ORIGINDEX_NONE)))) { - GPU_indexbuf_set_point_vert(elb, vert_idx, loop); + (mr->v_origindex[v_index] == ORIGINDEX_NONE)))) { + GPU_indexbuf_set_point_vert(elb, v_index, l_index); } else { - GPU_indexbuf_set_point_restart(elb, vert_idx); + GPU_indexbuf_set_point_restart(elb, v_index); } } -static void extract_points_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *elb) +static void extract_points_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *elb) { - vert_set_bmesh(elb, loop->v, l); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + vert_set_bm(elb, l->v, l_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_points_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *elb) +static void extract_points_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *elb) { - vert_set_mesh(elb, mr, mloop->v, l); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + vert_set_mesh(elb, mr, ml->v, ml_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_points_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *elb) +static void extract_points_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *elb) { - vert_set_bmesh(elb, eed->v1, mr->loop_len + e * 2); - vert_set_bmesh(elb, eed->v2, mr->loop_len + e * 2 + 1); + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + 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); + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_points_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *medge, - void *elb) +static void extract_points_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *elb) { - vert_set_mesh(elb, mr, medge->v1, mr->loop_len + e * 2); - vert_set_mesh(elb, mr, medge->v2, mr->loop_len + e * 2 + 1); + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + 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); + } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_points_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *elb) +static void extract_points_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *elb) { - vert_set_bmesh(elb, eve, mr->loop_len + mr->edge_loose_len * 2 + v); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + vert_set_bm(elb, eve, offset + lvert_index); + } + EXTRACT_LVERT_FOREACH_BM_END; } -static void extract_points_lvert_mesh(const MeshRenderData *mr, - int v, - const MVert *UNUSED(mvert), - void *elb) +static void extract_points_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *elb) { - vert_set_mesh(elb, mr, mr->lverts[v], mr->loop_len + mr->edge_loose_len * 2 + v); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) + { + vert_set_mesh(elb, mr, mr->lverts[lvert_index], offset + lvert_index); + } + EXTRACT_LVERT_FOREACH_MESH_END; } static void extract_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb) @@ -885,18 +1210,16 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, v } static const MeshExtract extract_points = { - extract_points_init, - NULL, - NULL, - extract_points_loop_bmesh, - extract_points_loop_mesh, - extract_points_ledge_bmesh, - extract_points_ledge_mesh, - extract_points_lvert_bmesh, - extract_points_lvert_mesh, - extract_points_finish, - 0, - false, + .init = extract_points_init, + .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, + .finish = extract_points_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -912,34 +1235,51 @@ static void *extract_fdots_init(const MeshRenderData *mr, void *UNUSED(buf)) return elb; } -static void extract_fdots_loop_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(l), - BMLoop *loop, - void *elb) +static void extract_fdots_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *elb) { - int face_idx = BM_elem_index_get(loop->f); - if (!BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN)) { - GPU_indexbuf_set_point_vert(elb, face_idx, face_idx); - } - else { - GPU_indexbuf_set_point_restart(elb, face_idx); + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + 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); + } } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_fdots_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *mloop, - int p, - const MPoly *mpoly, - void *elb) +static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *elb) { - const MVert *mvert = &mr->mvert[mloop->v]; - if ((!mr->use_subsurf_fdots || (mvert->flag & ME_VERT_FACEDOT)) && - !(mr->use_hide && (mpoly->flag & ME_HIDE))) { - GPU_indexbuf_set_point_vert(elb, p, p); + if (mr->use_subsurf_fdots) { + /* Check #ME_VERT_FACEDOT. */ + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + 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); + } + else { + GPU_indexbuf_set_point_restart(elb, mp_index); + } + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } else { - GPU_indexbuf_set_point_restart(elb, p); + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + 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); + } + } + EXTRACT_POLY_FOREACH_MESH_END; } } @@ -950,18 +1290,12 @@ static void extract_fdots_finish(const MeshRenderData *UNUSED(mr), void *ibo, vo } static const MeshExtract extract_fdots = { - extract_fdots_init, - NULL, - NULL, - extract_fdots_loop_bmesh, - extract_fdots_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_fdots_finish, - 0, - false, + .init = extract_fdots_init, + .iter_poly_bm = extract_fdots_iter_poly_bm, + .iter_poly_mesh = extract_fdots_iter_poly_mesh, + .finish = extract_fdots_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -984,66 +1318,60 @@ static void *extract_lines_paint_mask_init(const MeshRenderData *mr, void *UNUSE return data; } -static void extract_lines_paint_mask_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *_data) -{ - MeshExtract_LinePaintMask_Data *data = (MeshExtract_LinePaintMask_Data *)_data; - const int edge_idx = mloop->e; - const MEdge *medge = &mr->medge[edge_idx]; - if (!((mr->use_hide && (medge->flag & ME_HIDE)) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[edge_idx] == ORIGINDEX_NONE)))) { - - int loopend = mpoly->totloop + mpoly->loopstart - 1; - int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1); - if (mpoly->flag & ME_FACE_SEL) { - if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, edge_idx)) { - /* Hide edge as it has more than 2 selected loop. */ - GPU_indexbuf_set_line_restart(&data->elb, edge_idx); +static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) +{ + MeshExtract_LinePaintMask_Data *data = _data; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + 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); + } } else { - /* First selected loop. Set edge visible, overwritting any unsel loop. */ - GPU_indexbuf_set_line_verts(&data->elb, edge_idx, l, other_loop); + /* Set theses unselected loop only if this edge has no other selected loop. */ + if (!BLI_BITMAP_TEST(data->select_map, e_index)) { + GPU_indexbuf_set_line_verts(&data->elb, e_index, ml_index, ml_index_other); + } } } else { - /* Set theses unselected loop only if this edge has no other selected loop. */ - if (!BLI_BITMAP_TEST(data->select_map, edge_idx)) { - GPU_indexbuf_set_line_verts(&data->elb, edge_idx, l, other_loop); - } + GPU_indexbuf_set_line_restart(&data->elb, e_index); } } - else { - GPU_indexbuf_set_line_restart(&data->elb, edge_idx); - } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *_data) { - MeshExtract_LinePaintMask_Data *data = (MeshExtract_LinePaintMask_Data *)_data; + MeshExtract_LinePaintMask_Data *data = _data; GPU_indexbuf_build_in_place(&data->elb, ibo); MEM_freeN(data); } static const MeshExtract extract_lines_paint_mask = { - extract_lines_paint_mask_init, - NULL, - NULL, - NULL, - extract_lines_paint_mask_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_lines_paint_mask_finish, - 0, - false, + .init = extract_lines_paint_mask_init, + .iter_poly_mesh = extract_lines_paint_mask_iter_poly_mesh, + .finish = extract_lines_paint_mask_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1065,7 +1393,7 @@ typedef struct MeshExtract_LineAdjacency_Data { static void *extract_lines_adjacency_init(const MeshRenderData *mr, void *UNUSED(buf)) { /* Similar to poly_to_tri_count(). - * There is always loop + tri - 1 edges inside a polygon. + * There is always (loop + triangle - 1) edges inside a polygon. * Accumulate for all polys and you get : */ uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len; @@ -1082,7 +1410,7 @@ BLI_INLINE void lines_adjacency_triangle( uint v1, uint v2, uint v3, uint l1, uint l2, uint l3, MeshExtract_LineAdjacency_Data *data) { GPUIndexBufBuilder *elb = &data->elb; - /* Iter around the triangle's edges. */ + /* Iterate around the triangle's edges. */ for (int e = 0; e < 3; e++) { SHIFT3(uint, v3, v2, v1); SHIFT3(uint, l3, l2, l1); @@ -1093,7 +1421,7 @@ BLI_INLINE void lines_adjacency_triangle( int v_data = POINTER_AS_INT(*pval); if (!value_is_init || v_data == NO_EDGE) { /* Save the winding order inside the sign bit. Because the - * edgehash sort the keys and we need to compare winding later. */ + * Edge-hash sort the keys and we need to compare winding later. */ int value = (int)l1 + 1; /* 0 cannot be signed so add one. */ *pval = POINTER_FROM_INT((inv_indices) ? -value : value); /* Store loop indices for remaining non-manifold edges. */ @@ -1105,7 +1433,7 @@ BLI_INLINE void lines_adjacency_triangle( *pval = POINTER_FROM_INT(NO_EDGE); bool inv_opposite = (v_data < 0); uint l_opposite = (uint)abs(v_data) - 1; - /* TODO Make this part threadsafe. */ + /* TODO Make this part thread-safe. */ 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); @@ -1119,42 +1447,48 @@ BLI_INLINE void lines_adjacency_triangle( } } -static void extract_lines_adjacency_looptri_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(t), - BMLoop **elt, - void *data) +static void extract_lines_adjacency_iter_looptri_bm(const MeshRenderData *UNUSED(mr), + const struct ExtractTriBMesh_Params *params, + void *data) { - if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { - lines_adjacency_triangle(BM_elem_index_get(elt[0]->v), - BM_elem_index_get(elt[1]->v), - BM_elem_index_get(elt[2]->v), - BM_elem_index_get(elt[0]), - BM_elem_index_get(elt[1]), - BM_elem_index_get(elt[2]), - data); + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params) + { + 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); + } } + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; } -static void extract_lines_adjacency_looptri_mesh(const MeshRenderData *mr, - int UNUSED(t), - const MLoopTri *mlt, - void *data) +static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData *mr, + const struct ExtractTriMesh_Params *params, + void *data) { - const MPoly *mpoly = &mr->mpoly[mlt->poly]; - if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) { - lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v, - mr->mloop[mlt->tri[1]].v, - mr->mloop[mlt->tri[2]].v, - mlt->tri[0], - mlt->tri[1], - mlt->tri[2], - data); + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params) + { + 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); + } } + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; } static void extract_lines_adjacency_finish(const MeshRenderData *mr, void *ibo, void *_data) { - MeshExtract_LineAdjacency_Data *data = (MeshExtract_LineAdjacency_Data *)_data; + MeshExtract_LineAdjacency_Data *data = _data; /* Create edges for remaining non manifold edges. */ EdgeHashIterator *ehi = BLI_edgehashIterator_new(data->eh); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { @@ -1184,18 +1518,12 @@ static void extract_lines_adjacency_finish(const MeshRenderData *mr, void *ibo, #undef NO_EDGE static const MeshExtract extract_lines_adjacency = { - extract_lines_adjacency_init, - extract_lines_adjacency_looptri_bmesh, - extract_lines_adjacency_looptri_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_lines_adjacency_finish, - 0, - false, + .init = extract_lines_adjacency_init, + .iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm, + .iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh, + .finish = extract_lines_adjacency_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1225,53 +1553,53 @@ BLI_INLINE void edituv_tri_add( } } -static void extract_edituv_tris_looptri_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(t), - BMLoop **elt, - void *data) +static void extract_edituv_tris_iter_looptri_bm(const MeshRenderData *UNUSED(mr), + const struct ExtractTriBMesh_Params *params, + void *data) { - edituv_tri_add(data, - BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT), - BM_elem_index_get(elt[0]), - BM_elem_index_get(elt[1]), - BM_elem_index_get(elt[2])); + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params) + { + 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])); + } + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; } -static void extract_edituv_tris_looptri_mesh(const MeshRenderData *mr, - int UNUSED(t), - const MLoopTri *mlt, - void *data) +static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData *mr, + const struct ExtractTriMesh_Params *params, + void *data) { - const MPoly *mpoly = &mr->mpoly[mlt->poly]; - edituv_tri_add(data, - (mpoly->flag & ME_HIDE) != 0, - (mpoly->flag & ME_FACE_SEL) != 0, - mlt->tri[0], - mlt->tri[1], - mlt->tri[2]); + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params) + { + 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]); + } + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; } static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data) { - MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data; + MeshExtract_EditUvElem_Data *extract_data = data; GPU_indexbuf_build_in_place(&extract_data->elb, ibo); MEM_freeN(extract_data); } static const MeshExtract extract_edituv_tris = { - extract_edituv_tris_init, - extract_edituv_tris_looptri_bmesh, - extract_edituv_tris_looptri_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_edituv_tris_finish, - 0, - false, + .init = extract_edituv_tris_init, + .iter_looptri_bm = extract_edituv_tris_iter_looptri_bm, + .iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh, + .finish = extract_edituv_tris_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1297,55 +1625,53 @@ BLI_INLINE void edituv_edge_add( } } -static void extract_edituv_lines_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - edituv_edge_add(data, - BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(loop->f, BM_ELEM_SELECT), - l, - BM_elem_index_get(loop->next)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(loop, l_index, params, mr) + { + edituv_edge_add(data, + BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), + BM_elem_flag_test(loop->f, BM_ELEM_SELECT), + l_index, + BM_elem_index_get(loop->next)); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(loop); } -static void extract_edituv_lines_loop_mesh(const MeshRenderData *mr, - int loop_idx, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *data) +static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - int loopend = mpoly->totloop + mpoly->loopstart - 1; - int loop_next_idx = (loop_idx == loopend) ? mpoly->loopstart : (loop_idx + 1); - const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[mloop->e] != ORIGINDEX_NONE); - edituv_edge_add(data, - (mpoly->flag & ME_HIDE) != 0 || !real_edge, - (mpoly->flag & ME_FACE_SEL) != 0, - loop_idx, - loop_next_idx); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + 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); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data) { - MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data; + MeshExtract_EditUvElem_Data *extract_data = data; GPU_indexbuf_build_in_place(&extract_data->elb, ibo); MEM_freeN(extract_data); } static const MeshExtract extract_edituv_lines = { - extract_edituv_lines_init, - NULL, - NULL, - extract_edituv_lines_loop_bmesh, - extract_edituv_lines_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_edituv_lines_finish, - 0, - false, + .init = extract_edituv_lines_init, + .iter_poly_bm = extract_edituv_lines_iter_poly_bm, + .iter_poly_mesh = extract_edituv_lines_iter_poly_mesh, + .finish = extract_edituv_lines_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1373,50 +1699,48 @@ BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data, } } -static void extract_edituv_points_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_edituv_points_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - edituv_point_add(data, - BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(loop->f, BM_ELEM_SELECT), - l); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + edituv_point_add(data, + BM_elem_flag_test(l->f, BM_ELEM_HIDDEN), + BM_elem_flag_test(l->f, BM_ELEM_SELECT), + l_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edituv_points_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *data) +static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && - mr->v_origindex[mloop->v] != ORIGINDEX_NONE); - edituv_point_add( - data, ((mpoly->flag & ME_HIDE) != 0) || !real_vert, (mpoly->flag & ME_FACE_SEL) != 0, l); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + 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); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data) { - MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data; + MeshExtract_EditUvElem_Data *extract_data = data; GPU_indexbuf_build_in_place(&extract_data->elb, ibo); MEM_freeN(extract_data); } static const MeshExtract extract_edituv_points = { - extract_edituv_points_init, - NULL, - NULL, - extract_edituv_points_loop_bmesh, - extract_edituv_points_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_edituv_points_finish, - 0, - false, + .init = extract_edituv_points_init, + .iter_poly_bm = extract_edituv_points_iter_poly_bm, + .iter_poly_mesh = extract_edituv_points_iter_poly_mesh, + .finish = extract_edituv_points_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1437,64 +1761,75 @@ static void *extract_edituv_fdots_init(const MeshRenderData *mr, void *UNUSED(ib BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, - int face_idx) + int face_index) { if (!hidden && (data->sync_selection || selected)) { - GPU_indexbuf_set_point_vert(&data->elb, face_idx, face_idx); + GPU_indexbuf_set_point_vert(&data->elb, face_index, face_index); } else { - GPU_indexbuf_set_point_restart(&data->elb, face_idx); + GPU_indexbuf_set_point_restart(&data->elb, face_index); } } -static void extract_edituv_fdots_loop_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(l), - BMLoop *loop, - void *data) +static void extract_edituv_fdots_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - edituv_facedot_add(data, - BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(loop->f, BM_ELEM_SELECT), - BM_elem_index_get(loop->f)); + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + edituv_facedot_add( + data, BM_elem_flag_test(f, BM_ELEM_HIDDEN), BM_elem_flag_test(f, BM_ELEM_SELECT), f_index); + } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_edituv_fdots_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *mloop, - int p, - const MPoly *mpoly, - void *data) +static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && - mr->p_origindex[p] != ORIGINDEX_NONE); - const bool subd_fdot = (!mr->use_subsurf_fdots || - (mr->mvert[mloop->v].flag & ME_VERT_FACEDOT) != 0); - edituv_facedot_add(data, - ((mpoly->flag & ME_HIDE) != 0) || !real_fdot || !subd_fdot, - (mpoly->flag & ME_FACE_SEL) != 0, - p); + if (mr->use_subsurf_fdots) { + /* Check #ME_VERT_FACEDOT. */ + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + 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); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; + } + else { + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + 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); + } + EXTRACT_POLY_FOREACH_MESH_END; + } } static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *_data) { - MeshExtract_EditUvElem_Data *data = (MeshExtract_EditUvElem_Data *)_data; + MeshExtract_EditUvElem_Data *data = _data; GPU_indexbuf_build_in_place(&data->elb, ibo); MEM_freeN(data); } static const MeshExtract extract_edituv_fdots = { - extract_edituv_fdots_init, - NULL, - NULL, - extract_edituv_fdots_loop_bmesh, - extract_edituv_fdots_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_edituv_fdots_finish, - 0, - false, + .init = extract_edituv_fdots_init, + .iter_poly_bm = extract_edituv_fdots_iter_poly_bm, + .iter_poly_mesh = extract_edituv_fdots_iter_poly_mesh, + .finish = extract_edituv_fdots_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1517,7 +1852,7 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - /* WARNING Adjust PosNorLoop struct accordingly. */ + /* WARNING Adjust #PosNorLoop struct accordingly. */ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); GPU_vertformat_alias_add(&format, "vnor"); @@ -1541,95 +1876,122 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf) } } else { - const MVert *mvert = mr->mvert; - for (int v = 0; v < mr->vert_len; v++, mvert++) { - data->packed_nor[v] = GPU_normal_convert_i10_s3(mvert->no); + const MVert *mv = mr->mvert; + for (int v = 0; v < mr->vert_len; v++, mv++) { + data->packed_nor[v] = GPU_normal_convert_i10_s3(mv->no); } } return data; } -static void extract_pos_nor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data) +static void extract_pos_nor_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, loop->v)); - vert->nor = data->packed_nor[BM_elem_index_get(loop->v)]; - BMFace *efa = loop->f; - vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + PosNorLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert->pos, bm_vert_co_get(mr, l->v)); + vert->nor = data->packed_nor[BM_elem_index_get(l->v)]; + BMFace *efa = l->f; + vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_pos_nor_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *_data) +static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - const MVert *mvert = &mr->mvert[mloop->v]; - copy_v3_v3(vert->pos, mvert->co); - vert->nor = data->packed_nor[mloop->v]; - /* Flag for paint mode overlay. */ - if (mpoly->flag & ME_HIDE || mvert->flag & ME_HIDE || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && - (mr->v_origindex[mloop->v] == ORIGINDEX_NONE))) { - vert->nor.w = -1; - } - else if (mvert->flag & SELECT) { - vert->nor.w = 1; - } - else { - vert->nor.w = 0; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + PosNorLoop *vert = &data->vbo_data[ml_index]; + const MVert *mv = &mr->mvert[ml->v]; + copy_v3_v3(vert->pos, mv->co); + vert->nor = data->packed_nor[ml->v]; + /* 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; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_pos_nor_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *_data) +static void extract_pos_nor_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *_data) { - int l = mr->loop_len + e * 2; MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); - copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); - vert[0].nor = data->packed_nor[BM_elem_index_get(eed->v1)]; - vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)]; + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + 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->packed_nor[BM_elem_index_get(eed->v1)]; + vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)]; + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_pos_nor_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *medge, - void *_data) +static void extract_pos_nor_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *_data) { - int l = mr->loop_len + e * 2; MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert[0].pos, mr->mvert[medge->v1].co); - copy_v3_v3(vert[1].pos, mr->mvert[medge->v2].co); - vert[0].nor = data->packed_nor[medge->v1]; - vert[1].nor = data->packed_nor[medge->v2]; + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + 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->packed_nor[med->v1]; + vert[1].nor = data->packed_nor[med->v2]; + } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_pos_nor_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *_data) +static void extract_pos_nor_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *_data) { - int l = mr->loop_len + mr->edge_loose_len * 2 + v; MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); - vert->nor = data->packed_nor[BM_elem_index_get(eve)]; + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + 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->packed_nor[BM_elem_index_get(eve)]; + } + EXTRACT_LVERT_FOREACH_BM_END; } -static void extract_pos_nor_lvert_mesh(const MeshRenderData *mr, - int v, - const MVert *mvert, - void *_data) +static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *_data) { - int l = mr->loop_len + mr->edge_loose_len * 2 + v; - int v_idx = mr->lverts[v]; MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, mvert->co); - vert->nor = data->packed_nor[v_idx]; + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) + { + 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->packed_nor[v_index]; + } + EXTRACT_LVERT_FOREACH_MESH_END; } static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(vbo), void *data) @@ -1638,18 +2000,16 @@ static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), void *UNUSE } static const MeshExtract extract_pos_nor = { - extract_pos_nor_init, - NULL, - NULL, - extract_pos_nor_loop_bmesh, - extract_pos_nor_loop_mesh, - extract_pos_nor_ledge_bmesh, - extract_pos_nor_ledge_mesh, - extract_pos_nor_lvert_bmesh, - extract_pos_nor_lvert_mesh, - extract_pos_nor_finish, - 0, - true, + .init = extract_pos_nor_init, + .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, + .finish = extract_pos_nor_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -1675,62 +2035,71 @@ static void *extract_lnor_hq_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_lnor_hq_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *data) +static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { if (mr->loop_normals) { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, mr->loop_normals[l]); - } - else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_vert_no_get(mr, loop->v)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(_l, l_index, params, mr) + { + normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, mr->loop_normals[l_index]); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(_l); } else { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_face_no_get(mr, loop->f)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH)) { + normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_vert_no_get(mr, l->v)); + } + else { + normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_face_no_get(mr, l->f)); + } + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } } -static void extract_lnor_hq_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data) +static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - gpuHQNor *lnor_data = &((gpuHQNor *)data)[l]; - if (mr->loop_normals) { - normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[l]); - } - else if (mpoly->flag & ME_SMOOTH) { - copy_v3_v3_short(&lnor_data->x, mr->mvert[mloop->v].no); - } - else { - normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[p]); - } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + 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]); + } - /* 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 unmapped data to draw the wireframe. */ - if (mpoly->flag & ME_HIDE || - (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && - mr->v_origindex[mloop->v] == ORIGINDEX_NONE)) { - lnor_data->w = -1; - } - else if (mpoly->flag & ME_FACE_SEL) { - lnor_data->w = 1; - } - else { - lnor_data->w = 0; + /* 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; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static const MeshExtract extract_lnor_hq = { - extract_lnor_hq_init, - NULL, - NULL, - extract_lnor_hq_loop_bmesh, - extract_lnor_hq_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - MR_DATA_LOOP_NOR, - true, + .init = extract_lnor_hq_init, + .iter_poly_bm = extract_lnor_hq_iter_poly_bm, + .iter_poly_mesh = extract_lnor_hq_iter_poly_mesh, + .data_flag = MR_DATA_LOOP_NOR, + .use_threading = true, }; /** \} */ @@ -1752,64 +2121,75 @@ static void *extract_lnor_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_lnor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *data) +static void extract_lnor_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { if (mr->loop_normals) { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->loop_normals[l]); - } - else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, loop->v)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]); + BMFace *efa = l->f; + ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } else { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, loop->f)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH)) { + ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, l->v)); + } + else { + ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, l->f)); + } + BMFace *efa = l->f; + ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } - BMFace *efa = loop->f; - ((GPUPackedNormal *)data)[l].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; } -static void extract_lnor_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data) +static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - GPUPackedNormal *lnor_data = &((GPUPackedNormal *)data)[l]; - if (mr->loop_normals) { - *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[l]); - } - else if (mpoly->flag & ME_SMOOTH) { - *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[mloop->v].no); - } - else { - *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[p]); - } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + 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]); + } - /* 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 unmapped data to draw the wireframe. */ - if (mpoly->flag & ME_HIDE || - (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && - mr->v_origindex[mloop->v] == ORIGINDEX_NONE)) { - lnor_data->w = -1; - } - else if (mpoly->flag & ME_FACE_SEL) { - lnor_data->w = 1; - } - else { - lnor_data->w = 0; + /* 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; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static const MeshExtract extract_lnor = { - extract_lnor_init, - NULL, - NULL, - extract_lnor_loop_bmesh, - extract_lnor_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - MR_DATA_LOOP_NOR, - true, + .init = extract_lnor_init, + .iter_poly_bm = extract_lnor_iter_poly_bm, + .iter_poly_mesh = extract_lnor_iter_poly_mesh, + .data_flag = MR_DATA_LOOP_NOR, + .use_threading = true, }; /** \} */ @@ -1853,7 +2233,7 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf) /* Active display layer name. */ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { GPU_vertformat_alias_add(&format, "au"); - /* Alias to pos for edit uvs. */ + /* Alias to `pos` for edit uvs. */ GPU_vertformat_alias_add(&format, "pos"); } /* Stencil mask uv layer name. */ @@ -1879,20 +2259,21 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf) if (uv_layers & (1 << i)) { if (mr->extract_type == MR_EXTRACT_BMESH) { int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPUV, i); - BMIter f_iter, l_iter; + BMIter f_iter; BMFace *efa; - BMLoop *loop; BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs); + 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); memcpy(uv_data, luv->uv, sizeof(*uv_data)); uv_data++; - } + } while ((l_iter = l_iter->next) != l_first); } } else { MLoopUV *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i); - for (int l = 0; l < mr->loop_len; l++, uv_data++, layer_data++) { + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, uv_data++, layer_data++) { memcpy(uv_data, layer_data->uv, sizeof(*uv_data)); } } @@ -1903,18 +2284,9 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf) } static const MeshExtract extract_uv = { - extract_uv_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - false, + .init = extract_uv_init, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1962,7 +2334,7 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool } } if (use_orco_tan && orco == NULL) { - /* If orco is not available compute it ourselves */ + /* If `orco` is not available compute it ourselves */ orco_allocated = true; orco = MEM_mallocN(sizeof(*orco) * mr->vert_len, __func__); @@ -1976,17 +2348,17 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool } } else { - const MVert *mvert = mr->mvert; - for (int v = 0; v < mr->vert_len; v++, mvert++) { - copy_v3_v3(orco[v], mvert->co); + const MVert *mv = mr->mvert; + for (int v = 0; v < mr->vert_len; v++, mv++) { + copy_v3_v3(orco[v], mv->co); } } BKE_mesh_orco_verts_transform(mr->me, orco, mr->vert_len, 0); } /* Start Fresh */ - CustomData_free_layers(cd_ldata, CD_TANGENT, mr->loop_len); - + CustomData loop_data; + CustomData_reset(&loop_data); if (tan_len != 0 || use_orco_tan) { short tangent_mask = 0; bool calc_active_tangent = false; @@ -1998,7 +2370,7 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool mr->poly_normals, mr->loop_normals, orco, - cd_ldata, + &loop_data, mr->loop_len, &tangent_mask); } @@ -2016,7 +2388,7 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool mr->poly_normals, mr->loop_normals, orco, - cd_ldata, + &loop_data, mr->loop_len, &tangent_mask); } @@ -2024,7 +2396,7 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool if (use_orco_tan) { char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; - const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_TANGENT, 0); + const char *layer_name = CustomData_get_layer_name(&loop_data, CD_TANGENT, 0); GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); BLI_snprintf(attr_name, sizeof(*attr_name), "t%s", attr_safe_name); GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode); @@ -2050,18 +2422,19 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool short(*tan_data)[4] = (short(*)[4])vbo->data; for (int i = 0; i < tan_len; i++) { const char *name = tangent_names[i]; - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(cd_ldata, CD_TANGENT, name); - for (int l = 0; l < mr->loop_len; l++) { - normal_float_to_short_v3(*tan_data, layer_data[l]); - (*tan_data)[3] = (layer_data[l][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named( + &loop_data, CD_TANGENT, name); + 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; tan_data++; } } if (use_orco_tan) { - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(cd_ldata, CD_TANGENT, 0); - for (int l = 0; l < mr->loop_len; l++) { - normal_float_to_short_v3(*tan_data, layer_data[l]); - (*tan_data)[3] = (layer_data[l][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0); + 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; tan_data++; } } @@ -2070,24 +2443,25 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool GPUPackedNormal *tan_data = (GPUPackedNormal *)vbo->data; for (int i = 0; i < tan_len; i++) { const char *name = tangent_names[i]; - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(cd_ldata, CD_TANGENT, name); - for (int l = 0; l < mr->loop_len; l++) { - *tan_data = GPU_normal_convert_i10_v3(layer_data[l]); - tan_data->w = (layer_data[l][3] > 0.0f) ? 1 : -2; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named( + &loop_data, CD_TANGENT, name); + 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; tan_data++; } } if (use_orco_tan) { - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(cd_ldata, CD_TANGENT, 0); - for (int l = 0; l < mr->loop_len; l++) { - *tan_data = GPU_normal_convert_i10_v3(layer_data[l]); - tan_data->w = (layer_data[l][3] > 0.0f) ? 1 : -2; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0); + 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; tan_data++; } } } - CustomData_free_layers(cd_ldata, CD_TANGENT, mr->loop_len); + CustomData_free(&loop_data, mr->loop_len); } static void *extract_tan_init(const MeshRenderData *mr, void *buf) @@ -2097,18 +2471,9 @@ static void *extract_tan_init(const MeshRenderData *mr, void *buf) } static const MeshExtract extract_tan = { - extract_tan_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, - false, + .init = extract_tan_init, + .data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, + .use_threading = false, }; /** \} */ @@ -2124,18 +2489,9 @@ static void *extract_tan_hq_init(const MeshRenderData *mr, void *buf) } static const MeshExtract extract_tan_hq = { - extract_tan_hq_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, - false, + .init = extract_tan_hq_init, + .data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, + .use_threading = false, }; /** \} */ @@ -2150,7 +2506,9 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) GPU_vertformat_deinterleave(&format); CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; uint32_t vcol_layers = mr->cache->cd_used.vcol; + uint32_t svcol_layers = mr->cache->cd_used.sculpt_vcol; for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { @@ -2167,14 +2525,44 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) { GPU_vertformat_alias_add(&format, "ac"); } + /* Gather number of auto layers. */ - /* We only do vcols that are not overridden by uvs */ - if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) { + /* We only do `vcols` that are not overridden by `uvs` and sculpt vertex colors. */ + 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 */ + 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); + } + } + } + } + GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -2184,27 +2572,30 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) } gpuMeshVcol; gpuMeshVcol *vcol_data = (gpuMeshVcol *)vbo->data; + MLoop *loops = CustomData_get_layer(cd_ldata, CD_MLOOP); + for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { if (mr->extract_type == MR_EXTRACT_BMESH) { int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPCOL, i); - BMIter f_iter, l_iter; + BMIter f_iter; BMFace *efa; - BMLoop *loop; BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { - const MLoopCol *mloopcol = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs); + 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); 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++; - } + } while ((l_iter = l_iter->next) != l_first); } } else { const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); - for (int l = 0; l < mr->loop_len; l++, mloopcol++, vcol_data++) { + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, mloopcol++, vcol_data++) { 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]); @@ -2212,22 +2603,45 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) } } } + + if (svcol_layers & (1 << i) && U.experimental.use_sculpt_vertex_colors) { + if (mr->extract_type == MR_EXTRACT_BMESH) { + int cd_ofs = CustomData_get_n_offset(cd_vdata, CD_PROP_COLOR, i); + 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 { + const MPropCol *prop_col = BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs); + 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++; + } while ((l_iter = l_iter->next) != l_first); + } + } + else { + MPropCol *vcol = CustomData_get_layer_n(cd_vdata, CD_PROP_COLOR, i); + 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]); + } + } + + vcol_data += mr->loop_len; + } } return NULL; } static const MeshExtract extract_vcol = { - extract_vcol_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - false, + .init = extract_vcol_init, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -2246,7 +2660,7 @@ static void *extract_orco_init(const MeshRenderData *mr, void *buf) static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex - * attributes. This is a substantial waste of Vram and should be done another way. + * attributes. This is a substantial waste of video-ram and should be done another way. * Unfortunately, at the time of writing, I did not found any other "non disruptive" * alternative. */ GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); @@ -2261,33 +2675,37 @@ static void *extract_orco_init(const MeshRenderData *mr, void *buf) MeshExtract_Orco_Data *data = MEM_mallocN(sizeof(*data), __func__); data->vbo_data = (float(*)[4])vbo->data; data->orco = CustomData_get_layer(cd_vdata, CD_ORCO); - /* Make sure orco layer was requested only if needed! */ + /* Make sure `orco` layer was requested only if needed! */ BLI_assert(data->orco); return data; } -static void extract_orco_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_orco_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; - float *loop_orco = orco_data->vbo_data[l]; - copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]); - loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(loop, l_index, params, mr) + { + float *loop_orco = orco_data->vbo_data[l_index]; + copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]); + loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(loop); } -static void extract_orco_loop_mesh(const MeshRenderData *UNUSED(mr), - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *data) +static void extract_orco_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; - float *loop_orco = orco_data->vbo_data[l]; - copy_v3_v3(loop_orco, orco_data->orco[mloop->v]); - loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + 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. */ + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_orco_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data) @@ -2296,18 +2714,12 @@ static void extract_orco_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(b } static const MeshExtract extract_orco = { - extract_orco_init, - NULL, - NULL, - extract_orco_loop_bmesh, - extract_orco_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_orco_finish, - 0, - true, + .init = extract_orco_init, + .iter_poly_bm = extract_orco_iter_poly_bm, + .iter_poly_mesh = extract_orco_iter_poly_mesh, + .finish = extract_orco_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -2334,7 +2746,7 @@ static float loop_edge_factor_get(const float f_no[3], cross_v3_v3v3(enor, v_no, evec); normalize_v3(enor); float d = fabsf(dot_v3v3(enor, f_no)); - /* Rescale to the slider range. */ + /* Re-scale to the slider range. */ d *= (1.0f / 0.065f); CLAMP(d, 0.0f, 1.0f); return d; @@ -2358,9 +2770,9 @@ static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf) /* HACK(fclem) Detecting the need for edge render. * We could have a flag in the mesh instead or check the modifier stack. */ - const MEdge *medge = mr->medge; - for (int e = 0; e < mr->edge_len; e++, medge++) { - if ((medge->flag & ME_EDGERENDER) == 0) { + const MEdge *med = mr->medge; + for (int e_index = 0; e_index < mr->edge_len; e_index++, med++) { + if ((med->flag & ME_EDGERENDER) == 0) { data->use_edge_render = true; break; } @@ -2376,81 +2788,103 @@ static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_edge_fac_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data) +static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; - if (BM_edge_is_manifold(loop->e)) { - float ratio = loop_edge_factor_get(bm_face_no_get(mr, loop->f), - bm_vert_co_get(mr, loop->v), - bm_vert_no_get(mr, loop->v), - bm_vert_co_get(mr, loop->next->v)); - data->vbo_data[l] = ratio * 253 + 1; - } - else { - data->vbo_data[l] = 255; + MeshExtract_EdgeFac_Data *data = _data; + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + if (BM_edge_is_manifold(l->e)) { + float ratio = loop_edge_factor_get(bm_face_no_get(mr, l->f), + bm_vert_co_get(mr, l->v), + bm_vert_no_get(mr, l->v), + bm_vert_co_get(mr, l->next->v)); + data->vbo_data[l_index] = ratio * 253 + 1; + } + else { + data->vbo_data[l_index] = 255; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edge_fac_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data) +static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; + if (data->use_edge_render) { - const MEdge *medge = &mr->medge[mloop->e]; - data->vbo_data[l] = (medge->flag & ME_EDGERENDER) ? 255 : 0; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MEdge *med = &mr->medge[ml->e]; + data->vbo_data[ml_index] = (med->flag & ME_EDGERENDER) ? 255 : 0; + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } else { - /* Count loop per edge to detect non-manifold. */ - if (data->edge_loop_count[mloop->e] < 3) { - data->edge_loop_count[mloop->e]++; - } - if (data->edge_loop_count[mloop->e] == 2) { - /* Manifold */ - int loopend = mpoly->totloop + mpoly->loopstart - 1; - int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1); - const MLoop *mloop_next = &mr->mloop[other_loop]; - const MVert *v1 = &mr->mvert[mloop->v]; - const MVert *v2 = &mr->mvert[mloop_next->v]; - float vnor_f[3]; - normal_short_to_float_v3(vnor_f, v1->no); - float ratio = loop_edge_factor_get(mr->poly_normals[p], v1->co, vnor_f, v2->co); - data->vbo_data[l] = ratio * 253 + 1; - } - else { - /* Non-manifold */ - data->vbo_data[l] = 255; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + /* 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; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } } -static void extract_edge_fac_ledge_bmesh(const MeshRenderData *mr, - int e, - BMEdge *UNUSED(eed), - void *_data) +static void extract_edge_fac_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *_data) { - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; - data->vbo_data[mr->loop_len + e * 2 + 0] = 255; - data->vbo_data[mr->loop_len + e * 2 + 1] = 255; + MeshExtract_EdgeFac_Data *data = _data; + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255; + data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255; + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_edge_fac_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *UNUSED(edge), - void *_data) +static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *_data) { - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; - data->vbo_data[mr->loop_len + e * 2 + 0] = 255; - data->vbo_data[mr->loop_len + e * 2 + 1] = 255; + MeshExtract_EdgeFac_Data *data = _data; + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255; + data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255; + } + EXTRACT_LEDGE_FOREACH_MESH_END; } static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_data) { - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; + MeshExtract_EdgeFac_Data *data = _data; if (GPU_crappy_amd_driver()) { GPUVertBuf *vbo = (GPUVertBuf *)buf; - /* Some AMD drivers strangely crash with VBOs with a one byte format. - * To workaround we reinit the vbo with another format and convert + /* Some AMD drivers strangely crash with VBO's with a one byte format. + * To workaround we reinitialize the VBO with another format and convert * all bytes to floats. */ static GPUVertFormat format = {0}; if (format.attr_len == 0) { @@ -2465,8 +2899,8 @@ static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_ GPU_vertbuf_data_alloc(vbo, buf_len); float *fdata = (float *)vbo->data; - for (int l = 0; l < buf_len; l++, fdata++) { - *fdata = data->vbo_data[l] / 255.0f; + for (int ml_index = 0; ml_index < buf_len; ml_index++, fdata++) { + *fdata = data->vbo_data[ml_index] / 255.0f; } /* Free old byte data. */ MEM_freeN(data->vbo_data); @@ -2475,18 +2909,14 @@ static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_ } static const MeshExtract extract_edge_fac = { - extract_edge_fac_init, - NULL, - NULL, - extract_edge_fac_loop_bmesh, - extract_edge_fac_loop_mesh, - extract_edge_fac_ledge_bmesh, - extract_edge_fac_ledge_mesh, - NULL, - NULL, - extract_edge_fac_finish, - MR_DATA_POLY_NOR, - false, + .init = extract_edge_fac_init, + .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, + .finish = extract_edge_fac_finish, + .data_flag = MR_DATA_POLY_NOR, + .use_threading = false, }; /** \} */ @@ -2497,8 +2927,8 @@ static const MeshExtract extract_edge_fac = { typedef struct MeshExtract_Weight_Data { float *vbo_data; const DRW_MeshWeightState *wstate; - const MDeformVert *dvert; /* For Mesh. */ - int cd_ofs; /* For BMesh. */ + const MDeformVert *dvert; /* For #Mesh. */ + int cd_ofs; /* For #BMesh. */ } MeshExtract_Weight_Data; static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate) @@ -2584,27 +3014,49 @@ static void *extract_weights_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_weights_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *_data) +static void extract_weights_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_Weight_Data *data = (MeshExtract_Weight_Data *)_data; - const MDeformVert *dvert = (data->cd_ofs != -1) ? BM_ELEM_CD_GET_VOID_P(loop->v, data->cd_ofs) : - NULL; - data->vbo_data[l] = evaluate_vertex_weight(dvert, data->wstate); + MeshExtract_Weight_Data *data = _data; + if (data->cd_ofs != -1) { + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(l->v, data->cd_ofs); + data->vbo_data[l_index] = evaluate_vertex_weight(dvert, data->wstate); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + } + else { + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + data->vbo_data[l_index] = evaluate_vertex_weight(NULL, data->wstate); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + } } -static void extract_weights_loop_mesh(const MeshRenderData *UNUSED(mr), - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *_data) +static void extract_weights_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - MeshExtract_Weight_Data *data = (MeshExtract_Weight_Data *)_data; - const MDeformVert *dvert = data->dvert ? &data->dvert[mloop->v] : NULL; - data->vbo_data[l] = evaluate_vertex_weight(dvert, data->wstate); + MeshExtract_Weight_Data *data = _data; + if (data->dvert != NULL) { + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MDeformVert *dvert = &data->dvert[ml->v]; + data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; + } + else { + const MDeformVert *dvert = NULL; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; + } } static void extract_weights_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data) @@ -2613,18 +3065,12 @@ static void extract_weights_finish(const MeshRenderData *UNUSED(mr), void *UNUSE } static const MeshExtract extract_weights = { - extract_weights_init, - NULL, - NULL, - extract_weights_loop_bmesh, - extract_weights_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_weights_finish, - 0, - true, + .init = extract_weights_init, + .iter_poly_bm = extract_weights_iter_poly_bm, + .iter_poly_mesh = extract_weights_iter_poly_mesh, + .finish = extract_weights_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -2731,31 +3177,31 @@ static void mesh_render_data_edge_flag(const MeshRenderData *mr, BMEdge *eed, Ed } static void mesh_render_data_loop_flag(const MeshRenderData *mr, - BMLoop *loop, + BMLoop *l, const int cd_ofs, EditLoopData *eattr) { if (cd_ofs == -1) { return; } - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs); + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_ofs); if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) { eattr->v_flag |= VFLAG_VERT_UV_PINNED; } - if (uvedit_uv_select_test_ex(mr->toolsettings, loop, cd_ofs)) { + if (uvedit_uv_select_test_ex(mr->toolsettings, l, cd_ofs)) { eattr->v_flag |= VFLAG_VERT_UV_SELECT; } } static void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, - BMLoop *loop, + BMLoop *l, const int cd_ofs, EditLoopData *eattr) { if (cd_ofs == -1) { return; } - if (uvedit_edge_select_test_ex(mr->toolsettings, loop, cd_ofs)) { + if (uvedit_edge_select_test_ex(mr->toolsettings, l, cd_ofs)) { eattr->v_flag |= VFLAG_EDGE_UV_SELECT; eattr->v_flag |= VFLAG_VERT_UV_SELECT; } @@ -2775,7 +3221,7 @@ static void *extract_edit_data_init(const MeshRenderData *mr, void *buf) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - /* WARNING Adjust EditLoopData struct accordingly. */ + /* WARNING: Adjust #EditLoopData struct accordingly. */ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); GPU_vertformat_alias_add(&format, "flag"); } @@ -2785,114 +3231,130 @@ static void *extract_edit_data_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_edit_data_loop_bmesh(const MeshRenderData *mr, - int l, - BMLoop *loop, - void *_data) +static void extract_edit_data_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + l; - memset(data, 0x0, sizeof(*data)); - mesh_render_data_face_flag(mr, loop->f, -1, data); - mesh_render_data_edge_flag(mr, loop->e, data); - mesh_render_data_vert_flag(mr, loop->v, data); -} -static void extract_edit_data_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int p, - const MPoly *UNUSED(mpoly), - void *_data) -{ - EditLoopData *data = (EditLoopData *)_data + l; - memset(data, 0x0, sizeof(*data)); - BMFace *efa = bm_original_face_get(mr, p); - BMEdge *eed = bm_original_edge_get(mr, mloop->e); - BMVert *eve = bm_original_vert_get(mr, mloop->v); - if (efa) { - mesh_render_data_face_flag(mr, efa, -1, data); - } - if (eed) { - mesh_render_data_edge_flag(mr, eed, data); - } - if (eve) { - mesh_render_data_vert_flag(mr, eve, data); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + EditLoopData *data = (EditLoopData *)_data + l_index; + memset(data, 0x0, sizeof(*data)); + mesh_render_data_face_flag(mr, l->f, -1, data); + mesh_render_data_edge_flag(mr, l->e, data); + mesh_render_data_vert_flag(mr, l->v, data); } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edit_data_ledge_bmesh(const MeshRenderData *mr, - int e, - BMEdge *eed, - void *_data) +static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + e * 2; - memset(data, 0x0, sizeof(*data) * 2); - mesh_render_data_edge_flag(mr, eed, &data[0]); - data[1] = data[0]; - mesh_render_data_vert_flag(mr, eed->v1, &data[0]); - mesh_render_data_vert_flag(mr, eed->v2, &data[1]); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + 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); + } + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_edit_data_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *edge, - void *_data) +static void extract_edit_data_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + e * 2; - memset(data, 0x0, sizeof(*data) * 2); - int e_idx = mr->ledges[e]; - BMEdge *eed = bm_original_edge_get(mr, e_idx); - BMVert *eve1 = bm_original_vert_get(mr, edge->v1); - BMVert *eve2 = bm_original_vert_get(mr, edge->v2); - if (eed) { + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + 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]); + } + EXTRACT_LEDGE_FOREACH_BM_END; +} + +static void extract_edit_data_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *_data) +{ + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + 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]); + } } - if (eve1) { - mesh_render_data_vert_flag(mr, eve1, &data[0]); - } - if (eve2) { - mesh_render_data_vert_flag(mr, eve2, &data[1]); - } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_edit_data_lvert_bmesh(const MeshRenderData *mr, - int v, - BMVert *eve, - void *_data) +static void extract_edit_data_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + mr->edge_loose_len * 2 + v; - memset(data, 0x0, sizeof(*data)); - mesh_render_data_vert_flag(mr, eve, data); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + EditLoopData *data = (EditLoopData *)_data + offset + lvert_index; + memset(data, 0x0, sizeof(*data)); + mesh_render_data_vert_flag(mr, eve, data); + } + EXTRACT_LVERT_FOREACH_BM_END; } -static void extract_edit_data_lvert_mesh(const MeshRenderData *mr, - int v, - const MVert *UNUSED(mvert), - void *_data) +static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + mr->edge_loose_len * 2 + v; - memset(data, 0x0, sizeof(*data)); - int v_idx = mr->lverts[v]; - BMVert *eve = bm_original_vert_get(mr, v_idx); - if (eve) { - mesh_render_data_vert_flag(mr, eve, data); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) + { + 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); + } } + EXTRACT_LVERT_FOREACH_MESH_END; } static const MeshExtract extract_edit_data = { - extract_edit_data_init, - NULL, - NULL, - extract_edit_data_loop_bmesh, - extract_edit_data_loop_mesh, - extract_edit_data_ledge_bmesh, - extract_edit_data_ledge_mesh, - extract_edit_data_lvert_bmesh, - extract_edit_data_lvert_mesh, - NULL, - 0, - true, + .init = extract_edit_data_init, + .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, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -2910,7 +3372,7 @@ static void *extract_edituv_data_init(const MeshRenderData *mr, void *buf) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - /* WARNING Adjust EditLoopData struct accordingly. */ + /* WARNING: Adjust #EditLoopData struct accordingly. */ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); GPU_vertformat_alias_add(&format, "flag"); } @@ -2927,51 +3389,59 @@ static void *extract_edituv_data_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_edituv_data_loop_bmesh(const MeshRenderData *mr, - int l, - BMLoop *loop, - void *_data) +static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_EditUVData_Data *data = (MeshExtract_EditUVData_Data *)_data; - EditLoopData *eldata = data->vbo_data + l; - memset(eldata, 0x0, sizeof(*eldata)); - mesh_render_data_loop_flag(mr, loop, data->cd_ofs, eldata); - mesh_render_data_face_flag(mr, loop->f, data->cd_ofs, eldata); - mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata); -} - -static void extract_edituv_data_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data) -{ - MeshExtract_EditUVData_Data *data = (MeshExtract_EditUVData_Data *)_data; - EditLoopData *eldata = data->vbo_data + l; - memset(eldata, 0x0, sizeof(*eldata)); - BMFace *efa = bm_original_face_get(mr, p); - if (efa) { - BMEdge *eed = bm_original_edge_get(mr, mloop->e); - BMVert *eve = bm_original_vert_get(mr, mloop->v); - if (eed && eve) { - /* Loop on an edge endpoint. */ - BMLoop *loop = BM_face_edge_share_loop(efa, eed); - mesh_render_data_loop_flag(mr, loop, data->cd_ofs, eldata); - mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata); - } - else { - if (eed == NULL) { - /* Find if the loop's vert is not part of an edit edge. - * For this, we check if the previous loop was on an edge. */ - int loopend = mpoly->loopstart + mpoly->totloop - 1; - int l_prev = (l == mpoly->loopstart) ? loopend : (l - 1); - const MLoop *mloop_prev = &mr->mloop[l_prev]; - eed = bm_original_edge_get(mr, mloop_prev->e); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + MeshExtract_EditUVData_Data *data = _data; + EditLoopData *eldata = &data->vbo_data[l_index]; + memset(eldata, 0x0, sizeof(*eldata)); + mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata); + mesh_render_data_face_flag(mr, l->f, data->cd_ofs, eldata); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); +} + +static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) +{ + MeshExtract_EditUVData_Data *data = _data; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + 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); } - if (eed) { - /* Mapped points on an edge between two edit verts. */ - BMLoop *loop = BM_face_edge_share_loop(efa, eed); - mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata); + 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); + } } } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr), @@ -2982,18 +3452,12 @@ static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr), } static const MeshExtract extract_edituv_data = { - extract_edituv_data_init, - NULL, - NULL, - extract_edituv_data_loop_bmesh, - extract_edituv_data_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_edituv_data_finish, - 0, - true, + .init = extract_edituv_data_init, + .iter_poly_bm = extract_edituv_data_iter_poly_bm, + .iter_poly_mesh = extract_edituv_data_iter_poly_mesh, + .finish = extract_edituv_data_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -3053,13 +3517,13 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void * } else if (mr->extract_type == MR_EXTRACT_MAPPED) { const MLoopUV *uv_data = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV); - const MPoly *mpoly = mr->mpoly; - for (int p = 0; p < mr->poly_len; p++, mpoly++) { - float area = BKE_mesh_calc_poly_area(mpoly, &mr->mloop[mpoly->loopstart], mr->mvert); - float uvarea = BKE_mesh_calc_poly_uv_area(mpoly, uv_data); + 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); tot_area += area; tot_uv_area += uvarea; - area_ratio[p] = area_ratio_get(area, uvarea); + area_ratio[mp_index] = area_ratio_get(area, uvarea); } } else { @@ -3072,8 +3536,8 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void * /* Convert in place to avoid an extra allocation */ uint16_t *poly_stretch = (uint16_t *)area_ratio; - for (int p = 0; p < mr->poly_len; p++) { - poly_stretch[p] = area_ratio[p] * SHRT_MAX; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) { + poly_stretch[mp_index] = area_ratio[mp_index] * SHRT_MAX; } /* Copy face data for each loop. */ @@ -3083,18 +3547,18 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void * if (mr->extract_type == MR_EXTRACT_BMESH) { BMFace *efa; BMIter f_iter; - int f, l = 0; + int f, l_index = 0; BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) { - for (int i = 0; i < efa->len; i++, l++) { - loop_stretch[l] = poly_stretch[f]; + for (int i = 0; i < efa->len; i++, l_index++) { + loop_stretch[l_index] = poly_stretch[f]; } } } else if (mr->extract_type == MR_EXTRACT_MAPPED) { - const MPoly *mpoly = mr->mpoly; - for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) { - for (int i = 0; i < mpoly->totloop; i++, l++) { - loop_stretch[l] = poly_stretch[p]; + 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]; } } } @@ -3107,18 +3571,10 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void * } static const MeshExtract extract_stretch_area = { - extract_stretch_area_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - mesh_stretch_area_finish, - 0, - false, + .init = extract_stretch_area_init, + .finish = mesh_stretch_area_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -3165,7 +3621,7 @@ static short v2_to_short_angle(float v[2]) static void edituv_get_stretch_angle(float auv[2][2], float av[2][3], UVStretchAngle *r_stretch) { - /* Send uvs to the shader and let it compute the aspect corrected angle. */ + /* Send UV's to the shader and let it compute the aspect corrected angle. */ r_stretch->uv_angles[0] = v2_to_short_angle(auv[0]); r_stretch->uv_angles[1] = v2_to_short_angle(auv[1]); /* Compute 3D angle here. */ @@ -3183,7 +3639,7 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - /* WARNING Adjust UVStretchAngle struct accordingly. */ + /* Waning: adjust #UVStretchAngle struct accordingly. */ GPU_vertformat_attr_add(&format, "angle", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT); } @@ -3195,7 +3651,7 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf) MeshExtract_StretchAngle_Data *data = MEM_callocN(sizeof(*data), __func__); data->vbo_data = (UVStretchAngle *)vbo->data; - /* Special iter nneded to save about half of the computing cost. */ + /* Special iterator needed to save about half of the computing cost. */ if (mr->extract_type == MR_EXTRACT_BMESH) { data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV); } @@ -3208,94 +3664,95 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_stretch_angle_loop_bmesh(const MeshRenderData *mr, - int l, - BMLoop *loop, - void *_data) +static void extract_stretch_angle_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_StretchAngle_Data *data = (MeshExtract_StretchAngle_Data *)_data; + MeshExtract_StretchAngle_Data *data = _data; float(*auv)[2] = data->auv, *last_auv = data->last_auv; float(*av)[3] = data->av, *last_av = data->last_av; - const MLoopUV *luv, *luv_next; - BMLoop *l_next = loop->next; - BMFace *efa = loop->f; - if (loop == efa->l_first) { - /* First loop in face. */ - BMLoop *l_tmp = loop->prev; - BMLoop *l_next_tmp = loop; - luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs); - luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs); - compute_normalize_edge_vectors(auv, - av, - luv->uv, - luv_next->uv, - 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]); - } - if (l_next == efa->l_first) { - /* Move previous edge. */ - copy_v2_v2(auv[0], auv[1]); - copy_v3_v3(av[0], av[1]); - /* Copy already calculated last edge. */ - copy_v2_v2(auv[1], last_auv); - copy_v3_v3(av[1], last_av); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + const MLoopUV *luv, *luv_next; + BMLoop *l_next = l->next; + BMFace *efa = l->f; + if (l == BM_FACE_FIRST_LOOP(efa)) { + /* First loop in face. */ + BMLoop *l_tmp = l->prev; + BMLoop *l_next_tmp = l; + 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]); + } + if (l_next == BM_FACE_FIRST_LOOP(efa)) { + /* Move previous edge. */ + copy_v2_v2(auv[0], auv[1]); + copy_v3_v3(av[0], av[1]); + /* Copy already calculated last edge. */ + copy_v2_v2(auv[1], last_auv); + copy_v3_v3(av[1], last_av); + } + else { + luv = BM_ELEM_CD_GET_VOID_P(l, data->cd_ofs); + luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs); + compute_normalize_edge_vectors( + auv, av, luv->uv, luv_next->uv, bm_vert_co_get(mr, l->v), bm_vert_co_get(mr, l_next->v)); + } + edituv_get_stretch_angle(auv, av, &data->vbo_data[l_index]); } - else { - luv = BM_ELEM_CD_GET_VOID_P(loop, data->cd_ofs); - luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs); - compute_normalize_edge_vectors(auv, - av, - luv->uv, - luv_next->uv, - bm_vert_co_get(mr, loop->v), - bm_vert_co_get(mr, l_next->v)); - } - edituv_get_stretch_angle(auv, av, data->vbo_data + l); -} - -static void extract_stretch_angle_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *UNUSED(mloop), - int UNUSED(p), - const MPoly *mpoly, - void *_data) + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); +} + +static void extract_stretch_angle_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - MeshExtract_StretchAngle_Data *data = (MeshExtract_StretchAngle_Data *)_data; - float(*auv)[2] = data->auv, *last_auv = data->last_auv; - float(*av)[3] = data->av, *last_av = data->last_av; - int l_next = l + 1, loopend = mpoly->loopstart + mpoly->totloop; - const MVert *v, *v_next; - if (l == mpoly->loopstart) { - /* First loop in face. */ - int l_tmp = loopend - 1; - int l_next_tmp = mpoly->loopstart; - v = &mr->mvert[mr->mloop[l_tmp].v]; - v_next = &mr->mvert[mr->mloop[l_next_tmp].v]; - compute_normalize_edge_vectors( - auv, av, data->luv[l_tmp].uv, data->luv[l_next_tmp].uv, v->co, v_next->co); - /* Save last edge. */ - copy_v2_v2(last_auv, auv[1]); - copy_v3_v3(last_av, av[1]); - } - if (l_next == loopend) { - l_next = mpoly->loopstart; - /* Move previous edge. */ - copy_v2_v2(auv[0], auv[1]); - copy_v3_v3(av[0], av[1]); - /* Copy already calculated last edge. */ - copy_v2_v2(auv[1], last_auv); - copy_v3_v3(av[1], last_av); - } - else { - v = &mr->mvert[mr->mloop[l].v]; - v_next = &mr->mvert[mr->mloop[l_next].v]; - compute_normalize_edge_vectors( - auv, av, data->luv[l].uv, data->luv[l_next].uv, v->co, v_next->co); + MeshExtract_StretchAngle_Data *data = _data; + + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + float(*auv)[2] = data->auv, *last_auv = data->last_auv; + float(*av)[3] = data->av, *last_av = data->last_av; + int l_next = ml_index + 1, ml_index_end = mp->loopstart + mp->totloop; + 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); + } + edituv_get_stretch_angle(auv, av, &data->vbo_data[ml_index]); } - edituv_get_stretch_angle(auv, av, data->vbo_data + l); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_stretch_angle_finish(const MeshRenderData *UNUSED(mr), @@ -3306,18 +3763,12 @@ static void extract_stretch_angle_finish(const MeshRenderData *UNUSED(mr), } static const MeshExtract extract_stretch_angle = { - extract_stretch_angle_init, - NULL, - NULL, - extract_stretch_angle_loop_bmesh, - extract_stretch_angle_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_stretch_angle_finish, - 0, - false, + .init = extract_stretch_angle_init, + .iter_poly_bm = extract_stretch_angle_iter_poly_bm, + .iter_poly_mesh = extract_stretch_angle_iter_poly_mesh, + .finish = extract_stretch_angle_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -3389,28 +3840,30 @@ static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang) normalize_v3(dir); if (mr->extract_type == MR_EXTRACT_BMESH) { - int l = 0; + int l_index = 0; BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { float fac = angle_normalized_v3v3(bm_face_no_get(mr, f), dir) / (float)M_PI; fac = overhang_remap(fac, min, max, minmax_irange); - for (int i = 0; i < f->len; i++, l++) { - r_overhang[l] = fac; + for (int i = 0; i < f->len; i++, l_index++) { + r_overhang[l_index] = fac; } } } else { - const MPoly *mpoly = mr->mpoly; - for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) { - float fac = angle_normalized_v3v3(mr->poly_normals[p], dir) / (float)M_PI; + 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; fac = overhang_remap(fac, min, max, minmax_irange); - for (int i = 0; i < mpoly->totloop; i++, l++) { - r_overhang[l] = fac; + for (int i = 0; i < mp->totloop; i++, l_index++) { + r_overhang[l_index] = fac; } } } } -/* so we can use jitter values for face interpolation */ +/** + * Needed so we can use jitter values for face interpolation. + */ static void uv_from_jitter_v2(float uv[2]) { uv[0] += 0.5f; @@ -3502,12 +3955,12 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness) BMIter iter; BMFace *f; - int l = 0; + int l_index = 0; BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { float fac = face_dists[BM_elem_index_get(f)]; fac = thickness_remap(fac, min, max, minmax_irange); - for (int i = 0; i < f->len; i++, l++) { - r_thickness[l] = fac; + for (int i = 0; i < f->len; i++, l_index++) { + r_thickness[l_index] = fac; } } } @@ -3548,12 +4001,12 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness) } } - const MPoly *mpoly = mr->mpoly; - for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) { - float fac = face_dists[p]; + 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]; fac = thickness_remap(fac, min, max, minmax_irange); - for (int i = 0; i < mpoly->totloop; i++, l++) { - r_thickness[l] = fac; + for (int i = 0; i < mp->totloop; i++, l_index++) { + r_thickness[l_index] = fac; } } } @@ -3604,8 +4057,8 @@ static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect) { BMEditMesh *em = mr->edit_bmesh; - for (int l = 0; l < mr->loop_len; l++) { - r_intersect[l] = -1.0f; + for (int l_index = 0; l_index < mr->loop_len; l_index++) { + r_intersect[l_index] = -1.0f; } if (mr->extract_type == MR_EXTRACT_BMESH) { @@ -3626,9 +4079,9 @@ static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect) for (int j = 0; j < 2; j++) { BMFace *f_hit = f_hit_pair[j]; BMLoop *l_first = BM_FACE_FIRST_LOOP(f_hit); - int l = BM_elem_index_get(l_first); - for (int k = 0; k < f_hit->len; k++, l++) { - r_intersect[l] = 1.0f; + 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; } } } @@ -3655,9 +4108,9 @@ static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect) }; for (int j = 0; j < 2; j++) { const MPoly *f_hit = f_hit_pair[j]; - int l = f_hit->loopstart; - for (int k = 0; k < f_hit->totloop; k++, l++) { - r_intersect[l] = 1.0f; + int l_index = f_hit->loopstart; + for (int k = 0; k < f_hit->totloop; k++, l_index++) { + r_intersect[l_index] = 1.0f; } } } @@ -3700,9 +4153,9 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) BM_mesh_elem_index_ensure(em->bm, BM_VERT); } - int l = 0; - int p = 0; - BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, p) { + int l_index = 0; + int f_index = 0; + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, f_index) { float fac = -1.0f; if (f->len > 3) { @@ -3714,7 +4167,7 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) const float *no_face; float no_corner[3]; if (mr->bm_vert_coords != NULL) { - no_face = mr->bm_poly_normals[p]; + no_face = mr->bm_poly_normals[f_index]; BM_loop_calc_face_normal_safe_vcos(l_iter, no_face, mr->bm_vert_coords, no_corner); } else { @@ -3733,24 +4186,24 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) } fac = distort_remap(fac, min, max, minmax_irange); - for (int i = 0; i < f->len; i++, l++) { - r_distort[l] = fac; + for (int i = 0; i < f->len; i++, l_index++) { + r_distort[l_index] = fac; } } } else { - const MPoly *mpoly = mr->mpoly; - for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) { + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { float fac = -1.0f; - if (mpoly->totloop > 3) { - float *f_no = mr->poly_normals[p]; + if (mp->totloop > 3) { + float *f_no = mr->poly_normals[mp_index]; fac = 0.0f; - for (int i = 1; i <= mpoly->totloop; i++) { - const MLoop *l_prev = &mr->mloop[mpoly->loopstart + (i - 1) % mpoly->totloop]; - const MLoop *l_curr = &mr->mloop[mpoly->loopstart + (i + 0) % mpoly->totloop]; - const MLoop *l_next = &mr->mloop[mpoly->loopstart + (i + 1) % mpoly->totloop]; + 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]; float no_corner[3]; normal_tri_v3(no_corner, mr->mvert[l_prev->v].co, @@ -3766,8 +4219,8 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) } fac = distort_remap(fac, min, max, minmax_irange); - for (int i = 0; i < mpoly->totloop; i++, l++) { - r_distort[l] = fac; + for (int i = 0; i < mp->totloop; i++, l_index++) { + r_distort[l_index] = fac; } } } @@ -3800,11 +4253,10 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) copy_vn_fl(vert_angles, mr->vert_len, -M_PI); if (mr->extract_type == MR_EXTRACT_BMESH) { - BMIter iter, l_iter; + BMIter iter; BMesh *bm = em->bm; BMFace *efa; BMEdge *e; - BMLoop *loop; /* first assign float values to verts */ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { float angle = BM_edge_calc_face_angle_signed(e); @@ -3815,35 +4267,37 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) } /* Copy vert value to loops. */ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { - int l = BM_elem_index_get(loop); - int v = BM_elem_index_get(loop->v); - r_sharp[l] = sharp_remap(vert_angles[v], min, max, minmax_irange); - } + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + 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); + } while ((l_iter = l_iter->next) != l_first); } } else { /* first assign float values to verts */ - const MPoly *mpoly = mr->mpoly; + const MPoly *mp = mr->mpoly; EdgeHash *eh = BLI_edgehash_new_ex(__func__, mr->edge_len); - for (int p = 0; p < mr->poly_len; p++, mpoly++) { - for (int i = 0; i < mpoly->totloop; i++) { - const MLoop *l_curr = &mr->mloop[mpoly->loopstart + (i + 0) % mpoly->totloop]; - const MLoop *l_next = &mr->mloop[mpoly->loopstart + (i + 1) % mpoly->totloop]; + 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]; const MVert *v_curr = &mr->mvert[l_curr->v]; const MVert *v_next = &mr->mvert[l_next->v]; float angle; void **pval; bool value_is_init = BLI_edgehash_ensure_p(eh, l_curr->v, l_next->v, &pval); if (!value_is_init) { - *pval = mr->poly_normals[p]; + *pval = mr->poly_normals[mp_index]; /* non-manifold edge, yet... */ continue; } else if (*pval != NULL) { - const float *f1_no = mr->poly_normals[p]; + const float *f1_no = mr->poly_normals[mp_index]; 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; @@ -3876,9 +4330,9 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) BLI_edgehashIterator_free(ehi); BLI_edgehash_free(eh, NULL); - const MLoop *mloop = mr->mloop; - for (int l = 0; l < mr->loop_len; l++, mloop++) { - r_sharp[l] = sharp_remap(vert_angles[mloop->v], min, max, minmax_irange); + 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); } } @@ -3912,20 +4366,12 @@ static void extract_mesh_analysis_finish(const MeshRenderData *mr, void *buf, vo } static const MeshExtract extract_mesh_analysis = { - extract_mesh_analysis_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_mesh_analysis_finish, - /* This is not needed for all vis type. - * Maybe split into different extract. */ - MR_DATA_POLY_NOR | MR_DATA_LOOPTRI, - false, + .init = extract_mesh_analysis_init, + .finish = extract_mesh_analysis_finish, + /* This is not needed for all visualization types. + * * Maybe split into different extract. */ + .data_flag = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI, + .use_threading = false, }; /** \} */ @@ -3943,56 +4389,71 @@ static void *extract_fdots_pos_init(const MeshRenderData *mr, void *buf) GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->poly_len); - if (!mr->use_subsurf_fdots) { - /* Clear so we can accumulate on it. */ - memset(vbo->data, 0x0, mr->poly_len * vbo->format.stride); - } return vbo->data; } -static void extract_fdots_pos_loop_bmesh(const MeshRenderData *mr, - int UNUSED(l), - BMLoop *loop, - void *data) +static void extract_fdots_pos_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - float(*center)[3] = (float(*)[3])data; - float w = 1.0f / (float)loop->f->len; - madd_v3_v3fl(center[BM_elem_index_get(loop->f)], bm_vert_co_get(mr, loop->v), w); + float(*center)[3] = data; + + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + float *co = center[f_index]; + zero_v3(co); + + 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); + } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_fdots_pos_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *mloop, - int p, - const MPoly *mpoly, - void *data) +static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { float(*center)[3] = (float(*)[3])data; - const MVert *mvert = &mr->mvert[mloop->v]; + const MVert *mvert = mr->mvert; + const MLoop *mloop = mr->mloop; + if (mr->use_subsurf_fdots) { - if (mvert->flag & ME_VERT_FACEDOT) { - copy_v3_v3(center[p], mvert->co); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MVert *mv = &mr->mvert[ml->v]; + if (mv->flag & ME_VERT_FACEDOT) { + copy_v3_v3(center[mp_index], mv->co); + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } else { - float w = 1.0f / (float)mpoly->totloop; - madd_v3_v3fl(center[p], mvert->co, w); + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + float *co = center[mp_index]; + zero_v3(co); + + const MLoop *ml = &mloop[mp->loopstart]; + for (int i = 0; i < mp->totloop; i++, ml++) { + const MVert *mv = &mvert[ml->v]; + add_v3_v3(center[mp_index], mv->co); + } + mul_v3_fl(co, 1.0f / (float)mp->totloop); + } + EXTRACT_POLY_FOREACH_MESH_END; } } static const MeshExtract extract_fdots_pos = { - extract_fdots_pos_init, - NULL, - NULL, - extract_fdots_pos_loop_bmesh, - extract_fdots_pos_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - true, + .init = extract_fdots_pos_init, + .iter_poly_bm = extract_fdots_pos_iter_poly_bm, + .iter_poly_mesh = extract_fdots_pos_iter_poly_mesh, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -4065,18 +4526,10 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void * } static const MeshExtract extract_fdots_nor = { - extract_fdots_nor_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_fdots_nor_finish, - MR_DATA_POLY_NOR, - false, + .init = extract_fdots_nor_init, + .finish = extract_fdots_nor_finish, + .data_flag = MR_DATA_POLY_NOR, + .use_threading = false, }; /** \} */ @@ -4120,30 +4573,42 @@ static void *extract_fdots_uv_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_fdots_uv_loop_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(l), - BMLoop *loop, - void *_data) +static void extract_fdots_uv_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_FdotUV_Data *data = (MeshExtract_FdotUV_Data *)_data; - float w = 1.0f / (float)loop->f->len; - const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, data->cd_ofs); - madd_v2_v2fl(data->vbo_data[BM_elem_index_get(loop->f)], luv->uv, w); + MeshExtract_FdotUV_Data *data = _data; + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + float w = 1.0f / (float)l->f->len; + const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, data->cd_ofs); + madd_v2_v2fl(data->vbo_data[BM_elem_index_get(l->f)], luv->uv, w); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_fdots_uv_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data) +static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - MeshExtract_FdotUV_Data *data = (MeshExtract_FdotUV_Data *)_data; + MeshExtract_FdotUV_Data *data = _data; if (mr->use_subsurf_fdots) { - const MVert *mvert = &mr->mvert[mloop->v]; - if (mvert->flag & ME_VERT_FACEDOT) { - copy_v2_v2(data->vbo_data[p], data->uv_data[l].uv); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + 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); + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } else { - float w = 1.0f / (float)mpoly->totloop; - madd_v2_v2fl(data->vbo_data[p], data->uv_data[l].uv, w); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + float w = 1.0f / (float)mp->totloop; + madd_v2_v2fl(data->vbo_data[mp_index], data->uv_data[ml_index].uv, w); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } } @@ -4155,18 +4620,12 @@ static void extract_fdots_uv_finish(const MeshRenderData *UNUSED(mr), } static const MeshExtract extract_fdots_uv = { - extract_fdots_uv_init, - NULL, - NULL, - extract_fdots_uv_loop_bmesh, - extract_fdots_uv_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_fdots_uv_finish, - 0, - true, + .init = extract_fdots_uv_init, + .iter_poly_bm = extract_fdots_uv_iter_poly_bm, + .iter_poly_mesh = extract_fdots_uv_iter_poly_mesh, + .finish = extract_fdots_uv_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -4195,31 +4654,35 @@ static void *extract_fdots_edituv_data_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_fdots_edituv_data_loop_bmesh(const MeshRenderData *mr, - int UNUSED(l), - BMLoop *loop, - void *_data) +static void extract_fdots_edituv_data_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_EditUVFdotData_Data *data = (MeshExtract_EditUVFdotData_Data *)_data; - EditLoopData *eldata = data->vbo_data + BM_elem_index_get(loop->f); - memset(eldata, 0x0, sizeof(*eldata)); - mesh_render_data_face_flag(mr, loop->f, data->cd_ofs, eldata); + MeshExtract_EditUVFdotData_Data *data = _data; + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + 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); + } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_fdots_edituv_data_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *UNUSED(mloop), - int p, - const MPoly *UNUSED(mpoly), - void *_data) +static void extract_fdots_edituv_data_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - MeshExtract_EditUVFdotData_Data *data = (MeshExtract_EditUVFdotData_Data *)_data; - EditLoopData *eldata = data->vbo_data + p; - memset(eldata, 0x0, sizeof(*eldata)); - BMFace *efa = bm_original_face_get(mr, p); - if (efa) { - mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata); + MeshExtract_EditUVFdotData_Data *data = _data; + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + 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); + } } + EXTRACT_POLY_FOREACH_MESH_END; } static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr), @@ -4230,18 +4693,12 @@ static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr), } static const MeshExtract extract_fdots_edituv_data = { - extract_fdots_edituv_data_init, - NULL, - NULL, - extract_fdots_edituv_data_loop_bmesh, - extract_fdots_edituv_data_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_fdots_edituv_data_finish, - 0, - true, + .init = extract_fdots_edituv_data_init, + .iter_poly_bm = extract_fdots_edituv_data_iter_poly_bm, + .iter_poly_mesh = extract_fdots_edituv_data_iter_poly_mesh, + .finish = extract_fdots_edituv_data_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -4292,18 +4749,9 @@ static void *extract_skin_roots_init(const MeshRenderData *mr, void *buf) } static const MeshExtract extract_skin_roots = { - extract_skin_roots_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - false, + .init = extract_skin_roots_init, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -4325,157 +4773,183 @@ static void *extract_select_idx_init(const MeshRenderData *mr, void *buf) return vbo->data; } -/* TODO Use glVertexID to get loop index and use the data structure on the CPU to retrieve the +/* TODO Use #glVertexID to get loop index and use the data structure on the CPU to retrieve the * select element associated with this loop ID. This would remove the need for this separate - * index VBOs. We could upload the p/e/v_origindex as a buffer texture and sample it inside the + * index VBO's. We could upload the p/e/v_origindex as a buffer texture and sample it inside the * shader to output original index. */ -static void extract_poly_idx_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_poly_idx_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = BM_elem_index_get(loop->f); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + ((uint32_t *)data)[l_index] = BM_elem_index_get(l->f); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edge_idx_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_edge_idx_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = BM_elem_index_get(loop->e); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + ((uint32_t *)data)[l_index] = BM_elem_index_get(l->e); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_vert_idx_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_vert_idx_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = BM_elem_index_get(loop->v); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + ((uint32_t *)data)[l_index] = BM_elem_index_get(l->v); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edge_idx_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *data) +static void extract_edge_idx_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *data) { - ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = BM_elem_index_get(eed); - ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = BM_elem_index_get(eed); + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + ((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); + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_vert_idx_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *data) +static void extract_vert_idx_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *data) { - ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = BM_elem_index_get(eed->v1); - ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = BM_elem_index_get(eed->v2); + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + ((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); + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_vert_idx_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *data) +static void extract_vert_idx_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *data) { - ((uint32_t *)data)[mr->loop_len + mr->edge_loose_len * 2 + v] = BM_elem_index_get(eve); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + ((uint32_t *)data)[offset + lvert_index] = BM_elem_index_get(eve); + } + EXTRACT_LVERT_FOREACH_BM_END; } -static void extract_poly_idx_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *UNUSED(mloop), - int p, - const MPoly *UNUSED(mpoly), - void *data) +static void extract_poly_idx_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = (mr->p_origindex) ? mr->p_origindex[p] : p; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + ((uint32_t *)data)[ml_index] = (mr->p_origindex) ? mr->p_origindex[mp_index] : mp_index; + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_edge_idx_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *data) +static void extract_edge_idx_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = (mr->e_origindex) ? mr->e_origindex[mloop->e] : mloop->e; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + ((uint32_t *)data)[ml_index] = (mr->e_origindex) ? mr->e_origindex[ml->e] : ml->e; + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_vert_idx_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *data) +static void extract_vert_idx_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = (mr->v_origindex) ? mr->v_origindex[mloop->v] : mloop->v; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + ((uint32_t *)data)[ml_index] = (mr->v_origindex) ? mr->v_origindex[ml->v] : ml->v; + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_edge_idx_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *UNUSED(medge), - void *data) +static void extract_edge_idx_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *data) { - int e_idx = mr->ledges[e]; - int e_orig = (mr->e_origindex) ? mr->e_origindex[e_idx] : e_idx; - ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = e_orig; - ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = e_orig; + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + 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; + } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_vert_idx_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *medge, - void *data) +static void extract_vert_idx_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *data) { - int v1_orig = (mr->v_origindex) ? mr->v_origindex[medge->v1] : medge->v1; - int v2_orig = (mr->v_origindex) ? mr->v_origindex[medge->v2] : medge->v2; - ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = v1_orig; - ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = v2_orig; + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + 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; + } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_vert_idx_lvert_mesh(const MeshRenderData *mr, - int v, - const MVert *UNUSED(mvert), - void *data) +static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *data) { - int v_idx = mr->lverts[v]; - int v_orig = (mr->v_origindex) ? mr->v_origindex[v_idx] : v_idx; - ((uint32_t *)data)[mr->loop_len + mr->edge_loose_len * 2 + v] = v_orig; + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_MESH_BEGIN(med, lvert_index, params, mr) + { + 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; + } + EXTRACT_LVERT_FOREACH_MESH_END; } static const MeshExtract extract_poly_idx = { - extract_select_idx_init, - NULL, - NULL, - extract_poly_idx_loop_bmesh, - extract_poly_idx_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - true, + .init = extract_select_idx_init, + .iter_poly_bm = extract_poly_idx_iter_poly_bm, + .iter_poly_mesh = extract_poly_idx_iter_poly_mesh, + .data_flag = 0, + .use_threading = true, }; static const MeshExtract extract_edge_idx = { - extract_select_idx_init, - NULL, - NULL, - extract_edge_idx_loop_bmesh, - extract_edge_idx_loop_mesh, - extract_edge_idx_ledge_bmesh, - extract_edge_idx_ledge_mesh, - NULL, - NULL, - NULL, - 0, - true, + .init = extract_select_idx_init, + .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, + .data_flag = 0, + .use_threading = true, }; static const MeshExtract extract_vert_idx = { - extract_select_idx_init, - NULL, - NULL, - extract_vert_idx_loop_bmesh, - extract_vert_idx_loop_mesh, - extract_vert_idx_ledge_bmesh, - extract_vert_idx_ledge_mesh, - extract_vert_idx_lvert_bmesh, - extract_vert_idx_lvert_mesh, - NULL, - 0, - true, + .init = extract_select_idx_init, + .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, + .data_flag = 0, + .use_threading = true, }; static void *extract_select_fdot_idx_init(const MeshRenderData *mr, void *buf) @@ -4491,37 +4965,43 @@ static void *extract_select_fdot_idx_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_fdot_idx_loop_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(l), - BMLoop *loop, - void *data) +static void extract_fdot_idx_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - ((uint32_t *)data)[BM_elem_index_get(loop->f)] = BM_elem_index_get(loop->f); + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + ((uint32_t *)data)[f_index] = f_index; + } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_fdot_idx_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *UNUSED(mloop), - int p, - const MPoly *UNUSED(mpoly), - void *data) +static void extract_fdot_idx_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - ((uint32_t *)data)[p] = (mr->p_origindex) ? mr->p_origindex[p] : p; + if (mr->p_origindex != NULL) { + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + ((uint32_t *)data)[mp_index] = mr->p_origindex[mp_index]; + } + EXTRACT_POLY_FOREACH_MESH_END; + } + else { + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + ((uint32_t *)data)[mp_index] = mp_index; + } + EXTRACT_POLY_FOREACH_MESH_END; + } } static const MeshExtract extract_fdot_idx = { - extract_select_fdot_idx_init, - NULL, - NULL, - extract_fdot_idx_loop_bmesh, - extract_fdot_idx_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - true, + .init = extract_select_fdot_idx_init, + .iter_poly_bm = extract_fdot_idx_iter_poly_bm, + .iter_poly_mesh = extract_fdot_idx_iter_poly_mesh, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -4533,10 +5013,16 @@ typedef struct ExtractUserData { void *user_data; } ExtractUserData; +typedef enum ExtractTaskDataType { + EXTRACT_MESH_EXTRACT, + EXTRACT_LINES_LOOSE, +} ExtractTaskDataType; + typedef struct ExtractTaskData { void *next, *prev; const MeshRenderData *mr; const MeshExtract *extract; + ExtractTaskDataType tasktype; eMRIterType iter_type; int start, end; /** Decremented each time a task is finished. */ @@ -4545,6 +5031,41 @@ typedef struct ExtractTaskData { ExtractUserData *user_data; } ExtractTaskData; +static ExtractTaskData *extract_task_data_create_mesh_extract(const MeshRenderData *mr, + const MeshExtract *extract, + void *buf, + int32_t *task_counter) +{ + ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), __func__); + taskdata->next = NULL; + taskdata->prev = NULL; + taskdata->tasktype = EXTRACT_MESH_EXTRACT; + taskdata->mr = mr; + taskdata->extract = extract; + taskdata->buf = buf; + + /* #ExtractUserData is shared between the iterations as it holds counters to detect if the + * 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. + * + * This structure makes sure that when extract_init is called, that the user data of all + * iterations are updated. */ + taskdata->user_data = MEM_callocN(sizeof(ExtractUserData), __func__); + taskdata->iter_type = mesh_extract_iter_type(extract); + taskdata->task_counter = task_counter; + taskdata->start = 0; + taskdata->end = INT_MAX; + return taskdata; +} + +static ExtractTaskData *extract_task_data_create_lines_loose(const MeshRenderData *mr) +{ + ExtractTaskData *taskdata = MEM_callocN(sizeof(*taskdata), __func__); + taskdata->tasktype = EXTRACT_LINES_LOOSE; + taskdata->mr = mr; + return taskdata; +} + static void extract_task_data_free(void *data) { ExtractTaskData *task_data = data; @@ -4562,67 +5083,69 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, switch (mr->extract_type) { case MR_EXTRACT_BMESH: if (iter_type & MR_ITER_LOOPTRI) { - int t_end = min_ii(mr->tri_len, end); - for (int t = start; t < t_end; t++) { - BMLoop **elt = &mr->edit_bmesh->looptris[t][0]; - extract->iter_looptri_bm(mr, t, elt, user_data); - } + extract->iter_looptri_bm(mr, + &(const ExtractTriBMesh_Params){ + .looptris = mr->edit_bmesh->looptris, + .tri_range = {start, min_ii(mr->tri_len, end)}, + }, + user_data); } - if (iter_type & MR_ITER_LOOP) { - int l_end = min_ii(mr->poly_len, end); - for (int f = start; f < l_end; f++) { - BMFace *efa = BM_face_at_index(mr->bm, f); - BMLoop *loop; - BMIter l_iter; - BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { - extract->iter_loop_bm(mr, BM_elem_index_get(loop), loop, user_data); - } - } + if (iter_type & MR_ITER_POLY) { + extract->iter_poly_bm(mr, + &(const ExtractPolyBMesh_Params){ + .poly_range = {start, min_ii(mr->poly_len, end)}, + }, + user_data); } if (iter_type & MR_ITER_LEDGE) { - int le_end = min_ii(mr->edge_loose_len, end); - for (int e = start; e < le_end; e++) { - BMEdge *eed = BM_edge_at_index(mr->bm, mr->ledges[e]); - extract->iter_ledge_bm(mr, e, eed, user_data); - } + extract->iter_ledge_bm(mr, + &(const ExtractLEdgeBMesh_Params){ + .ledge = mr->ledges, + .ledge_range = {start, min_ii(mr->edge_loose_len, end)}, + }, + user_data); } if (iter_type & MR_ITER_LVERT) { - int lv_end = min_ii(mr->vert_loose_len, end); - for (int v = start; v < lv_end; v++) { - BMVert *eve = BM_vert_at_index(mr->bm, mr->lverts[v]); - extract->iter_lvert_bm(mr, v, eve, user_data); - } + extract->iter_lvert_bm(mr, + &(const ExtractLVertBMesh_Params){ + .lvert = mr->lverts, + .lvert_range = {start, min_ii(mr->vert_loose_len, end)}, + }, + user_data); } break; case MR_EXTRACT_MAPPED: case MR_EXTRACT_MESH: if (iter_type & MR_ITER_LOOPTRI) { - int t_end = min_ii(mr->tri_len, end); - for (int t = start; t < t_end; t++) { - extract->iter_looptri(mr, t, &mr->mlooptri[t], user_data); - } + extract->iter_looptri_mesh(mr, + &(const ExtractTriMesh_Params){ + .mlooptri = mr->mlooptri, + .tri_range = {start, min_ii(mr->tri_len, end)}, + }, + user_data); } - if (iter_type & MR_ITER_LOOP) { - int l_end = min_ii(mr->poly_len, end); - for (int p = start; p < l_end; p++) { - const MPoly *mpoly = &mr->mpoly[p]; - int l = mpoly->loopstart; - for (int i = 0; i < mpoly->totloop; i++, l++) { - extract->iter_loop(mr, l, &mr->mloop[l], p, mpoly, user_data); - } - } + if (iter_type & MR_ITER_POLY) { + extract->iter_poly_mesh(mr, + &(const ExtractPolyMesh_Params){ + .poly_range = {start, min_ii(mr->poly_len, end)}, + }, + user_data); } if (iter_type & MR_ITER_LEDGE) { - int le_end = min_ii(mr->edge_loose_len, end); - for (int e = start; e < le_end; e++) { - extract->iter_ledge(mr, e, &mr->medge[mr->ledges[e]], user_data); - } + extract->iter_ledge_mesh(mr, + &(const ExtractLEdgeMesh_Params){ + .ledge = mr->ledges, + .ledge_range = {start, min_ii(mr->edge_loose_len, end)}, + }, + user_data); } if (iter_type & MR_ITER_LVERT) { - int lv_end = min_ii(mr->vert_loose_len, end); - for (int v = start; v < lv_end; v++) { - extract->iter_lvert(mr, v, &mr->mvert[mr->lverts[v]], user_data); - } + extract->iter_lvert_mesh(mr, + &(const ExtractLVertMesh_Params){ + .lvert = mr->lverts, + .lvert_range = {start, min_ii(mr->vert_loose_len, end)}, + }, + user_data); } break; } @@ -4630,23 +5153,30 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, static void extract_init(ExtractTaskData *data) { - data->user_data->user_data = data->extract->init(data->mr, data->buf); + if (data->tasktype == EXTRACT_MESH_EXTRACT) { + data->user_data->user_data = data->extract->init(data->mr, data->buf); + } } static void extract_run(void *__restrict taskdata) { ExtractTaskData *data = (ExtractTaskData *)taskdata; - mesh_extract_iter(data->mr, - data->iter_type, - data->start, - data->end, - data->extract, - data->user_data->user_data); - - /* If this is the last task, we do the finish function. */ - int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1); - if (remainin_tasks == 0 && data->extract->finish != NULL) { - data->extract->finish(data->mr, data->buf, data->user_data->user_data); + if (data->tasktype == EXTRACT_MESH_EXTRACT) { + mesh_extract_iter(data->mr, + data->iter_type, + data->start, + data->end, + data->extract, + data->user_data->user_data); + + /* If this is the last task, we do the finish function. */ + int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1); + if (remainin_tasks == 0 && data->extract->finish != NULL) { + data->extract->finish(data->mr, data->buf, data->user_data->user_data); + } + } + else if (data->tasktype == EXTRACT_LINES_LOOSE) { + extract_lines_loose_subbuffer(data->mr); } } @@ -4670,15 +5200,20 @@ typedef struct MeshRenderDataUpdateTaskData { static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata) { BLI_assert(taskdata); - mesh_render_data_free(taskdata->mr); + MeshRenderData *mr = taskdata->mr; + mesh_render_data_free(mr); MEM_freeN(taskdata); } static void mesh_extract_render_data_node_exec(void *__restrict task_data) { MeshRenderDataUpdateTaskData *update_task_data = task_data; - mesh_render_data_update( - update_task_data->mr, update_task_data->iter_type, update_task_data->data_flag); + 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); } static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph, @@ -4822,24 +5357,8 @@ static void extract_task_create(struct TaskGraph *task_graph, } /* Divide extraction of the VBO/IBO into sensible chunks of works. */ - ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), "ExtractTaskData"); - taskdata->next = NULL; - taskdata->prev = NULL; - taskdata->mr = mr; - taskdata->extract = extract; - taskdata->buf = buf; - - /* ExtractUserData is shared between the iterations as it holds counters to detect if the - * extraction is finished. To make sure the duplication of the userdata does not create a new - * instance of the counters we allocate the userdata in its own container. - * - * This structure makes sure that when extract_init is called, that the user data of all - * iterations are updated. */ - taskdata->user_data = MEM_callocN(sizeof(ExtractUserData), __func__); - taskdata->iter_type = mesh_extract_iter_type(extract); - taskdata->task_counter = task_counter; - taskdata->start = 0; - taskdata->end = INT_MAX; + ExtractTaskData *taskdata = extract_task_data_create_mesh_extract( + mr, extract, buf, task_counter); /* Simple heuristic. */ const int chunk_size = 8192; @@ -4853,10 +5372,10 @@ static void extract_task_create(struct TaskGraph *task_graph, task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOPTRI, i, chunk_size); } } - if (taskdata->iter_type & MR_ITER_LOOP) { + if (taskdata->iter_type & MR_ITER_POLY) { for (int i = 0; i < mr->poly_len; i += chunk_size) { extract_range_task_create( - task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOP, i, chunk_size); + task_graph, task_node_user_data_init, taskdata, MR_ITER_POLY, i, chunk_size); } } if (taskdata->iter_type & MR_ITER_LEDGE) { @@ -4911,9 +5430,9 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, * `extract_single_threaded_task_node`. * * Other extractions will create a node for each loop exceeding 8192 items. these nodes are - * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the userdata - * 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. + * 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. * * Mesh extraction sub graph * @@ -4980,14 +5499,26 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, TEST_ASSIGN(IBO, ibo, edituv_points); TEST_ASSIGN(IBO, ibo, edituv_fdots); + if (do_lines_loose_subbuffer) { + iter_flag |= MR_ITER_LEDGE; + } + #undef TEST_ASSIGN #ifdef DEBUG_TIME double rdata_start = PIL_check_seconds_timer(); #endif - MeshRenderData *mr = mesh_render_data_create( - me, is_editmode, is_paint_mode, obmat, do_final, do_uvedit, cd_layer_used, ts); + MeshRenderData *mr = mesh_render_data_create(me, + is_editmode, + is_paint_mode, + obmat, + do_final, + do_uvedit, + cd_layer_used, + ts, + iter_flag, + data_flag); mr->cache = cache; /* HACK */ mr->use_hide = use_hide; mr->use_subsurf_fdots = use_subsurf_fdots; @@ -5069,12 +5600,8 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, } else { if (do_lines_loose_subbuffer) { - /* When `lines_loose` is requested without `lines` we can create the sub-buffer on the fly as - * the `lines` buffer should then already be up-to-date. - * (see `DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)` in - * `DRW_mesh_batch_cache_create_requested`). - */ - extract_lines_loose_subbuffer(mr); + ExtractTaskData *taskdata = extract_task_data_create_lines_loose(mr); + BLI_addtail(&single_threaded_task_data->task_datas, taskdata); } } EXTRACT(ibo, points); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 80649143537..96d351794e6 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -144,6 +144,10 @@ int DRW_hair_material_count_get(struct Hair *hair); int DRW_pointcloud_material_count_get(struct PointCloud *pointcloud); struct GPUBatch *DRW_pointcloud_batch_cache_get_dots(struct Object *ob); +struct GPUBatch *DRW_pointcloud_batch_cache_get_surface(struct Object *ob); +struct GPUBatch **DRW_cache_pointcloud_surface_shaded_get(struct Object *ob, + struct GPUMaterial **gpumat_array, + uint gpumat_array_len); /* Volume */ int DRW_volume_material_count_get(struct Volume *volume); @@ -170,6 +174,7 @@ struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(struct Mesh *me, struct GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_weights(struct Mesh *me); /* edit-mesh drawing */ struct GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(struct Mesh *me); @@ -199,20 +204,26 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_uv_edges(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(struct Mesh *me); +/* For direct data access. */ +struct GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(struct Mesh *me); +struct GPUVertBuf *DRW_curve_batch_cache_pos_vertbuf_get(struct Curve *cu); +struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(struct Object *ob); + int DRW_mesh_material_count_get(struct Mesh *me); +/* See 'common_globals_lib.glsl' for duplicate defines. */ + /* Edit mesh bitflags (is this the right place?) */ enum { VFLAG_VERT_ACTIVE = 1 << 0, VFLAG_VERT_SELECTED = 1 << 1, - VFLAG_EDGE_ACTIVE = 1 << 2, - VFLAG_EDGE_SELECTED = 1 << 3, - VFLAG_EDGE_SEAM = 1 << 4, - VFLAG_EDGE_SHARP = 1 << 5, - VFLAG_EDGE_FREESTYLE = 1 << 6, - VFLAG_HANDLE_SELECTED = 1 << 7, - /* Beware to not go over 1 << 7 (it's a byte flag) - * (see gpu_shader_edit_mesh_overlay_geom.glsl) */ + VFLAG_VERT_SELECTED_BEZT_HANDLE = 1 << 2, + VFLAG_EDGE_ACTIVE = 1 << 3, + VFLAG_EDGE_SELECTED = 1 << 4, + VFLAG_EDGE_SEAM = 1 << 5, + VFLAG_EDGE_SHARP = 1 << 6, + VFLAG_EDGE_FREESTYLE = 1 << 7, + /* Beware to not go over 1 << 7 (it's a byte flag). */ }; enum { @@ -224,8 +235,7 @@ enum { VFLAG_EDGE_UV_SELECT = 1 << 5, VFLAG_FACE_UV_ACTIVE = 1 << 6, VFLAG_FACE_UV_SELECT = 1 << 7, - /* Beware to not go over 1 << 7 (it's a byte flag) - * (see gpu_shader_edit_mesh_overlay_geom.glsl) */ + /* Beware to not go over 1 << 7 (it's a byte flag). */ }; /* Particles */ diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c index c6112994b65..73e0ff7ef83 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.c +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -47,6 +47,7 @@ #include "draw_cache_impl.h" /* own include */ +/* See: edit_curve_point_vert.glsl for duplicate includes. */ #define SELECT 1 #define ACTIVE_NURB 1 << 2 #define BEZIER_HANDLE 1 << 3 @@ -698,7 +699,9 @@ static char beztriple_vflag_get(CurveRenderData *rdata, SET_FLAG_FROM_TEST(vflag, (v_idx == rdata->actvert && nu_id == rdata->actnu), VFLAG_VERT_ACTIVE); SET_FLAG_FROM_TEST(vflag, (nu_id == rdata->actnu), ACTIVE_NURB); SET_FLAG_FROM_TEST(vflag, handle_point, BEZIER_HANDLE); - SET_FLAG_FROM_TEST(vflag, handle_selected, VFLAG_HANDLE_SELECTED); + SET_FLAG_FROM_TEST(vflag, handle_selected, VFLAG_VERT_SELECTED_BEZT_HANDLE); + /* Setting flags that overlap with will cause the color id not to work properly. */ + BLI_assert((vflag >> COLOR_SHIFT) == 0); /* handle color id */ vflag |= col_id << COLOR_SHIFT; return vflag; @@ -711,6 +714,8 @@ static char bpoint_vflag_get(CurveRenderData *rdata, char flag, int v_idx, int n SET_FLAG_FROM_TEST(vflag, (v_idx == rdata->actvert && nu_id == rdata->actnu), VFLAG_VERT_ACTIVE); SET_FLAG_FROM_TEST(vflag, (nu_id == rdata->actnu), ACTIVE_NURB); SET_FLAG_FROM_TEST(vflag, ((u % 2) == 0), EVEN_U_BIT); + /* Setting flags that overlap with will cause the color id not to work properly. */ + BLI_assert((vflag >> COLOR_SHIFT) == 0); vflag |= COLOR_NURB_ULINE_ID << COLOR_SHIFT; return vflag; } @@ -898,6 +903,16 @@ GPUBatch **DRW_curve_batch_cache_get_surface_shaded(struct Curve *cu, return cache->surf_per_mat; } +GPUVertBuf *DRW_curve_batch_cache_pos_vertbuf_get(struct Curve *cu) +{ + CurveBatchCache *cache = curve_batch_cache_get(cu); + /* Request surface to trigger the vbo filling. Otherwise it may do nothing. */ + DRW_batch_request(&cache->batch.surfaces); + + DRW_vbo_request(NULL, &cache->ordered.loop_pos_nor); + return cache->ordered.loop_pos_nor; +} + GPUBatch *DRW_curve_batch_cache_get_wireframes_face(Curve *cu) { CurveBatchCache *cache = curve_batch_cache_get(cu); diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c index b4974330043..d648245f232 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c @@ -150,7 +150,6 @@ void DRW_gpencil_batch_cache_free(bGPdata *gpd) gpencil_batch_cache_clear(gpd->runtime.gpencil_cache); MEM_SAFE_FREE(gpd->runtime.gpencil_cache); gpd->flag |= GP_DATA_CACHE_IS_DIRTY; - return; } /** \} */ @@ -349,10 +348,10 @@ static void gpencil_stroke_iter_cb(bGPDlayer *UNUSED(gpl), } } -static void gp_object_verts_count_cb(bGPDlayer *UNUSED(gpl), - bGPDframe *UNUSED(gpf), - bGPDstroke *gps, - void *thunk) +static void gpencil_object_verts_count_cb(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) { gpIterData *iter = (gpIterData *)thunk; @@ -387,7 +386,7 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr .tri_len = 0, }; BKE_gpencil_visible_stroke_iter( - NULL, ob, NULL, gp_object_verts_count_cb, &iter, do_onion, cfra); + NULL, ob, NULL, gpencil_object_verts_count_cb, &iter, do_onion, cfra); /* Create VBOs. */ GPUVertFormat *format = gpencil_stroke_format(); @@ -441,10 +440,10 @@ GPUBatch *DRW_cache_gpencil_fills_get(Object *ob, int cfra) return cache->fill_batch; } -static void gp_lines_indices_cb(bGPDlayer *UNUSED(gpl), - bGPDframe *UNUSED(gpf), - bGPDstroke *gps, - void *thunk) +static void gpencil_lines_indices_cb(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) { gpIterData *iter = (gpIterData *)thunk; int pts_len = gps->totpoints + gpencil_stroke_is_cyclic(gps); @@ -477,7 +476,8 @@ GPUBatch *DRW_cache_gpencil_face_wireframe_get(Object *ob) /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */ bool do_onion = true; - BKE_gpencil_visible_stroke_iter(NULL, ob, NULL, gp_lines_indices_cb, &iter, do_onion, cfra); + BKE_gpencil_visible_stroke_iter( + NULL, ob, NULL, gpencil_lines_indices_cb, &iter, do_onion, cfra); GPUIndexBuf *ibo = GPU_indexbuf_build(&iter.ibo); diff --git a/source/blender/draw/intern/draw_cache_impl_lattice.c b/source/blender/draw/intern/draw_cache_impl_lattice.c index bb313b31deb..66a67d6b8fe 100644 --- a/source/blender/draw/intern/draw_cache_impl_lattice.c +++ b/source/blender/draw/intern/draw_cache_impl_lattice.c @@ -127,7 +127,7 @@ typedef struct LatticeRenderData { int actbp; - struct MDeformVert *dvert; + const struct MDeformVert *dvert; } LatticeRenderData; enum { diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 99e285a18f1..7cc10bd14e8 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -74,22 +74,30 @@ static void mesh_batch_cache_clear(Mesh *me); /* Return true is all layers in _b_ are inside _a_. */ BLI_INLINE bool mesh_cd_layers_type_overlap(DRW_MeshCDMask a, DRW_MeshCDMask b) { - return (*((uint32_t *)&a) & *((uint32_t *)&b)) == *((uint32_t *)&b); + return (*((uint64_t *)&a) & *((uint64_t *)&b)) == *((uint64_t *)&b); } BLI_INLINE bool mesh_cd_layers_type_equal(DRW_MeshCDMask a, DRW_MeshCDMask b) { - return *((uint32_t *)&a) == *((uint32_t *)&b); + return *((uint64_t *)&a) == *((uint64_t *)&b); } BLI_INLINE void mesh_cd_layers_type_merge(DRW_MeshCDMask *a, DRW_MeshCDMask b) { - atomic_fetch_and_or_uint32((uint32_t *)a, *(uint32_t *)&b); + uint32_t *a_p = (uint32_t *)a; + uint32_t *b_p = (uint32_t *)&b; + atomic_fetch_and_or_uint32(a_p, *b_p); + atomic_fetch_and_or_uint32(a_p + 1, *(b_p + 1)); } BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a) { - *((uint32_t *)a) = 0; + *((uint64_t *)a) = 0; +} + +BLI_INLINE const Mesh *editmesh_final_or_this(const Mesh *me) +{ + return (me->edit_mesh && me->edit_mesh->mesh_eval_final) ? me->edit_mesh->mesh_eval_final : me; } static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *cd_used) @@ -112,9 +120,24 @@ BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me) return &me->ldata; } +BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me) +{ + switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_MDATA: + return &me->vdata; + break; + case ME_WRAPPER_TYPE_BMESH: + return &me->edit_mesh->bm->vdata; + break; + } + + BLI_assert(0); + return &me->vdata; +} + static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { - const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const Mesh *me_final = editmesh_final_or_this(me); const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { @@ -124,7 +147,7 @@ static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { - const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const Mesh *me_final = editmesh_final_or_this(me); const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { @@ -134,8 +157,20 @@ static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { - const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; - const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); + const Mesh *me_final = editmesh_final_or_this(me); + const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); + + int layer = CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR); + if (layer != -1) { + cd_used->sculpt_vcol |= (1 << layer); + } +} + +static void mesh_cd_calc_active_mloopcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used) +{ + const Mesh *me_final = editmesh_final_or_this(me); + const CustomData *cd_ldata = &me_final->ldata; + int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL); if (layer != -1) { cd_used->vcol |= (1 << layer); @@ -146,8 +181,9 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, struct GPUMaterial **gpumat_array, int gpumat_array_len) { - const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const Mesh *me_final = editmesh_final_or_this(me); const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); + const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); /* See: DM_vertex_attributes_from_gpu for similar logic */ DRW_MeshCDMask cd_used; @@ -172,9 +208,17 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, type = CD_MTFACE; if (layer == -1) { + if (U.experimental.use_sculpt_vertex_colors) { + layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name); + type = CD_PROP_COLOR; + } + } + + if (layer == -1) { layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name); type = CD_MCOL; } + #if 0 /* Tangents are always from UV's - this will never happen. */ if (layer == -1) { layer = CustomData_get_named_layer(cd_ldata, CD_TANGENT, name); @@ -222,7 +266,33 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, } break; } + case CD_PROP_COLOR: { + /* Sculpt Vertex Colors */ + bool use_mloop_cols = false; + if (layer == -1) { + layer = (name[0] != '\0') ? + CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name) : + CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR); + /* Fallback to Vertex Color data */ + if (layer == -1) { + layer = (name[0] != '\0') ? + CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name) : + CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL); + use_mloop_cols = true; + } + } + if (layer != -1) { + if (use_mloop_cols) { + cd_used.vcol |= (1 << layer); + } + else { + cd_used.sculpt_vcol |= (1 << layer); + } + } + break; + } case CD_MCOL: { + /* Vertex Color Data */ if (layer == -1) { layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name) : CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL); @@ -230,6 +300,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, if (layer != -1) { cd_used.vcol |= (1 << layer); } + break; } case CD_ORCO: { @@ -461,14 +532,26 @@ static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, } } -static void mesh_batch_cache_discard_shaded_batches(MeshBatchCache *cache) +static void mesh_batch_cache_request_surface_batches(MeshBatchCache *cache) { + mesh_batch_cache_add_request(cache, MBC_SURFACE); + DRW_batch_request(&cache->batch.surface); + if (cache->surface_per_mat) { + for (int i = 0; i < cache->mat_len; i++) { + DRW_batch_request(&cache->surface_per_mat[i]); + } + } +} + +static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache) +{ + GPU_BATCH_DISCARD_SAFE(cache->batch.surface); if (cache->surface_per_mat) { for (int i = 0; i < cache->mat_len; i++) { GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); } } - cache->batch_ready &= ~MBC_SURF_PER_MAT; + cache->batch_ready &= ~MBC_SURFACE; } static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) @@ -480,7 +563,7 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.vcol); GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.orco); } - mesh_batch_cache_discard_shaded_batches(cache); + mesh_batch_cache_discard_surface_batches(cache); mesh_cd_layers_type_clear(&cache->cd_used); MEM_SAFE_FREE(cache->surface_per_mat); @@ -520,10 +603,7 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache) cache->cd_used.edit_uv = 0; /* Discard other batches that uses vbo.uv */ - mesh_batch_cache_discard_shaded_batches(cache); - - GPU_BATCH_DISCARD_SAFE(cache->batch.surface); - cache->batch_ready &= ~MBC_SURFACE; + mesh_batch_cache_discard_surface_batches(cache); } static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache) @@ -585,12 +665,8 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) GPU_BATCH_DISCARD_SAFE(cache->batch.surface); GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops); GPU_BATCH_DISCARD_SAFE(cache->batch.wire_edges); - if (cache->surface_per_mat) { - for (int i = 0; i < cache->mat_len; i++) { - GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); - } - } - cache->batch_ready &= ~(MBC_SURFACE | MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SURF_PER_MAT); + mesh_batch_cache_discard_surface_batches(cache); + cache->batch_ready &= ~(MBC_SURFACE | MBC_WIRE_EDGES | MBC_WIRE_LOOPS); break; case BKE_MESH_BATCH_DIRTY_ALL: cache->is_dirty = true; @@ -679,10 +755,22 @@ static void texpaint_request_active_vcol(MeshBatchCache *cache, Mesh *me) { DRW_MeshCDMask cd_needed; mesh_cd_layers_type_clear(&cd_needed); - mesh_cd_calc_active_vcol_layer(me, &cd_needed); + mesh_cd_calc_active_mloopcol_layer(me, &cd_needed); BLI_assert(cd_needed.vcol != 0 && - "No vcol layer available in vertpaint, but batches requested anyway!"); + "No MLOOPCOL layer available in vertpaint, but batches requested anyway!"); + + mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); +} + +static void sculpt_request_active_vcol(MeshBatchCache *cache, Mesh *me) +{ + DRW_MeshCDMask cd_needed; + mesh_cd_layers_type_clear(&cd_needed); + mesh_cd_calc_active_vcol_layer(me, &cd_needed); + + BLI_assert(cd_needed.sculpt_vcol != 0 && + "No MPropCol layer available in Sculpt, but batches requested anyway!"); mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); } @@ -704,8 +792,8 @@ GPUBatch *DRW_mesh_batch_cache_get_all_edges(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_surface(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_SURFACE); - return DRW_batch_request(&cache->batch.surface); + mesh_batch_cache_request_surface_batches(cache); + return cache->batch.surface; } GPUBatch *DRW_mesh_batch_cache_get_loose_edges(Mesh *me) @@ -763,23 +851,15 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me, BLI_assert(gpumat_array_len == cache->mat_len); mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); - - mesh_batch_cache_add_request(cache, MBC_SURF_PER_MAT); - - for (int i = 0; i < cache->mat_len; i++) { - DRW_batch_request(&cache->surface_per_mat[i]); - } + mesh_batch_cache_request_surface_batches(cache); return cache->surface_per_mat; } GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_SURF_PER_MAT); texpaint_request_active_uv(cache, me); - for (int i = 0; i < cache->mat_len; i++) { - DRW_batch_request(&cache->surface_per_mat[i]); - } + mesh_batch_cache_request_surface_batches(cache); return cache->surface_per_mat; } @@ -787,16 +867,24 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); texpaint_request_active_uv(cache, me); - mesh_batch_cache_add_request(cache, MBC_SURFACE); - return DRW_batch_request(&cache->batch.surface); + mesh_batch_cache_request_surface_batches(cache); + return cache->batch.surface; } GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); texpaint_request_active_vcol(cache, me); - mesh_batch_cache_add_request(cache, MBC_SURFACE); - return DRW_batch_request(&cache->batch.surface); + mesh_batch_cache_request_surface_batches(cache); + return cache->batch.surface; +} + +GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + sculpt_request_active_vcol(cache, me); + mesh_batch_cache_request_surface_batches(cache); + return cache->batch.surface; } int DRW_mesh_material_count_get(Mesh *me) @@ -810,6 +898,22 @@ int DRW_mesh_material_count_get(Mesh *me) /** \name Edit Mode API * \{ */ +GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + /* Request surface to trigger the vbo filling. Otherwise it may do nothing. */ + mesh_batch_cache_request_surface_batches(cache); + + DRW_vbo_request(NULL, &cache->final.vbo.pos_nor); + return cache->final.vbo.pos_nor; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Edit Mode API + * \{ */ + GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); @@ -1019,6 +1123,40 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime) mesh_cd_layers_type_clear(&cache->cd_used_over_time); } +#ifdef DEBUG +/* Sanity check function to test if all requested batches are available. */ +static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + /* Make sure all requested batches have been setup. */ + /* Note: The next line creates a different scheduling than during release builds what can lead to + * some issues (See T77867 where we needed to disable this function in order to debug what was + * happening in release builds). */ + BLI_task_graph_work_and_wait(task_graph); + for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) { + BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); + } + for (int i = 0; i < sizeof(cache->final.vbo) / sizeof(void *); i++) { + BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.vbo)[i])); + } + for (int i = 0; i < sizeof(cache->final.ibo) / sizeof(void *); i++) { + BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->final.ibo)[i])); + } + for (int i = 0; i < sizeof(cache->cage.vbo) / sizeof(void *); i++) { + BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.vbo)[i])); + } + for (int i = 0; i < sizeof(cache->cage.ibo) / sizeof(void *); i++) { + BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->cage.ibo)[i])); + } + for (int i = 0; i < sizeof(cache->uv_cage.vbo) / sizeof(void *); i++) { + BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.vbo)[i])); + } + for (int i = 0; i < sizeof(cache->uv_cage.ibo) / sizeof(void *); i++) { + BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->uv_cage.ibo)[i])); + } +} +#endif + /* Can be called for any surface type. Mesh *me is the final mesh. */ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, Object *ob, @@ -1039,10 +1177,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, /* Early out */ if (cache->batch_requested == 0) { #ifdef DEBUG - goto check; -#else - return; + drw_mesh_batch_cache_check_available(task_graph, me); #endif + return; } /* Sanity check. */ @@ -1067,30 +1204,8 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, } } - /* HACK: if MBC_SURF_PER_MAT is requested and ibo.tris is already available, it won't have it's - * index ranges initialized. So discard ibo.tris in order to recreate it. - * This needs to happen before saved_elem_ranges is populated. */ - if ((batch_requested & MBC_SURF_PER_MAT) != 0 && (cache->batch_ready & MBC_SURF_PER_MAT) == 0) { - FOREACH_MESH_BUFFER_CACHE (cache, mbuffercache) { - GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.tris); - } - /* Clear all batches that reference ibo.tris. */ - GPU_BATCH_CLEAR_SAFE(cache->batch.surface); - GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights); - GPU_BATCH_CLEAR_SAFE(cache->batch.edit_mesh_analysis); - GPU_BATCH_CLEAR_SAFE(cache->batch.edit_triangles); - GPU_BATCH_CLEAR_SAFE(cache->batch.edit_lnor); - GPU_BATCH_CLEAR_SAFE(cache->batch.edit_selection_faces); - for (int i = 0; i < cache->mat_len; i++) { - GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]); - } - - cache->batch_ready &= ~(MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_MESH_ANALYSIS | - MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR | MBC_EDIT_SELECTION_FACES); - } - if (batch_requested & - (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRETCH_AREA | + (MBC_SURFACE | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) { /* Modifiers will only generate an orco layer if the mesh is deformed. */ if (cache->cd_needed.orco != 0) { @@ -1120,7 +1235,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, if (cache->cd_used.orco != cache->cd_needed.orco) { GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.orco); } - if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) { + if (((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) || + ((cache->cd_used.sculpt_vcol & cache->cd_needed.sculpt_vcol) != + cache->cd_needed.sculpt_vcol)) { GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.vcol); } } @@ -1141,7 +1258,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]); } GPU_BATCH_CLEAR_SAFE(cache->batch.surface); - cache->batch_ready &= ~(MBC_SURFACE | MBC_SURF_PER_MAT); + cache->batch_ready &= ~(MBC_SURFACE); mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed); } @@ -1177,10 +1294,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, /* Second chance to early out */ if ((batch_requested & ~cache->batch_ready) == 0) { #ifdef DEBUG - goto check; -#else - return; + drw_mesh_batch_cache_check_available(task_graph, me); #endif + return; } cache->batch_ready |= batch_requested; @@ -1201,7 +1317,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, if (cache->cd_used.uv != 0) { DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.uv); } - if (cache->cd_used.vcol != 0) { + if (cache->cd_used.vcol != 0 || cache->cd_used.sculpt_vcol != 0) { DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.vcol); } } @@ -1269,7 +1385,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, if ((cache->cd_used.tan != 0) || (cache->cd_used.tan_orco != 0)) { DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.tan); } - if (cache->cd_used.vcol != 0) { + if (cache->cd_used.vcol != 0 || cache->cd_used.sculpt_vcol != 0) { DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.vcol); } if (cache->cd_used.orco != 0) { @@ -1432,32 +1548,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, ts, use_hide); #ifdef DEBUG -check: - /* Make sure all requested batches have been setup. */ - /* TODO(jbakker): we should move this to the draw_manager but that needs refactoring and - * additional looping.*/ - BLI_task_graph_work_and_wait(task_graph); - for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) { - BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); - } - for (int i = 0; i < sizeof(cache->final.vbo) / sizeof(void *); i++) { - BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.vbo)[i])); - } - for (int i = 0; i < sizeof(cache->final.ibo) / sizeof(void *); i++) { - BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->final.ibo)[i])); - } - for (int i = 0; i < sizeof(cache->cage.vbo) / sizeof(void *); i++) { - BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.vbo)[i])); - } - for (int i = 0; i < sizeof(cache->cage.ibo) / sizeof(void *); i++) { - BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->cage.ibo)[i])); - } - for (int i = 0; i < sizeof(cache->uv_cage.vbo) / sizeof(void *); i++) { - BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.vbo)[i])); - } - for (int i = 0; i < sizeof(cache->uv_cage.ibo) / sizeof(void *); i++) { - BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->uv_cage.ibo)[i])); - } + drw_mesh_batch_cache_check_available(task_graph, me); #endif } diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c index c14e66c2b47..076d32ffe1f 100644 --- a/source/blender/draw/intern/draw_cache_impl_metaball.c +++ b/source/blender/draw/intern/draw_cache_impl_metaball.c @@ -274,6 +274,18 @@ struct GPUBatch *DRW_metaball_batch_cache_get_edge_detection(struct Object *ob, return cache->edge_detection; } +struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(Object *ob) +{ + if (!BKE_mball_is_basis(ob)) { + return NULL; + } + + MetaBall *mb = ob->data; + MetaBallBatchCache *cache = metaball_batch_cache_get(mb); + + return mball_batch_cache_get_pos_and_normals(ob, cache); +} + int DRW_metaball_material_count_get(MetaBall *mb) { return max_ii(1, mb->totcol); diff --git a/source/blender/draw/intern/draw_cache_impl_pointcloud.c b/source/blender/draw/intern/draw_cache_impl_pointcloud.c index 53939b35285..06cedb9f72c 100644 --- a/source/blender/draw/intern/draw_cache_impl_pointcloud.c +++ b/source/blender/draw/intern/draw_cache_impl_pointcloud.c @@ -28,6 +28,7 @@ #include "MEM_guardedalloc.h" #include "BLI_math_base.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #include "DNA_object_types.h" @@ -45,11 +46,18 @@ static void pointcloud_batch_cache_clear(PointCloud *pointcloud); /* PointCloud GPUBatch Cache */ typedef struct PointCloudBatchCache { - GPUVertBuf *pos; - GPUBatch *batch; + GPUVertBuf *pos; /* Position and radius. */ + GPUVertBuf *geom; /* Instanced geometry for each point in the cloud (small sphere). */ + GPUIndexBuf *geom_indices; + + GPUBatch *dots; + GPUBatch *surface; + GPUBatch **surface_per_mat; /* settings to determine if cache is invalid */ bool is_dirty; + + int mat_len; } PointCloudBatchCache; /* GPUBatch cache management. */ @@ -57,7 +65,14 @@ typedef struct PointCloudBatchCache { static bool pointcloud_batch_cache_valid(PointCloud *pointcloud) { PointCloudBatchCache *cache = pointcloud->batch_cache; - return (cache && cache->is_dirty == false); + + if (cache == NULL) { + return false; + } + if (cache->mat_len != DRW_pointcloud_material_count_get(pointcloud)) { + return false; + } + return cache->is_dirty == false; } static void pointcloud_batch_cache_init(PointCloud *pointcloud) @@ -71,6 +86,10 @@ static void pointcloud_batch_cache_init(PointCloud *pointcloud) memset(cache, 0, sizeof(*cache)); } + cache->mat_len = DRW_pointcloud_material_count_get(pointcloud); + cache->surface_per_mat = MEM_callocN(sizeof(GPUBatch *) * cache->mat_len, + "pointcloud suface_per_mat"); + cache->is_dirty = false; } @@ -109,8 +128,18 @@ static void pointcloud_batch_cache_clear(PointCloud *pointcloud) return; } - GPU_BATCH_DISCARD_SAFE(cache->batch); + GPU_BATCH_DISCARD_SAFE(cache->dots); + GPU_BATCH_DISCARD_SAFE(cache->surface); GPU_VERTBUF_DISCARD_SAFE(cache->pos); + GPU_VERTBUF_DISCARD_SAFE(cache->geom); + GPU_INDEXBUF_DISCARD_SAFE(cache->geom_indices); + + if (cache->surface_per_mat) { + for (int i = 0; i < cache->mat_len; i++) { + GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); + } + } + MEM_SAFE_FREE(cache->surface_per_mat); } void DRW_pointcloud_batch_cache_free(PointCloud *pointcloud) @@ -126,35 +155,84 @@ static void pointcloud_batch_cache_ensure_pos(Object *ob, PointCloudBatchCache * } PointCloud *pointcloud = ob->data; + const bool has_radius = pointcloud->radius != NULL; static GPUVertFormat format = {0}; - static uint pos_id; - static uint radius_id; + static GPUVertFormat format_no_radius = {0}; + static uint pos; if (format.attr_len == 0) { /* initialize vertex format */ - pos_id = GPU_vertformat_attr_add(&format, "pointcloud_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - radius_id = GPU_vertformat_attr_add( - &format, "pointcloud_radius", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + /* From the opengl wiki: + * Note that size does not have to exactly match the size used by the vertex shader. If the + * vertex shader has fewer components than the attribute provides, then the extras are ignored. + * If the vertex shader has more components than the array provides, the extras are given + * values from the vector (0, 0, 0, 1) for the missing XYZW components. + */ + pos = GPU_vertformat_attr_add(&format_no_radius, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); } - GPU_VERTBUF_DISCARD_SAFE(cache->pos); - cache->pos = GPU_vertbuf_create_with_format(&format); + cache->pos = GPU_vertbuf_create_with_format(has_radius ? &format : &format_no_radius); GPU_vertbuf_data_alloc(cache->pos, pointcloud->totpoint); - GPU_vertbuf_attr_fill(cache->pos, pos_id, pointcloud->co); - if (pointcloud->radius) { - GPU_vertbuf_attr_fill(cache->pos, radius_id, pointcloud->radius); - } - else if (pointcloud->totpoint) { - /* TODO: optimize for constant radius by not including in vertex buffer at all? */ - float *radius = MEM_malloc_arrayN(pointcloud->totpoint, sizeof(float), __func__); + if (has_radius) { + float(*vbo_data)[4] = (float(*)[4])cache->pos->data; for (int i = 0; i < pointcloud->totpoint; i++) { - /* TODO: add default radius to PointCloud data structure. */ - radius[i] = 0.01f; + copy_v3_v3(vbo_data[i], pointcloud->co[i]); + /* TODO(fclem) remove multiplication here. Here only for keeping the size correct for now. */ + vbo_data[i][3] = pointcloud->radius[i] * 100.0f; } - GPU_vertbuf_attr_fill(cache->pos, radius_id, radius); - MEM_freeN(radius); } + else { + GPU_vertbuf_attr_fill(cache->pos, pos, pointcloud->co); + } +} + +static const float half_octahedron_normals[5][3] = { + {0.0f, 0.0f, 1.0f}, + {1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, + {-1.0f, 0.0f, 0.0f}, + {0.0f, -1.0f, 0.0f}, +}; + +static const uint half_octahedron_tris[4][3] = { + {0, 1, 2}, + {0, 2, 3}, + {0, 3, 4}, + {0, 4, 1}, +}; + +static void pointcloud_batch_cache_ensure_geom(Object *UNUSED(ob), PointCloudBatchCache *cache) +{ + if (cache->geom != NULL) { + return; + } + + static GPUVertFormat format = {0}; + static uint pos; + if (format.attr_len == 0) { + /* initialize vertex format */ + pos = GPU_vertformat_attr_add(&format, "pos_inst", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "nor"); + } + + cache->geom = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(cache->geom, ARRAY_SIZE(half_octahedron_normals)); + + GPU_vertbuf_attr_fill(cache->geom, pos, half_octahedron_normals); + + GPUIndexBufBuilder builder; + GPU_indexbuf_init(&builder, + GPU_PRIM_TRIS, + ARRAY_SIZE(half_octahedron_tris), + ARRAY_SIZE(half_octahedron_normals)); + + for (int i = 0; i < ARRAY_SIZE(half_octahedron_tris); i++) { + GPU_indexbuf_add_tri_verts(&builder, UNPACK3(half_octahedron_tris[i])); + } + + cache->geom_indices = GPU_indexbuf_build(&builder); } GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob) @@ -162,12 +240,48 @@ GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob) PointCloud *pointcloud = ob->data; PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); - if (cache->batch == NULL) { + if (cache->dots == NULL) { pointcloud_batch_cache_ensure_pos(ob, cache); - cache->batch = GPU_batch_create(GPU_PRIM_POINTS, cache->pos, NULL); + cache->dots = GPU_batch_create(GPU_PRIM_POINTS, cache->pos, NULL); + } + + return cache->dots; +} + +GPUBatch *DRW_pointcloud_batch_cache_get_surface(Object *ob) +{ + PointCloud *pointcloud = ob->data; + PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); + + if (cache->surface == NULL) { + pointcloud_batch_cache_ensure_pos(ob, cache); + pointcloud_batch_cache_ensure_geom(ob, cache); + + cache->surface = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices); + GPU_batch_instbuf_add_ex(cache->surface, cache->pos, false); + } + + return cache->surface; +} + +GPUBatch **DRW_cache_pointcloud_surface_shaded_get(Object *ob, + struct GPUMaterial **UNUSED(gpumat_array), + uint gpumat_array_len) +{ + PointCloud *pointcloud = ob->data; + PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); + BLI_assert(cache->mat_len == gpumat_array_len); + UNUSED_VARS(gpumat_array_len); + + if (cache->surface_per_mat[0] == NULL) { + pointcloud_batch_cache_ensure_pos(ob, cache); + pointcloud_batch_cache_ensure_geom(ob, cache); + + cache->surface_per_mat[0] = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices); + GPU_batch_instbuf_add_ex(cache->surface_per_mat[0], cache->pos, false); } - return cache->batch; + return cache->surface_per_mat; } int DRW_pointcloud_material_count_get(PointCloud *pointcloud) diff --git a/source/blender/draw/intern/draw_cache_impl_volume.c b/source/blender/draw/intern/draw_cache_impl_volume.c index 9c2c075ab4f..e07f5b33d58 100644 --- a/source/blender/draw/intern/draw_cache_impl_volume.c +++ b/source/blender/draw/intern/draw_cache_impl_volume.c @@ -266,7 +266,7 @@ static DRWVolumeGrid *volume_grid_cache_get(Volume *volume, NULL); GPU_texture_bind(cache_grid->texture, 0); - GPU_texture_swizzle_channel_auto(cache_grid->texture, channels); + GPU_texture_swizzle_set(cache_grid->texture, (channels == 3) ? "rgb1" : "rrr1"); GPU_texture_wrap_mode(cache_grid->texture, false, false); GPU_texture_unbind(cache_grid->texture); diff --git a/source/blender/draw/intern/draw_cache_inline.h b/source/blender/draw/intern/draw_cache_inline.h index a067434f3bb..67f44b5fb0c 100644 --- a/source/blender/draw/intern/draw_cache_inline.h +++ b/source/blender/draw/intern/draw_cache_inline.h @@ -90,17 +90,19 @@ BLI_INLINE void DRW_vbo_request(GPUBatch *batch, GPUVertBuf **vbo) if (*vbo == NULL) { *vbo = MEM_callocN(sizeof(GPUVertBuf), "GPUVertBuf"); } - /* HACK set first vbo if not init. */ - if (batch->verts[0] == NULL) { - GPU_batch_vao_cache_clear(batch); - batch->verts[0] = *vbo; - } - else { - /* HACK: bypass assert */ - int vbo_vert_len = (*vbo)->vertex_len; - (*vbo)->vertex_len = batch->verts[0]->vertex_len; - GPU_batch_vertbuf_add(batch, *vbo); - (*vbo)->vertex_len = vbo_vert_len; + if (batch != NULL) { + /* HACK set first vbo if not init. */ + if (batch->verts[0] == NULL) { + GPU_batch_vao_cache_clear(batch); + batch->verts[0] = *vbo; + } + else { + /* HACK: bypass assert */ + int vbo_vert_len = (*vbo)->vertex_len; + (*vbo)->vertex_len = batch->verts[0]->vertex_len; + GPU_batch_vertbuf_add(batch, *vbo); + (*vbo)->vertex_len = vbo_vert_len; + } } } diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index 2be0249a2cd..095e928aa74 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -22,6 +22,7 @@ #include "DRW_render.h" +#include "GPU_matrix.h" #include "GPU_shader.h" #include "GPU_texture.h" @@ -31,8 +32,6 @@ #include "BKE_global.h" #include "BKE_object.h" -#include "BIF_glutil.h" - #include "draw_common.h" #if 0 @@ -280,7 +279,7 @@ DRWView *DRW_view_create_with_zoffset(const DRWView *parent_view, viewdist = 1.0f / max_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1])); } - winmat[3][2] -= bglPolygonOffsetCalc((float *)winmat, viewdist, offset); + winmat[3][2] -= GPU_polygon_offset_calc(winmat, viewdist, offset); return DRW_view_create_sub(parent_view, viewmat, winmat); } @@ -509,5 +508,5 @@ static GPUTexture *DRW_create_weight_colorramp_texture(void) pixels[i][3] = 1.0f; } - return GPU_texture_create_1d(256, GPU_RGBA8, pixels[0], error); + return GPU_texture_create_1d(256, GPU_SRGB8_A8, pixels[0], error); } diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 656d72b2808..09f901c344f 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -27,8 +27,10 @@ struct DRWPass; struct DRWShadingGroup; struct GPUMaterial; struct ModifierData; +struct FluidModifierData; struct Object; struct ParticleSystem; +struct RegionView3D; struct ViewLayer; #define UBO_FIRST_COLOR colorWire @@ -159,14 +161,14 @@ void DRW_globals_update(void); void DRW_globals_free(void); struct DRWView *DRW_view_create_with_zoffset(const struct DRWView *parent_view, - const RegionView3D *rv3d, + const struct RegionView3D *rv3d, float offset); int DRW_object_wire_theme_get(struct Object *ob, struct ViewLayer *view_layer, float **r_color); float *DRW_color_background_blend_get(int theme_id); -bool DRW_object_is_flat(Object *ob, int *r_axis); -bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis); +bool DRW_object_is_flat(struct Object *ob, int *r_axis); +bool DRW_object_axis_orthogonal_to_view(struct Object *ob, int axis); /* draw_hair.c */ @@ -176,11 +178,28 @@ struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object, struct ParticleSystem *psys, struct ModifierData *md, struct DRWShadingGroup *shgrp); +struct GPUVertBuf *DRW_hair_pos_buffer_get(struct Object *object, + struct ParticleSystem *psys, + struct ModifierData *md); +void DRW_hair_duplimat_get(struct Object *object, + struct ParticleSystem *psys, + struct ModifierData *md, + float (*dupli_mat)[4]); void DRW_hair_init(void); void DRW_hair_update(void); void DRW_hair_free(void); +/* draw_fluid.c */ + +/* Fluid simulation. */ +void DRW_smoke_ensure(struct FluidModifierData *fmd, int highres); +void DRW_smoke_ensure_coba_field(struct FluidModifierData *fmd); +void DRW_smoke_ensure_velocity(struct FluidModifierData *fmd); + +void DRW_smoke_free(struct FluidModifierData *fmd); +void DRW_smoke_free_velocity(struct FluidModifierData *fmd); + /* draw_common.c */ struct DRW_Global { /** If needed, contains all global/Theme colors diff --git a/source/blender/draw/intern/draw_fluid.c b/source/blender/draw/intern/draw_fluid.c new file mode 100644 index 00000000000..33311dc698f --- /dev/null +++ b/source/blender/draw/intern/draw_fluid.c @@ -0,0 +1,419 @@ +/* + * 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) 2005 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * GPU fluid drawing functions. + */ + +#include <string.h> + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "DNA_fluid_types.h" +#include "DNA_modifier_types.h" + +#include "MEM_guardedalloc.h" + +#include "BKE_colorband.h" + +#include "GPU_texture.h" + +#include "draw_common.h" /* Own include. */ + +#ifdef WITH_FLUID +# include "manta_fluid_API.h" +#endif + +/* -------------------------------------------------------------------- */ +/** \name Private API + * \{ */ + +#ifdef WITH_FLUID + +enum { + TFUNC_FLAME_SPECTRUM = 0, + TFUNC_COLOR_RAMP = 1, +}; + +# define TFUNC_WIDTH 256 + +static void create_flame_spectrum_texture(float *data) +{ +# define FIRE_THRESH 7 +# define MAX_FIRE_ALPHA 0.06f +# define FULL_ON_FIRE 100 + + float *spec_pixels = (float *)MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), + "spec_pixels"); + + blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000); + + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + for (int k = 0; k < TFUNC_WIDTH; k++) { + int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4; + if (k >= FIRE_THRESH) { + spec_pixels[index] = (data[k * 4]); + spec_pixels[index + 1] = (data[k * 4 + 1]); + spec_pixels[index + 2] = (data[k * 4 + 2]); + spec_pixels[index + 3] = MAX_FIRE_ALPHA * + ((k > FULL_ON_FIRE) ? + 1.0f : + (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); + } + else { + zero_v4(&spec_pixels[index]); + } + } + } + } + + memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH); + + MEM_freeN(spec_pixels); + +# undef FIRE_THRESH +# undef MAX_FIRE_ALPHA +# undef FULL_ON_FIRE +} + +static void create_color_ramp(const struct ColorBand *coba, float *data) +{ + for (int i = 0; i < TFUNC_WIDTH; i++) { + BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); + straight_to_premul_v4(&data[i * 4]); + } +} + +static GPUTexture *create_transfer_function(int type, const struct ColorBand *coba) +{ + float *data = (float *)MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__); + + switch (type) { + case TFUNC_FLAME_SPECTRUM: + create_flame_spectrum_texture(data); + break; + case TFUNC_COLOR_RAMP: + create_color_ramp(coba, data); + break; + } + + GPUTexture *tex = GPU_texture_create_1d(TFUNC_WIDTH, GPU_SRGB8_A8, data, NULL); + + MEM_freeN(data); + + return tex; +} + +static void swizzle_texture_channel_single(GPUTexture *tex) +{ + /* Swizzle texture channels so that we get useful RGBA values when sampling + * a texture with fewer channels, e.g. when using density as color. */ + GPU_texture_bind(tex, 0); + GPU_texture_swizzle_set(tex, "rrr1"); + GPU_texture_unbind(tex); +} + +static GPUTexture *create_field_texture(FluidDomainSettings *fds) +{ + float *field = NULL; + + switch (fds->coba_field) { + case FLUID_DOMAIN_FIELD_DENSITY: + field = manta_smoke_get_density(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_HEAT: + field = manta_smoke_get_heat(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_FUEL: + field = manta_smoke_get_fuel(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_REACT: + field = manta_smoke_get_react(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_FLAME: + field = manta_smoke_get_flame(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_VELOCITY_X: + field = manta_get_velocity_x(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_VELOCITY_Y: + field = manta_get_velocity_y(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_VELOCITY_Z: + field = manta_get_velocity_z(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_COLOR_R: + field = manta_smoke_get_color_r(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_COLOR_G: + field = manta_smoke_get_color_g(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_COLOR_B: + field = manta_smoke_get_color_b(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_FORCE_X: + field = manta_get_force_x(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_FORCE_Y: + field = manta_get_force_y(fds->fluid); + break; + case FLUID_DOMAIN_FIELD_FORCE_Z: + field = manta_get_force_z(fds->fluid); + break; + default: + return NULL; + } + + GPUTexture *tex = GPU_texture_create_nD( + UNPACK3(fds->res), 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); + + swizzle_texture_channel_single(tex); + return tex; +} + +static GPUTexture *create_density_texture(FluidDomainSettings *fds, int highres) +{ + int *dim = (highres) ? fds->res_noise : fds->res; + + float *data; + if (highres) { + data = manta_noise_get_density(fds->fluid); + } + else { + data = manta_smoke_get_density(fds->fluid); + } + + GPUTexture *tex = GPU_texture_create_nD( + UNPACK3(dim), 3, data, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); + + swizzle_texture_channel_single(tex); + + return tex; +} + +static GPUTexture *create_color_texture(FluidDomainSettings *fds, int highres) +{ + const bool has_color = (highres) ? manta_noise_has_colors(fds->fluid) : + manta_smoke_has_colors(fds->fluid); + + if (!has_color) { + return NULL; + } + + int cell_count = (highres) ? manta_noise_get_cells(fds->fluid) : fds->total_cells; + int *dim = (highres) ? fds->res_noise : fds->res; + float *data = (float *)MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture"); + + if (data == NULL) { + return NULL; + } + + if (highres) { + manta_noise_get_rgba(fds->fluid, data, 0); + } + else { + manta_smoke_get_rgba(fds->fluid, data, 0); + } + + GPUTexture *tex = GPU_texture_create_nD( + dim[0], dim[1], dim[2], 3, data, GPU_RGBA8, GPU_DATA_FLOAT, 0, true, NULL); + + MEM_freeN(data); + + return tex; +} + +static GPUTexture *create_flame_texture(FluidDomainSettings *fds, int highres) +{ + float *source = NULL; + const bool has_fuel = (highres) ? manta_noise_has_fuel(fds->fluid) : + manta_smoke_has_fuel(fds->fluid); + int *dim = (highres) ? fds->res_noise : fds->res; + + if (!has_fuel) { + return NULL; + } + + if (highres) { + source = manta_noise_get_flame(fds->fluid); + } + else { + source = manta_smoke_get_flame(fds->fluid); + } + + GPUTexture *tex = GPU_texture_create_nD( + dim[0], dim[1], dim[2], 3, source, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); + + swizzle_texture_channel_single(tex); + + return tex; +} + +#endif /* WITH_FLUID */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public API + * \{ */ + +void DRW_smoke_free(FluidModifierData *fmd) +{ + if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) { + if (fmd->domain->tex_density) { + GPU_texture_free(fmd->domain->tex_density); + fmd->domain->tex_density = NULL; + } + + if (fmd->domain->tex_color) { + GPU_texture_free(fmd->domain->tex_color); + fmd->domain->tex_color = NULL; + } + + if (fmd->domain->tex_shadow) { + GPU_texture_free(fmd->domain->tex_shadow); + fmd->domain->tex_shadow = NULL; + } + + if (fmd->domain->tex_flame) { + GPU_texture_free(fmd->domain->tex_flame); + fmd->domain->tex_flame = NULL; + } + + if (fmd->domain->tex_flame_coba) { + GPU_texture_free(fmd->domain->tex_flame_coba); + fmd->domain->tex_flame_coba = NULL; + } + + if (fmd->domain->tex_coba) { + GPU_texture_free(fmd->domain->tex_coba); + fmd->domain->tex_coba = NULL; + } + + if (fmd->domain->tex_field) { + GPU_texture_free(fmd->domain->tex_field); + fmd->domain->tex_field = NULL; + } + } +} + +void DRW_smoke_ensure_coba_field(FluidModifierData *fmd) +{ +#ifndef WITH_FLUID + UNUSED_VARS(fmd); +#else + if (fmd->type & MOD_FLUID_TYPE_DOMAIN) { + FluidDomainSettings *fds = fmd->domain; + + if (!fds->tex_field) { + fds->tex_field = create_field_texture(fds); + } + if (!fds->tex_coba) { + fds->tex_coba = create_transfer_function(TFUNC_COLOR_RAMP, fds->coba); + } + } +#endif +} + +void DRW_smoke_ensure(FluidModifierData *fmd, int highres) +{ +#ifndef WITH_FLUID + UNUSED_VARS(fmd, highres); +#else + if (fmd->type & MOD_FLUID_TYPE_DOMAIN) { + FluidDomainSettings *fds = fmd->domain; + + if (!fds->tex_density) { + fds->tex_density = create_density_texture(fds, highres); + } + if (!fds->tex_color) { + fds->tex_color = create_color_texture(fds, highres); + } + if (!fds->tex_flame) { + fds->tex_flame = create_flame_texture(fds, highres); + } + if (!fds->tex_flame_coba && fds->tex_flame) { + fds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL); + } + if (!fds->tex_shadow) { + fds->tex_shadow = GPU_texture_create_nD(UNPACK3(fds->res), + 3, + manta_smoke_get_shadow(fds->fluid), + GPU_R8, + GPU_DATA_FLOAT, + 0, + true, + NULL); + } + } +#endif /* WITH_FLUID */ +} + +void DRW_smoke_ensure_velocity(FluidModifierData *fmd) +{ +#ifndef WITH_FLUID + UNUSED_VARS(fmd); +#else + if (fmd->type & MOD_FLUID_TYPE_DOMAIN) { + FluidDomainSettings *fds = fmd->domain; + + const float *vel_x = manta_get_velocity_x(fds->fluid); + const float *vel_y = manta_get_velocity_y(fds->fluid); + const float *vel_z = manta_get_velocity_z(fds->fluid); + + if (ELEM(NULL, vel_x, vel_y, vel_z)) { + return; + } + + if (!fds->tex_velocity_x) { + fds->tex_velocity_x = GPU_texture_create_3d(UNPACK3(fds->res), GPU_R16F, vel_x, NULL); + fds->tex_velocity_y = GPU_texture_create_3d(UNPACK3(fds->res), GPU_R16F, vel_y, NULL); + fds->tex_velocity_z = GPU_texture_create_3d(UNPACK3(fds->res), GPU_R16F, vel_z, NULL); + } + } +#endif /* WITH_FLUID */ +} + +/* TODO Unify with the other DRW_smoke_free. */ +void DRW_smoke_free_velocity(FluidModifierData *fmd) +{ + if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) { + if (fmd->domain->tex_velocity_x) { + GPU_texture_free(fmd->domain->tex_velocity_x); + } + + if (fmd->domain->tex_velocity_y) { + GPU_texture_free(fmd->domain->tex_velocity_y); + } + + if (fmd->domain->tex_velocity_z) { + GPU_texture_free(fmd->domain->tex_velocity_z); + } + + fmd->domain->tex_velocity_x = NULL; + fmd->domain->tex_velocity_y = NULL; + fmd->domain->tex_velocity_z = NULL; + } +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 2fdaf0d5345..cbdcbbf9090 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -124,32 +124,109 @@ void DRW_hair_init(void) } } -DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, - ParticleSystem *psys, - ModifierData *md, - DRWShadingGroup *shgrp_parent) +static ParticleHairCache *drw_hair_particle_cache_get( + Object *object, ParticleSystem *psys, ModifierData *md, int subdiv, int thickness_res) +{ + bool update; + ParticleHairCache *cache; + if (psys) { + /* Old particle hair. */ + update = particles_ensure_procedural_data(object, psys, md, &cache, subdiv, thickness_res); + } + else { + /* New hair object. */ + update = hair_ensure_procedural_data(object, &cache, subdiv, thickness_res); + } + + if (update) { + int final_points_len = cache->final[subdiv].strands_res * cache->strands_len; + if (final_points_len > 0) { + GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM); + +#ifdef USE_TRANSFORM_FEEDBACK + DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create( + tf_shader, g_tf_pass, cache->final[subdiv].proc_buf); +#else + DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); + + ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__); + pr_call->next = g_tf_calls; + pr_call->vbo = cache->final[subdiv].proc_buf; + pr_call->shgrp = tf_shgrp; + pr_call->vert_len = final_points_len; + g_tf_calls = pr_call; + DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1); + DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1); + DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1); +#endif + + DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", cache->point_tex); + DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", cache->strand_tex); + DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", cache->strand_seg_tex); + DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1); + DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len); + } + } + return cache; +} + +/* Note: Only valid after DRW_hair_update(). */ +GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, ModifierData *md) { - /* TODO(fclem): Pass the scene as parameter */ const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - float dupli_mat[4][4]; - Object *dupli_parent = DRW_object_get_dupli_parent(object); - DupliObject *dupli_object = DRW_object_get_dupli(object); int subdiv = scene->r.hair_subdiv; int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; - ParticleHairCache *hair_cache; - bool need_ft_update; + ParticleHairCache *cache = drw_hair_particle_cache_get(object, psys, md, subdiv, thickness_res); + + return cache->final[subdiv].proc_buf; +} + +void DRW_hair_duplimat_get(Object *object, + ParticleSystem *psys, + ModifierData *UNUSED(md), + float (*dupli_mat)[4]) +{ + Object *dupli_parent = DRW_object_get_dupli_parent(object); + DupliObject *dupli_object = DRW_object_get_dupli(object); + if (psys) { - /* Old particle hair. */ - need_ft_update = particles_ensure_procedural_data( - object, psys, md, &hair_cache, subdiv, thickness_res); + if ((dupli_parent != NULL) && (dupli_object != NULL)) { + if (dupli_object->type & OB_DUPLICOLLECTION) { + copy_m4_m4(dupli_mat, dupli_parent->obmat); + } + else { + copy_m4_m4(dupli_mat, dupli_object->ob->obmat); + invert_m4(dupli_mat); + mul_m4_m4m4(dupli_mat, object->obmat, dupli_mat); + } + } + else { + unit_m4(dupli_mat); + } } else { /* New hair object. */ - need_ft_update = hair_ensure_procedural_data(object, &hair_cache, subdiv, thickness_res); + copy_m4_m4(dupli_mat, object->obmat); } +} + +DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, + ParticleSystem *psys, + ModifierData *md, + DRWShadingGroup *shgrp_parent) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + float dupli_mat[4][4]; + + int subdiv = scene->r.hair_subdiv; + int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; + + ParticleHairCache *hair_cache = drw_hair_particle_cache_get( + object, psys, md, subdiv, thickness_res); DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent); @@ -177,25 +254,7 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture); } - if (psys) { - if ((dupli_parent != NULL) && (dupli_object != NULL)) { - if (dupli_object->type & OB_DUPLICOLLECTION) { - copy_m4_m4(dupli_mat, dupli_parent->obmat); - } - else { - copy_m4_m4(dupli_mat, dupli_object->ob->obmat); - invert_m4(dupli_mat); - mul_m4_m4m4(dupli_mat, object->obmat, dupli_mat); - } - } - else { - unit_m4(dupli_mat); - } - } - else { - /* New hair object. */ - copy_m4_m4(dupli_mat, object->obmat); - } + DRW_hair_duplimat_get(object, psys, md, dupli_mat); /* Get hair shape parameters. */ float hair_rad_shape, hair_rad_root, hair_rad_tip; @@ -229,38 +288,6 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, GPUBatch *geom = hair_cache->final[subdiv].proc_hairs[thickness_res - 1]; DRW_shgroup_call_no_cull(shgrp, geom, object); - /* Transform Feedback subdiv. */ - if (need_ft_update) { - int final_points_len = hair_cache->final[subdiv].strands_res * hair_cache->strands_len; - if (final_points_len) { - GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM); - -#ifdef USE_TRANSFORM_FEEDBACK - DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create( - tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf); -#else - DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); - - ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__); - pr_call->next = g_tf_calls; - pr_call->vbo = hair_cache->final[subdiv].proc_buf; - pr_call->shgrp = tf_shgrp; - pr_call->vert_len = final_points_len; - g_tf_calls = pr_call; - DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1); - DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1); - DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1); -#endif - - DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex); - DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex); - DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex); - DRW_shgroup_uniform_int( - tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1); - DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len); - } - } - return shgrp; } @@ -316,7 +343,7 @@ void DRW_hair_update(void) DRW_draw_pass_subset(g_tf_pass, pr_call->shgrp, pr_call->shgrp); /* Readback result to main memory. */ - GPU_framebuffer_read_color(fb, 0, 0, width, height, 4, 0, data); + GPU_framebuffer_read_color(fb, 0, 0, width, height, 4, 0, GPU_DATA_FLOAT, data); /* Upload back to VBO. */ GPU_vertbuf_use(pr_call->vbo); glBufferSubData(GL_ARRAY_BUFFER, diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index e7dff422105..712a93e8880 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -132,11 +132,17 @@ static void drw_task_graph_init(void) { BLI_assert(DST.task_graph == NULL); DST.task_graph = BLI_task_graph_create(); + DST.delayed_extraction = BLI_gset_ptr_new(__func__); } static void drw_task_graph_deinit(void) { BLI_task_graph_work_and_wait(DST.task_graph); + + BLI_gset_free(DST.delayed_extraction, (void (*)(void *key))drw_batch_cache_generate_requested); + DST.delayed_extraction = NULL; + BLI_task_graph_work_and_wait(DST.task_graph); + BLI_task_graph_free(DST.task_graph); DST.task_graph = NULL; } @@ -363,10 +369,12 @@ void DRW_engine_viewport_data_size_get( } /* WARNING: only use for custom pipeline. 99% of the time, you don't want to use this. */ -void DRW_render_viewport_size_set(int size[2]) +void DRW_render_viewport_size_set(const int size[2]) { DST.size[0] = size[0]; DST.size[1] = size[1]; + DST.inv_size[0] = 1.0f / size[0]; + DST.inv_size[1] = 1.0f / size[1]; } const float *DRW_viewport_size_get(void) @@ -1467,6 +1475,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, /* Only iterate over objects for internal engines or when overlays are enabled */ if (do_populate_loop) { + DST.dupli_origin = NULL; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; @@ -1485,6 +1494,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, drw_duplidata_free(); drw_engines_cache_finish(); + drw_task_graph_deinit(); DRW_render_instance_buffer_finish(); #ifdef USE_PROFILE @@ -1493,7 +1503,6 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, #endif } - drw_task_graph_deinit(); DRW_stats_begin(); GPU_framebuffer_bind(DST.default_framebuffer); @@ -1628,13 +1637,6 @@ bool DRW_render_check_grease_pencil(Depsgraph *depsgraph) return false; } -static void drw_view_reset(void) -{ - DST.view_default = NULL; - DST.view_active = NULL; - DST.view_previous = NULL; -} - static void DRW_render_gpencil_to_image(RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect) @@ -1658,24 +1660,8 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph RenderEngineType *engine_type = engine->type; RenderData *r = &scene->r; Render *render = engine->re; - /* Changing Context */ - if (G.background && DST.gl_context == NULL) { - WM_init_opengl(G_MAIN); - } - void *re_gl_context = RE_gl_context_get(render); - void *re_gpu_context = NULL; - - /* Changing Context */ - if (re_gl_context != NULL) { - DRW_opengl_render_context_enable(re_gl_context); - /* We need to query gpu context after a gl context has been bound. */ - re_gpu_context = RE_gpu_context_get(render); - DRW_gpu_render_context_enable(re_gpu_context); - } - else { - DRW_opengl_context_enable(); - } + DRW_render_context_enable(render); /* Reset before using it. */ drw_state_prepare_clean_for_draw(&DST); @@ -1712,7 +1698,7 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph for (RenderView *render_view = render_result->views.first; render_view != NULL; render_view = render_view->next) { RE_SetActiveRenderView(render, render_view->name); - drw_view_reset(); + DRW_view_reset(); DST.buffer_finish_called = false; DRW_render_gpencil_to_image(engine, render_layer, &render_rect); } @@ -1727,14 +1713,7 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph /* Restore Drawing area. */ GPU_framebuffer_restore(); - /* Changing Context */ - if (re_gl_context != NULL) { - DRW_gpu_render_context_disable(re_gpu_context); - DRW_opengl_render_context_disable(re_gl_context); - } - else { - DRW_opengl_context_disable(); - } + DRW_render_context_disable(render); DST.buffer_finish_called = false; } @@ -1747,24 +1726,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) DrawEngineType *draw_engine_type = engine_type->draw_engine; Render *render = engine->re; - if (G.background && DST.gl_context == NULL) { - WM_init_opengl(G_MAIN); - } - - void *re_gl_context = RE_gl_context_get(render); - void *re_gpu_context = NULL; - - /* Changing Context */ - if (re_gl_context != NULL) { - DRW_opengl_render_context_enable(re_gl_context); - /* We need to query gpu context after a gl context has been bound. */ - re_gpu_context = RE_gpu_context_get(render); - DRW_gpu_render_context_enable(re_gpu_context); - } - else { - DRW_opengl_context_enable(); - } - /* IMPORTANT: We don't support immediate mode in render mode! * This shall remain in effect until immediate mode supports * multiple threads. */ @@ -1791,9 +1752,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine_type); - /* set default viewport */ - glViewport(0, 0, size[0], size[1]); - /* Main rendering. */ rctf view_rect; rcti render_rect; @@ -1807,12 +1765,15 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) /* Reset state before drawing */ DRW_state_reset(); + /* set default viewport */ + GPU_viewport(0, 0, size[0], size[1]); + /* Init render result. */ RenderResult *render_result = RE_engine_begin_result(engine, 0, 0, - (int)size[0], - (int)size[1], + size[0], + size[1], view_layer->name, /* RR_ALL_VIEWS */ NULL); @@ -1820,7 +1781,7 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) for (RenderView *render_view = render_result->views.first; render_view != NULL; render_view = render_view->next) { RE_SetActiveRenderView(render, render_view->name); - drw_view_reset(); + DRW_view_reset(); engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect); DST.buffer_finish_called = false; } @@ -1840,15 +1801,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) /* Reset state after drawing */ DRW_state_reset(); - - /* Changing Context */ - if (re_gl_context != NULL) { - DRW_gpu_render_context_disable(re_gpu_context); - DRW_opengl_render_context_disable(re_gl_context); - } - else { - DRW_opengl_context_disable(); - } } void DRW_render_object_iter( @@ -1864,6 +1816,7 @@ void DRW_render_object_iter( const int object_type_exclude_viewport = draw_ctx->v3d ? draw_ctx->v3d->object_type_exclude_viewport : 0; + DST.dupli_origin = NULL; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { if ((object_type_exclude_viewport & (1 << ob->type)) == 0) { DST.dupli_parent = data_.dupli_parent; @@ -1941,6 +1894,28 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, #endif } +/* Used when the render engine want to redo another cache populate inside the same render frame. */ +void DRW_cache_restart(void) +{ + /* Save viewport size. */ + float size[2], inv_size[2]; + copy_v2_v2(size, DST.size); + copy_v2_v2(inv_size, DST.inv_size); + + /* Force cache to reset. */ + drw_viewport_cache_resize(); + + drw_viewport_var_init(); + + DST.buffer_finish_called = false; + + DRW_hair_init(); + + /* Restore. */ + copy_v2_v2(DST.size, size); + copy_v2_v2(DST.inv_size, inv_size); +} + static struct DRWSelectBuffer { struct GPUFrameBuffer *framebuffer_depth_only; struct GPUTexture *texture_depth; @@ -2121,6 +2096,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, const int object_type_exclude_select = (v3d->object_type_exclude_viewport | v3d->object_type_exclude_select); bool filter_exclude = false; + DST.dupli_origin = NULL; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { if (!BKE_object_is_visible_in_viewport(v3d, ob)) { continue; @@ -2271,6 +2247,7 @@ static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph, drw_engines_world_update(DST.draw_ctx.scene); const int object_type_exclude_viewport = v3d->object_type_exclude_viewport; + DST.dupli_origin = NULL; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (DST.draw_ctx.depsgraph, ob) { if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; @@ -2288,9 +2265,9 @@ static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph, drw_duplidata_free(); drw_engines_cache_finish(); + drw_task_graph_deinit(); DRW_render_instance_buffer_finish(); } - drw_task_graph_deinit(); /* Start Drawing */ DRW_state_reset(); @@ -2364,6 +2341,17 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph, void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, const rcti *rect) { + SELECTID_Context *sel_ctx = DRW_select_engine_context_get(); + GPUViewport *viewport = WM_draw_region_get_viewport(region); + if (!viewport) { + /* Selection engine requires a viewport. + * TODO (germano): This should be done internally in the engine. */ + sel_ctx->is_dirty = true; + sel_ctx->objects_drawn_len = 0; + sel_ctx->index_drawn_len = 1; + return; + } + Scene *scene = DEG_get_evaluated_scene(depsgraph); ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); @@ -2384,14 +2372,13 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons drw_context_state_init(); /* Setup viewport */ - DST.viewport = WM_draw_region_get_viewport(region); + DST.viewport = viewport; drw_viewport_var_init(); /* Update ubos */ DRW_globals_update(); /* Init Select Engine */ - struct SELECTID_Context *sel_ctx = DRW_select_engine_context_get(); sel_ctx->last_rect = *rect; use_drw_engine(&draw_engine_select_type); @@ -2407,6 +2394,7 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons drw_engines_cache_finish(); + drw_task_graph_deinit(); #if 0 /* This is a workaround to a nasty bug that seems to be a nasty driver bug. (See T69377) */ DRW_render_instance_buffer_finish(); #else @@ -2415,7 +2403,6 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons drw_resource_buffer_finish(DST.vmempool); #endif } - drw_task_graph_deinit(); /* Start Drawing */ DRW_state_reset(); @@ -2432,12 +2419,6 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons #endif } -/** See #DRW_shgroup_world_clip_planes_from_rv3d. */ -static void draw_world_clip_planes_from_rv3d(GPUBatch *batch, const float world_clip_planes[6][4]) -{ - GPU_batch_uniform_4fv_array(batch, "WorldClipPlanes", 6, world_clip_planes[0]); -} - /** * Clears the Depth Buffer and draws only the specified object. */ @@ -2460,7 +2441,7 @@ void DRW_draw_depth_object( const float(*world_clip_planes)[4] = NULL; if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { - ED_view3d_clipping_set(rv3d); + GPU_clip_distances(6); ED_view3d_clipping_local(rv3d, object->obmat); world_clip_planes = rv3d->clip_local; } @@ -2488,7 +2469,7 @@ void DRW_draw_depth_object( GPU_SHADER_CFG_DEFAULT; GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_DEPTH_ONLY, sh_cfg); if (world_clip_planes != NULL) { - draw_world_clip_planes_from_rv3d(batch, world_clip_planes); + GPU_batch_uniform_4fv_array(batch, "WorldClipPlanes", 6, world_clip_planes[0]); } GPU_batch_draw(batch); @@ -2499,7 +2480,7 @@ void DRW_draw_depth_object( } if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { - ED_view3d_clipping_disable(); + GPU_clip_distances(0); } GPU_matrix_set(rv3d->viewmat); @@ -2732,6 +2713,42 @@ void DRW_engines_free(void) DRW_opengl_context_disable(); } +void DRW_render_context_enable(Render *render) +{ + if (G.background && DST.gl_context == NULL) { + WM_init_opengl(G_MAIN); + } + + void *re_gl_context = RE_gl_context_get(render); + + /* Changing Context */ + if (re_gl_context != NULL) { + DRW_opengl_render_context_enable(re_gl_context); + /* We need to query gpu context after a gl context has been bound. */ + void *re_gpu_context = NULL; + re_gpu_context = RE_gpu_context_get(render); + DRW_gpu_render_context_enable(re_gpu_context); + } + else { + DRW_opengl_context_enable(); + } +} + +void DRW_render_context_disable(Render *render) +{ + void *re_gl_context = RE_gl_context_get(render); + + if (re_gl_context != NULL) { + void *re_gpu_context = NULL; + re_gpu_context = RE_gpu_context_get(render); + DRW_gpu_render_context_disable(re_gpu_context); + DRW_opengl_render_context_disable(re_gl_context); + } + else { + DRW_opengl_context_disable(); + } +} + /** \} */ /** \name Init/Exit (DRW_opengl_ctx) @@ -2872,8 +2889,8 @@ void DRW_gpu_render_context_disable(void *UNUSED(re_gpu_context)) * switch to it just to submit the final frame, which has notable performance impact. * * We could "inject" a context through DRW_opengl_render_context_enable(), but that would have to - * work from the main thread, which is tricky to get working too. The preferable solution would be - * using a separate thread for VR drawing where a single context can stay active. */ + * work from the main thread, which is tricky to get working too. The preferable solution would + * be using a separate thread for VR drawing where a single context can stay active. */ void *DRW_xr_opengl_context_get(void) { return DST.gl_context; diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index 6cae2a4f9f6..a448a94185a 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -380,6 +380,7 @@ typedef struct DRWViewUboStorage { float wininv[4][4]; float clipplanes[6][4]; + float viewvecs[2][4]; /* Should not be here. Not view dependent (only main view). */ float viewcamtexcofac[4]; } DRWViewUboStorage; @@ -548,6 +549,8 @@ typedef struct DRWManager { #endif struct TaskGraph *task_graph; + /* Contains list of objects that needs to be extracted from other objects. */ + struct GSet *delayed_extraction; /* ---------- Nothing after this point is cleared after use ----------- */ @@ -581,10 +584,11 @@ void drw_state_set(DRWState state); void drw_debug_draw(void); void drw_debug_init(void); -eDRWCommandType command_type_get(uint64_t *command_type_bits, int index); +eDRWCommandType command_type_get(const uint64_t *command_type_bits, int index); void drw_batch_cache_validate(Object *ob); void drw_batch_cache_generate_requested(struct Object *ob); +void drw_batch_cache_generate_requested_delayed(Object *ob); void drw_resource_buffer_finish(ViewportMemoryPool *vmempool); diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 07fb97236fb..3184d6155d2 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -76,7 +76,7 @@ static void draw_call_sort(DRWCommand *array, DRWCommand *array_tmp, int array_l for (int i = 1; i < ARRAY_SIZE(idx); i++) { idx[i] += idx[i - 1]; } - /* Traverse in reverse to not change the order of the resource ids. */ + /* Traverse in reverse to not change the order of the resource ID's. */ for (int src = array_len - 1; src >= 0; src--) { array_tmp[--idx[KEY(array[src])]] = array[src]; } @@ -116,7 +116,7 @@ void drw_resource_buffer_finish(ViewportMemoryPool *vmempool) vmempool->ubo_len = ubo_len; } - /* Remove unecessary buffers */ + /* Remove unnecessary buffers */ for (int i = ubo_len; i < vmempool->ubo_len; i++) { GPU_uniformbuffer_free(vmempool->matrices_ubo[i]); GPU_uniformbuffer_free(vmempool->obinfos_ubo[i]); @@ -151,7 +151,7 @@ void drw_resource_buffer_finish(ViewportMemoryPool *vmempool) BLI_memblock_iternew(vmempool->commands, &iter); while ((chunk = BLI_memblock_iterstep(&iter))) { bool sortable = true; - /* We can only sort chunks that contain DRWCommandDraw only. */ + /* We can only sort chunks that contain #DRWCommandDraw only. */ for (int i = 0; i < ARRAY_SIZE(chunk->command_type) && sortable; i++) { if (chunk->command_type[i] != 0) { sortable = false; @@ -179,7 +179,7 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, int arraysize) { if (loc == -1) { - /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ + /* Nice to enable eventually, for now EEVEE uses uniforms that might not exist. */ // BLI_assert(0); return; } @@ -262,11 +262,19 @@ void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, con DRW_shgroup_uniform_texture_ex(shgroup, name, tex, GPU_SAMPLER_MAX); } -void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) +void DRW_shgroup_uniform_texture_ref_ex(DRWShadingGroup *shgroup, + const char *name, + GPUTexture **tex, + eGPUSamplerState sampler_state) { BLI_assert(tex != NULL); int loc = GPU_shader_get_texture_binding(shgroup->shader, name); - drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE_REF, tex, GPU_SAMPLER_MAX, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE_REF, tex, sampler_state, 0, 1); +} + +void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) +{ + DRW_shgroup_uniform_texture_ref_ex(shgroup, name, tex, GPU_SAMPLER_MAX); } void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, @@ -424,7 +432,7 @@ void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, int location = GPU_shader_get_uniform(shgroup->shader, name); if (location == -1) { - /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ + /* Nice to enable eventually, for now EEVEE uses uniforms that might not exist. */ // BLI_assert(0); return; } @@ -530,6 +538,11 @@ static void drw_call_culling_init(DRWCullingState *cull, Object *ob) mul_v3_m4v3(corner, ob->obmat, bbox->vec[0]); mul_m4_v3(ob->obmat, cull->bsphere.center); cull->bsphere.radius = len_v3v3(cull->bsphere.center, corner); + + /* Bypass test for very large objects (see T67319). */ + if (UNLIKELY(cull->bsphere.radius > 1e12)) { + cull->bsphere.radius = -1.0f; + } } else { /* Bypass test. */ @@ -569,7 +582,7 @@ uint32_t DRW_object_resource_id_get(Object *UNUSED(ob)) /* Handle not yet allocated. Return next handle. */ handle = DST.resource_handle; } - return handle; + return handle & ~(1 << 31); } static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup, @@ -610,7 +623,7 @@ static void command_type_set(uint64_t *command_type_bits, int index, eDRWCommand command_type_bits[index / 16] |= ((uint64_t)type) << ((index % 16) * 4); } -eDRWCommandType command_type_get(uint64_t *command_type_bits, int index) +eDRWCommandType command_type_get(const uint64_t *command_type_bits, int index) { return ((command_type_bits[index / 16] >> ((index % 16) * 4)) & 0xF); } @@ -780,10 +793,10 @@ void DRW_shgroup_call_range( drw_command_draw_range(shgroup, geom, handle, v_sta, v_ct); } +/* A count of 0 instance will use the default number of instance in the batch. */ void DRW_shgroup_call_instance_range( DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct) { - BLI_assert(i_ct > 0); BLI_assert(geom != NULL); if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, NULL, DST.select_id); @@ -1279,13 +1292,10 @@ static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass } static void drw_shgroup_material_texture(DRWShadingGroup *grp, - GPUMaterialTexture *tex, + GPUTexture *gputex, const char *name, - eGPUSamplerState state, - int textarget) + eGPUSamplerState state) { - GPUTexture *gputex = GPU_texture_from_blender(tex->ima, tex->iuser, NULL, textarget); - DRW_shgroup_uniform_texture_ex(grp, name, gputex, state); GPUTexture **gputex_ref = BLI_memblock_alloc(DST.vmempool->images); @@ -1301,15 +1311,16 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial LISTBASE_FOREACH (GPUMaterialTexture *, tex, &textures) { if (tex->ima) { /* Image */ + GPUTexture *gputex; if (tex->tiled_mapping_name[0]) { - drw_shgroup_material_texture( - grp, tex, tex->sampler_name, tex->sampler_state, GL_TEXTURE_2D_ARRAY); - drw_shgroup_material_texture( - grp, tex, tex->tiled_mapping_name, tex->sampler_state, GL_TEXTURE_1D_ARRAY); + gputex = BKE_image_get_gpu_tiles(tex->ima, tex->iuser, NULL); + drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state); + gputex = BKE_image_get_gpu_tilemap(tex->ima, tex->iuser, NULL); + drw_shgroup_material_texture(grp, gputex, tex->tiled_mapping_name, tex->sampler_state); } else { - drw_shgroup_material_texture( - grp, tex, tex->sampler_name, tex->sampler_state, GL_TEXTURE_2D); + gputex = BKE_image_get_gpu_texture(tex->ima, tex->iuser, NULL); + drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state); } } else if (tex->colorband) { @@ -1643,6 +1654,52 @@ static void draw_view_matrix_state_update(DRWViewUboStorage *storage, mul_m4_m4m4(storage->persmat, winmat, viewmat); invert_m4_m4(storage->persinv, storage->persmat); + + const bool is_persp = (winmat[3][3] == 0.0f); + + /* Near clip distance. */ + storage->viewvecs[0][3] = (is_persp) ? -winmat[3][2] / (winmat[2][2] - 1.0f) : + -(winmat[3][2] + 1.0f) / winmat[2][2]; + + /* Far clip distance. */ + storage->viewvecs[1][3] = (is_persp) ? -winmat[3][2] / (winmat[2][2] + 1.0f) : + -(winmat[3][2] - 1.0f) / winmat[2][2]; + + /* view vectors for the corners of the view frustum. + * Can be used to recreate the world space position easily */ + float view_vecs[4][3] = { + {-1.0f, -1.0f, -1.0f}, + {1.0f, -1.0f, -1.0f}, + {-1.0f, 1.0f, -1.0f}, + {-1.0f, -1.0f, 1.0f}, + }; + + /* convert the view vectors to view space */ + for (int i = 0; i < 4; i++) { + mul_project_m4_v3(storage->wininv, view_vecs[i]); + /* normalized trick see: + * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ + if (is_persp) { + /* Divide XY by Z. */ + mul_v2_fl(view_vecs[i], 1.0f / view_vecs[i][2]); + } + } + + /** + * If ortho : view_vecs[0] is the near-bottom-left corner of the frustum and + * view_vecs[1] is the vector going from the near-bottom-left corner to + * the far-top-right corner. + * If Persp : view_vecs[0].xy and view_vecs[1].xy are respectively the bottom-left corner + * when Z = 1, and top-left corner if Z = 1. + * view_vecs[0].z the near clip distance and view_vecs[1].z is the (signed) + * distance from the near plane to the far clip plane. + */ + copy_v3_v3(storage->viewvecs[0], view_vecs[0]); + + /* we need to store the differences */ + storage->viewvecs[1][0] = view_vecs[1][0] - view_vecs[0][0]; + storage->viewvecs[1][1] = view_vecs[2][1] - view_vecs[0][1]; + storage->viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2]; } /* Create a view with culling. */ @@ -1786,6 +1843,14 @@ const DRWView *DRW_view_default_get(void) return DST.view_default; } +/* WARNING: Only use in render AND only if you are going to set view_default again. */ +void DRW_view_reset(void) +{ + DST.view_default = NULL; + DST.view_active = NULL; + DST.view_previous = NULL; +} + /* MUST only be called once per render and only in render mode. Sets default view. */ void DRW_view_default_set(DRWView *view) { diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 59b4e9af14e..91cbc03e5a4 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -98,12 +98,7 @@ void drw_state_set(DRWState state) { int test; if ((test = CHANGED_TO(DRW_STATE_WRITE_DEPTH))) { - if (test == 1) { - glDepthMask(GL_TRUE); - } - else { - glDepthMask(GL_FALSE); - } + GPU_depth_mask(test == 1); } } @@ -142,10 +137,10 @@ void drw_state_set(DRWState state) int test; if ((test = CHANGED_TO(DRW_STATE_WRITE_COLOR))) { if (test == 1) { - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + GPU_color_mask(true, true, true, true); } else { - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + GPU_color_mask(false, false, false, false); } } } @@ -355,14 +350,10 @@ void drw_state_set(DRWState state) int test; if ((test = CHANGED_TO(DRW_STATE_CLIP_PLANES))) { if (test == 1) { - for (int i = 0; i < DST.view_active->clip_planes_len; i++) { - glEnable(GL_CLIP_DISTANCE0 + i); - } + GPU_clip_distances(DST.view_active->clip_planes_len); } else { - for (int i = 0; i < MAX_CLIP_PLANES; i++) { - glDisable(GL_CLIP_DISTANCE0 + i); - } + GPU_clip_distances(0); } } } @@ -455,6 +446,7 @@ void DRW_state_reset(void) DRW_state_reset_ex(DRW_STATE_DEFAULT); GPU_texture_unbind_all(); + GPU_uniformbuffer_unbind_all(); /* Should stay constant during the whole rendering. */ GPU_point_size(5); @@ -678,8 +670,7 @@ BLI_INLINE void draw_geometry_bind(DRWShadingGroup *shgroup, GPUBatch *geom) DST.batch = geom; - GPU_batch_program_set_no_use( - geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader)); + GPU_batch_set_shader_no_bind(geom, shgroup->shader); geom->program_in_use = true; /* XXX hacking #GPUBatch */ @@ -782,10 +773,11 @@ static bool ubo_bindings_validate(DRWShadingGroup *shgroup) DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes, &shgroup->pass_handle); - printf("Pass : %s, Shader : %s, Block : %s\n", + printf("Pass : %s, Shader : %s, Block : %s, Binding %d\n", parent_pass->name, shgroup->shader->name, - blockname); + blockname, + binding); } } # endif @@ -1115,6 +1107,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) /* Unbinding can be costly. Skip in normal condition. */ if (G.debug & G_DEBUG_GPU) { GPU_texture_unbind_all(); + GPU_uniformbuffer_unbind_all(); } } GPU_shader_bind(shgroup->shader); diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 6304b707cb9..fec234c5015 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -91,10 +91,13 @@ static void drw_deferred_shader_queue_free(ListBase *queue) } } -static void drw_deferred_shader_compilation_exec(void *custom_data, - short *stop, - short *do_update, - float *progress) +static void drw_deferred_shader_compilation_exec( + void *custom_data, + /* Cannot be const, this function implements wm_jobs_start_callback. + * NOLINTNEXTLINE: readability-non-const-parameter. */ + short *stop, + short *do_update, + float *progress) { DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data; void *gl_context = comp->gl_context; @@ -325,6 +328,26 @@ GPUShader *DRW_shader_create_with_lib( return sh; } +GPUShader *DRW_shader_create_with_shaderlib(const char *vert, + const char *geom, + const char *frag, + const DRWShaderLibrary *lib, + const char *defines) +{ + GPUShader *sh; + char *vert_with_lib = DRW_shader_library_create_shader_string(lib, vert); + char *frag_with_lib = DRW_shader_library_create_shader_string(lib, frag); + char *geom_with_lib = (geom) ? DRW_shader_library_create_shader_string(lib, geom) : NULL; + + sh = GPU_shader_create(vert_with_lib, frag_with_lib, geom_with_lib, NULL, defines, __func__); + + MEM_SAFE_FREE(vert_with_lib); + MEM_SAFE_FREE(frag_with_lib); + MEM_SAFE_FREE(geom_with_lib); + + return sh; +} + GPUShader *DRW_shader_create_with_transform_feedback(const char *vert, const char *geom, const char *defines, @@ -349,6 +372,22 @@ GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines) datatoc_common_fullscreen_vert_glsl, frag, NULL, NULL, defines, __func__); } +GPUShader *DRW_shader_create_fullscreen_with_shaderlib(const char *frag, + const DRWShaderLibrary *lib, + const char *defines) +{ + + GPUShader *sh; + char *vert = datatoc_common_fullscreen_vert_glsl; + char *frag_with_lib = DRW_shader_library_create_shader_string(lib, frag); + + sh = GPU_shader_create(vert, frag_with_lib, NULL, NULL, defines, __func__); + + MEM_SAFE_FREE(frag_with_lib); + + return sh; +} + GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, const int options, @@ -391,7 +430,8 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, const char *geom, const char *frag_lib, const char *defines, - bool deferred) + bool deferred, + GPUMaterialEvalCallbackFn callback) { GPUMaterial *mat = NULL; if (DRW_state_is_image_render() || !deferred) { @@ -411,7 +451,8 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, geom, frag_lib, defines, - wo->id.name); + wo->id.name, + callback); } if (GPU_material_status(mat) == GPU_MAT_QUEUED) { @@ -431,7 +472,8 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, const char *geom, const char *frag_lib, const char *defines, - bool deferred) + bool deferred, + GPUMaterialEvalCallbackFn callback) { GPUMaterial *mat = NULL; if (DRW_state_is_image_render() || !deferred) { @@ -451,7 +493,8 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, geom, frag_lib, defines, - ma->id.name); + ma->id.name, + callback); } if (GPU_material_status(mat) == GPU_MAT_QUEUED) { @@ -502,7 +545,7 @@ void DRW_shader_library_free(DRWShaderLibrary *lib) MEM_SAFE_FREE(lib); } -static int drw_shader_library_search(DRWShaderLibrary *lib, const char *name) +static int drw_shader_library_search(const DRWShaderLibrary *lib, const char *name) { for (int i = 0; i < MAX_LIB; i++) { if (lib->libs[i]) { @@ -518,18 +561,28 @@ static int drw_shader_library_search(DRWShaderLibrary *lib, const char *name) } /* Return bitmap of dependencies. */ -static uint32_t drw_shader_dependencies_get(DRWShaderLibrary *lib, char *lib_code) +static uint32_t drw_shader_dependencies_get(const DRWShaderLibrary *lib, const char *lib_code) { /* Search dependencies. */ uint32_t deps = 0; - char *haystack = lib_code; + const char *haystack = lib_code; while ((haystack = strstr(haystack, "BLENDER_REQUIRE("))) { haystack += 16; int dep = drw_shader_library_search(lib, haystack); if (dep == -1) { + char dbg_name[32]; + int i = 0; + while ((haystack[0] != ')') && (i < 31)) { + dbg_name[i] = haystack[0]; + haystack++; + i++; + } + dbg_name[i + 1] = '\0'; + printf( - "Error: Dependency not found.\n" - "This might be due to bad lib ordering.\n"); + "Error: Dependency not found: %s\n" + "This might be due to bad lib ordering.\n", + dbg_name); BLI_assert(0); } else { @@ -562,7 +615,7 @@ void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const ch /* Return an allocN'ed string containing the shader code with its dependencies prepended. * Caller must free the string with MEM_freeN after use. */ -char *DRW_shader_library_create_shader_string(DRWShaderLibrary *lib, char *shader_code) +char *DRW_shader_library_create_shader_string(const DRWShaderLibrary *lib, const char *shader_code) { uint32_t deps = drw_shader_dependencies_get(lib, shader_code); diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c index f4601fe4f48..b3c4c97715e 100644 --- a/source/blender/draw/intern/draw_manager_text.c +++ b/source/blender/draw/intern/draw_manager_text.c @@ -38,6 +38,7 @@ #include "DNA_view3d_types.h" #include "GPU_matrix.h" +#include "GPU_state.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -149,8 +150,9 @@ void DRW_text_cache_draw(DRWTextStore *dt, ARegion *region, struct View3D *v3d) if (tot) { int col_pack_prev = 0; + /* Disable clipping for text */ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { - ED_view3d_clipping_disable(); + GPU_clip_distances(0); } float original_proj[4][4]; @@ -188,7 +190,7 @@ void DRW_text_cache_draw(DRWTextStore *dt, ARegion *region, struct View3D *v3d) GPU_matrix_projection_set(original_proj); if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { - ED_view3d_clipping_enable(); + GPU_clip_distances(6); } } } diff --git a/source/blender/draw/intern/draw_select_buffer.c b/source/blender/draw/intern/draw_select_buffer.c index 81c9f400f6e..ee5561e1e38 100644 --- a/source/blender/draw/intern/draw_select_buffer.c +++ b/source/blender/draw/intern/draw_select_buffer.c @@ -84,14 +84,15 @@ uint *DRW_select_buffer_read(struct Depsgraph *depsgraph, GPUFrameBuffer *select_id_fb = DRW_engine_select_framebuffer_get(); GPU_framebuffer_bind(select_id_fb); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glReadPixels(rect_clamp.xmin, - rect_clamp.ymin, - BLI_rcti_size_x(&rect_clamp), - BLI_rcti_size_y(&rect_clamp), - GL_RED_INTEGER, - GL_UNSIGNED_INT, - r_buf); + GPU_framebuffer_read_color(select_id_fb, + rect_clamp.xmin, + rect_clamp.ymin, + BLI_rcti_size_x(&rect_clamp), + BLI_rcti_size_y(&rect_clamp), + 1, + 0, + GPU_DATA_UNSIGNED_INT, + r_buf); if (!BLI_rcti_compare(rect, &rect_clamp)) { /* The rect has been clamped so you need to realign the buffer and fill in the blanks */ @@ -122,7 +123,6 @@ uint *DRW_select_buffer_read(struct Depsgraph *depsgraph, /** * \param rect: The rectangle to sample indices from (min/max inclusive). - * \param mask: Specifies the rect pixels (optional). * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure. */ uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph, @@ -165,10 +165,10 @@ uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph, } /** - * \param bitmap_len: Number of indices in the selection id buffer. * \param center: Circle center. * \param radius: Circle radius. - * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure. + * \param r_bitmap_len: Number of indices in the selection id buffer. + * \returns a #BLI_bitmap the length of \a r_bitmap_len or NULL on failure. */ uint *DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph, struct ARegion *region, @@ -338,7 +338,7 @@ uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph, /** * Find the selection id closest to \a center. - * \param dist[in,out]: Use to initialize the distance, + * \param dist: Use to initialize the distance, * when found, this value is set to the distance of the selection that's returned. */ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, @@ -395,7 +395,7 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, int center_x = width / 2; int center_y = height / 2; - /* Manhatten distance in keeping with other screen-based selection. */ + /* Manhattan distance in keeping with other screen-based selection. */ *dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y)); /* Indices start at 1 here. */ diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c index 06026d51faf..b42700b2c7e 100644 --- a/source/blender/draw/intern/draw_view.c +++ b/source/blender/draw/intern/draw_view.c @@ -103,9 +103,9 @@ void DRW_draw_cursor(void) Scene *scene = draw_ctx->scene; ViewLayer *view_layer = draw_ctx->view_layer; - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); + GPU_color_mask(true, true, true, true); + GPU_depth_mask(false); + GPU_depth_test(false); if (is_cursor_visible(draw_ctx, scene, view_layer)) { int co[2]; @@ -184,8 +184,7 @@ void DRW_draw_cursor(void) GPUBatch *cursor_batch = DRW_cache_cursor_get(is_aligned); GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_FLAT_COLOR); - GPU_batch_program_set( - cursor_batch, GPU_shader_get_program(shader), GPU_shader_get_interface(shader)); + GPU_batch_set_shader(cursor_batch, shader); GPU_batch_draw(cursor_batch); @@ -217,5 +216,5 @@ void DRW_draw_gizmo_2d(void) WM_gizmomap_draw(region->gizmo_map, draw_ctx->evil_C, WM_GIZMOMAP_DRAWSTEP_2D); - glDepthMask(GL_TRUE); + GPU_depth_mask(true); } diff --git a/source/blender/draw/intern/shaders/common_globals_lib.glsl b/source/blender/draw/intern/shaders/common_globals_lib.glsl index a479a87e14b..40a527a6ba4 100644 --- a/source/blender/draw/intern/shaders/common_globals_lib.glsl +++ b/source/blender/draw/intern/shaders/common_globals_lib.glsl @@ -123,6 +123,8 @@ layout(std140) uniform globalsBlock #define sizeViewportInv (sizeViewport.zw) +/* See: 'draw_cache_impl.h' for matching includes. */ + /* data[0] (1st byte flags) */ #define FACE_ACTIVE (1 << 0) #define FACE_SELECTED (1 << 1) @@ -135,9 +137,9 @@ layout(std140) uniform globalsBlock /* data[1] (2st byte flags) */ #define VERT_ACTIVE (1 << 0) #define VERT_SELECTED (1 << 1) -#define EDGE_ACTIVE (1 << 2) -#define EDGE_SELECTED (1 << 3) -#define EDGE_SEAM (1 << 4) -#define EDGE_SHARP (1 << 5) -#define EDGE_FREESTYLE (1 << 6) -#define HANDLE_SELECTED (1 << 7) +#define VERT_SELECTED_BEZT_HANDLE (1 << 2) +#define EDGE_ACTIVE (1 << 3) +#define EDGE_SELECTED (1 << 4) +#define EDGE_SEAM (1 << 5) +#define EDGE_SHARP (1 << 6) +#define EDGE_FREESTYLE (1 << 7) diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl index ffff631e34b..8684d82f228 100644 --- a/source/blender/draw/intern/shaders/common_hair_lib.glsl +++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl @@ -95,7 +95,7 @@ void hair_get_interp_attrs( * For final drawing, the vertex index and the number of vertex per segment */ -#ifndef HAIR_PHASE_SUBDIV +#if !defined(HAIR_PHASE_SUBDIV) && defined(GPU_VERTEX_SHADER) int hair_get_strand_id(void) { return gl_VertexID / (hairStrandsRes * hairThicknessRes); @@ -206,4 +206,24 @@ vec3 hair_get_strand_pos(void) return texelFetch(hairPointBuffer, id).point_position; } +vec2 hair_get_barycentric(void) +{ + /* To match cycles without breaking into individual segment we encode if we need to invert + * the first component into the second component. We invert if the barycentricTexCo.y + * is NOT 0.0 or 1.0. */ + int id = hair_get_base_id(); + return vec2(float((id % 2) == 1), float(((id % 4) % 3) > 0)); +} + #endif + +/* To be fed the result of hair_get_barycentric from vertex shader. */ +vec2 hair_resolve_barycentric(vec2 vert_barycentric) +{ + if (fract(vert_barycentric.y) != 0.0) { + return vec2(vert_barycentric.x, 0.0); + } + else { + return vec2(1.0 - vert_barycentric.x, 0.0); + } +} diff --git a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl new file mode 100644 index 00000000000..e337376d7c4 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl @@ -0,0 +1,119 @@ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + +/* ---------------------------------------------------------------------- */ +/** \name Math intersection & projection functions. + * \{ */ + +float point_plane_projection_dist(vec3 lineorigin, vec3 planeorigin, vec3 planenormal) +{ + return dot(planenormal, planeorigin - lineorigin); +} + +float line_plane_intersect_dist(vec3 lineorigin, + vec3 linedirection, + vec3 planeorigin, + vec3 planenormal) +{ + return dot(planenormal, planeorigin - lineorigin) / dot(planenormal, linedirection); +} + +float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec4 plane) +{ + vec3 plane_co = plane.xyz * (-plane.w / len_squared(plane.xyz)); + vec3 h = lineorigin - plane_co; + return -dot(plane.xyz, h) / dot(plane.xyz, linedirection); +} + +vec3 line_plane_intersect(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal) +{ + float dist = line_plane_intersect_dist(lineorigin, linedirection, planeorigin, planenormal); + return lineorigin + linedirection * dist; +} + +vec3 line_plane_intersect(vec3 lineorigin, vec3 linedirection, vec4 plane) +{ + float dist = line_plane_intersect_dist(lineorigin, linedirection, plane); + return lineorigin + linedirection * dist; +} + +float line_aligned_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin) +{ + /* aligned plane normal */ + vec3 L = planeorigin - lineorigin; + float diskdist = length(L); + vec3 planenormal = -normalize(L); + return -diskdist / dot(planenormal, linedirection); +} + +vec3 line_aligned_plane_intersect(vec3 lineorigin, vec3 linedirection, vec3 planeorigin) +{ + float dist = line_aligned_plane_intersect_dist(lineorigin, linedirection, planeorigin); + if (dist < 0) { + /* if intersection is behind we fake the intersection to be + * really far and (hopefully) not inside the radius of interest */ + dist = 1e16; + } + return lineorigin + linedirection * dist; +} + +float line_unit_sphere_intersect_dist(vec3 lineorigin, vec3 linedirection) +{ + float a = dot(linedirection, linedirection); + float b = dot(linedirection, lineorigin); + float c = dot(lineorigin, lineorigin) - 1; + + float dist = 1e15; + float determinant = b * b - a * c; + if (determinant >= 0) { + dist = (sqrt(determinant) - b) / a; + } + + return dist; +} + +float line_unit_box_intersect_dist(vec3 lineorigin, vec3 linedirection) +{ + /* https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ + */ + vec3 firstplane = (vec3(1.0) - lineorigin) / linedirection; + vec3 secondplane = (vec3(-1.0) - lineorigin) / linedirection; + vec3 furthestplane = max(firstplane, secondplane); + + return min_v3(furthestplane); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Other useful functions. + * \{ */ + +void make_orthonormal_basis(vec3 N, out vec3 T, out vec3 B) +{ + vec3 UpVector = abs(N.z) < 0.99999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + T = normalize(cross(UpVector, N)); + B = cross(N, T); +} + +/* ---- Encode / Decode Normal buffer data ---- */ +/* From http://aras-p.info/texts/CompactNormalStorage.html + * Using Method #4: Spheremap Transform */ +vec2 normal_encode(vec3 n, vec3 view) +{ + float p = sqrt(n.z * 8.0 + 8.0); + return n.xy / p + 0.5; +} + +vec3 normal_decode(vec2 enc, vec3 view) +{ + vec2 fenc = enc * 4.0 - 2.0; + float f = dot(fenc, fenc); + float g = sqrt(1.0 - f / 4.0); + vec3 n; + n.xy = fenc * g; + n.z = 1 - f / 2; + return n; +} + +/** \} */
\ No newline at end of file diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl new file mode 100644 index 00000000000..a82e0b5a5e9 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_math_lib.glsl @@ -0,0 +1,130 @@ + +/* ---------------------------------------------------------------------- */ +/** \name Common Math Utilities + * \{ */ + +#define M_PI 3.14159265358979323846 /* pi */ +#define M_2PI 6.28318530717958647692 /* 2*pi */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#define M_1_PI 0.318309886183790671538 /* 1/pi */ +#define M_1_2PI 0.159154943091895335768 /* 1/(2*pi) */ +#define M_1_PI2 0.101321183642337771443 /* 1/(pi^2) */ +#define FLT_MAX 3.402823e+38 + +vec3 mul(mat3 m, vec3 v) +{ + return m * v; +} +mat3 mul(mat3 m1, mat3 m2) +{ + return m1 * m2; +} +vec3 transform_direction(mat4 m, vec3 v) +{ + return mat3(m) * v; +} +vec3 transform_point(mat4 m, vec3 v) +{ + return (m * vec4(v, 1.0)).xyz; +} +vec3 project_point(mat4 m, vec3 v) +{ + vec4 tmp = m * vec4(v, 1.0); + return tmp.xyz / tmp.w; +} + +#define min3(a, b, c) min(a, min(b, c)) +#define min4(a, b, c, d) min(a, min3(b, c, d)) +#define min5(a, b, c, d, e) min(a, min4(b, c, d, e)) +#define min6(a, b, c, d, e, f) min(a, min5(b, c, d, e, f)) +#define min7(a, b, c, d, e, f, g) min(a, min6(b, c, d, e, f, g)) +#define min8(a, b, c, d, e, f, g, h) min(a, min7(b, c, d, e, f, g, h)) +#define min9(a, b, c, d, e, f, g, h, i) min(a, min8(b, c, d, e, f, g, h, i)) + +#define max3(a, b, c) max(a, max(b, c)) +#define max4(a, b, c, d) max(a, max3(b, c, d)) +#define max5(a, b, c, d, e) max(a, max4(b, c, d, e)) +#define max6(a, b, c, d, e, f) max(a, max5(b, c, d, e, f)) +#define max7(a, b, c, d, e, f, g) max(a, max6(b, c, d, e, f, g)) +#define max8(a, b, c, d, e, f, g, h) max(a, max7(b, c, d, e, f, g, h)) +#define max9(a, b, c, d, e, f, g, h, i) max(a, max8(b, c, d, e, f, g, h, i)) + +#define avg3(a, b, c) (a + b + c) * (1.0 / 3.0) +#define avg4(a, b, c, d) (a + b + c + d) * (1.0 / 4.0) +#define avg5(a, b, c, d, e) (a + b + c + d + e) * (1.0 / 5.0) +#define avg6(a, b, c, d, e, f) (a + b + c + d + e + f) * (1.0 / 6.0) +#define avg7(a, b, c, d, e, f, g) (a + b + c + d + e + f + g) * (1.0 / 7.0) +#define avg8(a, b, c, d, e, f, g, h) (a + b + c + d + e + f + g + h) * (1.0 / 8.0) +#define avg9(a, b, c, d, e, f, g, h, i) (a + b + c + d + e + f + g + h + i) * (1.0 / 9.0) + +/* clang-format off */ +float min_v2(vec2 v) { return min(v.x, v.y); } +float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); } +float min_v4(vec4 v) { return min(min(v.x, v.y), min(v.z, v.w)); } +float max_v2(vec2 v) { return max(v.x, v.y); } +float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); } +float max_v4(vec4 v) { return max(max(v.x, v.y), max(v.z, v.w)); } + +float sum(vec2 v) { return dot(vec2(1.0), v); } +float sum(vec3 v) { return dot(vec3(1.0), v); } +float sum(vec4 v) { return dot(vec4(1.0), v); } + +float avg(vec2 v) { return dot(vec2(1.0 / 2.0), v); } +float avg(vec3 v) { return dot(vec3(1.0 / 3.0), v); } +float avg(vec4 v) { return dot(vec4(1.0 / 4.0), v); } +/* clang-format on */ + +#define saturate(a) clamp(a, 0.0, 1.0) + +float distance_squared(vec2 a, vec2 b) +{ + a -= b; + return dot(a, a); +} + +float distance_squared(vec3 a, vec3 b) +{ + a -= b; + return dot(a, a); +} + +float len_squared(vec3 a) +{ + return dot(a, a); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Fast Math + * \{ */ + +/* [Drobot2014a] Low Level Optimizations for GCN */ +float fast_sqrt(float v) +{ + return intBitsToFloat(0x1fbd1df5 + (floatBitsToInt(v) >> 1)); +} + +vec2 fast_sqrt(vec2 v) +{ + return intBitsToFloat(0x1fbd1df5 + (floatBitsToInt(v) >> 1)); +} + +/* [Eberly2014] GPGPU Programming for Games and Science */ +float fast_acos(float v) +{ + float res = -0.156583 * abs(v) + M_PI_2; + res *= fast_sqrt(1.0 - abs(v)); + return (v >= 0) ? res : M_PI - res; +} + +vec2 fast_acos(vec2 v) +{ + vec2 res = -0.156583 * abs(v) + M_PI_2; + res *= fast_sqrt(1.0 - abs(v)); + v.x = (v.x >= 0) ? res.x : M_PI - res.x; + v.y = (v.y >= 0) ? res.y : M_PI - res.y; + return v; +} + +/** \} */ diff --git a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl new file mode 100644 index 00000000000..36b67f2bd60 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl @@ -0,0 +1,39 @@ + +/* NOTE: To be used with UNIFORM_RESOURCE_ID and INSTANCED_ATTR as define. */ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +in vec4 pos; /* Position and radius. */ + +/* ---- Instanced attribs ---- */ + +in vec3 pos_inst; +in vec3 nor; + +mat3 pointcloud_get_facing_matrix(vec3 p) +{ + mat3 facing_mat; + facing_mat[2] = normalize(ViewMatrixInverse[3].xyz - p); + facing_mat[1] = normalize(cross(ViewMatrixInverse[0].xyz, facing_mat[2])); + facing_mat[0] = cross(facing_mat[1], facing_mat[2]); + return facing_mat; +} + +/* Return world position and normal. */ +void pointcloud_get_pos_and_nor(out vec3 outpos, out vec3 outnor) +{ + vec3 p = point_object_to_world(pos.xyz); + mat3 facing_mat = pointcloud_get_facing_matrix(p); + + float radius = dot(abs(mat3(ModelMatrix) * pos.www), vec3(1.0 / 3.0)); + /* TODO(fclem) remove multiplication here. Here only for keeping the size correct for now. */ + radius *= 0.01; + outpos = p + (facing_mat * pos_inst) * radius; + outnor = facing_mat * nor; +} + +vec3 pointcloud_get_pos(void) +{ + vec3 outpos, outnor; + pointcloud_get_pos_and_nor(outpos, outnor); + return outpos; +}
\ No newline at end of file diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl index 1054f4d11c9..a55d2cd8c1a 100644 --- a/source/blender/draw/intern/shaders/common_view_lib.glsl +++ b/source/blender/draw/intern/shaders/common_view_lib.glsl @@ -14,10 +14,24 @@ layout(std140) uniform viewBlock vec4 clipPlanes[6]; + /* View frustum corners [NDC(-1.0, -1.0, -1.0) & NDC(1.0, 1.0, 1.0)]. + * Fourth components are near and far values. */ + vec4 ViewVecs[2]; + /* TODO move it elsewhere. */ vec4 CameraTexCoFactors; }; +#define ViewNear (ViewVecs[0].w) +#define ViewFar (ViewVecs[1].w) + +#define cameraForward ViewMatrixInverse[2].xyz +#define cameraPos ViewMatrixInverse[3].xyz +#define cameraVec \ + ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - worldPosition) : cameraForward) +#define viewCameraVec \ + ((ProjectionMatrix[3][3] == 0.0) ? normalize(-viewPosition) : vec3(0.0, 0.0, 1.0)) + #ifdef world_clip_planes_calc_clip_distance # undef world_clip_planes_calc_clip_distance # define world_clip_planes_calc_clip_distance(p) \ @@ -100,10 +114,13 @@ uniform int resourceId; /* Use this to declare and pass the value if * the fragment shader uses the resource_id. */ -# define RESOURCE_ID_VARYING flat out int resourceIDFrag; -# define RESOURCE_ID_VARYING_GEOM flat out int resourceIDGeom; -# define PASS_RESOURCE_ID resourceIDFrag = resource_id; -# define PASS_RESOURCE_ID_GEOM resourceIDGeom = resource_id; +# ifdef USE_GEOMETRY_SHADER +# define RESOURCE_ID_VARYING flat out int resourceIDGeom; +# define PASS_RESOURCE_ID resourceIDGeom = resource_id; +# else +# define RESOURCE_ID_VARYING flat out int resourceIDFrag; +# define PASS_RESOURCE_ID resourceIDFrag = resource_id; +# endif #endif /* If used in a fragment / geometry shader, we pass @@ -114,7 +131,7 @@ uniform int resourceId; flat in int resourceIDGeom[]; # define resource_id resourceIDGeom -# define PASS_RESOURCE_ID(i) resourceIDFrag = resource_id[i]; +# define PASS_RESOURCE_ID resourceIDFrag = resource_id[0]; #endif #ifdef GPU_FRAGMENT_SHADER @@ -167,10 +184,14 @@ uniform mat4 ModelMatrixInverse; * Note: This is only valid because we are only using the mat3 of the ViewMatrixInverse. * ViewMatrix * transpose(ModelMatrixInverse) **/ -#define normal_object_to_view(n) (mat3(ViewMatrix) * (transpose(mat3(ModelMatrixInverse)) * n)) -#define normal_object_to_world(n) (transpose(mat3(ModelMatrixInverse)) * n) -#define normal_world_to_object(n) (transpose(mat3(ModelMatrix)) * n) +#define NormalMatrix transpose(mat3(ModelMatrixInverse)) +#define NormalMatrixInverse transpose(mat3(ModelMatrix)) + +#define normal_object_to_view(n) (mat3(ViewMatrix) * (NormalMatrix * n)) +#define normal_object_to_world(n) (NormalMatrix * n) +#define normal_world_to_object(n) (NormalMatrixInverse * n) #define normal_world_to_view(n) (mat3(ViewMatrix) * n) +#define normal_view_to_world(n) (mat3(ViewMatrixInverse) * n) #define point_object_to_ndc(p) (ViewProjectionMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0)) #define point_object_to_view(p) ((ViewMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0)).xyz) @@ -194,3 +215,78 @@ uniform mat4 ModelMatrixInverse; #define DRW_BASE_FROM_DUPLI (1 << 2) #define DRW_BASE_FROM_SET (1 << 3) #define DRW_BASE_ACTIVE (1 << 4) + +/* ---- Opengl Depth conversion ---- */ + +float linear_depth(bool is_persp, float z, float zf, float zn) +{ + if (is_persp) { + return (zn * zf) / (z * (zn - zf) + zf); + } + else { + return (z * 2.0 - 1.0) * zf; + } +} + +float buffer_depth(bool is_persp, float z, float zf, float zn) +{ + if (is_persp) { + return (zf * (zn - z)) / (z * (zn - zf)); + } + else { + return (z / (zf * 2.0)) + 0.5; + } +} + +float get_view_z_from_depth(float depth) +{ + if (ProjectionMatrix[3][3] == 0.0) { + float d = 2.0 * depth - 1.0; + return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]); + } + else { + return ViewVecs[0].z + depth * ViewVecs[1].z; + } +} + +float get_depth_from_view_z(float z) +{ + if (ProjectionMatrix[3][3] == 0.0) { + float d = (-ProjectionMatrix[3][2] / z) - ProjectionMatrix[2][2]; + return d * 0.5 + 0.5; + } + else { + return (z - ViewVecs[0].z) / ViewVecs[1].z; + } +} + +vec2 get_uvs_from_view(vec3 view) +{ + vec4 ndc = ProjectionMatrix * vec4(view, 1.0); + return (ndc.xy / ndc.w) * 0.5 + 0.5; +} + +vec3 get_view_space_from_depth(vec2 uvcoords, float depth) +{ + if (ProjectionMatrix[3][3] == 0.0) { + return vec3(ViewVecs[0].xy + uvcoords * ViewVecs[1].xy, 1.0) * get_view_z_from_depth(depth); + } + else { + return ViewVecs[0].xyz + vec3(uvcoords, depth) * ViewVecs[1].xyz; + } +} + +vec3 get_world_space_from_depth(vec2 uvcoords, float depth) +{ + return (ViewMatrixInverse * vec4(get_view_space_from_depth(uvcoords, depth), 1.0)).xyz; +} + +vec3 get_view_vector_from_screen_uv(vec2 uv) +{ + if (ProjectionMatrix[3][3] == 0.0) { + return normalize(vec3(ViewVecs[0].xy + uv * ViewVecs[1].xy, 1.0)); + } + else { + return vec3(0.0, 0.0, 1.0); + } +} |