diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2019-05-04 02:39:35 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2019-05-04 15:11:04 +0300 |
commit | b2f1a6587410d00ad3bbd22e045979f80048afe2 (patch) | |
tree | 8312daea35aed37a1cdba6d6e6e97958b7f21d47 /source | |
parent | 1d8ed6dcd7cd2b3ccfaaacb59387dca481262eb6 (diff) |
Sculpt: Refactor draw manager sculpt drawing mechanism
Workbench/Eevee now displays multiple multi-materials correctly.
Iterate over pbvh nodes when doing object iteration. This makes the
rendering process more streamlined and allow for using different materials.
This change will make possible to:
- Add culling pass of each pbvh leaf node. (speedup if zoomed on a small
area)
- Reduce number of lead node iteration.
- Reduce code complexity
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_pbvh.h | 41 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pbvh.c | 52 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_materials.c | 106 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_deferred.c | 30 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_forward.c | 128 | ||||
-rw-r--r-- | source/blender/draw/intern/DRW_render.h | 19 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager_data.c | 200 | ||||
-rw-r--r-- | source/blender/draw/modes/overlay_mode.c | 2 | ||||
-rw-r--r-- | source/blender/draw/modes/sculpt_mode.c | 6 |
9 files changed, 310 insertions, 274 deletions
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index f59288f54bd..9b15462de6b 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -40,6 +40,7 @@ struct MPoly; struct MVert; struct PBVH; struct PBVHNode; +struct GPU_PBVH_Buffers; typedef struct PBVH PBVH; typedef struct PBVHNode PBVHNode; @@ -48,6 +49,21 @@ typedef struct { float (*co)[3]; } PBVHProxyNode; +typedef enum { + PBVH_Leaf = 1, + + PBVH_UpdateNormals = 2, + PBVH_UpdateBB = 4, + PBVH_UpdateOriginalBB = 8, + PBVH_UpdateDrawBuffers = 16, + PBVH_UpdateRedraw = 32, + + PBVH_RebuildDrawBuffers = 64, + PBVH_FullyHidden = 128, + + PBVH_UpdateTopology = 256, +} PBVHNodeFlags; + /* Callbacks */ /* returns 1 if the search should continue from this node, 0 otherwise */ @@ -151,13 +167,15 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh, void BKE_pbvh_draw_cb(PBVH *bvh, float (*planes)[4], float (*fnors)[3], - bool fast, - bool wires, - bool only_mask, bool show_vcol, - void (*draw_fn)(void *user_data, struct GPUBatch *batch), + void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers), void *user_data); +void BKE_pbvh_draw_debug_cb( + PBVH *bvh, + void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag), + void *user_data); + /* PBVH Access */ typedef enum { PBVH_FACES, @@ -202,21 +220,6 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, /* Node Access */ -typedef enum { - PBVH_Leaf = 1, - - PBVH_UpdateNormals = 2, - PBVH_UpdateBB = 4, - PBVH_UpdateOriginalBB = 8, - PBVH_UpdateDrawBuffers = 16, - PBVH_UpdateRedraw = 32, - - PBVH_RebuildDrawBuffers = 64, - PBVH_FullyHidden = 128, - - PBVH_UpdateTopology = 256, -} PBVHNodeFlags; - void BKE_pbvh_node_mark_update(PBVHNode *node); void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node); void BKE_pbvh_node_mark_redraw(PBVHNode *node); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index cb4ac0ea01b..f1d5347c48b 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -2202,26 +2202,17 @@ bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data) return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE; } -struct PBVHNodeDrawCallbackData { - void (*draw_fn)(void *user_data, GPUBatch *batch); +typedef struct PBVHNodeDrawCallbackData { + void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers); void *user_data; - bool fast; - bool only_mask; /* Only draw nodes that have mask data. */ - bool wires; -}; +} PBVHNodeDrawCallbackData; static void pbvh_node_draw_cb(PBVHNode *node, void *data_v) { - struct PBVHNodeDrawCallbackData *data = data_v; + PBVHNodeDrawCallbackData *data = data_v; if (!(node->flag & PBVH_FullyHidden)) { - GPUBatch *batch = GPU_pbvh_buffers_batch_get(node->draw_buffers, data->fast, data->wires); - bool show_mask = GPU_pbvh_buffers_has_mask(node->draw_buffers); - if (!data->only_mask || show_mask) { - if (batch != NULL) { - data->draw_fn(data->user_data, batch); - } - } + data->draw_fn(data->user_data, node->draw_buffers); } } @@ -2231,20 +2222,10 @@ static void pbvh_node_draw_cb(PBVHNode *node, void *data_v) void BKE_pbvh_draw_cb(PBVH *bvh, float (*planes)[4], float (*fnors)[3], - bool fast, - bool wires, - bool only_mask, bool show_vcol, - void (*draw_fn)(void *user_data, GPUBatch *batch), + void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers), void *user_data) { - struct PBVHNodeDrawCallbackData draw_data = { - .only_mask = only_mask, - .fast = fast, - .wires = wires, - .draw_fn = draw_fn, - .user_data = user_data, - }; PBVHNode **nodes; int totnode; @@ -2261,6 +2242,11 @@ void BKE_pbvh_draw_cb(PBVH *bvh, MEM_freeN(nodes); } + PBVHNodeDrawCallbackData draw_data = { + .draw_fn = draw_fn, + .user_data = user_data, + }; + if (planes) { BKE_pbvh_search_callback( bvh, BKE_pbvh_node_planes_contain_AABB, planes, pbvh_node_draw_cb, &draw_data); @@ -2268,10 +2254,18 @@ void BKE_pbvh_draw_cb(PBVH *bvh, else { BKE_pbvh_search_callback(bvh, NULL, NULL, pbvh_node_draw_cb, &draw_data); } -#if 0 - if (G.debug_value == 14) - pbvh_draw_BB(bvh); -#endif +} + +void BKE_pbvh_draw_debug_cb( + PBVH *bvh, + void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag), + void *user_data) +{ + for (int a = 0; a < bvh->totnode; a++) { + PBVHNode *node = &bvh->nodes[a]; + + draw_fn(user_data, node->vb.bmin, node->vb.bmax, node->flag); + } } void BKE_pbvh_grids_update( diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index c6a523e4822..8ee5b51d825 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -1190,17 +1190,12 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) #define ADD_SHGROUP_CALL(shgrp, ob, ma, geom, oedata) \ do { \ - if (is_sculpt_mode_draw) { \ - DRW_shgroup_call_sculpt_add(shgrp, ob, ob->obmat); \ + if (oedata) { \ + DRW_shgroup_call_object_add_with_callback( \ + shgrp, geom, ob, ma, EEVEE_lightprobes_obj_visibility_cb, oedata); \ } \ else { \ - if (oedata) { \ - DRW_shgroup_call_object_add_with_callback( \ - shgrp, geom, ob, ma, EEVEE_lightprobes_obj_visibility_cb, oedata); \ - } \ - else { \ - DRW_shgroup_call_object_add_ex(shgrp, geom, ob, ma, false); \ - } \ + DRW_shgroup_call_object_add_ex(shgrp, geom, ob, ma, false); \ } \ } while (0) @@ -1604,6 +1599,16 @@ static void material_transparent(Material *ma, } } +/* Return correct material or &defmaterial if slot is empty. */ +BLI_INLINE Material *eevee_object_material_get(Object *ob, int slot) +{ + Material *ma = give_current_material(ob, slot + 1); + if (ma == NULL) { + ma = &defmaterial; + } + return ma; +} + void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, @@ -1617,15 +1622,14 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, const bool do_cull = (draw_ctx->v3d && (draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING)); - const bool is_sculpt_mode = DRW_object_use_pbvh_drawing(ob); + bool is_sculpt_mode = DRW_object_use_pbvh_drawing(ob); /* For now just force fully shaded with eevee when supported. */ - const bool is_sculpt_mode_draw = ob->sculpt && ob->sculpt->pbvh && - BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES; - const bool is_default_mode_shader = is_sculpt_mode; + is_sculpt_mode = is_sculpt_mode && + !(ob->sculpt->pbvh && BKE_pbvh_type(ob->sculpt->pbvh) == PBVH_FACES); /* First get materials for this mesh. */ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { - const int materials_len = MAX2(1, (is_sculpt_mode_draw ? 1 : ob->totcol)); + const int materials_len = MAX2(1, ob->totcol); struct DRWShadingGroup **shgrp_array = BLI_array_alloca(shgrp_array, materials_len); struct DRWShadingGroup **shgrp_depth_array = BLI_array_alloca(shgrp_depth_array, @@ -1635,40 +1639,22 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); struct GPUMaterial **gpumat_depth_array = BLI_array_alloca(gpumat_array, materials_len); + struct Material **ma_array = BLI_array_alloca(ma_array, materials_len); bool use_flat_nor = false; - - if (is_default_mode_shader) { - if (is_sculpt_mode_draw) { - use_flat_nor = DRW_object_is_flat_normal(ob); - } - } - for (int i = 0; i < materials_len; ++i) { - Material *ma; - - if (is_sculpt_mode_draw) { - ma = NULL; - } - else { - ma = give_current_material(ob, i + 1); - } - + ma_array[i] = eevee_object_material_get(ob, i); gpumat_array[i] = NULL; gpumat_depth_array[i] = NULL; shgrp_array[i] = NULL; shgrp_depth_array[i] = NULL; shgrp_depth_clip_array[i] = NULL; - if (ma == NULL) { - ma = &defmaterial; - } - - switch (ma->blend_method) { + switch (ma_array[i]->blend_method) { case MA_BM_SOLID: case MA_BM_CLIP: case MA_BM_HASHED: - material_opaque(ma, + material_opaque(ma_array[i], material_hash, sldata, vedata, @@ -1683,7 +1669,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, case MA_BM_ADD: case MA_BM_MULTIPLY: case MA_BM_BLEND: - material_transparent(ma, + material_transparent(ma_array[i], sldata, vedata, do_cull, @@ -1725,17 +1711,18 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, &auto_layer_count); } - if (is_sculpt_mode_draw || mat_geom) { + if (is_sculpt_mode) { + /* TODO(fclem): Support Vcol. */ + DRW_shgroup_call_sculpt_with_materials_add(shgrp_array, ma_array, ob, false); + DRW_shgroup_call_sculpt_with_materials_add(shgrp_depth_array, ma_array, ob, false); + DRW_shgroup_call_sculpt_with_materials_add(shgrp_depth_clip_array, ma_array, ob, false); + /* TODO(fclem): Support shadows in sculpt mode. */ + } + else if (mat_geom) { for (int i = 0; i < materials_len; ++i) { - if (!is_sculpt_mode_draw && mat_geom[i] == NULL) { + if (mat_geom[i] == NULL) { continue; } - EEVEE_ObjectEngineData *oedata = NULL; - Material *ma = give_current_material(ob, i + 1); - - if (ma == NULL) { - ma = &defmaterial; - } /* Do not render surface if we are rendering a volume object * and do not have a surface closure. */ @@ -1746,23 +1733,16 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, /* XXX TODO rewrite this to include the dupli objects. * This means we cannot exclude dupli objects from reflections!!! */ + EEVEE_ObjectEngineData *oedata = NULL; if ((ob->base_flag & BASE_FROM_DUPLI) == 0) { oedata = EEVEE_object_data_ensure(ob); oedata->ob = ob; oedata->test_data = &sldata->probes->vis_data; } - /* Shading pass */ - ADD_SHGROUP_CALL(shgrp_array[i], ob, ma, mat_geom[i], oedata); - - /* Depth Prepass */ - ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, ma, mat_geom[i], oedata); - ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, ma, mat_geom[i], oedata); - - /* TODO(fclem): Don't support shadows in sculpt mode. */ - if (is_sculpt_mode_draw) { - break; - } + ADD_SHGROUP_CALL(shgrp_array[i], ob, ma_array[i], mat_geom[i], oedata); + ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, ma_array[i], mat_geom[i], oedata); + ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, ma_array[i], mat_geom[i], oedata); char *name = auto_layer_names; for (int j = 0; j < auto_layer_count; ++j) { @@ -1785,19 +1765,19 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, /* Shadow Pass */ struct GPUMaterial *gpumat; - switch (ma->blend_shadow) { + switch (ma_array[i]->blend_shadow) { case MA_BS_SOLID: EEVEE_lights_cache_shcaster_add(sldata, stl, mat_geom[i], ob); *cast_shadow = true; break; case MA_BS_CLIP: - gpumat = EEVEE_material_mesh_depth_get(scene, ma, false, true); + gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], false, true); EEVEE_lights_cache_shcaster_material_add( - sldata, psl, gpumat, mat_geom[i], ob, &ma->alpha_threshold); + sldata, psl, gpumat, mat_geom[i], ob, &ma_array[i]->alpha_threshold); *cast_shadow = true; break; case MA_BS_HASHED: - gpumat = EEVEE_material_mesh_depth_get(scene, ma, true, true); + gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], true, true); EEVEE_lights_cache_shcaster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL); *cast_shadow = true; break; @@ -1845,11 +1825,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata, } DRWShadingGroup *shgrp = NULL; - Material *ma = give_current_material(ob, part->omat); - - if (ma == NULL) { - ma = &defmaterial; - } + Material *ma = eevee_object_material_get(ob, part->omat - 1); float *color_p = &ma->r; float *metal_p = &ma->metallic; diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 9dcd53a8158..343ad26b802 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -937,7 +937,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) const bool is_active = (ob == draw_ctx->obact); const bool is_sculpt_mode = DRW_object_use_pbvh_drawing(ob); const bool use_hide = is_active && DRW_object_use_hide_faces(ob); - const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); + const int materials_len = MAX2(1, ob->totcol); const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; bool has_transp_mat = false; @@ -983,8 +983,10 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) /* Draw solid color */ material = get_or_create_material_data(vedata, ob, NULL, NULL, NULL, color_type, 0); } + if (is_sculpt_mode) { - DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat); + bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR); + DRW_shgroup_call_sculpt_add(material->shgrp, ob, false, false, use_vcol); } else { struct GPUBatch *geom; @@ -1003,11 +1005,25 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) else { /* Draw material color */ if (is_sculpt_mode) { - /* Multiple materials are not supported in sculpt mode yet. */ - Material *mat = give_current_material(ob, 1); - material = get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat); + struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len); + struct Material **mats = BLI_array_alloca(mats, materials_len); + + for (int i = 0; i < materials_len; ++i) { + mats[i] = give_current_material(ob, i + 1); + if (mats[i] != NULL && mats[i]->a < 1.0f) { + /* Hack */ + wpd->shading.xray_alpha = mats[i]->a; + material = workbench_forward_get_or_create_material_data( + vedata, ob, mats[i], NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, is_sculpt_mode); + has_transp_mat = true; + } + else { + material = get_or_create_material_data( + vedata, ob, mats[i], NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); + } + shgrps[i] = material->shgrp; + } + DRW_shgroup_call_sculpt_with_materials_add(shgrps, mats, ob, false); } else { struct GPUBatch **geoms; diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index 1d55a54df8d..fe3e0579c8e 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -566,69 +566,78 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) WORKBENCH_MaterialData *material; if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { const bool is_sculpt_mode = DRW_object_use_pbvh_drawing(ob); - bool is_drawn = false; - - if (!is_sculpt_mode && TEXTURE_DRAWING_ENABLED(wpd) && ELEM(ob->type, OB_MESH)) { - const Mesh *me = ob->data; - if (me->mloopuv) { - const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); - struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); - for (int i = 0; i < materials_len; i++) { - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); - int color_type = workbench_material_determine_color_type(wpd, image, ob, is_sculpt_mode); - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp, is_sculpt_mode); - DRW_shgroup_call_object_add(material->shgrp_object_outline, geom_array[i], ob); - DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob); - } - is_drawn = true; + const int materials_len = MAX2(1, ob->totcol); + const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; + + if (!is_sculpt_mode && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { + struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); + for (int i = 0; i < materials_len; i++) { + Material *mat; + Image *image; + ImageUser *iuser; + int interp; + workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); + int color_type = workbench_material_determine_color_type(wpd, image, ob, is_sculpt_mode); + material = workbench_forward_get_or_create_material_data( + vedata, ob, mat, image, iuser, color_type, interp, is_sculpt_mode); + DRW_shgroup_call_object_add(material->shgrp_object_outline, geom_array[i], ob); + DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob); } } - - /* Fallback from not drawn OB_TEXTURE mode or just OB_SOLID mode */ - if (!is_drawn) { - if (ELEM(wpd->shading.color_type, - V3D_SHADING_SINGLE_COLOR, - V3D_SHADING_OBJECT_COLOR, - V3D_SHADING_RANDOM_COLOR, - V3D_SHADING_VERTEX_COLOR)) { - /* No material split needed */ - int color_type = workbench_material_determine_color_type(wpd, NULL, ob, is_sculpt_mode); - - struct GPUBatch *geom; - if (color_type == V3D_SHADING_VERTEX_COLOR) { - geom = DRW_cache_mesh_surface_vertpaint_get(ob); - } - else { - geom = DRW_cache_object_surface_get(ob); + else if (ELEM(wpd->shading.color_type, + V3D_SHADING_SINGLE_COLOR, + V3D_SHADING_OBJECT_COLOR, + V3D_SHADING_RANDOM_COLOR, + V3D_SHADING_VERTEX_COLOR)) { + /* No material split needed */ + int color_type = workbench_material_determine_color_type(wpd, NULL, ob, is_sculpt_mode); + + if (is_sculpt_mode) { + material = workbench_forward_get_or_create_material_data( + vedata, ob, NULL, NULL, NULL, color_type, 0, is_sculpt_mode); + bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR); + /* TODO(fclem) make this call optional */ + DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, false, false, false); + if (!is_wire) { + DRW_shgroup_call_sculpt_add(material->shgrp, ob, false, false, use_vcol); } + } + else { + struct GPUBatch *geom = (color_type == V3D_SHADING_VERTEX_COLOR) ? + DRW_cache_mesh_surface_vertpaint_get(ob) : + DRW_cache_object_surface_get(ob); if (geom) { material = workbench_forward_get_or_create_material_data( vedata, ob, NULL, NULL, NULL, color_type, 0, is_sculpt_mode); - if (is_sculpt_mode) { - DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, ob->obmat); - if (!is_wire) { - DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat); - } - } - else { - DRW_shgroup_call_object_add(material->shgrp_object_outline, geom, ob); - if (!is_wire) { - DRW_shgroup_call_object_add(material->shgrp, geom, ob); - } + /* TODO(fclem) make this call optional */ + DRW_shgroup_call_object_add(material->shgrp_object_outline, geom, ob); + if (!is_wire) { + DRW_shgroup_call_object_add(material->shgrp, geom, ob); } } } + } + else { + /* Draw material color */ + if (is_sculpt_mode) { + struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len); + struct Material **mats = BLI_array_alloca(mats, materials_len); + + for (int i = 0; i < materials_len; ++i) { + mats[i] = give_current_material(ob, i + 1); + material = workbench_forward_get_or_create_material_data( + vedata, ob, mats[i], NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, is_sculpt_mode); + shgrps[i] = material->shgrp; + } + /* TODO(fclem) make this call optional */ + DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, false, false, false); + if (!is_wire) { + DRW_shgroup_call_sculpt_with_materials_add(shgrps, mats, ob, false); + } + } else { - const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - for (int i = 0; i < materials_len; i++) { - gpumat_array[i] = NULL; - } + memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len); struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get( ob, gpumat_array, materials_len, NULL, NULL, NULL); @@ -641,17 +650,10 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) Material *mat = give_current_material(ob, i + 1); material = workbench_forward_get_or_create_material_data( vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, is_sculpt_mode); - if (is_sculpt_mode) { - DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, ob->obmat); - if (!is_wire) { - DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat); - } - } - else { - DRW_shgroup_call_object_add(material->shgrp_object_outline, mat_geom[i], ob); - if (!is_wire) { - DRW_shgroup_call_object_add(material->shgrp, mat_geom[i], ob); - } + /* TODO(fclem) make this call optional */ + DRW_shgroup_call_object_add(material->shgrp_object_outline, mat_geom[i], ob); + if (!is_wire) { + DRW_shgroup_call_object_add(material->shgrp, mat_geom[i], ob); } } } diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 134fb5d99f8..363cf67623a 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -440,6 +440,17 @@ void DRW_shgroup_call_object_add_with_callback(DRWShadingGroup *shgroup, struct Material *ma, DRWCallVisibilityFn *callback, void *user_data); + +void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shading_group, + Object *object, + bool use_wire, + bool use_mask, + bool use_vert_color); +void DRW_shgroup_call_sculpt_with_materials_add(DRWShadingGroup **shgroups, + Material **materials, + Object *ob, + bool use_vcol); + /* Used for drawing a batch with instancing without instance attributes. */ void DRW_shgroup_call_instances_add(DRWShadingGroup *shgroup, struct GPUBatch *geom, @@ -449,14 +460,6 @@ void DRW_shgroup_call_object_instances_add(DRWShadingGroup *shgroup, struct GPUBatch *geom, struct Object *ob, uint *count); -void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, struct Object *ob, float (*obmat)[4]); -void DRW_shgroup_call_sculpt_wires_add(DRWShadingGroup *shgroup, - struct Object *ob, - float (*obmat)[4]); -void DRW_shgroup_call_generate_add(DRWShadingGroup *shgroup, - DRWCallGenerateFn *geometry_fn, - void *user_data, - float (*obmat)[4]); void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *attr[], uint attr_len); diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 65ef2fa66fa..c63e30e65d7 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -38,6 +38,8 @@ #include "BLI_link_utils.h" #include "BLI_mempool.h" +#include "GPU_buffers.h" + #include "intern/gpu_codegen.h" struct GPUVertFormat *g_pos_format = NULL; @@ -616,110 +618,150 @@ void DRW_shgroup_call_object_instances_add(DRWShadingGroup *shgroup, BLI_LINKS_APPEND(&shgroup->calls, call); } -void DRW_shgroup_call_generate_add(DRWShadingGroup *shgroup, - DRWCallGenerateFn *geometry_fn, - void *user_data, - float (*obmat)[4]) -{ - BLI_assert(geometry_fn != NULL); - BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)); +// #define SCULPT_DEBUG_BUFFERS - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); - call->state = drw_call_state_create(shgroup, obmat, NULL); - call->type = DRW_CALL_GENERATE; - call->generate.geometry_fn = geometry_fn; - call->generate.user_data = user_data; -#ifdef USE_GPU_SELECT - call->select_id = DST.select_id; +typedef struct DRWSculptCallbackData { + Object *ob; + DRWShadingGroup **shading_groups; + Material **materials; + bool use_wire; + bool use_mats; + bool use_mask; + bool fast_mode; /* Set by draw manager. Do not init. */ +#ifdef SCULPT_DEBUG_BUFFERS + int node_nr; +#endif +} DRWSculptCallbackData; + +#ifdef SCULPT_DEBUG_BUFFERS +# define SCULPT_DEBUG_COLOR(id) (sculpt_debug_colors[id % 9]) +static float sculpt_debug_colors[9][4] = { + {1.0f, 0.2f, 0.2f, 1.0f}, + {0.2f, 1.0f, 0.2f, 1.0f}, + {0.2f, 0.2f, 1.0f, 1.0f}, + {1.0f, 1.0f, 0.2f, 1.0f}, + {0.2f, 1.0f, 1.0f, 1.0f}, + {1.0f, 0.2f, 1.0f, 1.0f}, + {1.0f, 0.7f, 0.2f, 1.0f}, + {0.2f, 1.0f, 0.7f, 1.0f}, + {0.7f, 0.2f, 1.0f, 1.0f}, +}; #endif - BLI_LINKS_APPEND(&shgroup->calls, call); -} - -/* This function tests if the current draw engine draws the vertex colors - * It is used when drawing sculpts - * - * XXX: should we use a callback to a the draw engine to retrieve this - * setting, this makes the draw manager more clean? */ -static bool DRW_draw_vertex_color_active(const DRWContextState *draw_ctx) -{ - View3D *v3d = draw_ctx->v3d; - return v3d->shading.type == OB_SOLID && v3d->shading.color_type == V3D_SHADING_VERTEX_COLOR; -} - -static void sculpt_draw_cb(DRWShadingGroup *shgroup, - void (*draw_fn)(DRWShadingGroup *shgroup, GPUBatch *geom), - void *user_data) +static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers) { - Object *ob = user_data; - - /* XXX should be ensured before but sometime it's not... go figure (see T57040). */ - PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(DST.draw_ctx.depsgraph, ob); + GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire); + Material *ma = NULL; + short index = 0; - const DRWContextState *drwctx = DRW_context_state_get(); - int fast_mode = 0; + /* Meh... use_mask is a bit misleading here. */ + if (scd->use_mask && !GPU_pbvh_buffers_has_mask(buffers)) { + return; + } - if (drwctx->evil_C != NULL) { - Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C); - if (p && (p->flags & PAINT_FAST_NAVIGATE)) { - fast_mode = drwctx->rv3d->rflag & RV3D_NAVIGATING; - } + if (scd->use_mats) { + index = GPU_pbvh_buffers_material_index_get(buffers); + ma = scd->materials[index]; } - if (pbvh) { - const bool show_vcol = DRW_draw_vertex_color_active(drwctx); - BKE_pbvh_draw_cb(pbvh, - NULL, - NULL, - fast_mode, - false, - false, - show_vcol, - (void (*)(void *, GPUBatch *))draw_fn, - shgroup); + DRWShadingGroup *shgrp = scd->shading_groups[index]; + if (geom != NULL && shgrp != NULL) { +#ifdef SCULPT_DEBUG_BUFFERS + /* Color each buffers in different colors. Only work in solid/Xray mode. */ + shgrp = DRW_shgroup_create_sub(shgrp); + DRW_shgroup_uniform_vec3(shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->node_nr++), 1); +#endif + /* DRW_shgroup_call_object_add_ex reuses matrices calculations for all the drawcalls of this + * object. */ + DRW_shgroup_call_object_add_ex(shgrp, geom, scd->ob, ma, true); } } -static void sculpt_draw_wires_cb(DRWShadingGroup *shgroup, - void (*draw_fn)(DRWShadingGroup *shgroup, GPUBatch *geom), - void *user_data) +#ifdef SCULPT_DEBUG_BUFFERS +static void sculpt_debug_cb(void *user_data, + const float bmin[3], + const float bmax[3], + PBVHNodeFlags flag) { - Object *ob = user_data; + int *node_nr = (int *)user_data; + BoundBox bb; + BKE_boundbox_init_from_minmax(&bb, bmin, bmax); + +# if 0 /* Nodes hierarchy. */ + if (flag & PBVH_Leaf) { + DRW_debug_bbox(&bb, (float[4]){0.0f, 1.0f, 0.0f, 1.0f}); + } + else { + DRW_debug_bbox(&bb, (float[4]){0.5f, 0.5f, 0.5f, 0.6f}); + } +# else /* Color coded leaf bounds. */ + if (flag & PBVH_Leaf) { + DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*node_nr)++)); + } +# endif +} +#endif +static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol) +{ /* XXX should be ensured before but sometime it's not... go figure (see T57040). */ - PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(DST.draw_ctx.depsgraph, ob); + PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(DST.draw_ctx.depsgraph, scd->ob); + if (!pbvh) { + return; + } - const DRWContextState *drwctx = DRW_context_state_get(); - int fast_mode = 0; + float(*planes)[4] = NULL; /* TODO proper culling. */ + scd->fast_mode = false; + const DRWContextState *drwctx = DRW_context_state_get(); if (drwctx->evil_C != NULL) { Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C); if (p && (p->flags & PAINT_FAST_NAVIGATE)) { - fast_mode = drwctx->rv3d->rflag & RV3D_NAVIGATING; + scd->fast_mode = (drwctx->rv3d->rflag & RV3D_NAVIGATING) != 0; } } - if (pbvh) { - BKE_pbvh_draw_cb(pbvh, - NULL, - NULL, - fast_mode, - true, - false, - false, - (void (*)(void *, GPUBatch *))draw_fn, - shgroup); - } -} + BKE_pbvh_draw_cb( + pbvh, planes, NULL, use_vcol, (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb, scd); -void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4]) -{ - DRW_shgroup_call_generate_add(shgroup, sculpt_draw_cb, ob, obmat); +#ifdef SCULPT_DEBUG_BUFFERS + int node_nr = 0; + DRW_debug_modelmat(scd->ob->obmat); + BKE_pbvh_draw_debug_cb( + pbvh, + (void (*)(void *d, const float min[3], const float max[3], PBVHNodeFlags f))sculpt_debug_cb, + &node_nr); +#endif } -void DRW_shgroup_call_sculpt_wires_add(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4]) -{ - DRW_shgroup_call_generate_add(shgroup, sculpt_draw_wires_cb, ob, obmat); +void DRW_shgroup_call_sculpt_add( + DRWShadingGroup *shgroup, Object *ob, bool use_wire, bool use_mask, bool use_vcol) +{ + DRWSculptCallbackData scd = { + .ob = ob, + .shading_groups = &shgroup, + .materials = NULL, + .use_wire = use_wire, + .use_mats = false, + .use_mask = use_mask, + }; + drw_sculpt_generate_calls(&scd, use_vcol); +} + +void DRW_shgroup_call_sculpt_with_materials_add(DRWShadingGroup **shgroups, + Material **materials, + Object *ob, + bool use_vcol) +{ + DRWSculptCallbackData scd = { + .ob = ob, + .shading_groups = shgroups, + .materials = materials, + .use_wire = false, + .use_mats = true, + .use_mask = false, + }; + drw_sculpt_generate_calls(&scd, use_vcol); } void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c index 68d9a7d3bed..90fac136f73 100644 --- a/source/blender/draw/modes/overlay_mode.c +++ b/source/blender/draw/modes/overlay_mode.c @@ -389,7 +389,7 @@ static void overlay_cache_populate(void *vedata, Object *ob) } if (is_sculpt_mode) { - DRW_shgroup_call_sculpt_wires_add(shgrp, ob, ob->obmat); + DRW_shgroup_call_sculpt_add(shgrp, ob, true, false, false); } else { DRW_shgroup_call_add(shgrp, geom, ob->obmat); diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c index 8adae0a4238..fb2619ce768 100644 --- a/source/blender/draw/modes/sculpt_mode.c +++ b/source/blender/draw/modes/sculpt_mode.c @@ -98,6 +98,7 @@ static struct { } e_data = {NULL}; /* Engine data */ typedef struct SCULPT_PrivateData { + DRWShadingGroup *mask_overlay_grp; /* This keeps the references of the shading groups for * easy access in SCULPT_cache_populate() */ DRWShadingGroup *group_flat; @@ -143,7 +144,7 @@ static void SCULPT_cache_init(void *vedata) DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.shader_smooth, psl->pass); DRW_shgroup_uniform_float(shgrp, "maskOpacity", &v3d->overlay.sculpt_mode_mask_opacity, 1); - stl->g_data->group_smooth = shgrp; + stl->g_data->mask_overlay_grp = shgrp; } } @@ -213,8 +214,7 @@ static void SCULPT_cache_populate(void *vedata, Object *ob) PBVH *pbvh = ob->sculpt->pbvh; if (pbvh && pbvh_has_mask(pbvh)) { - DRW_shgroup_call_generate_add( - stl->g_data->group_smooth, sculpt_draw_mask_cb, ob, ob->obmat); + DRW_shgroup_call_sculpt_add(stl->g_data->mask_overlay_grp, ob, false, true, false); } } } |