diff options
author | Lukas Toenne <lukas.toenne@gmail.com> | 2018-12-18 13:58:54 +0300 |
---|---|---|
committer | Lukas Toenne <lukas.toenne@gmail.com> | 2018-12-18 13:58:54 +0300 |
commit | fdca73fd4aea4a1a0a2e37b8ccc82951cfb08ca2 (patch) | |
tree | c6c6492d1c33522e4b088f2cd44076e6e4de54de /source/blender/draw | |
parent | b62f226cac06431aa17eb692b47de0dd58cf68ad (diff) | |
parent | d3e1b043c37398ac1e1027a6004239dee8a055f0 (diff) |
Merge branch 'blender2.8' into hair_object
Diffstat (limited to 'source/blender/draw')
91 files changed, 5569 insertions, 4715 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 9f2fa378e3c..2671a6e0f0a 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -226,6 +226,7 @@ data_to_c_simple(engines/workbench/shaders/workbench_checkerboard_depth_frag.gls data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_deferred_composite_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_deferred_background_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_effect_fxaa_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_forward_composite_frag.glsl SRC) @@ -233,6 +234,7 @@ data_to_c_simple(engines/workbench/shaders/workbench_forward_depth_frag.glsl SRC data_to_c_simple(engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_ghost_resolve_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_object_outline_lib.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC) @@ -275,13 +277,13 @@ data_to_c_simple(modes/shaders/edit_mesh_overlay_geom_edge.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_points_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_facedot_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_facedot_vert.glsl SRC) -data_to_c_simple(modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_mix_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_curve_overlay_handle_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_curve_overlay_handle_geom.glsl SRC) data_to_c_simple(modes/shaders/edit_curve_overlay_loosevert_vert.glsl SRC) +data_to_c_simple(modes/shaders/edit_curve_overlay_normals_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_hair_overlay_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_hair_overlay_loosevert_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_lattice_overlay_frag.glsl SRC) @@ -309,12 +311,14 @@ data_to_c_simple(modes/shaders/object_mball_handles_vert.glsl SRC) data_to_c_simple(modes/shaders/object_particle_prim_vert.glsl SRC) data_to_c_simple(modes/shaders/object_particle_dot_vert.glsl SRC) data_to_c_simple(modes/shaders/object_particle_dot_frag.glsl SRC) +data_to_c_simple(modes/shaders/object_loose_points_frag.glsl SRC) data_to_c_simple(modes/shaders/paint_texture_frag.glsl SRC) data_to_c_simple(modes/shaders/paint_texture_vert.glsl SRC) data_to_c_simple(modes/shaders/paint_vertex_frag.glsl SRC) data_to_c_simple(modes/shaders/paint_vertex_vert.glsl SRC) data_to_c_simple(modes/shaders/paint_weight_frag.glsl SRC) data_to_c_simple(modes/shaders/paint_weight_vert.glsl SRC) +data_to_c_simple(modes/shaders/paint_face_vert.glsl SRC) data_to_c_simple(modes/shaders/paint_wire_frag.glsl SRC) data_to_c_simple(modes/shaders/paint_wire_vert.glsl SRC) data_to_c_simple(modes/shaders/paint_vert_frag.glsl SRC) @@ -330,6 +334,7 @@ data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_geom.glsl SRC) data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_frag.glsl SRC) data_to_c_simple(engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl SRC) data_to_c_simple(engines/gpencil/shaders/gpencil_simple_mix_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_blend_frag.glsl SRC) data_to_c_simple(engines/gpencil/shaders/gpencil_point_vert.glsl SRC) data_to_c_simple(engines/gpencil/shaders/gpencil_point_geom.glsl SRC) data_to_c_simple(engines/gpencil/shaders/gpencil_point_frag.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 48a73ccef18..787957a4a33 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -460,10 +460,10 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l /* Restore */ GPU_framebuffer_bind(fbl->main_fb); - if (GPU_mip_render_workaround()) { - /* Fix dot corruption on intel HD5XX/HD6XX series. - * It seems affected drivers are the same that needs - * GPU_mip_render_workaround. */ + if (GPU_mip_render_workaround() || + GPU_type_matches(GPU_DEVICE_INTEL_UHD, GPU_OS_WIN, GPU_DRIVER_ANY)) + { + /* Fix dot corruption on intel HD5XX/HD6XX series. */ GPU_flush(); } } diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 451e7174a94..71082268f10 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -1050,7 +1050,7 @@ void EEVEE_lightbake_update(void *custom_data) EEVEE_lightcache_info_update(&lbake->scene->eevee); - DEG_id_tag_update(&scene_orig->id, DEG_TAG_COPY_ON_WRITE); + DEG_id_tag_update(&scene_orig->id, ID_RECALC_COPY_ON_WRITE); } static bool lightbake_do_sample(EEVEE_LightBake *lbake, void (*render_callback)(void *ved, void *user_data)) diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c index e46526ce6af..aa2f480597b 100644 --- a/source/blender/draw/engines/eevee/eevee_lookdev.c +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -62,8 +62,8 @@ void EEVEE_lookdev_cache_init( const DRWContextState *draw_ctx = DRW_context_state_get(); View3D *v3d = draw_ctx->v3d; if (LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d)) { - StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE); - if (sl && (sl->flag & STUDIOLIGHT_ORIENTATION_WORLD)) { + StudioLight *sl = BKE_studiolight_find(v3d->shading.lookdev_light, STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE); + if (sl && (sl->flag & STUDIOLIGHT_TYPE_WORLD)) { GPUShader *shader = EEVEE_shaders_default_studiolight_sh_get(); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); GPUTexture *tex = NULL; diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index bda6c633523..a2ceb2a5190 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -1401,7 +1401,7 @@ static void material_transparent( DRW_shgroup_uniform_float(*shgrp, "roughness", rough_p, 1); } - const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKSIDE) != 0); + const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0); DRWState all_state = ( DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK | @@ -1655,14 +1655,10 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld const bool do_cull = (draw_ctx->v3d && (draw_ctx->v3d->flag2 & V3D_BACKFACE_CULLING)); const bool is_active = (ob == draw_ctx->obact); const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0; -#if 0 - const bool is_sculpt_mode_draw = is_sculpt_mode && (draw_ctx->v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE) == 0; -#else /* For now just force fully shaded with eevee when supported. */ const bool is_sculpt_mode_draw = is_sculpt_mode && ((ob->sculpt && ob->sculpt->pbvh) && (BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES)); -#endif const bool is_default_mode_shader = is_sculpt_mode; /* First get materials for this mesh. */ diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index 03aee102136..3763e13533d 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -253,10 +253,10 @@ void EEVEE_occlusion_compute( DRW_draw_pass(psl->ao_horizon_search); } - if (GPU_mip_render_workaround()) { - /* Fix dot corruption on intel HD5XX/HD6XX series. - * It seems affected drivers are the same that needs - * GPU_mip_render_workaround. */ + if (GPU_mip_render_workaround() || + GPU_type_matches(GPU_DEVICE_INTEL_UHD, GPU_OS_WIN, GPU_DRIVER_ANY)) + { + /* Fix dot corruption on intel HD5XX/HD6XX series. */ GPU_flush(); } diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 40c6bb1f1e0..4c9d04ff339 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -177,12 +177,11 @@ void integrate_slice(vec3 normal, vec2 t_phi, vec2 horizons, inout float visibil visibility += vis; - /* Finding Bent normal */ + /* O. Klehm, T. Ritschel, E. Eisemann, H.-P. Seidel + * Bent Normals and Cones in Screen-space + * Sec. 3.1 : Bent normals */ float b_angle = (h.x + h.y) * 0.5; - /* The 0.5 factor below is here to equilibrate the accumulated vectors. - * (sin(b_angle) * -t_phi) will accumulate to (phi_step * result_nor.xy * 0.5). - * (cos(b_angle) * 0.5) will accumulate to (phi_step * result_nor.z * 0.5). */ - bent_normal += vec3(sin(b_angle) * -t_phi, cos(b_angle) * 0.5); + bent_normal += vec3(sin(b_angle) * -t_phi, cos(b_angle)) * vis; } void gtao_deferred( @@ -203,9 +202,9 @@ void gtao_deferred( integrate_slice(normal, dirs.xy, horizons.xy, visibility, bent_normal); integrate_slice(normal, dirs.zw, horizons.zw, visibility, bent_normal); - visibility *= 0.5; /* We integrated 2 slices. */ + bent_normal = normalize(bent_normal / visibility); - bent_normal = normalize(bent_normal); + visibility *= 0.5; /* We integrated 2 slices. */ } void gtao(vec3 normal, vec3 position, vec4 noise, out float visibility, out vec3 bent_normal) @@ -222,7 +221,7 @@ void gtao(vec3 normal, vec3 position, vec4 noise, out float visibility, out vec3 vec2 horizons = search_horizon_sweep(dir, position, uvs, noise.y, max_dir); integrate_slice(normal, dir, horizons, visibility, bent_normal); - bent_normal = normalize(bent_normal); + bent_normal = normalize(bent_normal / visibility); } /* Multibounce approximation base on surface albedo. @@ -261,7 +260,7 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out if ((int(aoSettings) & USE_BENT_NORMAL) != 0) { /* The bent normal will show the facet look of the mesh. Try to minimize this. */ - float mix_fac = visibility * visibility; + float mix_fac = visibility * visibility * visibility; bent_normal = normalize(mix(bent_normal, vnor, mix_fac)); bent_normal = transform_direction(ViewMatrixInverse, bent_normal); diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 15ac3f37add..63af8ecc141 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -83,8 +83,12 @@ tGPencilObjectCache *gpencil_object_cache_add( cache_elem->pixfactor = cache_elem->gpd->pixfactor; cache_elem->shader_fx = ob_orig->shader_fx; - cache_elem->init_grp = NULL; - cache_elem->end_grp = NULL; + /* shgrp array */ + cache_elem->tot_layers = 0; + int totgpl = BLI_listbase_count(&cache_elem->gpd->layers); + if (totgpl > 0) { + cache_elem->shgrp_array = MEM_callocN(sizeof(tGPencilObjectCache_shgrp) * totgpl, __func__); + } /* calculate zdepth from point of view */ float zdepth = 0.0; @@ -182,7 +186,7 @@ static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, in else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) { valid = false; } - else if (gpd->flag & GP_DATA_SHOW_ONIONSKINS) { + else if (DRW_gpencil_onion_active(gpd)) { /* if onion, set as dirty always * This reduces performance, but avoid any crash in the multiple * overlay and multiwindow options and keep all windows working diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c index 6289e76664d..0f37e8824ee 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c @@ -245,7 +245,6 @@ GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - View3D *v3d = draw_ctx->v3d; ARegion *ar = draw_ctx->ar; RegionView3D *rv3d = draw_ctx->rv3d; ToolSettings *ts = scene->toolsettings; @@ -253,6 +252,9 @@ GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness) tGPspoint *points = gpd->runtime.sbuffer; int totpoints = gpd->runtime.sbuffer_size; + /* if cyclic needs more vertex */ + int cyclic_add = (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC) ? 1 : 0; + int totvertex = totpoints + cyclic_add + 2; static GPUVertFormat format = { 0 }; static uint pos_id, color_id, thickness_id, uvdata_id; @@ -264,17 +266,17 @@ GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness) } GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, totpoints + 2); + GPU_vertbuf_data_alloc(vbo, totvertex); /* draw stroke curve */ const tGPspoint *tpt = points; - bGPDspoint pt, pt2; + bGPDspoint pt, pt2, pt3; int idx = 0; /* get origin to reproject point */ float origin[3]; bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); - ED_gp_get_drawing_reference(v3d, scene, ob, gpl, ts->gpencil_v3d_align, origin); + ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin); for (int i = 0; i < totpoints; i++, tpt++) { ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt); @@ -282,19 +284,22 @@ GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness) /* first point for adjacency (not drawn) */ if (i == 0) { - if (totpoints > 1) { - ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt2); + if (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC && totpoints > 2) { + ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 1], &pt2); gpencil_set_stroke_point( - vbo, &pt2, idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + vbo, &pt2, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + idx++; } else { + ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt2); gpencil_set_stroke_point( - vbo, &pt, idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + vbo, &pt2, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + idx++; } - idx++; } + /* set point */ gpencil_set_stroke_point( vbo, &pt, idx, @@ -303,16 +308,27 @@ GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness) } /* last adjacency point (not drawn) */ - if (totpoints > 2) { - ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 2], &pt2); + if (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC && totpoints > 2) { + /* draw line to first point to complete the cycle */ + ED_gpencil_tpoint_to_point(ar, origin, &points[0], &pt2); gpencil_set_stroke_point( - vbo, &pt2, idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + vbo, &pt2, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + idx++; + /* now add adjacency point (not drawn) */ + ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt3); + gpencil_set_stroke_point( + vbo, &pt3, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + idx++; } + /* last adjacency point (not drawn) */ else { + ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 2], &pt2); gpencil_set_stroke_point( - vbo, &pt, idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + vbo, &pt2, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + idx++; } return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO); @@ -323,7 +339,6 @@ GPUBatch *DRW_gpencil_get_buffer_point_geom(bGPdata *gpd, short thickness) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - View3D *v3d = draw_ctx->v3d; ARegion *ar = draw_ctx->ar; RegionView3D *rv3d = draw_ctx->rv3d; ToolSettings *ts = scene->toolsettings; @@ -352,7 +367,7 @@ GPUBatch *DRW_gpencil_get_buffer_point_geom(bGPdata *gpd, short thickness) /* get origin to reproject point */ float origin[3]; bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); - ED_gp_get_drawing_reference(v3d, scene, ob, gpl, ts->gpencil_v3d_align, origin); + ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin); for (int i = 0; i < totpoints; i++, tpt++) { ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt); @@ -369,6 +384,40 @@ GPUBatch *DRW_gpencil_get_buffer_point_geom(bGPdata *gpd, short thickness) return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); } +/* create batch geometry data for current buffer control point shader */ +GPUBatch *DRW_gpencil_get_buffer_ctrlpoint_geom(bGPdata *gpd) +{ + bGPDcontrolpoint *cps = gpd->runtime.cp_points; + int totpoints = gpd->runtime.tot_cp_points; + + static GPUVertFormat format = { 0 }; + static uint pos_id, color_id, size_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + size_id = GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, totpoints); + + int idx = 0; + for (int i = 0; i < gpd->runtime.tot_cp_points; i++) { + bGPDcontrolpoint *cp = &cps[i]; + + GPU_vertbuf_attr_set(vbo, color_id, idx, cp->color); + + /* scale size */ + float size = cp->size * 0.8f; + GPU_vertbuf_attr_set(vbo, size_id, idx, &size); + + GPU_vertbuf_attr_set(vbo, pos_id, idx, &cp->x); + idx++; + } + + return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); +} + /* create batch geometry data for current buffer fill shader */ GPUBatch *DRW_gpencil_get_buffer_fill_geom(bGPdata *gpd) { @@ -384,7 +433,6 @@ GPUBatch *DRW_gpencil_get_buffer_fill_geom(bGPdata *gpd) const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - View3D *v3d = draw_ctx->v3d; ARegion *ar = draw_ctx->ar; ToolSettings *ts = scene->toolsettings; Object *ob = draw_ctx->obact; @@ -392,7 +440,7 @@ GPUBatch *DRW_gpencil_get_buffer_fill_geom(bGPdata *gpd) /* get origin to reproject point */ float origin[3]; bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); - ED_gp_get_drawing_reference(v3d, scene, ob, gpl, ts->gpencil_v3d_align, origin); + ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin); int tot_triangles = totpoints - 2; /* allocate memory for temporary areas */ @@ -455,7 +503,7 @@ void DRW_gpencil_get_edit_geom(struct GpencilBatchCacheElem *be, bGPDstroke *gps const DRWContextState *draw_ctx = DRW_context_state_get(); Object *ob = draw_ctx->obact; bGPdata *gpd = ob->data; - bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); + const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); int vgindex = ob->actdef - 1; if (!BLI_findlink(&ob->defbase, vgindex)) { @@ -553,7 +601,7 @@ void DRW_gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be, bGPDstroke *gp const DRWContextState *draw_ctx = DRW_context_state_get(); Object *ob = draw_ctx->obact; bGPdata *gpd = ob->data; - bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); + const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); int vgindex = ob->actdef - 1; if (!BLI_findlink(&ob->defbase, vgindex)) { diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c index c8b70953f87..32bf80d4757 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c @@ -73,7 +73,9 @@ static void gpencil_calc_vertex( { Object *ob = cache_ob->ob; const DRWContextState *draw_ctx = DRW_context_state_get(); - bGPDframe *gpf = NULL; + const bool main_onion = draw_ctx->v3d != NULL ? (draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true; + const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && + main_onion && DRW_gpencil_onion_active(gpd); const bool time_remap = BKE_gpencil_has_time_modifiers(ob); @@ -81,28 +83,41 @@ static void gpencil_calc_vertex( cache_ob->tot_triangles = 0; for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + bGPDframe *init_gpf = NULL; + const bool is_onion = ((do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN)); if (gpl->flag & GP_LAYER_HIDE) { continue; } - /* verify time modifiers */ - if ((time_remap) && (!stl->storage->simplify_modif)) { - int remap_cfra = BKE_gpencil_time_modifier( - draw_ctx->depsgraph, draw_ctx->scene, ob, gpl, cfra_eval, - stl->storage->is_render); - gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV); + /* if onion skin need to count all frames of the layer */ + if (is_onion) { + init_gpf = gpl->actframe; } else { - gpf = gpl->actframe; + /* verify time modifiers */ + if ((time_remap) && (!stl->storage->simplify_modif)) { + int remap_cfra = BKE_gpencil_time_modifier( + draw_ctx->depsgraph, draw_ctx->scene, ob, gpl, cfra_eval, + stl->storage->is_render); + init_gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV); + } + else { + init_gpf = gpl->actframe; + } } - if (gpf == NULL) { + if (init_gpf == NULL) { continue; } - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - cache_ob->tot_vertex += gps->totpoints + 3; - cache_ob->tot_triangles += gps->totpoints - 1; + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + cache_ob->tot_vertex += gps->totpoints + 3; + cache_ob->tot_triangles += gps->totpoints - 1; + } + if (!is_onion) { + break; + } } } @@ -244,13 +259,15 @@ static void gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, floa } /* recalc the internal geometry caches for fill and uvs */ -static void DRW_gpencil_recalc_geometry_caches(Object *ob, MaterialGPencilStyle *gp_style, bGPDstroke *gps) +static void DRW_gpencil_recalc_geometry_caches( + Object *ob, bGPDlayer *gpl, MaterialGPencilStyle *gp_style, bGPDstroke *gps) { if (gps->flag & GP_STROKE_RECALC_CACHES) { /* Calculate triangles cache for filling area (must be done only after changes) */ if ((gps->tot_triangles == 0) || (gps->triangles == NULL)) { if ((gps->totpoints > 2) && - ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0))) + ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || + (gp_style->fill_style > 0) || (gpl->blend_mode != eGplBlendMode_Normal))) { DRW_gpencil_triangulate_stroke_fill(ob, gps); } @@ -364,6 +381,17 @@ static DRWShadingGroup *DRW_gpencil_shgroup_fill_create( return grp; } +/* check if some onion is enabled */ +bool DRW_gpencil_onion_active(bGPdata *gpd) +{ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->onion_flag & GP_LAYER_ONIONSKIN) { + return true; + } + } + return false; +} + /* create shading group for strokes */ DRWShadingGroup *DRW_gpencil_shgroup_stroke_create( GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob, @@ -421,7 +449,7 @@ DRWShadingGroup *DRW_gpencil_shgroup_stroke_create( DRW_shgroup_uniform_int(grp, "xraymode", (const int *) &gpd->xray_mode, 1); } else { - /* for drawing always on front */ + /* for drawing always on predefined z-depth */ DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1); } @@ -514,7 +542,7 @@ static DRWShadingGroup *DRW_gpencil_shgroup_point_create( DRW_shgroup_uniform_int(grp, "xraymode", (const int *)&gpd->xray_mode, 1); } else { - /* for drawing always on front */ + /* for drawing always on on predefined z-depth */ DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1); } @@ -559,7 +587,10 @@ static void gpencil_add_fill_vertexdata( /* set color using material, tint color and opacity */ interp_v3_v3v3(tfill, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]); tfill[3] = gps->runtime.tmp_fill_rgba[3] * opacity; - if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) { + if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || + (gp_style->fill_style > 0) || + (gpl->blend_mode != eGplBlendMode_Normal)) + { if (cache->is_dirty) { const float *color; if (!onion) { @@ -581,7 +612,8 @@ static void gpencil_add_fill_vertexdata( /* add to list of groups */ if (old_len < cache->b_fill.vbo_len) { cache->grp_cache = gpencil_group_cache_add( - cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Fill, onion, + cache->grp_cache, gpl, gpf, gps, + eGpencilBatchGroupType_Fill, onion, cache->b_fill.vbo_len, &cache->grp_size, &cache->grp_used); } @@ -637,7 +669,8 @@ static void gpencil_add_stroke_vertexdata( /* add to list of groups */ if (old_len < cache->b_stroke.vbo_len) { cache->grp_cache = gpencil_group_cache_add( - cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Stroke, onion, + cache->grp_cache, gpl, gpf, gps, + eGpencilBatchGroupType_Stroke, onion, cache->b_stroke.vbo_len, &cache->grp_size, &cache->grp_used); } @@ -687,7 +720,8 @@ static void gpencil_add_editpoints_vertexdata( /* add to list of groups */ cache->grp_cache = gpencil_group_cache_add( - cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Edlin, false, + cache->grp_cache, gpl, gpf, gps, + eGpencilBatchGroupType_Edlin, false, cache->b_edlin.vbo_len, &cache->grp_size, &cache->grp_used); } @@ -699,7 +733,8 @@ static void gpencil_add_editpoints_vertexdata( /* add to list of groups */ cache->grp_cache = gpencil_group_cache_add( - cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Edit, false, + cache->grp_cache, gpl, gpf, gps, + eGpencilBatchGroupType_Edit, false, cache->b_edit.vbo_len, &cache->grp_size, &cache->grp_used); } @@ -771,13 +806,14 @@ static void gpencil_draw_strokes( /* be sure recalc all cache in source stroke to avoid recalculation when frame change * and improve fps */ if (src_gps) { - DRW_gpencil_recalc_geometry_caches(ob, gp_style, src_gps); + DRW_gpencil_recalc_geometry_caches(ob, gpl, gp_style, src_gps); } /* if the fill has any value, it's considered a fill and is not drawn if simplify fill is enabled */ if ((stl->storage->simplify_fill) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_REMOVE_FILL_LINE)) { if ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || - (gp_style->fill_style > GP_STYLE_FILL_STYLE_SOLID)) + (gp_style->fill_style > GP_STYLE_FILL_STYLE_SOLID) || + (gpl->blend_mode != eGplBlendMode_Normal)) { GP_SET_SRC_GPS(src_gps); continue; @@ -798,21 +834,28 @@ static void gpencil_draw_strokes( } } - /* fill */ - if ((gp_style->flag & GP_STYLE_FILL_SHOW) && - (!stl->storage->simplify_fill)) - { - gpencil_add_fill_vertexdata( - cache, ob, gpl, derived_gpf, gps, - opacity, tintcolor, false, custonion); - } - /* stroke */ - if ((gp_style->flag & GP_STYLE_STROKE_SHOW) && - (gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH)) + /* hide any blend layer */ + if ((!stl->storage->simplify_blend) || + (gpl->blend_mode == eGplBlendMode_Normal)) { - gpencil_add_stroke_vertexdata( - cache, ob, gpl, derived_gpf, gps, - opacity, tintcolor, false, custonion); + /* fill */ + if ((gp_style->flag & GP_STYLE_FILL_SHOW) && + (!stl->storage->simplify_fill) && + ((gps->flag & GP_STROKE_NOFILL) == 0)) + { + gpencil_add_fill_vertexdata( + cache, ob, gpl, derived_gpf, gps, + opacity, tintcolor, false, custonion); + } + /* stroke */ + if ((gp_style->flag & GP_STYLE_STROKE_SHOW) && + ((gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || + (gpl->blend_mode == eGplBlendMode_Normal))) + { + gpencil_add_stroke_vertexdata( + cache, ob, gpl, derived_gpf, gps, + opacity, tintcolor, false, custonion); + } } } @@ -1133,6 +1176,9 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, T { GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) : true; Brush *brush = BKE_paint_brush(&ts->gp_paint->paint); bGPdata *gpd_eval = ob->data; /* need the original to avoid cow overhead while drawing */ @@ -1156,7 +1202,7 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, T /* Check if may need to draw the active stroke cache, only if this layer is the active layer * that is being edited. (Stroke buffer is currently stored in gp-data) */ - if (ED_gpencil_session_active() && (gpd->runtime.sbuffer_size > 0)) { + if (gpd->runtime.sbuffer_size > 0) { if ((gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) { /* It should also be noted that sbuffer contains temporary point types * i.e. tGPspoints NOT bGPDspoints @@ -1166,11 +1212,11 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, T if (gpd->runtime.sbuffer_size > 1) { if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) { stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_stroke_create( - e_data, vedata, psl->drawing_pass, e_data->gpencil_stroke_sh, NULL, gpd, gp_style, -1, false); + e_data, vedata, psl->drawing_pass, e_data->gpencil_stroke_sh, NULL, gpd, gp_style, -1, false); } else { stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_point_create( - e_data, vedata, psl->drawing_pass, e_data->gpencil_point_sh, NULL, gpd, gp_style, -1, false); + e_data, vedata, psl->drawing_pass, e_data->gpencil_point_sh, NULL, gpd, gp_style, -1, false); } /* clean previous version of the batch */ @@ -1183,18 +1229,18 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, T /* use unit matrix because the buffer is in screen space and does not need conversion */ if (gpd->runtime.mode == GP_STYLE_MODE_LINE) { e_data->batch_buffer_stroke = DRW_gpencil_get_buffer_stroke_geom( - gpd, lthick); + gpd, lthick); } else { e_data->batch_buffer_stroke = DRW_gpencil_get_buffer_point_geom( - gpd, lthick); + gpd, lthick); } if (gp_style->flag & GP_STYLE_STROKE_SHOW) { DRW_shgroup_call_add( - stl->g_data->shgrps_drawing_stroke, - e_data->batch_buffer_stroke, - stl->storage->unit_matrix); + stl->g_data->shgrps_drawing_stroke, + e_data->batch_buffer_stroke, + stl->storage->unit_matrix); } if ((gpd->runtime.sbuffer_size >= 3) && @@ -1208,7 +1254,7 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, T gpd->runtime.sfill[3] = 0.5f; } stl->g_data->shgrps_drawing_fill = DRW_shgroup_create( - e_data->gpencil_drawing_fill_sh, psl->drawing_pass); + e_data->gpencil_drawing_fill_sh, psl->drawing_pass); /* clean previous version of the batch */ if (stl->storage->buffer_fill) { @@ -1219,15 +1265,44 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, T e_data->batch_buffer_fill = DRW_gpencil_get_buffer_fill_geom(gpd); DRW_shgroup_call_add( - stl->g_data->shgrps_drawing_fill, - e_data->batch_buffer_fill, - stl->storage->unit_matrix); + stl->g_data->shgrps_drawing_fill, + e_data->batch_buffer_fill, + stl->storage->unit_matrix); stl->storage->buffer_fill = true; } stl->storage->buffer_stroke = true; } } } + + /* control points */ + if ((overlay) && (gpd->runtime.tot_cp_points > 0) && + ((gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) && + ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) && + ((v3d->gizmo_flag & V3D_GIZMO_HIDE_TOOL) == 0)) + { + + DRWShadingGroup *shgrp = DRW_shgroup_create( + e_data->gpencil_edit_point_sh, psl->drawing_pass); + const float *viewport_size = DRW_viewport_size_get(); + DRW_shgroup_uniform_vec2(shgrp, "Viewport", viewport_size, 1); + + /* clean previous version of the batch */ + if (stl->storage->buffer_ctrlpoint) { + GPU_BATCH_DISCARD_SAFE(e_data->batch_buffer_ctrlpoint); + MEM_SAFE_FREE(e_data->batch_buffer_ctrlpoint); + stl->storage->buffer_ctrlpoint = false; + } + + e_data->batch_buffer_ctrlpoint = DRW_gpencil_get_buffer_ctrlpoint_geom(gpd); + + DRW_shgroup_call_add( + shgrp, + e_data->batch_buffer_ctrlpoint, + stl->storage->unit_matrix); + + stl->storage->buffer_ctrlpoint = true; + } } /* create all missing batches */ @@ -1253,12 +1328,21 @@ static void DRW_gpencil_create_batches(GpencilBatchCache *cache) /* create all shading groups */ static void DRW_gpencil_shgroups_create( GPENCIL_e_data *e_data, void *vedata, - Object *ob, bGPdata *gpd, + Object *ob, GpencilBatchCache *cache, tGPencilObjectCache *cache_ob) { GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + bGPdata *gpd = (bGPdata *)ob->data; + + GpencilBatchGroup *elm = NULL; DRWShadingGroup *shgrp = NULL; + tGPencilObjectCache_shgrp *array_elm = NULL; + + bGPDlayer *gpl = NULL; + bGPDlayer *gpl_prev = NULL; + int idx = 0; + bool tag_first = false; int start_stroke = 0; int start_point = 0; @@ -1266,12 +1350,27 @@ static void DRW_gpencil_shgroups_create( int start_edit = 0; int start_edlin = 0; - cache_ob->init_grp = NULL; - cache_ob->end_grp = NULL; - for (int i = 0; i < cache->grp_used; i++) { - GpencilBatchGroup *elm = &cache->grp_cache[i]; - bGPDlayer *gpl = elm->gpl; + elm = &cache->grp_cache[i]; + array_elm = &cache_ob->shgrp_array[idx]; + + /* save last group when change */ + if (gpl_prev == NULL) { + gpl_prev = elm->gpl; + tag_first = true; + } + else { + if (elm->gpl != gpl_prev) { + /* first layer is always blend Normal */ + array_elm->mode = idx == 0 ? eGplBlendMode_Normal: gpl->blend_mode; + array_elm->end_shgrp = shgrp; + gpl_prev = elm->gpl; + tag_first = true; + idx++; + } + } + + gpl = elm->gpl; bGPDframe *gpf = elm->gpf; bGPDstroke *gps = elm->gps; MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); @@ -1335,28 +1434,32 @@ static void DRW_gpencil_shgroups_create( } case eGpencilBatchGroupType_Edit: { - const int len = elm->vertex_idx - start_edit; - /* use always the same group */ - DRW_shgroup_call_range_add( - stl->g_data->shgrps_edit_point, - cache->b_edit.batch, - (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat, - start_edit, len); - - start_edit = elm->vertex_idx; + if (stl->g_data->shgrps_edit_point) { + const int len = elm->vertex_idx - start_edit; + /* use always the same group */ + DRW_shgroup_call_range_add( + stl->g_data->shgrps_edit_point, + cache->b_edit.batch, + (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat, + start_edit, len); + + start_edit = elm->vertex_idx; + } break; } case eGpencilBatchGroupType_Edlin: { - const int len = elm->vertex_idx - start_edlin; - /* use always the same group */ - DRW_shgroup_call_range_add( - stl->g_data->shgrps_edit_line, - cache->b_edlin.batch, - (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat, - start_edlin, len); - - start_edlin = elm->vertex_idx; + if (stl->g_data->shgrps_edit_line) { + const int len = elm->vertex_idx - start_edlin; + /* use always the same group */ + DRW_shgroup_call_range_add( + stl->g_data->shgrps_edit_line, + cache->b_edlin.batch, + (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat, + start_edlin, len); + + start_edlin = elm->vertex_idx; + } break; } default: @@ -1365,14 +1468,22 @@ static void DRW_gpencil_shgroups_create( } } /* save first group */ - if ((shgrp != NULL) && (cache_ob->init_grp == NULL)) { - cache_ob->init_grp = shgrp; + if ((shgrp != NULL) && (tag_first)) { + array_elm = &cache_ob->shgrp_array[idx]; + array_elm->mode = idx == 0 ? eGplBlendMode_Normal: gpl->blend_mode; + array_elm->clamp_layer = gpl->flag & GP_LAYER_USE_MASK; + array_elm->blend_opacity = gpl->opacity; + array_elm->init_shgrp = shgrp; + cache_ob->tot_layers++; + + tag_first = false; } } /* save last group */ if (shgrp != NULL) { - cache_ob->end_grp = shgrp; + array_elm->mode = idx == 0 ? eGplBlendMode_Normal : gpl->blend_mode; + array_elm->end_shgrp = shgrp; } } /* populate a datablock for multiedit (no onions, no modifiers) */ @@ -1425,7 +1536,7 @@ void DRW_gpencil_populate_multiedit( /* create batchs and shading groups */ DRW_gpencil_create_batches(cache); - DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob); + DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob); cache->is_dirty = false; } @@ -1450,7 +1561,8 @@ void DRW_gpencil_populate_datablock( bGPDframe *derived_gpf = NULL; const bool main_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true; - const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && main_onion; + const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && + main_onion && DRW_gpencil_onion_active(gpd); const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) : true; const bool time_remap = BKE_gpencil_has_time_modifiers(ob); @@ -1465,7 +1577,7 @@ void DRW_gpencil_populate_datablock( /* if object is duplicate, only create shading groups */ if (cache_ob->is_dup_ob) { - DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob); + DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob); return; } @@ -1481,8 +1593,9 @@ void DRW_gpencil_populate_datablock( /* draw normal strokes */ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* don't draw layer if hidden */ - if (gpl->flag & GP_LAYER_HIDE) + if (gpl->flag & GP_LAYER_HIDE) { continue; + } /* filter view layer to gp layers in the same view layer (for compo) */ if ((stl->storage->is_render) && (gpl->viewlayername[0] != '\0')) { @@ -1511,7 +1624,7 @@ void DRW_gpencil_populate_datablock( opacity = opacity * v3d->overlay.xray_alpha_bone; } /* fade no active layers */ - if ((overlay) && (draw_ctx->object_mode == OB_MODE_GPENCIL_PAINT) && + if ((overlay) && (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL) && (v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS) && (draw_ctx->obact) && (draw_ctx->obact == ob) && (gpl != gpl_active)) @@ -1535,8 +1648,7 @@ void DRW_gpencil_populate_datablock( /* draw onion skins */ if (!ID_IS_LINKED(&gpd->id)) { - if ((gpd->flag & GP_DATA_SHOW_ONIONSKINS) && - (do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN) && + if ((do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN) && ((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)) && (!cache_ob->is_dup_ob) && (gpd->id.us <= 1)) { @@ -1560,7 +1672,7 @@ void DRW_gpencil_populate_datablock( /* create batchs and shading groups */ DRW_gpencil_create_batches(cache); - DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob); + DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob); cache->is_dirty = false; } @@ -1574,9 +1686,10 @@ void DRW_gpencil_populate_particles(GPENCIL_e_data *e_data, void *vedata) tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i]; Object *ob = cache_ob->ob; if (cache_ob->is_dup_ob) { - bGPdata *gpd = (bGPdata *)ob->data; GpencilBatchCache *cache = ob->runtime.gpencil_cache; - DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob); + if (cache != NULL) { + DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob); + } } } } diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 7be06d501f1..dc62ca34c92 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -64,6 +64,7 @@ extern char datatoc_gpencil_paper_frag_glsl[]; extern char datatoc_gpencil_edit_point_vert_glsl[]; extern char datatoc_gpencil_edit_point_geom_glsl[]; extern char datatoc_gpencil_edit_point_frag_glsl[]; +extern char datatoc_gpencil_blend_frag_glsl[]; /* *********** STATIC *********** */ static GPENCIL_e_data e_data = {NULL}; /* Engine data */ @@ -89,7 +90,7 @@ void DRW_gpencil_multisample_ensure(GPENCIL_Data *vedata, int rect_w, int rect_h } if (txl->multisample_depth == NULL) { txl->multisample_depth = GPU_texture_create_2D_multisample( - rect_w, rect_h, GPU_DEPTH24_STENCIL8, NULL, samples, NULL); + rect_w, rect_h, GPU_DEPTH_COMPONENT24, NULL, samples, NULL); } GPU_framebuffer_ensure_config( &fbl->multisample_fb, { @@ -114,58 +115,66 @@ static void GPENCIL_create_framebuffers(void *vedata) const int size[2] = { (int)viewport_size[0], (int)viewport_size[1] }; /* create multiframe framebuffer for AA */ - if (stl->storage->multisamples > 0) { + if ((stl->storage->framebuffer_flag & GP_FRAMEBUFFER_MULTISAMPLE) && + (stl->storage->multisamples > 0)) + { DRW_gpencil_multisample_ensure(vedata, size[0], size[1]); } - /* temp textures */ - e_data.temp_depth_tx_a = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, - &draw_engine_gpencil_type); - e_data.temp_color_tx_a = DRW_texture_pool_query_2D(size[0], size[1], fb_format, - &draw_engine_gpencil_type); - GPU_framebuffer_ensure_config( - &fbl->temp_fb_a, { - GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_a), - GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_a) - }); - - e_data.temp_depth_tx_b = DRW_texture_pool_query_2D( - size[0], size[1], GPU_DEPTH24_STENCIL8, - &draw_engine_gpencil_type); - e_data.temp_color_tx_b = DRW_texture_pool_query_2D( - size[0], size[1], fb_format, - &draw_engine_gpencil_type); - GPU_framebuffer_ensure_config( - &fbl->temp_fb_b, { - GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_b), - GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_b) - }); - - /* used for rim and shadow FX effects */ - e_data.temp_depth_tx_fx = DRW_texture_pool_query_2D( - size[0], size[1], GPU_DEPTH24_STENCIL8, - &draw_engine_gpencil_type); - e_data.temp_color_tx_fx = DRW_texture_pool_query_2D( - size[0], size[1], fb_format, - &draw_engine_gpencil_type); - GPU_framebuffer_ensure_config( - &fbl->temp_fb_fx, { - GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_fx), - GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_fx), - }); + /* Framebufers for basic object drawing */ + if (stl->storage->framebuffer_flag & GP_FRAMEBUFFER_BASIC) { + /* temp textures for ping-pong buffers */ + e_data.temp_depth_tx_a = DRW_texture_pool_query_2D( + size[0], size[1], GPU_DEPTH_COMPONENT24, + &draw_engine_gpencil_type); + e_data.temp_color_tx_a = DRW_texture_pool_query_2D(size[0], size[1], fb_format, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config( + &fbl->temp_fb_a, { + GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_a), + GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_a) + }); + + e_data.temp_depth_tx_b = DRW_texture_pool_query_2D( + size[0], size[1], GPU_DEPTH_COMPONENT24, + &draw_engine_gpencil_type); + e_data.temp_color_tx_b = DRW_texture_pool_query_2D( + size[0], size[1], fb_format, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config( + &fbl->temp_fb_b, { + GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_b), + GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_b) + }); + + /* used for FX effects and Layer blending */ + e_data.temp_depth_tx_fx = DRW_texture_pool_query_2D( + size[0], size[1], GPU_DEPTH_COMPONENT24, + &draw_engine_gpencil_type); + e_data.temp_color_tx_fx = DRW_texture_pool_query_2D( + size[0], size[1], fb_format, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config( + &fbl->temp_fb_fx, { + GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_fx), + GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_fx), + }); + } /* background framebuffer to speed up drawing process (always 16 bits) */ - e_data.background_depth_tx = DRW_texture_pool_query_2D( - size[0], size[1], GPU_DEPTH24_STENCIL8, - &draw_engine_gpencil_type); - e_data.background_color_tx = DRW_texture_pool_query_2D( - size[0], size[1], GPU_RGBA32F, - &draw_engine_gpencil_type); - GPU_framebuffer_ensure_config( - &fbl->background_fb, { - GPU_ATTACHMENT_TEXTURE(e_data.background_depth_tx), - GPU_ATTACHMENT_TEXTURE(e_data.background_color_tx) - }); + if (stl->storage->framebuffer_flag & GP_FRAMEBUFFER_DRAW) { + e_data.background_depth_tx = DRW_texture_pool_query_2D( + size[0], size[1], GPU_DEPTH_COMPONENT24, + &draw_engine_gpencil_type); + e_data.background_color_tx = DRW_texture_pool_query_2D( + size[0], size[1], GPU_RGBA32F, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config( + &fbl->background_fb, { + GPU_ATTACHMENT_TEXTURE(e_data.background_depth_tx), + GPU_ATTACHMENT_TEXTURE(e_data.background_color_tx) + }); + } } } @@ -221,6 +230,11 @@ static void GPENCIL_create_shaders(void) e_data.gpencil_simple_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_simple_mix_frag_glsl, NULL); } + /* blend */ + if (!e_data.gpencil_blend_fullscreen_sh) { + e_data.gpencil_blend_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_blend_frag_glsl, NULL); + } + /* shaders for use when drawing */ if (!e_data.gpencil_background_sh) { e_data.gpencil_background_sh = DRW_shader_create_fullscreen(datatoc_gpencil_background_frag_glsl, NULL); @@ -243,9 +257,6 @@ void GPENCIL_engine_init(void *vedata) stl->storage->multisamples = U.gpencil_multisamples; - /* create framebuffers */ - GPENCIL_create_framebuffers(vedata); - /* create shaders */ GPENCIL_create_shaders(); GPENCIL_create_fx_shaders(&e_data); @@ -266,6 +277,7 @@ static void GPENCIL_engine_free(void) DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh); DRW_SHADER_FREE_SAFE(e_data.gpencil_fullscreen_sh); DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_fullscreen_sh); + DRW_SHADER_FREE_SAFE(e_data.gpencil_blend_fullscreen_sh); DRW_SHADER_FREE_SAFE(e_data.gpencil_background_sh); DRW_SHADER_FREE_SAFE(e_data.gpencil_paper_sh); @@ -277,6 +289,9 @@ static void GPENCIL_engine_free(void) GPU_BATCH_DISCARD_SAFE(e_data.batch_buffer_fill); MEM_SAFE_FREE(e_data.batch_buffer_fill); + GPU_BATCH_DISCARD_SAFE(e_data.batch_buffer_ctrlpoint); + MEM_SAFE_FREE(e_data.batch_buffer_ctrlpoint); + GPU_BATCH_DISCARD_SAFE(e_data.batch_grid); MEM_SAFE_FREE(e_data.batch_grid); @@ -371,6 +386,7 @@ void GPENCIL_cache_init(void *vedata) stl->storage->simplify_fill = GP_SIMPLIFY_FILL(scene, stl->storage->is_playing); stl->storage->simplify_modif = GP_SIMPLIFY_MODIF(scene, stl->storage->is_playing); stl->storage->simplify_fx = GP_SIMPLIFY_FX(scene, stl->storage->is_playing); + stl->storage->simplify_blend = GP_SIMPLIFY_BLEND(scene, stl->storage->is_playing); /* save pixsize */ stl->storage->pixsize = DRW_viewport_pixelsize_get(); @@ -485,6 +501,21 @@ void GPENCIL_cache_init(void *vedata) stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass); } + /* blend layers pass */ + psl->blend_pass = DRW_pass_create( + "GPencil Blend Layers Pass", + DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + DRWShadingGroup *blend_shgrp = DRW_shgroup_create(e_data.gpencil_blend_fullscreen_sh, psl->blend_pass); + DRW_shgroup_call_add(blend_shgrp, quad, NULL); + DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeColor", &e_data.temp_color_tx_a); + DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeDepth", &e_data.temp_depth_tx_a); + DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendColor", &e_data.temp_color_tx_fx); + DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendDepth", &e_data.temp_depth_tx_fx); + DRW_shgroup_uniform_int(blend_shgrp, "mode", &stl->storage->blend_mode, 1); + DRW_shgroup_uniform_int(blend_shgrp, "clamp_layer", &stl->storage->clamp_layer, 1); + DRW_shgroup_uniform_float(blend_shgrp, "blend_opacity", &stl->storage->blend_opacity, 1); + DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1); + /* create effects passes */ if (!stl->storage->simplify_fx) { GPENCIL_create_fx_passes(psl); @@ -540,6 +571,10 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) if (ob->type == OB_GPENCIL && ob->data) { bGPdata *gpd = (bGPdata *)ob->data; + /* enable multisample and basic framebuffer creation */ + stl->storage->framebuffer_flag |= GP_FRAMEBUFFER_MULTISAMPLE; + stl->storage->framebuffer_flag |= GP_FRAMEBUFFER_BASIC; + /* when start/stop animation the cache must be set as dirty to reset all data */ if (stl->storage->reset_cache) { gpd->flag |= GP_DATA_CACHE_IS_DIRTY; @@ -598,7 +633,18 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) void GPENCIL_cache_finish(void *vedata) { + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + + /* draw particles */ DRW_gpencil_populate_particles(&e_data, vedata); + + if (stl->g_data->session_flag & (GP_DRW_PAINT_IDLE | GP_DRW_PAINT_FILLING)) { + stl->storage->framebuffer_flag |= GP_FRAMEBUFFER_DRAW; + } + + /* create framebuffers */ + GPENCIL_create_framebuffers(vedata); + } /* helper function to sort inverse gpencil objects using qsort */ @@ -639,12 +685,40 @@ static void gpencil_free_obj_runtime(GPENCIL_StorageList *stl) tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i]; bGPdata *gpd = cache_ob->gpd; gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY; + + /* free shgrp array */ + cache_ob->tot_layers = 0; + MEM_SAFE_FREE(cache_ob->shgrp_array); } /* free the cache itself */ MEM_SAFE_FREE(stl->g_data->gp_object_cache); } +static void gpencil_draw_pass_range( + GPENCIL_FramebufferList *fbl, GPENCIL_StorageList *stl, + GPENCIL_PassList *psl, GPENCIL_TextureList *txl, + GPUFrameBuffer *fb, + DRWShadingGroup *init_shgrp, DRWShadingGroup *end_shgrp, bool multi) +{ + if (init_shgrp == NULL) { + return; + } + + /* previews don't use AA */ + if ((!stl->storage->is_mat_preview) && (multi)) { + MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl); + } + + DRW_draw_pass_subset( + psl->stroke_pass, init_shgrp, end_shgrp); + + if ((!stl->storage->is_mat_preview) && (multi)) { + MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fb, txl); + } + +} + /* draw scene */ void GPENCIL_draw_scene(void *ved) { @@ -657,6 +731,10 @@ void GPENCIL_draw_scene(void *ved) GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl; tGPencilObjectCache *cache_ob; + tGPencilObjectCache_shgrp *array_elm = NULL; + DRWShadingGroup *init_shgrp = NULL; + DRWShadingGroup *end_shgrp = NULL; + const float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -664,6 +742,8 @@ void GPENCIL_draw_scene(void *ved) Object *obact = draw_ctx->obact; const bool playing = stl->storage->is_playing; const bool is_render = stl->storage->is_render; + bGPdata *gpd_act = (obact) && (obact->type == OB_GPENCIL) ? (bGPdata *)obact->data : NULL; + const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd_act); /* paper pass to display a comfortable area to draw over complex scenes with geometry */ if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) { @@ -712,7 +792,7 @@ void GPENCIL_draw_scene(void *ved) for (int i = 0; i < stl->g_data->gp_cache_used; i++) { cache_ob = &stl->g_data->gp_object_cache[i]; bGPdata *gpd = cache_ob->gpd; - + init_shgrp = NULL; /* Render stroke in separated framebuffer */ GPU_framebuffer_bind(fbl->temp_fb_a); GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f); @@ -720,19 +800,69 @@ void GPENCIL_draw_scene(void *ved) /* Stroke Pass: * draw only a subset that usually starts with a fill and ends with stroke */ - if (cache_ob->init_grp) { - /* previews don't use AA */ - if (!stl->storage->is_mat_preview) { - MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl); - } + bool use_blend = false; + if (cache_ob->tot_layers > 0) { + for (int e = 0; e < cache_ob->tot_layers; e++) { + bool is_last = e == cache_ob->tot_layers - 1 ? true : false; + array_elm = &cache_ob->shgrp_array[e]; + + if (((array_elm->mode == eGplBlendMode_Normal) && + (!use_blend) && (!array_elm->clamp_layer)) || + (e == 0)) + { + if (init_shgrp == NULL) { + init_shgrp = array_elm->init_shgrp; + } + end_shgrp = array_elm->end_shgrp; + } + else { + use_blend = true; + /* draw pending groups */ + gpencil_draw_pass_range( + fbl, stl, psl, txl, fbl->temp_fb_a, + init_shgrp, end_shgrp, is_last); + + /* draw current group in separated texture */ + init_shgrp = array_elm->init_shgrp; + end_shgrp = array_elm->end_shgrp; + + GPU_framebuffer_bind(fbl->temp_fb_fx); + GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f); + gpencil_draw_pass_range( + fbl, stl, psl, txl, fbl->temp_fb_fx, + init_shgrp, end_shgrp, + is_last); + + /* Blend A texture and FX texture */ + GPU_framebuffer_bind(fbl->temp_fb_b); + GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f); + stl->storage->blend_mode = array_elm->mode; + stl->storage->clamp_layer = (int)array_elm->clamp_layer; + stl->storage->blend_opacity = array_elm->blend_opacity; + stl->storage->tonemapping = stl->storage->is_render ? 1 : 0; + DRW_draw_pass(psl->blend_pass); + stl->storage->tonemapping = 0; + + /* Copy B texture to A texture to follow loop */ + e_data.input_depth_tx = e_data.temp_depth_tx_b; + e_data.input_color_tx = e_data.temp_color_tx_b; + + GPU_framebuffer_bind(fbl->temp_fb_a); + GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f); + DRW_draw_pass(psl->mix_pass_noblend); + + /* prepare next group */ + init_shgrp = NULL; + } - DRW_draw_pass_subset( - psl->stroke_pass, cache_ob->init_grp, cache_ob->end_grp); - - if (!stl->storage->is_mat_preview) { - MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fbl->temp_fb_a, txl); } + /* last group */ + gpencil_draw_pass_range( + fbl, stl, psl, txl, fbl->temp_fb_a, + init_shgrp, end_shgrp, + true); } + /* Current buffer drawing */ if ((!is_render) && (cache_ob->is_dup_ob == false)) { DRW_draw_pass(psl->drawing_pass); @@ -770,7 +900,7 @@ void GPENCIL_draw_scene(void *ved) } } /* edit points */ - if ((!is_render) && (!playing)) { + if ((!is_render) && (!playing) && (is_edit)) { DRW_draw_pass(psl->edit_pass); } } diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 0fe25ba9f0f..6f2b40136ca 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -54,17 +54,23 @@ struct RenderLayer; #define GP_SIMPLIFY_FILL(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FILL))) #define GP_SIMPLIFY_MODIF(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER))) #define GP_SIMPLIFY_FX(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FX))) +#define GP_SIMPLIFY_BLEND(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_BLEND))) #define GP_IS_CAMERAVIEW ((rv3d != NULL) && (rv3d->persp == RV3D_CAMOB && v3d->camera)) /* *********** OBJECTS CACHE *********** */ +typedef struct tGPencilObjectCache_shgrp { + int mode; + bool clamp_layer; + float blend_opacity; + DRWShadingGroup *init_shgrp; + DRWShadingGroup *end_shgrp; +} tGPencilObjectCache_shgrp; /* used to save gpencil object data for drawing */ typedef struct tGPencilObjectCache { struct Object *ob; struct bGPdata *gpd; - DRWShadingGroup *init_grp; - DRWShadingGroup *end_grp; int idx; /*original index, can change after sort */ /* effects */ @@ -90,6 +96,11 @@ typedef struct tGPencilObjectCache { /* GPU data size */ int tot_vertex; int tot_triangles; + + /* Save shader groups by layer */ + int tot_layers; + tGPencilObjectCache_shgrp *shgrp_array; + } tGPencilObjectCache; /* *********** LISTS *********** */ @@ -122,15 +133,23 @@ typedef struct GPENCIL_Storage { bool reset_cache; bool buffer_stroke; bool buffer_fill; + bool buffer_ctrlpoint; const float *pixsize; float render_pixsize; int tonemapping; short multisamples; + short framebuffer_flag; /* flag what framebuffer need to create */ + + int blend_mode; + int clamp_layer; + float blend_opacity; + /* simplify settings*/ bool simplify_fill; bool simplify_modif; bool simplify_fx; + bool simplify_blend; /* Render Matrices and data */ float persmat[4][4], persinv[4][4]; @@ -143,6 +162,12 @@ typedef struct GPENCIL_Storage { Object *camera; /* camera pointer for render mode */ } GPENCIL_Storage; +typedef enum eGpencilFramebuffer_Flag { + GP_FRAMEBUFFER_MULTISAMPLE = (1 << 0), + GP_FRAMEBUFFER_BASIC = (1 << 1), + GP_FRAMEBUFFER_DRAW = (1 << 2), +} eGpencilFramebuffer_Flag; + typedef struct GPENCIL_StorageList { struct GPENCIL_Storage *storage; struct g_data *g_data; @@ -158,6 +183,7 @@ typedef struct GPENCIL_PassList { struct DRWPass *background_pass; struct DRWPass *paper_pass; struct DRWPass *grid_pass; + struct DRWPass *blend_pass; /* effects */ struct DRWPass *fx_shader_pass; @@ -232,6 +258,7 @@ typedef struct GPENCIL_e_data { struct GPUShader *gpencil_drawing_fill_sh; struct GPUShader *gpencil_fullscreen_sh; struct GPUShader *gpencil_simple_fullscreen_sh; + struct GPUShader *gpencil_blend_fullscreen_sh; struct GPUShader *gpencil_background_sh; struct GPUShader *gpencil_paper_sh; @@ -273,6 +300,7 @@ typedef struct GPENCIL_e_data { /* for buffer only one batch is nedeed because the drawing is only of one stroke */ GPUBatch *batch_buffer_stroke; GPUBatch *batch_buffer_fill; + GPUBatch *batch_buffer_ctrlpoint; /* grid geometry */ GPUBatch *batch_grid; @@ -360,6 +388,7 @@ void DRW_gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be, struct bGPDstr struct GPUBatch *DRW_gpencil_get_buffer_stroke_geom(struct bGPdata *gpd, short thickness); struct GPUBatch *DRW_gpencil_get_buffer_fill_geom(struct bGPdata *gpd); struct GPUBatch *DRW_gpencil_get_buffer_point_geom(struct bGPdata *gpd, short thickness); +struct GPUBatch *DRW_gpencil_get_buffer_ctrlpoint_geom(struct bGPdata *gpd); struct GPUBatch *DRW_gpencil_get_grid(Object *ob); /* object cache functions */ @@ -367,6 +396,8 @@ struct tGPencilObjectCache *gpencil_object_cache_add( struct tGPencilObjectCache *cache_array, struct Object *ob, int *gp_cache_size, int *gp_cache_used); +bool DRW_gpencil_onion_active(struct bGPdata *gpd); + /* shading groups cache functions */ struct GpencilBatchGroup *gpencil_group_cache_add( struct GpencilBatchGroup *cache_array, diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c index 8dc15472a20..51a8209fbf2 100644 --- a/source/blender/draw/engines/gpencil/gpencil_render.c +++ b/source/blender/draw/engines/gpencil/gpencil_render.c @@ -85,7 +85,7 @@ void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgra } vedata->render_depth_tx = DRW_texture_pool_query_2D( - size[0], size[1], GPU_DEPTH24_STENCIL8, + size[0], size[1], GPU_DEPTH_COMPONENT24, &draw_engine_gpencil_type); vedata->render_color_tx = DRW_texture_pool_query_2D( size[0], size[1], GPU_RGBA32F, diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c index fcadf296253..225dc1a58d7 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -82,9 +82,9 @@ static bool effect_is_active(bGPdata *gpd, ShaderFxData *fx, bool is_render) /** * Get normal of draw using one stroke of visible layer - * \param gpd GP datablock - * \param r_point Point on plane - * \param r_normal Normal vector + * \param gpd: GP datablock + * \param r_point: Point on plane + * \param r_normal: Normal vector */ static bool get_normal_vector(bGPdata *gpd, float r_point[3], float r_normal[3]) { @@ -443,6 +443,9 @@ static void DRW_gpencil_fx_shadow( } ShadowShaderFxData *fxd = (ShadowShaderFxData *)fx; if ((!fxd->object) && (fxd->flag & FX_SHADOW_USE_OBJECT)) { + fxd->runtime.fx_sh = NULL; + fxd->runtime.fx_sh_b = NULL; + fxd->runtime.fx_sh_c = NULL; return; } diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl new file mode 100644 index 00000000000..f5696116eea --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl @@ -0,0 +1,155 @@ +in vec4 uvcoordsvar; + +out vec4 FragColor; + +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; +uniform sampler2D blendColor; +uniform sampler2D blendDepth; +uniform int mode; +uniform int clamp_layer; +uniform float blend_opacity; +uniform int tonemapping; + +#define ON 1 +#define OFF 0 + +#define MODE_NORMAL 0 +#define MODE_OVERLAY 1 +#define MODE_ADD 2 +#define MODE_SUB 3 +#define MODE_MULTIPLY 4 +#define MODE_DIVIDE 5 + +float overlay_color(float a, float b) +{ + float rtn; + if (a < 0.5) { + rtn = 2.0 * a * b; + } + else { + rtn = 1.0 - 2.0 * (1.0 - a) * (1.0 - b); + } + + return rtn; +} + +vec4 get_blend_color(int mode, vec4 src_color, vec4 blend_color) +{ + vec4 mix_color = blend_color; + vec4 outcolor; + + if (mix_color.a == 0) { + outcolor = src_color; + } + else if (mode == MODE_OVERLAY) { + mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity; + outcolor.r = overlay_color(src_color.r, mix_color.r); + outcolor.g = overlay_color(src_color.g, mix_color.g); + outcolor.b = overlay_color(src_color.b, mix_color.b); + outcolor.a = src_color.a; + } + else if (mode == MODE_ADD){ + mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity; + outcolor = src_color + mix_color; + outcolor.a = src_color.a; + } + else if (mode == MODE_SUB){ + outcolor = src_color - mix_color; + outcolor.a = clamp(src_color.a - (mix_color.a * blend_opacity), 0.0, 1.0); + } + else if (mode == MODE_MULTIPLY) { + /* interpolate between 1 and color using opacity */ + mix_color.rgb = mix(vec3(1,1,1), mix_color.rgb * mix_color.a, blend_opacity); + outcolor = src_color * mix_color; + outcolor.a = src_color.a; + } + else if (mode == MODE_DIVIDE) { + mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity; + outcolor = src_color / mix_color; + outcolor.a = src_color.a; + } + else { + outcolor = mix_color * blend_opacity;; + outcolor.a = src_color.a; + } + + return outcolor; +} + +float linearrgb_to_srgb(float c) +{ + if (c < 0.0031308) + return (c < 0.0) ? 0.0 : c * 12.92; + else + return 1.055 * pow(c, 1.0 / 2.4) - 0.055; +} + +vec4 tone(vec4 stroke_color) +{ + if (tonemapping == 1) { + vec4 color = vec4(0, 0, 0, stroke_color.a); + color.r = linearrgb_to_srgb(stroke_color.r); + color.g = linearrgb_to_srgb(stroke_color.g); + color.b = linearrgb_to_srgb(stroke_color.b); + return color; + } + else { + return stroke_color; + } +} + +void main() +{ + vec4 outcolor; + ivec2 uv = ivec2(gl_FragCoord.xy); + vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba; + float stroke_depth = texelFetch(strokeDepth, uv, 0).r; + + vec4 mix_color = texelFetch(blendColor, uv, 0).rgba; + float mix_depth = texelFetch(blendDepth, uv, 0).r; + + /* premult alpha factor to remove double blend effects */ + if (stroke_color.a > 0) { + stroke_color = vec4(vec3(stroke_color.rgb / stroke_color.a), stroke_color.a); + } + if (mix_color.a > 0) { + mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a); + } + + /* Normal mode */ + if (mode == MODE_NORMAL) { + if (stroke_color.a > 0) { + if (mix_color.a > 0) { + FragColor = vec4(mix(stroke_color.rgb, mix_color.rgb, mix_color.a), stroke_color.a); + gl_FragDepth = mix_depth; + } + else { + FragColor = stroke_color; + gl_FragDepth = stroke_depth; + } + } + else { + if (clamp_layer == ON) { + discard; + } + else { + FragColor = mix_color; + gl_FragDepth = mix_depth; + } + } + FragColor = tone(FragColor); + return; + } + + /* if not using mask, return mix color */ + if ((stroke_color.a == 0) && (clamp_layer == OFF)) { + FragColor = tone(mix_color); + gl_FragDepth = mix_depth; + return; + } + + /* apply blend mode */ + FragColor = tone(get_blend_color(mode, stroke_color, mix_color)); + gl_FragDepth = stroke_depth; +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl index f9054b44996..748f69ab21a 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl @@ -45,6 +45,22 @@ float getZdepth(vec4 point) /* in front by default */ return 0.000001; } + +/* check equality but with a small tolerance */ +bool is_equal(vec4 p1, vec4 p2) +{ + float limit = 0.0001; + float x = abs(p1.x - p2.x); + float y = abs(p1.y - p2.y); + float z = abs(p1.z - p2.z); + + if ((x < limit) && (y < limit) && (z < limit)) { + return true; + } + + return false; +} + void main(void) { float MiterLimit = 0.75; @@ -143,7 +159,7 @@ void main(void) } /* generate the start endcap (alpha < 0 used as endcap flag)*/ - if ((P0 == P2) && (color_type == GPENCIL_COLOR_SOLID)){ + if (is_equal(P0,P2) && (color_type == GPENCIL_COLOR_SOLID)){ mTexCoord = vec2(2, 1); mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ; vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0; @@ -183,7 +199,7 @@ void main(void) EmitVertex(); /* generate the end endcap (alpha < 0 used as endcap flag)*/ - if ((P1 == P3) && (color_type == GPENCIL_COLOR_SOLID)){ + if (is_equal(P1,P3) && (color_type == GPENCIL_COLOR_SOLID) && (finaluvdata[2].x > 0)){ mTexCoord = vec2(finaluvdata[2].x, 2); mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ; uvfac = finaluvdata[2].x; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl index fafb164a694..769d453bb18 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl @@ -3,6 +3,7 @@ out vec4 fragColor; uniform sampler2D depthBuffer; uniform sampler2D colorBuffer; uniform sampler2D normalBuffer; +uniform usampler2D objectId; uniform vec2 invertedViewportSize; uniform mat4 WinMatrix; /* inverse WinMatrix */ @@ -10,6 +11,7 @@ uniform mat4 WinMatrix; /* inverse WinMatrix */ uniform vec4 viewvecs[3]; uniform vec4 ssao_params; uniform vec4 ssao_settings; +uniform vec2 curvature_settings; uniform sampler2D ssao_jitter; layout(std140) uniform samples_block { @@ -23,7 +25,7 @@ layout(std140) uniform samples_block { #define ssao_distance ssao_settings.x #define ssao_factor_cavity ssao_settings.y #define ssao_factor_edge ssao_settings.z -#define ssao_attenuation ssao_settings.a +#define ssao_attenuation ssao_settings.w vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth) { @@ -54,17 +56,22 @@ void main() vec2 screenco = vec2(gl_FragCoord.xy) * invertedViewportSize; ivec2 texel = ivec2(gl_FragCoord.xy); + float cavity = 0.0, edges = 0.0, curvature = 0.0; + +#ifdef USE_CAVITY float depth = texelFetch(depthBuffer, texel, 0).x; vec3 position = get_view_space_from_depth(screenco, depth); + vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg); - vec4 diffuse_color = texelFetch(colorBuffer, texel, 0); - vec3 normal_viewport = normal_decode(texelFetch(normalBuffer, texel, 0).rg); - if (diffuse_color.a == 0.0) { - normal_viewport = -normal_viewport; - } - - float cavity = 0.0, edges = 0.0; ssao_factors(depth, normal_viewport, position, screenco, cavity, edges); +#endif + +#ifdef USE_CURVATURE + curvature = calculate_curvature(objectId, normalBuffer, texel, curvature_settings.x, curvature_settings.y); +#endif + + float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0); - fragColor = vec4(cavity, edges, 0.0, 1.0); + /* Using UNORM render target so compress the range. */ + fragColor = vec4(final_cavity_factor / CAVITY_BUFFER_RANGE); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl index c56e02e72d6..25942b162ee 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl @@ -2,6 +2,8 @@ #define EPSILON 0.00001 #define M_PI 3.14159265358979323846 +#define CAVITY_BUFFER_RANGE 4.0 + /* 4x4 bayer matrix prepared for 8bit UNORM precision error. */ #define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0)) const vec4 dither_mat4x4[4] = vec4[4]( @@ -17,9 +19,13 @@ float bayer_dither_noise() { return dither_mat4x4[tx1.x][tx1.y]; } +#ifdef WORKBENCH_ENCODE_NORMALS + +#define WB_Normal vec2 + /* From http://aras-p.info/texts/CompactNormalStorage.html * Using Method #4: Spheremap Transform */ -vec3 normal_decode(vec2 enc) +vec3 workbench_normal_decode(WB_Normal enc) { vec2 fenc = enc.xy * 4.0 - 2.0; float f = dot(fenc, fenc); @@ -32,37 +38,53 @@ vec3 normal_decode(vec2 enc) /* From http://aras-p.info/texts/CompactNormalStorage.html * Using Method #4: Spheremap Transform */ -vec2 normal_encode(vec3 n) +WB_Normal workbench_normal_encode(vec3 n) { float p = sqrt(n.z * 8.0 + 8.0); - return vec2(n.xy / p + 0.5); + n.xy = clamp(n.xy / p + 0.5, 0.0, 1.0); + return n.xy; } -void fresnel(vec3 I, vec3 N, float ior, out float kr) +#else +#define WB_Normal vec3 +/* Well just do nothing... */ +# define workbench_normal_encode(a) (a) +# define workbench_normal_decode(a) (a) +#endif /* WORKBENCH_ENCODE_NORMALS */ + +/* Encoding into the alpha of a RGBA8 UNORM texture. */ +#define TARGET_BITCOUNT 8u +#define METALLIC_BITS 3u /* Metallic channel is less important. */ +#define ROUGHNESS_BITS (TARGET_BITCOUNT - METALLIC_BITS) +#define TOTAL_BITS (METALLIC_BITS + ROUGHNESS_BITS) + +/* Encode 2 float into 1 with the desired precision. */ +float workbench_float_pair_encode(float v1, float v2) { - float cosi = clamp(dot(I, N), -1.0, 1.0); - float etai = 1.0; - float etat = ior; - if (cosi > 0) { - etat = 1.0; - etai = ior; - } + // const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS); + // const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS); + // const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS); + /* Same as above because some compiler are dumb af. and think we use mediump int. */ + const int total_mask = 0xFF; + const int v1_mask = 0x1F; + const int v2_mask = 0x7; + int iv1 = int(v1 * float(v1_mask)); + int iv2 = int(v2 * float(v2_mask)) << int(ROUGHNESS_BITS); + return float(iv1 | iv2) * (1.0 / float(total_mask)); +} - // Compute sini using Snell's law - float sint = etai / etat * sqrt(max(0.0, 1.0 - cosi * cosi)); - // Total internal reflection - if (sint >= 1) { - kr = 1; - } - else { - float cost = sqrt(max(0.0, 1.0 - sint * sint)); - cosi = abs(cosi); - float Rs = ((etat * cosi) - (etai * cost)) / ((etat * cosi) + (etai * cost)); - float Rp = ((etai * cosi) - (etat * cost)) / ((etai * cosi) + (etat * cost)); - kr = (Rs * Rs + Rp * Rp) / 2; - } - // As a consequence of the conservation of energy, transmittance is given by: - // kt = 1 - kr; +void workbench_float_pair_decode(float data, out float v1, out float v2) +{ + // const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS); + // const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS); + // const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS); + /* Same as above because some compiler are dumb af. and think we use mediump int. */ + const int total_mask = 0xFF; + const int v1_mask = 0x1F; + const int v2_mask = 0x7; + int idata = int(data * float(total_mask)); + v1 = float(idata & v1_mask) * (1.0 / float(v1_mask)); + v2 = float(idata >> int(ROUGHNESS_BITS)) * (1.0 / float(v2_mask)); } float calculate_transparent_weight(float z, float alpha) @@ -119,3 +141,21 @@ vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped) } return matcap_uv * 0.496 + 0.5; } + +float srgb_to_linearrgb(float c) +{ + if (c < 0.04045) + return (c < 0.0) ? 0.0 : c * (1.0 / 12.92); + else + return pow((c + 0.055) * (1.0 / 1.055), 2.4); +} + +vec4 srgb_to_linearrgb(vec4 col_from) +{ + vec4 col_to; + col_to.r = srgb_to_linearrgb(col_from.r); + col_to.g = srgb_to_linearrgb(col_from.g); + col_to.b = srgb_to_linearrgb(col_from.b); + col_to.a = col_from.a; + return col_to; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl new file mode 100644 index 00000000000..d0281f6c85c --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl @@ -0,0 +1,41 @@ +#ifndef CURVATURE_OFFSET +# define CURVATURE_OFFSET 1 +#endif + +float curvature_soft_clamp(float curvature, float control) +{ + if (curvature < 0.5 / control) { + return curvature * (1.0 - curvature * control); + } + return 0.25 / control; +} + +float calculate_curvature(usampler2D objectId, sampler2D normalBuffer, ivec2 texel, float ridge, float valley) +{ + uint object_up = texelFetchOffset(objectId, texel, 0, ivec2(0, CURVATURE_OFFSET)).r; + uint object_down = texelFetchOffset(objectId, texel, 0, ivec2(0, -CURVATURE_OFFSET)).r; + uint object_left = texelFetchOffset(objectId, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).r; + uint object_right = texelFetchOffset(objectId, texel, 0, ivec2( CURVATURE_OFFSET, 0)).r; + + if((object_up != object_down) || (object_right != object_left)) { + return 0.0; + } + + vec2 normal_up = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, CURVATURE_OFFSET)).rg; + vec2 normal_down = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, -CURVATURE_OFFSET)).rg; + vec2 normal_left = texelFetchOffset(normalBuffer, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).rg; + vec2 normal_right = texelFetchOffset(normalBuffer, texel, 0, ivec2( CURVATURE_OFFSET, 0)).rg; + + normal_up = workbench_normal_decode(normal_up ).rg; + normal_down = workbench_normal_decode(normal_down ).rg; + normal_left = workbench_normal_decode(normal_left ).rg; + normal_right = workbench_normal_decode(normal_right).rg; + + float normal_diff = ((normal_up.g - normal_down.g) + (normal_right.r - normal_left.r)); + + if (normal_diff < 0) { + return -2.0 * curvature_soft_clamp(-normal_diff, valley); + } + + return 2.0 * curvature_soft_clamp(normal_diff, ridge); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl index 7ba6b3a5193..6deb29f6bca 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl @@ -1,17 +1,20 @@ struct LightData { - vec4 light_direction_vs; + vec4 direction; vec4 specular_color; + vec4 diffuse_color_wrap; /* rgb: diffuse col a: wrapped lighting factor */ }; struct WorldData { - vec3 spherical_harmonics_coefs[STUDIOLIGHT_SH_MAX_COMPONENTS]; vec4 background_color_low; vec4 background_color_high; vec4 object_outline_color; vec4 shadow_direction_vs; - LightData lights[3]; + LightData lights[4]; + vec4 ambient_color; int num_lights; int matcap_orientation; float background_alpha; - int pad[1]; + float curvature_ridge; + float curvature_valley; + int pad[3]; }; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl new file mode 100644 index 00000000000..9e4394238ff --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl @@ -0,0 +1,39 @@ + +uniform usampler2D objectId; + +uniform vec2 invertedViewportSize; + +out vec4 fragColor; + +layout(std140) uniform world_block { + WorldData world_data; +}; + +void main() +{ + vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; + vec3 background = background_color(world_data, uv_viewport.y); + +#ifndef V3D_SHADING_OBJECT_OUTLINE + + fragColor = vec4(background, world_data.background_alpha); + +#else /* !V3D_SHADING_OBJECT_OUTLINE */ + + ivec2 texel = ivec2(gl_FragCoord.xy); + uint object_id = texelFetch(objectId, texel, 0).r; + float object_outline = calculate_object_outline(objectId, texel, object_id); + + if (object_outline == 0.0) { + fragColor = vec4(background, world_data.background_alpha); + } + else { + /* Do correct alpha blending. */ + vec4 background_color = vec4(background, 1.0) * world_data.background_alpha; + vec4 outline_color = vec4(world_data.object_outline_color.rgb, 1.0); + fragColor = mix(outline_color, background_color, object_outline); + fragColor = vec4(fragColor.rgb / max(1e-8, fragColor.a), fragColor.a); + } + +#endif /* !V3D_SHADING_OBJECT_OUTLINE */ +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl index 508aeb1f0c1..40e166bc7ac 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl @@ -1,24 +1,23 @@ out vec4 fragColor; uniform mat4 ProjectionMatrix; +uniform mat4 ViewMatrixInverse; uniform usampler2D objectId; -uniform sampler2D colorBuffer; -uniform sampler2D specularBuffer; +uniform sampler2D materialBuffer; uniform sampler2D normalBuffer; /* normalBuffer contains viewport normals */ uniform sampler2D cavityBuffer; +uniform sampler2D matcapImage; uniform vec2 invertedViewportSize; uniform vec4 viewvecs[3]; uniform float shadowMultiplier; uniform float lightMultiplier; uniform float shadowShift = 0.1; -uniform mat3 normalWorldMatrix; +uniform float shadowFocus = 1.0; -#ifdef STUDIOLIGHT_ORIENTATION_VIEWNORMAL -uniform sampler2D matcapImage; -#endif +uniform vec3 materialSingleColor; layout(std140) uniform world_block { WorldData world_data; @@ -28,102 +27,72 @@ void main() { ivec2 texel = ivec2(gl_FragCoord.xy); vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - uint object_id = texelFetch(objectId, texel, 0).r; -#ifndef V3D_SHADING_OBJECT_OUTLINE - if (object_id == NO_OBJECT_ID) { - fragColor = vec4(background_color(world_data, uv_viewport.y), world_data.background_alpha); - return; - } -#else /* !V3D_SHADING_OBJECT_OUTLINE */ - float object_outline = calculate_object_outline(objectId, texel, object_id); + float roughness, metallic; + vec3 base_color; - if (object_id == NO_OBJECT_ID) { - vec3 background = background_color(world_data, uv_viewport.y); - if (object_outline == 0.0) { - fragColor = vec4(background, world_data.background_alpha); - } - else { - /* Do correct alpha blending. */ - vec4 background_color = vec4(background, 1.0) * world_data.background_alpha; - vec4 outline_color = vec4(world_data.object_outline_color.rgb, 1.0); - fragColor = mix(outline_color, background_color, object_outline); - fragColor = vec4(fragColor.rgb / max(1e-8, fragColor.a), fragColor.a); - } - return; - } -#endif /* !V3D_SHADING_OBJECT_OUTLINE */ - - vec4 diffuse_color = texelFetch(colorBuffer, texel, 0); +#ifndef MATDATA_PASS_ENABLED + base_color = materialSingleColor; + metallic = 0.0; + roughness = 0.5; +#else + vec4 material_data = texelFetch(materialBuffer, texel, 0); + base_color = material_data.rgb; + workbench_float_pair_decode(material_data.a, roughness, metallic); +#endif /* Do we need normals */ #ifdef NORMAL_VIEWPORT_PASS_ENABLED -# ifdef WORKBENCH_ENCODE_NORMALS - vec3 normal_viewport = normal_decode(texelFetch(normalBuffer, texel, 0).rg); - if (diffuse_color.a == 0.0) { - normal_viewport = -normal_viewport; - } -# else /* WORKBENCH_ENCODE_NORMALS */ - vec3 normal_viewport = texelFetch(normalBuffer, texel, 0).rgb; -# endif /* WORKBENCH_ENCODE_NORMALS */ + vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg); #endif vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix); -#ifdef STUDIOLIGHT_ORIENTATION_VIEWNORMAL + /* -------- SHADING --------- */ +#ifdef V3D_LIGHTING_FLAT + vec3 shaded_color = base_color; + +#elif defined(V3D_LIGHTING_MATCAP) + /* When using matcaps, the metallic is the backface sign. */ + normal_viewport = (metallic > 0.0) ? normal_viewport : -normal_viewport; bool flipped = world_data.matcap_orientation != 0; vec2 matcap_uv = matcap_uv_compute(I_vs, normal_viewport, flipped); - diffuse_color = textureLod(matcapImage, matcap_uv, 0.0); -#endif + vec3 matcap = textureLod(matcapImage, matcap_uv, 0.0).rgb; + vec3 shaded_color = matcap * base_color; -#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - vec4 specular_data = texelFetch(specularBuffer, texel, 0); - vec3 specular_color = get_world_specular_lights(world_data, specular_data, normal_viewport, I_vs); -#else - vec3 specular_color = vec3(0.0); -#endif +#elif defined(V3D_LIGHTING_STUDIO) -#ifdef V3D_LIGHTING_FLAT - vec3 diffuse_light = vec3(1.0); -#endif - -#ifdef V3D_LIGHTING_MATCAP - vec3 diffuse_light = texelFetch(specularBuffer, texel, 0).rgb; -#endif - -#ifdef V3D_LIGHTING_STUDIO -# ifdef STUDIOLIGHT_ORIENTATION_CAMERA - vec3 diffuse_light = get_camera_diffuse_light(world_data, normal_viewport); +# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT + vec3 specular_color = mix(vec3(0.05), base_color, metallic); + vec3 diffuse_color = mix(base_color, vec3(0.0), metallic); +# else + roughness = 0.0; + vec3 specular_color = vec3(0.0); + vec3 diffuse_color = base_color; # endif -# ifdef STUDIOLIGHT_ORIENTATION_WORLD - vec3 normal_world = normalWorldMatrix * normal_viewport; - vec3 diffuse_light = get_world_diffuse_light(world_data, normal_world); -# endif + vec3 shaded_color = get_world_lighting(world_data, + diffuse_color, specular_color, roughness, + normal_viewport, I_vs); #endif - vec3 shaded_color = diffuse_light * diffuse_color.rgb + specular_color; -#ifdef V3D_SHADING_CAVITY - vec2 cavity = texelFetch(cavityBuffer, texel, 0).rg; - shaded_color *= 1.0 - cavity.x; - shaded_color *= 1.0 + cavity.y; + /* -------- POST EFFECTS --------- */ +#ifdef WB_CAVITY + /* Using UNORM texture so decompress the range */ + shaded_color *= texelFetch(cavityBuffer, texel, 0).r * CAVITY_BUFFER_RANGE; #endif #ifdef V3D_SHADING_SHADOW float light_factor = -dot(normal_viewport, world_data.shadow_direction_vs.xyz); - /* The step function might be ok for meshes but it's - * clearly not the case for hairs. Do smoothstep in this case. */ - float shadow_mix = smoothstep(1.0, shadowShift, light_factor); - float light_multiplier = mix(lightMultiplier, shadowMultiplier, shadow_mix); - -#else /* V3D_SHADING_SHADOW */ - float light_multiplier = 1.0; -#endif /* V3D_SHADING_SHADOW */ - - shaded_color *= light_multiplier; + float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor); + shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix); +#endif #ifdef V3D_SHADING_OBJECT_OUTLINE + uint object_id = texelFetch(objectId, texel, 0).r; + float object_outline = calculate_object_outline(objectId, texel, object_id); shaded_color = mix(world_data.object_outline_color.rgb, shaded_color, object_outline); -#endif /* V3D_SHADING_OBJECT_OUTLINE */ +#endif + fragColor = vec4(shaded_color, 1.0); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl index 1d9f37274bd..cb5516ca34f 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl @@ -13,25 +13,23 @@ void main() { ivec2 texel = ivec2(gl_FragCoord.xy); vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - uint object_id = texelFetch(objectId, texel, 0).r; /* Listing 4 */ vec4 trans_accum = texelFetch(transparentAccum, texel, 0); float trans_revealage = trans_accum.a; trans_accum.a = texelFetch(transparentRevealage, texel, 0).r; -#ifdef V3D_SHADING_OBJECT_OUTLINE - float outline = calculate_object_outline(objectId, texel, object_id); -#else /* V3D_SHADING_OBJECT_OUTLINE */ - float outline = 1.0; -#endif /* V3D_SHADING_OBJECT_OUTLINE */ vec3 bg_color = background_color(world_data, uv_viewport.y); /* TODO: Bypass the whole shader if there is no xray pass and no outline pass. */ vec3 trans_color = trans_accum.rgb / clamp(trans_accum.a, 1e-4, 5e4); vec3 color = mix(trans_color, bg_color, trans_revealage); +#ifdef V3D_SHADING_OBJECT_OUTLINE + uint object_id = texelFetch(objectId, texel, 0).r; + float outline = calculate_object_outline(objectId, texel, object_id); color = mix(world_data.object_outline_color.rgb, color, outline); +#endif fragColor = vec4(color, 1.0); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl index 67a22073a4b..aed86937e0d 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl @@ -1,16 +1,16 @@ -#ifdef V3D_SHADING_TEXTURE_COLOR -uniform sampler2D image; + uniform float ImageTransparencyCutoff = 0.1; +uniform sampler2D image; +uniform bool imageSrgb; -#endif uniform mat4 ProjectionMatrix; -uniform mat3 normalWorldMatrix; +uniform mat4 ViewMatrixInverse; uniform float alpha = 0.5; uniform vec2 invertedViewportSize; uniform vec4 viewvecs[3]; -uniform vec4 materialDiffuseColor; -uniform vec4 materialSpecularColor; +uniform vec3 materialDiffuseColor; +uniform vec3 materialSpecularColor; uniform float materialRoughness; #ifdef NORMAL_VIEWPORT_PASS_ENABLED @@ -33,15 +33,17 @@ layout(location=1) out float revealageAccum; /* revealage actually stored in tra void main() { vec4 diffuse_color; - vec3 diffuse_light = vec3(1.0); #ifdef V3D_SHADING_TEXTURE_COLOR diffuse_color = texture(image, uv_interp); if (diffuse_color.a < ImageTransparencyCutoff) { discard; } + if (imageSrgb) { + diffuse_color = srgb_to_linearrgb(diffuse_color); + } #else - diffuse_color = materialDiffuseColor; + diffuse_color = vec4(materialDiffuseColor, 1.0); #endif /* V3D_SHADING_TEXTURE_COLOR */ vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; @@ -51,30 +53,22 @@ void main() vec3 nor = normalize(normal_viewport); #endif -#ifdef V3D_LIGHTING_MATCAP + /* -------- SHADING --------- */ +#ifdef V3D_LIGHTING_FLAT + vec3 shaded_color = diffuse_color.rgb; + +#elif defined(V3D_LIGHTING_MATCAP) bool flipped = world_data.matcap_orientation != 0; vec2 matcap_uv = matcap_uv_compute(I_vs, nor, flipped); - diffuse_light = texture(matcapImage, matcap_uv).rgb; -#endif - -#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - vec3 specular_color = get_world_specular_lights(world_data, vec4(materialSpecularColor.rgb, materialRoughness), nor, I_vs); -#else - vec3 specular_color = vec3(0.0); -#endif + vec3 matcap = textureLod(matcapImage, matcap_uv, 0.0).rgb; + vec3 shaded_color = matcap * diffuse_color.rgb; -#ifdef V3D_LIGHTING_STUDIO -# ifdef STUDIOLIGHT_ORIENTATION_CAMERA - diffuse_light = get_camera_diffuse_light(world_data, nor); -# endif -# ifdef STUDIOLIGHT_ORIENTATION_WORLD - vec3 normal_world = normalWorldMatrix * nor; - diffuse_light = get_world_diffuse_light(world_data, normal_world); -# endif +#elif defined(V3D_LIGHTING_STUDIO) + vec3 shaded_color = get_world_lighting(world_data, + diffuse_color.rgb, materialSpecularColor, materialRoughness, + nor, I_vs); #endif - vec3 shaded_color = diffuse_light * diffuse_color.rgb + specular_color; - /* Based on : * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013 diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl index 62c7e4515cd..2ce816c6484 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl @@ -1,81 +1,81 @@ uniform int object_id = 0; -uniform vec4 materialDiffuseColor; -uniform vec4 materialSpecularColor; +uniform vec3 materialDiffuseColor; +uniform float materialMetallic; uniform float materialRoughness; -#ifdef V3D_SHADING_TEXTURE_COLOR uniform sampler2D image; uniform float ImageTransparencyCutoff = 0.1; - -#endif +uniform bool imageSrgb; #ifdef NORMAL_VIEWPORT_PASS_ENABLED in vec3 normal_viewport; -#endif /* NORMAL_VIEWPORT_PASS_ENABLED */ +#endif #ifdef V3D_SHADING_TEXTURE_COLOR in vec2 uv_interp; -#endif /* V3D_SHADING_TEXTURE_COLOR */ +#endif #ifdef HAIR_SHADER flat in float hair_rand; #endif -layout(location=0) out uint objectId; -layout(location=1) out vec4 diffuseColor; -layout(location=2) out vec4 specularColor; +#ifdef MATDATA_PASS_ENABLED +layout(location=0) out vec4 materialData; +#endif +#ifdef OBJECT_ID_PASS_ENABLED +layout(location=1) out uint objectId; +#endif #ifdef NORMAL_VIEWPORT_PASS_ENABLED -# ifdef WORKBENCH_ENCODE_NORMALS -layout(location=3) out vec2 normalViewport; -# else /* WORKBENCH_ENCODE_NORMALS */ -layout(location=3) out vec3 normalViewport; -# endif /* WORKBENCH_ENCODE_NORMALS */ -#endif /* NORMAL_VIEWPORT_PASS_ENABLED */ +layout(location=2) out WB_Normal normalViewport; +#endif void main() { - objectId = uint(object_id); - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED - vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport; - n = normalize(n); -#endif +#ifdef MATDATA_PASS_ENABLED + float metallic, roughness; + vec4 color; -#ifdef V3D_SHADING_TEXTURE_COLOR - diffuseColor = texture(image, uv_interp); - if (diffuseColor.a < ImageTransparencyCutoff) { +# ifdef V3D_SHADING_TEXTURE_COLOR + color = texture(image, uv_interp); + if (color.a < ImageTransparencyCutoff) { discard; } -#else - diffuseColor = vec4(materialDiffuseColor.rgb, 0.0); -# ifdef STUDIOLIGHT_ORIENTATION_VIEWNORMAL - specularColor = vec4(materialDiffuseColor.rgb, 0.0); - + if (imageSrgb) { + color = srgb_to_linearrgb(color); + } +# else + color.rgb = materialDiffuseColor; # endif -#endif /* V3D_SHADING_TEXTURE_COLOR */ -#ifdef HAIR_SHADER - float hair_color_variation = hair_rand * 0.1; - diffuseColor.rgb = clamp(diffuseColor.rgb - hair_color_variation, 0.0, 1.0); -#endif +# ifdef V3D_LIGHTING_MATCAP + /* Encode front facing in metallic channel. */ + metallic = float(gl_FrontFacing); + roughness = 0.0; +# else + metallic = materialMetallic; + roughness = materialRoughness; +# endif -#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - specularColor = vec4(materialSpecularColor.rgb, materialRoughness); # ifdef HAIR_SHADER - specularColor.rgb = clamp(specularColor.rgb - hair_color_variation, 0.0, 1.0); + /* Add some variation to the hairs to avoid uniform look. */ + float hair_variation = hair_rand * 0.1; + color = clamp(color - hair_variation, 0.0, 1.0); + metallic = clamp(materialMetallic - hair_variation, 0.0, 1.0); + roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0); # endif + + materialData.rgb = color.rgb; + materialData.a = workbench_float_pair_encode(roughness, metallic); +#endif /* MATDATA_PASS_ENABLED */ + +#ifdef OBJECT_ID_PASS_ENABLED + objectId = uint(object_id); #endif #ifdef NORMAL_VIEWPORT_PASS_ENABLED -# ifdef WORKBENCH_ENCODE_NORMALS - diffuseColor.a = float(gl_FrontFacing); - normalViewport = normal_encode(n); -# else /* WORKBENCH_ENCODE_NORMALS */ - normalViewport = n; -# endif /* WORKBENCH_ENCODE_NORMALS */ -# ifdef HAIR_SHADER - diffuseColor.a = 0.5; -# endif -#endif /* NORMAL_VIEWPORT_PASS_ENABLED */ + vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport; + n = normalize(n); + normalViewport = workbench_normal_encode(n); +#endif } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index 66245ef0304..130575cbe9a 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -8,7 +8,8 @@ uniform mat3 NormalMatrix; #ifndef HAIR_SHADER in vec3 pos; in vec3 nor; -in vec2 uv; +in vec2 u; /* active texture layer */ +#define uv u #else /* HAIR_SHADER */ # ifdef V3D_SHADING_TEXTURE_COLOR uniform samplerBuffer u; /* active texture layer */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl index 7418f86a58e..a2f23fbf3dc 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl @@ -55,20 +55,19 @@ void main() vec3 v12 = vData[2].pos - vData[1].pos; vec3 v13 = vData[3].pos - vData[1].pos; -#ifdef DEGENERATE_THRESHOLD - vec3 v20 = vData[0].pos - vData[2].pos; - vec3 v23 = vData[3].pos - vData[2].pos; + vec3 n1 = cross(v12, v10); + vec3 n2 = cross(v13, v12); - vec4 edges_lensqr = vec4(len_sqr(v10), len_sqr(v13), len_sqr(v20), len_sqr(v23)); - bvec4 degen_edges = lessThan(edges_lensqr, vec4(DEGENERATE_THRESHOLD)); +#ifdef DEGENERATE_THRESHOLD + /* Check if area is null */ + vec2 faces_area = vec2(len_sqr(n1), len_sqr(n2)); + bvec2 degen_faces = lessThan(abs(faces_area), vec2(DEGENERATE_THRESHOLD)); /* Both triangles are degenerate, abort. */ - if (any(degen_edges.xz) && any(degen_edges.yw)) + if (all(degen_faces)) return; #endif - vec3 n1 = cross(v12, v10); - vec3 n2 = cross(v13, v12); vec2 facing = vec2(dot(n1, lightDirection), dot(n2, lightDirection)); @@ -81,15 +80,15 @@ void main() # ifndef DOUBLE_MANIFOLD /* If the mesh is known to be manifold and we don't use double count, * only create an quad if the we encounter a facing geom. */ - if ((any(degen_edges.xz) && backface.y) || - (any(degen_edges.yw) && backface.x)) + if ((degen_faces.x && backface.y) || + (degen_faces.y && backface.x)) return; # endif /* If one of the 2 triangles is degenerate, replace edge by a non-manifold one. */ - backface.x = (any(degen_edges.xz)) ? !backface.y : backface.x; - backface.y = (any(degen_edges.yw)) ? !backface.x : backface.y; - is_manifold = (any(degen_edges)) ? false : is_manifold; + backface.x = (degen_faces.x) ? !backface.y : backface.x; + backface.y = (degen_faces.y) ? !backface.x : backface.y; + is_manifold = (any(degen_faces)) ? false : is_manifold; #endif /* If both faces face the same direction it's not an outline edge. */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl index ab48aa5fa03..dbc29299fdc 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl @@ -1,129 +1,114 @@ -#define BLINN -#if STUDIOLIGHT_SH_BANDS == 2 -vec3 spherical_harmonics(vec3 N, vec3 sh_coefs[STUDIOLIGHT_SH_MAX_COMPONENTS]) +/* [Drobot2014a] Low Level Optimizations for GCN */ +vec4 fast_rcp(vec4 v) { - /* http://www.geomerics.com/wp-content/uploads/2015/08/CEDEC_Geomerics_ReconstructingDiffuseLighting1.pdf */ - /* Highly optimized form, precompute as much as we can. */ - /** - * R1 = 0.5 * vec3(L3.r, L2.r, L1.r); - * sh_coefs[0..2] = R1 / length(R1); - **/ - vec3 q; - q.x = dot(sh_coefs[1], N); - q.y = dot(sh_coefs[2], N); - q.z = dot(sh_coefs[3], N); - q = 0.5 * q + 0.5; - - /** - * R0 = L0.r; - * lr1_r0 = lenR1 / R0; - * p = 1.0 + 2.0 * lr1_r0; - * a = (1.0 - lr1_r0) / (1.0 + lr1_r0); - * return R0 * (a + (1.0 - a) * (p + 1.0) * pow(q, p)); - * - * sh_coefs[4] = p; - * sh_coefs[5] = R0 * a; - * sh_coefs[0] = R0 * (1.0 - a) * (p + 1.0); - **/ - q = pow(q, sh_coefs[4]); - return sh_coefs[0] * q + sh_coefs[5]; + return intBitsToFloat(0x7eef370b - floatBitsToInt(v)); } -#else - -vec3 spherical_harmonics(vec3 N, vec3 sh_coefs[STUDIOLIGHT_SH_MAX_COMPONENTS]) +vec3 brdf_approx(vec3 spec_color, float roughness, float NV) { - vec3 sh = 0.282095 * sh_coefs[0]; - -# if STUDIOLIGHT_SH_BANDS > 1 - float nx = N.x; - float ny = N.y; - float nz = N.z; - sh += -0.488603 * nz * sh_coefs[1]; - sh += 0.488603 * ny * sh_coefs[2]; - sh += -0.488603 * nx * sh_coefs[3]; -# endif -# if STUDIOLIGHT_SH_BANDS > 2 - float nx2 = nx * nx; - float ny2 = ny * ny; - float nz2 = nz * nz; - sh += 1.092548 * nx * nz * sh_coefs[4]; - sh += -1.092548 * nz * ny * sh_coefs[5]; - sh += 0.315392 * (3.0 * ny2 - 1.0) * sh_coefs[6]; - sh += -1.092548 * nx * ny * sh_coefs[7]; - sh += 0.546274 * (nx2 - nz2) * sh_coefs[8]; -# endif -# if STUDIOLIGHT_SH_BANDS > 4 - float nx4 = nx2 * nx2; - float ny4 = ny2 * ny2; - float nz4 = nz2 * nz2; - sh += (2.5033429417967046 * nx * nz * (nx2 - nz2)) * sh_coefs[9]; - sh += (-1.7701307697799304 * nz * ny * (3.0 * nx2 - nz2)) * sh_coefs[10]; - sh += (0.9461746957575601 * nz * nx * (-1.0 +7.0*ny2)) * sh_coefs[11]; - sh += (-0.6690465435572892 * nz * ny * (-3.0 + 7.0 * ny2)) * sh_coefs[12]; - sh += ((105.0*ny4-90.0*ny2+9.0)/28.359261614) * sh_coefs[13]; - sh += (-0.6690465435572892 * nx * ny * (-3.0 + 7.0 * ny2)) * sh_coefs[14]; - sh += (0.9461746957575601 * (nx2 - nz2) * (-1.0 + 7.0 * ny2)) * sh_coefs[15]; - sh += (-1.7701307697799304 * nx * ny * (nx2 - 3.0 * nz2)) * sh_coefs[16]; - sh += (0.6258357354491761 * (nx4 - 6.0 * nz2 * nx2 + nz4)) * sh_coefs[17]; -# endif - return sh; + /* Very rough own approx. We don't need it to be correct, just fast. + * Just simulate fresnel effect with roughness attenuation. */ + float fresnel = exp2(-8.35 * NV) * (1.0 - roughness); + return mix(spec_color, vec3(1.0), fresnel); } -#endif -vec3 get_world_diffuse_light(WorldData world_data, vec3 N) +void prep_specular( + vec3 L, vec3 I, vec3 N, vec3 R, + out float NL, out float wrapped_NL, out float spec_angle) { - return spherical_harmonics(N, world_data.spherical_harmonics_coefs); + wrapped_NL = dot(L, R); + vec3 half_dir = normalize(L + I); + spec_angle = clamp(dot(half_dir, N), 0.0, 1.0); + NL = clamp(dot(L, N), 0.0, 1.0); } -vec3 get_camera_diffuse_light(WorldData world_data, vec3 N) +/* Normalized Blinn shading */ +vec4 blinn_specular(vec4 shininess, vec4 spec_angle, vec4 NL) { - return spherical_harmonics(vec3(N.x, -N.z, N.y), world_data.spherical_harmonics_coefs); + /* Pi is already divided in the lamp power. + * normalization_factor = (shininess + 8.0) / (8.0 * M_PI) */ + vec4 normalization_factor = shininess * 0.125 + 1.0; + vec4 spec_light = pow(spec_angle, shininess) * NL * normalization_factor; + + return spec_light; } -/* N And I are in View Space. */ -vec3 get_world_specular_light(vec4 specular_data, LightData light_data, vec3 N, vec3 I) +/* NL need to be unclamped. w in [0..1] range. */ +vec4 wrapped_lighting(vec4 NL, vec4 w) { -#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - vec3 specular_light = specular_data.rgb * light_data.specular_color.rgb * light_data.specular_color.a; - - float shininess = exp2(10.0 * (1.0 - specular_data.a) + 1); - -# ifdef BLINN - float normalization_factor = (shininess + 8.0) / (8.0 * M_PI); - vec3 L = -light_data.light_direction_vs.xyz; - vec3 halfDir = normalize(L + I); - float spec_angle = max(dot(halfDir, N), 0.0); - float NL = max(dot(L, N), 0.0); - float specular_influence = pow(spec_angle, shininess) * NL * normalization_factor; - -# else - vec3 reflection_vector = reflect(I, N); - float spec_angle = max(dot(light_data.light_direction_vs.xyz, reflection_vector), 0.0); - float specular_influence = pow(spec_angle, shininess); -# endif - - vec3 specular_color = specular_light * specular_influence; - -#else /* V3D_SHADING_SPECULAR_HIGHLIGHT */ - vec3 specular_color = vec3(0.0); -#endif /* V3D_SHADING_SPECULAR_HIGHLIGHT */ - return specular_color; + vec4 w_1 = w + 1.0; + vec4 denom = fast_rcp(w_1 * w_1); + return clamp((NL + w) * denom, 0.0, 1.0); } -vec3 get_world_specular_lights(WorldData world_data, vec4 specular_data, vec3 N, vec3 I) +vec3 get_world_lighting( + WorldData world_data, + vec3 diffuse_color, vec3 specular_color, float roughness, + vec3 N, vec3 I) { - vec3 specular_light = vec3(0.0); - /* Manual loop unrolling provide much better perf. */ - if (world_data.num_lights > 0) { - specular_light += get_world_specular_light(specular_data, world_data.lights[0], N, I); - } - if (world_data.num_lights > 1) { - specular_light += get_world_specular_light(specular_data, world_data.lights[1], N, I); - } - if (world_data.num_lights > 2) { - specular_light += get_world_specular_light(specular_data, world_data.lights[2], N, I); - } - return specular_light; + vec3 specular_light = world_data.ambient_color.rgb; + vec3 diffuse_light = world_data.ambient_color.rgb; + vec4 wrap = vec4( + world_data.lights[0].diffuse_color_wrap.a, + world_data.lights[1].diffuse_color_wrap.a, + world_data.lights[2].diffuse_color_wrap.a, + world_data.lights[3].diffuse_color_wrap.a + ); + +#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT + /* Prepare Specular computation. Eval 4 lights at once. */ + vec3 R = -reflect(I, N); + vec4 spec_angle, spec_NL, wrap_NL; + prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x); + prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y); + prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z); + prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w); + + vec4 gloss = vec4(1.0 - roughness); + /* Reduce gloss for smooth light. (simulate bigger light) */ + gloss *= 1.0 - wrap; + vec4 shininess = exp2(10.0 * gloss + 1.0); + + vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL); + + /* Simulate Env. light. */ + vec4 w = mix(wrap, vec4(1.0), roughness); + vec4 spec_env = wrapped_lighting(wrap_NL, w); + + spec_light = mix(spec_light, spec_env, wrap * wrap); + + /* Multiply result by lights specular colors. */ + specular_light += spec_light.x * world_data.lights[0].specular_color.rgb; + specular_light += spec_light.y * world_data.lights[1].specular_color.rgb; + specular_light += spec_light.z * world_data.lights[2].specular_color.rgb; + specular_light += spec_light.w * world_data.lights[3].specular_color.rgb; + + float NV = clamp(dot(N, I), 0.0, 1.0); + specular_color = brdf_approx(specular_color, roughness, NV); +#endif + specular_light *= specular_color; + + /* Prepare diffuse computation. Eval 4 lights at once. */ + vec4 diff_NL; + diff_NL.x = dot(world_data.lights[0].direction.xyz, N); + diff_NL.y = dot(world_data.lights[1].direction.xyz, N); + diff_NL.z = dot(world_data.lights[2].direction.xyz, N); + diff_NL.w = dot(world_data.lights[3].direction.xyz, N); + + vec4 diff_light = wrapped_lighting(diff_NL, wrap); + + /* Multiply result by lights diffuse colors. */ + diffuse_light += diff_light.x * world_data.lights[0].diffuse_color_wrap.rgb; + diffuse_light += diff_light.y * world_data.lights[1].diffuse_color_wrap.rgb; + diffuse_light += diff_light.z * world_data.lights[2].diffuse_color_wrap.rgb; + diffuse_light += diff_light.w * world_data.lights[3].diffuse_color_wrap.rgb; + + /* Energy conservation with colored specular look strange. + * Limit this strangeness by using mono-chromatic specular intensity. */ + float spec_energy = dot(specular_color, vec3(0.33333)); + + diffuse_light *= diffuse_color * (1.0 - spec_energy); + + return diffuse_light + specular_light; } diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index aa99883bb6b..ab9417705e5 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -24,7 +24,7 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wpd->use_color_view_settings = true; } else if (v3d->shading.type == OB_RENDER && - BKE_scene_uses_blender_opengl(scene)) + BKE_scene_uses_blender_workbench(scene)) { wpd->shading = scene->display.shading; wpd->use_color_view_settings = true; @@ -36,17 +36,17 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) if (wpd->shading.light == V3D_LIGHTING_MATCAP) { wpd->studio_light = BKE_studiolight_find( - wpd->shading.matcap, STUDIOLIGHT_ORIENTATION_VIEWNORMAL); + wpd->shading.matcap, STUDIOLIGHT_TYPE_MATCAP); } else { wpd->studio_light = BKE_studiolight_find( - wpd->shading.studio_light, STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD); + wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO); } /* If matcaps are missing, use this as fallback. */ if (UNLIKELY(wpd->studio_light == NULL)) { wpd->studio_light = BKE_studiolight_find( - wpd->shading.studio_light, STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD); + wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO); } wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity; @@ -55,13 +55,14 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wd->matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0; wd->background_alpha = (DRW_state_is_image_render() && scene->r.alphamode == R_ALPHAPREMUL) ? 0.0f : 1.0f; - if (!v3d || ((v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) && - (scene->world != NULL))) + if ((scene->world != NULL) && + (!v3d || (v3d && ((v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) || + (v3d->shading.type == OB_RENDER))))) { copy_v3_v3(wd->background_color_low, &scene->world->horr); copy_v3_v3(wd->background_color_high, &scene->world->horr); } - else if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_VIEWPORT) { + else if (v3d && (v3d->shading.background_type == V3D_SHADING_BACKGROUND_VIEWPORT)) { copy_v3_v3(wd->background_color_low, v3d->shading.background_color); copy_v3_v3(wd->background_color_high, v3d->shading.background_color); } @@ -79,11 +80,14 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) zero_v3(wd->background_color_high); } - studiolight_update_world(wpd->studio_light, wd); + studiolight_update_world(wpd, wpd->studio_light, wd); copy_v3_v3(wd->object_outline_color, wpd->shading.object_outline_color); wd->object_outline_color[3] = 1.0f; + wd->curvature_ridge = 0.5f / max_ff(SQUARE(wpd->shading.curvature_ridge_factor), 1e-4f); + wd->curvature_valley = 0.7f / max_ff(SQUARE(wpd->shading.curvature_valley_factor), 1e-4f); + wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data); /* Cavity settings */ @@ -108,7 +112,12 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wpd->ssao_params[3] = 0; /* distance, factor, factor, attenuation */ - copy_v4_fl4(wpd->ssao_settings, scene->display.matcap_ssao_distance, wpd->shading.cavity_valley_factor, wpd->shading.cavity_ridge_factor, scene->display.matcap_ssao_attenuation); + copy_v4_fl4( + wpd->ssao_settings, + scene->display.matcap_ssao_distance, + wpd->shading.cavity_valley_factor, + wpd->shading.cavity_ridge_factor, + scene->display.matcap_ssao_attenuation); /* invert the view matrix */ DRW_viewport_matrix_get(wpd->winmat, DRW_MAT_WIN); @@ -153,32 +162,12 @@ void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, floa DRW_viewport_matrix_get(view_matrix, DRW_MAT_VIEW); copy_v3_v3(r_light_direction, scene->display.light_direction); - negate_v3(r_light_direction); - - { - WORKBENCH_UBO_Light *light = &wd->lights[0]; - mul_v3_mat3_m4v3(light->light_direction_vs, view_matrix, r_light_direction); - light->light_direction_vs[3] = 0.0f; - copy_v3_fl(light->specular_color, 1.0f); - light->energy = 1.0f; - copy_v4_v4(wd->shadow_direction_vs, light->light_direction_vs); - wd->num_lights = 1; - } + SWAP(float, r_light_direction[2], r_light_direction[1]); + r_light_direction[2] = -r_light_direction[2]; + r_light_direction[0] = -r_light_direction[0]; - if (!STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) { - int light_index = 0; - for (int index = 0 ; index < 3; index++) { - SolidLight *sl = &U.light[index]; - if (sl->flag) { - WORKBENCH_UBO_Light *light = &wd->lights[light_index++]; - copy_v4_v4(light->light_direction_vs, sl->vec); - negate_v3(light->light_direction_vs); - copy_v4_v4(light->specular_color, sl->spec); - light->energy = 1.0f; - } - } - wd->num_lights = light_index; - } + /* Shadow direction. */ + mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, r_light_direction); DRW_uniformbuffer_update(wpd->world_ubo, wd); } diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 2a5d97078b8..8663bd559e4 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -31,6 +31,7 @@ #include "BLI_dynstr.h" #include "BLI_utildefines.h" #include "BLI_rand.h" +#include "BLI_string_utils.h" #include "BKE_hair.h" #include "BKE_node.h" @@ -47,6 +48,7 @@ #include "GPU_shader.h" #include "GPU_texture.h" +#include "GPU_extensions.h" #include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */ @@ -59,9 +61,10 @@ #endif static struct { - struct GPUShader *prepass_sh_cache[MAX_SHADERS]; - struct GPUShader *composite_sh_cache[MAX_SHADERS]; - struct GPUShader *cavity_sh; + struct GPUShader *prepass_sh_cache[MAX_PREPASS_SHADERS]; + struct GPUShader *composite_sh_cache[MAX_COMPOSITE_SHADERS]; + struct GPUShader *cavity_sh[MAX_CAVITY_SHADERS]; + struct GPUShader *background_sh[2]; struct GPUShader *ghost_resolve_sh; struct GPUShader *shadow_fail_sh; struct GPUShader *shadow_fail_manifold_sh; @@ -74,13 +77,12 @@ static struct { struct GPUTexture *object_id_tx; /* ref only, not alloced */ struct GPUTexture *color_buffer_tx; /* ref only, not alloced */ struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */ - struct GPUTexture *specular_buffer_tx; /* ref only, not alloced */ + struct GPUTexture *metallic_buffer_tx; /* ref only, not alloced */ struct GPUTexture *normal_buffer_tx; /* ref only, not alloced */ struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */ SceneDisplay display; /* world light direction for shadows */ int next_object_id; - float normal_world_matrix[3][3]; struct GPUUniformBuffer *sampling_ubo; struct GPUTexture *jitter_tx; @@ -94,6 +96,7 @@ extern char datatoc_workbench_prepass_vert_glsl[]; extern char datatoc_workbench_prepass_frag_glsl[]; extern char datatoc_workbench_cavity_frag_glsl[]; extern char datatoc_workbench_deferred_composite_frag_glsl[]; +extern char datatoc_workbench_deferred_background_frag_glsl[]; extern char datatoc_workbench_ghost_resolve_frag_glsl[]; extern char datatoc_workbench_shadow_vert_glsl[]; @@ -106,6 +109,7 @@ extern char datatoc_workbench_cavity_lib_glsl[]; extern char datatoc_workbench_common_lib_glsl[]; extern char datatoc_workbench_data_lib_glsl[]; extern char datatoc_workbench_object_outline_lib_glsl[]; +extern char datatoc_workbench_curvature_lib_glsl[]; extern char datatoc_workbench_world_light_lib_glsl[]; extern char datatoc_gpu_shader_depth_only_frag_glsl[]; @@ -120,12 +124,15 @@ static char *workbench_build_composite_frag(WORKBENCH_PrivateData *wpd) BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_background_lib_glsl); - if ((wpd->shading.light & V3D_LIGHTING_MATCAP) || (wpd->shading.light & V3D_LIGHTING_STUDIO) || (wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT)) { + if (!FLAT_ENABLED(wpd)) { BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl); } - if (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) { + if (OBJECT_OUTLINE_ENABLED(wpd)) { BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl); } + if (CURVATURE_ENABLED(wpd)) { + BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl); + } BLI_dynstr_append(ds, datatoc_workbench_deferred_composite_frag_glsl); @@ -166,13 +173,26 @@ static char *workbench_build_prepass_vert(bool is_hair) return str; } -static char *workbench_build_cavity_frag(void) +static char *workbench_build_cavity_frag(bool cavity, bool curvature, bool high_dpi) { char *str = NULL; DynStr *ds = BLI_dynstr_new(); + if (cavity) { + BLI_dynstr_append(ds, "#define USE_CAVITY\n"); + } + if (curvature) { + BLI_dynstr_append(ds, "#define USE_CURVATURE\n"); + } + if (high_dpi) { + BLI_dynstr_append(ds, "#define CURVATURE_OFFSET 2\n"); + } + if (NORMAL_ENCODING_ENABLED()) { + BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n"); + } BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); + BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_cavity_frag_glsl); BLI_dynstr_append(ds, datatoc_workbench_cavity_lib_glsl); @@ -181,45 +201,79 @@ static char *workbench_build_cavity_frag(void) return str; } -static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, bool use_textures, bool is_hair) +static GPUShader *workbench_cavity_shader_get(bool cavity, bool curvature) { + const bool high_dpi = (U.pixelsize > 1.5f); + int index = 0; + SET_FLAG_FROM_TEST(index, cavity, 1 << 0); + SET_FLAG_FROM_TEST(index, curvature, 1 << 1); + SET_FLAG_FROM_TEST(index, high_dpi, 1 << 2); + + GPUShader **sh = &e_data.cavity_sh[index]; + if (*sh == NULL) { + char *cavity_frag = workbench_build_cavity_frag(cavity, curvature, high_dpi); + *sh = DRW_shader_create_fullscreen(cavity_frag, NULL); + MEM_freeN(cavity_frag); + } + return *sh; +} + +static GPUShader *ensure_deferred_prepass_shader(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair) +{ + int index = workbench_material_get_prepass_shader_index(wpd, use_textures, is_hair); if (e_data.prepass_sh_cache[index] == NULL) { char *defines = workbench_material_build_defines(wpd, use_textures, is_hair); - char *composite_frag = workbench_build_composite_frag(wpd); char *prepass_vert = workbench_build_prepass_vert(is_hair); char *prepass_frag = workbench_build_prepass_frag(); e_data.prepass_sh_cache[index] = DRW_shader_create( prepass_vert, NULL, prepass_frag, defines); - if (!use_textures && !is_hair) { - e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); - } MEM_freeN(prepass_vert); MEM_freeN(prepass_frag); + MEM_freeN(defines); + } + return e_data.prepass_sh_cache[index]; +} + +static GPUShader *ensure_deferred_composite_shader(WORKBENCH_PrivateData *wpd) +{ + int index = workbench_material_get_composite_shader_index(wpd); + if (e_data.composite_sh_cache[index] == NULL) { + char *defines = workbench_material_build_defines(wpd, false, false); + char *composite_frag = workbench_build_composite_frag(wpd); + e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); MEM_freeN(composite_frag); MEM_freeN(defines); } + return e_data.composite_sh_cache[index]; } -static void select_deferred_shaders(WORKBENCH_PrivateData *wpd) +static GPUShader *ensure_background_shader(WORKBENCH_PrivateData *wpd) { - int index_solid = workbench_material_get_shader_index(wpd, false, false); - int index_solid_hair = workbench_material_get_shader_index(wpd, false, true); - int index_texture = workbench_material_get_shader_index(wpd, true, false); - int index_texture_hair = workbench_material_get_shader_index(wpd, true, true); - - ensure_deferred_shaders(wpd, index_solid, false, false); - ensure_deferred_shaders(wpd, index_solid_hair, false, true); - ensure_deferred_shaders(wpd, index_texture, true, false); - ensure_deferred_shaders(wpd, index_texture_hair, true, true); - - wpd->prepass_solid_sh = e_data.prepass_sh_cache[index_solid]; - wpd->prepass_solid_hair_sh = e_data.prepass_sh_cache[index_solid_hair]; - wpd->prepass_texture_sh = e_data.prepass_sh_cache[index_texture]; - wpd->prepass_texture_hair_sh = e_data.prepass_sh_cache[index_texture_hair]; - wpd->composite_sh = e_data.composite_sh_cache[index_solid]; + const int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0; + if (e_data.background_sh[index] == NULL) { + const char *defines = (index) ? "#define V3D_SHADING_OBJECT_OUTLINE\n" : NULL; + char *frag = BLI_string_joinN( + datatoc_workbench_data_lib_glsl, + datatoc_workbench_common_lib_glsl, + datatoc_workbench_background_lib_glsl, + datatoc_workbench_object_outline_lib_glsl, + datatoc_workbench_deferred_background_frag_glsl); + e_data.background_sh[index] = DRW_shader_create_fullscreen(frag, defines); + MEM_freeN(frag); + } + return e_data.background_sh[index]; } +static void select_deferred_shaders(WORKBENCH_PrivateData *wpd) +{ + wpd->prepass_solid_sh = ensure_deferred_prepass_shader(wpd, false, false); + wpd->prepass_solid_hair_sh = ensure_deferred_prepass_shader(wpd, false, true); + wpd->prepass_texture_sh = ensure_deferred_prepass_shader(wpd, true, false); + wpd->prepass_texture_hair_sh = ensure_deferred_prepass_shader(wpd, true, true); + wpd->composite_sh = ensure_deferred_composite_shader(wpd); + wpd->background_sh = ensure_background_shader(wpd); +} /* Using Hammersley distribution */ static float *create_disk_samples(int num_samples, int num_iterations) @@ -294,14 +348,15 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) } if (!e_data.next_object_id) { - memset(e_data.prepass_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS); - memset(e_data.composite_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS); + memset(e_data.prepass_sh_cache, 0, sizeof(e_data.prepass_sh_cache)); + memset(e_data.composite_sh_cache, 0, sizeof(e_data.composite_sh_cache)); e_data.next_object_id = 1; #ifdef DEBUG_SHADOW_VOLUME const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl; #else const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl; #endif + /* TODO only compile on demand */ e_data.shadow_pass_sh = DRW_shader_create( datatoc_workbench_shadow_vert_glsl, datatoc_workbench_shadow_geom_glsl, @@ -336,10 +391,6 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) shadow_frag, "#define SHADOW_FAIL\n"); - char *cavity_frag = workbench_build_cavity_frag(); - e_data.cavity_sh = DRW_shader_create_fullscreen(cavity_frag, NULL); - MEM_freeN(cavity_frag); - e_data.ghost_resolve_sh = DRW_shader_create_fullscreen(datatoc_workbench_ghost_resolve_frag_glsl, NULL); } workbench_volume_engine_init(); @@ -352,27 +403,35 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) { const float *viewport_size = DRW_viewport_size_get(); const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; - e_data.object_id_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R32UI, &draw_engine_workbench_solid); - e_data.color_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid); - e_data.cavity_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RG16, &draw_engine_workbench_solid); - e_data.specular_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid); - e_data.composite_buffer_tx = DRW_texture_pool_query_2D( - size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid); - - if (NORMAL_ENCODING_ENABLED()) { - e_data.normal_buffer_tx = DRW_texture_pool_query_2D( - size[0], size[1], GPU_RG16, &draw_engine_workbench_solid); + const GPUTextureFormat nor_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16 : GPU_RGBA32F; + const GPUTextureFormat comp_tex_format = DRW_state_is_image_render() ? GPU_RGBA16F : GPU_R11F_G11F_B10F; + const GPUTextureFormat id_tex_format = OBJECT_ID_PASS_ENABLED(wpd) ? GPU_R32UI : GPU_R8; + + e_data.object_id_tx = NULL; + e_data.color_buffer_tx = NULL; + e_data.composite_buffer_tx = NULL; + e_data.normal_buffer_tx = NULL; + e_data.cavity_buffer_tx = NULL; + + e_data.composite_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], comp_tex_format, &draw_engine_workbench_solid); + + if (MATDATA_PASS_ENABLED(wpd) || GPU_unused_fb_slot_workaround()) { + e_data.color_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid); } - else { - e_data.normal_buffer_tx = DRW_texture_pool_query_2D( - size[0], size[1], GPU_RGBA32F, &draw_engine_workbench_solid); + if (OBJECT_ID_PASS_ENABLED(wpd) || GPU_unused_fb_slot_workaround()) { + e_data.object_id_tx = DRW_texture_pool_query_2D(size[0], size[1], id_tex_format, &draw_engine_workbench_solid); + } + if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { + e_data.normal_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], nor_tex_format, &draw_engine_workbench_solid); + } + if (CAVITY_ENABLED(wpd)) { + e_data.cavity_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R16, &draw_engine_workbench_solid); } GPU_framebuffer_ensure_config(&fbl->prepass_fb, { GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx), - GPU_ATTACHMENT_TEXTURE(e_data.specular_buffer_tx), + GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx), }); GPU_framebuffer_ensure_config(&fbl->cavity_fb, { @@ -387,10 +446,22 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), }); + + if (!MATDATA_PASS_ENABLED(wpd) && !GPU_unused_fb_slot_workaround()) { + e_data.color_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid); + } + GPU_framebuffer_ensure_config(&fbl->effect_fb, { GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx), }); + + if (OBJECT_ID_PASS_ENABLED(wpd)) { + GPU_framebuffer_ensure_config(&fbl->id_clear_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), + }); + } } { @@ -437,21 +508,29 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) workbench_aa_create_pass(vedata, &e_data.color_buffer_tx); } - { + if (CAVITY_ENABLED(wpd)) { int state = DRW_STATE_WRITE_COLOR; + GPUShader *shader = workbench_cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd)); psl->cavity_pass = DRW_pass_create("Cavity", state); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.cavity_sh, psl->cavity_pass); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &e_data.color_buffer_tx); + DRWShadingGroup *grp = DRW_shgroup_create(shader, psl->cavity_pass); DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx); - - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); - DRW_shgroup_uniform_vec4(grp, "ssao_params", wpd->ssao_params, 1); - DRW_shgroup_uniform_vec4(grp, "ssao_settings", wpd->ssao_settings, 1); - DRW_shgroup_uniform_mat4(grp, "WinMatrix", wpd->winmat); - DRW_shgroup_uniform_texture(grp, "ssao_jitter", e_data.jitter_tx); DRW_shgroup_uniform_block(grp, "samples_block", e_data.sampling_ubo); + + if (SSAO_ENABLED(wpd)) { + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); + DRW_shgroup_uniform_vec4(grp, "ssao_params", wpd->ssao_params, 1); + DRW_shgroup_uniform_vec4(grp, "ssao_settings", wpd->ssao_settings, 1); + DRW_shgroup_uniform_mat4(grp, "WinMatrix", wpd->winmat); + DRW_shgroup_uniform_texture(grp, "ssao_jitter", e_data.jitter_tx); + } + + if (CURVATURE_ENABLED(wpd)) { + DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); + DRW_shgroup_uniform_vec2(grp, "curvature_settings", &wpd->world_data.curvature_ridge, 1); + } + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } } @@ -462,25 +541,31 @@ static void workbench_setup_ghost_framebuffer(WORKBENCH_FramebufferList *fbl) const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; e_data.ghost_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH_COMPONENT24, &draw_engine_workbench_solid); + GPU_framebuffer_ensure_config(&fbl->ghost_prepass_fb, { GPU_ATTACHMENT_TEXTURE(e_data.ghost_depth_tx), - GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx), - GPU_ATTACHMENT_TEXTURE(e_data.specular_buffer_tx), + GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx), }); } void workbench_deferred_engine_free(void) { - for (int index = 0; index < MAX_SHADERS; index++) { + for (int index = 0; index < MAX_PREPASS_SHADERS; index++) { DRW_SHADER_FREE_SAFE(e_data.prepass_sh_cache[index]); + } + for (int index = 0; index < MAX_COMPOSITE_SHADERS; index++) { DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]); } - DRW_SHADER_FREE_SAFE(e_data.cavity_sh); + for (int index = 0; index < MAX_CAVITY_SHADERS; ++index) { + DRW_SHADER_FREE_SAFE(e_data.cavity_sh[index]); + } DRW_SHADER_FREE_SAFE(e_data.ghost_resolve_sh); DRW_UBO_FREE_SAFE(e_data.sampling_ubo); DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx); + DRW_SHADER_FREE_SAFE(e_data.background_sh[0]); + DRW_SHADER_FREE_SAFE(e_data.background_sh[1]); DRW_SHADER_FREE_SAFE(e_data.shadow_pass_sh); DRW_SHADER_FREE_SAFE(e_data.shadow_pass_manifold_sh); @@ -496,27 +581,32 @@ void workbench_deferred_engine_free(void) static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp) { - DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &e_data.color_buffer_tx); - DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + if (MATDATA_PASS_ENABLED(wpd)) { + DRW_shgroup_uniform_texture_ref(grp, "materialBuffer", &e_data.color_buffer_tx); + } + else { + DRW_shgroup_uniform_vec3(grp, "materialSingleColor", wpd->shading.single_color, 1); + } + if (OBJECT_OUTLINE_ENABLED(wpd)) { + DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); + } if (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd)) { DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx); } if (CAVITY_ENABLED(wpd)) { DRW_shgroup_uniform_texture_ref(grp, "cavityBuffer", &e_data.cavity_buffer_tx); } - if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "specularBuffer", &e_data.specular_buffer_tx); + if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); } - DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - - if (STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)) { + if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { + DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); + } + if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE); - DRW_shgroup_uniform_texture(grp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture ); + DRW_shgroup_uniform_texture(grp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture); } - - workbench_material_set_normal_world_matrix(grp, wpd, e_data.normal_world_matrix); } void workbench_deferred_cache_init(WORKBENCH_Data *vedata) @@ -533,22 +623,39 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata) select_deferred_shaders(wpd); + /* Background Pass */ + { + psl->background_pass = DRW_pass_create( + "Background", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + grp = DRW_shgroup_create(wpd->background_sh, psl->background_pass); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); + if (OBJECT_OUTLINE_ENABLED(wpd)) { + DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); + } + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } + /* Deferred Mix Pass */ { workbench_private_data_get_light_direction(wpd, e_data.display.light_direction); studiolight_update_light(wpd, e_data.display.light_direction); - e_data.display.shadow_shift = scene->display.shadow_shift; + float shadow_focus = scene->display.shadow_focus; + /* Clamp to avoid overshadowing and shading errors. */ + CLAMP(shadow_focus, 0.0001f, 0.99999f); + shadow_focus = 1.0f - shadow_focus * (1.0f - scene->display.shadow_shift); if (SHADOW_ENABLED(wpd)) { psl->composite_pass = DRW_pass_create( - "Composite", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL); + "Composite", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL | DRW_STATE_DEPTH_GREATER); grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); workbench_composite_uniforms(wpd, grp); DRW_shgroup_stencil_mask(grp, 0x00); DRW_shgroup_uniform_float_copy(grp, "lightMultiplier", 1.0f); DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1); - DRW_shgroup_uniform_float(grp, "shadowShift", &scene->display.shadow_shift, 1); + DRW_shgroup_uniform_float_copy(grp, "shadowShift", scene->display.shadow_shift); + DRW_shgroup_uniform_float_copy(grp, "shadowFocus", shadow_focus); DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); /* Stencil Shadow passes. */ @@ -580,20 +687,21 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata) grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh, psl->shadow_depth_fail_caps_mani_pass); DRW_shgroup_stencil_mask(grp, 0xFF); - psl->composite_shadow_pass = DRW_pass_create("Composite Shadow", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL); + psl->composite_shadow_pass = DRW_pass_create( + "Composite Shadow", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL | DRW_STATE_DEPTH_GREATER); grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_shadow_pass); DRW_shgroup_stencil_mask(grp, 0x00); workbench_composite_uniforms(wpd, grp); DRW_shgroup_uniform_float(grp, "lightMultiplier", &wpd->shadow_multiplier, 1); DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1); - DRW_shgroup_uniform_float(grp, "shadowShift", &scene->display.shadow_shift, 1); + DRW_shgroup_uniform_float_copy(grp, "shadowShift", scene->display.shadow_shift); + DRW_shgroup_uniform_float_copy(grp, "shadowFocus", shadow_focus); DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); #endif - } else { psl->composite_pass = DRW_pass_create( - "Composite", DRW_STATE_WRITE_COLOR); + "Composite", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER); grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); workbench_composite_uniforms(wpd, grp); DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); @@ -629,7 +737,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data( workbench_material_copy(material, &material_template); DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF); DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1); - workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob); + workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, true); BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material); } @@ -641,10 +749,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o WORKBENCH_StorageList *stl = vedata->stl; WORKBENCH_PassList *psl = vedata->psl; WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (ob == draw_ctx->object_edit) { - return; - } + for (ModifierData *md = ob->modifiers.first; md; md = md->next) { if (md->type != eModifierType_ParticleSystem) { continue; @@ -675,7 +780,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o shader); DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF); DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1); - workbench_material_shgroup_uniform(wpd, shgrp, material, ob); + workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, true); } } } @@ -702,7 +807,7 @@ static void workbench_cache_populate_hair(WORKBENCH_Data *vedata, Object *ob) DRWShadingGroup *shgrp = DRW_shgroup_hair_create(ob, hsys, psl->prepass_hair_pass, shader); DRW_shgroup_stencil_mask(shgrp, 0xFF); DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1); - workbench_material_shgroup_uniform(wpd, shgrp, material, ob); + workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, true); } void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) @@ -741,28 +846,22 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_HAIR)) { const bool is_active = (ob == draw_ctx->obact); const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0; + const bool use_hide = is_active && DRW_object_use_hide_faces(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 GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - struct GPUBatch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob) : NULL; - if (materials_len > 0 && geom_array) { - for (int i = 0; i < materials_len; i++) { - if (geom_array[i] == NULL) { - continue; - } - - Material *mat = give_current_material(ob, i + 1); - Image *image; - ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL); - int color_type = workbench_material_determine_color_type(wpd, image, ob); - material = get_or_create_material_data(vedata, ob, mat, image, color_type); - DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob); - } - is_drawn = true; + struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); + for (int i = 0; i < materials_len; i++) { + Material *mat = give_current_material(ob, i + 1); + Image *image; + ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL); + int color_type = workbench_material_determine_color_type(wpd, image, ob); + material = get_or_create_material_data(vedata, ob, mat, image, color_type); + DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob); } + is_drawn = true; } } @@ -813,7 +912,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) bool is_manifold; struct GPUBatch *geom_shadow = DRW_cache_object_edge_detection_get(ob, &is_manifold); if (geom_shadow) { - if (is_sculpt_mode) { + if (is_sculpt_mode || use_hide) { /* Currently unsupported in sculpt mode. We could revert to the slow * method in this case but I'm not sure if it's a good idea given that * sculpted meshes are heavy to begin with. */ @@ -896,8 +995,15 @@ void workbench_deferred_draw_background(WORKBENCH_Data *vedata) uint clear_stencil = 0x00; DRW_stats_group_start("Clear Background"); + + if (OBJECT_ID_PASS_ENABLED(wpd)) { + /* From all the color buffers, only object id needs to be cleared. */ + GPU_framebuffer_bind(fbl->id_clear_fb); + GPU_framebuffer_clear_color(fbl->id_clear_fb, clear_color); + } + GPU_framebuffer_bind(fbl->prepass_fb); - int clear_bits = GPU_DEPTH_BIT | GPU_COLOR_BIT; + int clear_bits = GPU_DEPTH_BIT; SET_FLAG_FROM_TEST(clear_bits, SHADOW_ENABLED(wpd), GPU_STENCIL_BIT); GPU_framebuffer_clear(fbl->prepass_fb, clear_bits, clear_color, clear_depth, clear_stencil); DRW_stats_group_end(); @@ -987,6 +1093,9 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata) DRW_draw_pass(psl->ghost_prepass_hair_pass); } + GPU_framebuffer_bind(fbl->composite_fb); + DRW_draw_pass(psl->background_pass); + if (wpd->volumes_do) { GPU_framebuffer_bind(fbl->volume_fb); DRW_draw_pass(psl->volume_pass); diff --git a/source/blender/draw/engines/workbench/workbench_effect_taa.c b/source/blender/draw/engines/workbench/workbench_effect_taa.c index 403338d55c4..929281daaf4 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_taa.c +++ b/source/blender/draw/engines/workbench/workbench_effect_taa.c @@ -171,7 +171,8 @@ DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_bu int previous_jitter_index = effect_info->jitter_index; { - DRW_texture_ensure_fullscreen_2D(&txl->history_buffer_tx, GPU_RGBA16F, 0); + const GPUTextureFormat hist_buffer_format = DRW_state_is_image_render() ? GPU_RGBA16F : GPU_RGBA8; + DRW_texture_ensure_fullscreen_2D(&txl->history_buffer_tx, hist_buffer_format, 0); DRW_texture_ensure_fullscreen_2D(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0); } diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 642c5820895..180932b9b64 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -31,12 +31,12 @@ #include "workbench_engine.h" #include "workbench_private.h" -#define OPENGL_ENGINE "BLENDER_OPENGL" +#define WORKBENCH_ENGINE "BLENDER_WORKBENCH" /* Note: currently unused, we may want to register so we can see this when debugging the view. */ -RenderEngineType DRW_engine_viewport_opengl_type = { +RenderEngineType DRW_engine_viewport_workbench_type = { NULL, NULL, - OPENGL_ENGINE, N_("OpenGL"), RE_INTERNAL, + WORKBENCH_ENGINE, N_("Workbench"), RE_INTERNAL, NULL, &DRW_render_to_image, NULL, NULL, NULL, NULL, &workbench_render_update_passes, &draw_engine_workbench_solid, diff --git a/source/blender/draw/engines/workbench/workbench_engine.h b/source/blender/draw/engines/workbench/workbench_engine.h index 24f68cacd21..a7f168db093 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.h +++ b/source/blender/draw/engines/workbench/workbench_engine.h @@ -28,6 +28,6 @@ extern DrawEngineType draw_engine_workbench_solid; extern DrawEngineType draw_engine_workbench_transparent; -extern RenderEngineType DRW_engine_viewport_opengl_type; +extern RenderEngineType DRW_engine_viewport_workbench_type; #endif /* __WORKBENCH_ENGINE_H__ */ diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index b5b4a3ec364..835bb09dcd5 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -51,8 +51,8 @@ /* *********** STATIC *********** */ static struct { - struct GPUShader *composite_sh_cache[MAX_SHADERS]; - struct GPUShader *transparent_accum_sh_cache[MAX_SHADERS]; + struct GPUShader *composite_sh_cache[2]; + struct GPUShader *transparent_accum_sh_cache[MAX_ACCUM_SHADERS]; struct GPUShader *object_outline_sh; struct GPUShader *object_outline_texture_sh; struct GPUShader *object_outline_hair_sh; @@ -64,7 +64,6 @@ static struct { struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */ int next_object_id; - float normal_world_matrix[3][3]; } e_data = {{NULL}}; /* Shaders */ @@ -77,6 +76,7 @@ extern char datatoc_workbench_data_lib_glsl[]; extern char datatoc_workbench_background_lib_glsl[]; extern char datatoc_workbench_checkerboard_depth_frag_glsl[]; extern char datatoc_workbench_object_outline_lib_glsl[]; +extern char datatoc_workbench_curvature_lib_glsl[]; extern char datatoc_workbench_prepass_vert_glsl[]; extern char datatoc_workbench_common_lib_glsl[]; extern char datatoc_workbench_world_light_lib_glsl[]; @@ -125,6 +125,7 @@ static char *workbench_build_forward_composite_frag(void) BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_background_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl); + BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_forward_composite_frag_glsl); str = BLI_dynstr_get_cstring(ds); @@ -168,9 +169,8 @@ static WORKBENCH_MaterialData *get_or_create_material_data( DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); DRW_shgroup_uniform_float(grp, "alpha", &wpd->shading.xray_alpha, 1); DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); - workbench_material_set_normal_world_matrix(grp, wpd, e_data.normal_world_matrix); workbench_material_copy(material, &material_template); - if (STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)) { + if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE); DRW_shgroup_uniform_texture(grp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture ); } @@ -178,7 +178,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data( DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); } - workbench_material_shgroup_uniform(wpd, grp, material, ob); + workbench_material_shgroup_uniform(wpd, grp, material, ob, false, false); material->shgrp = grp; /* Depth */ @@ -199,16 +199,9 @@ static WORKBENCH_MaterialData *get_or_create_material_data( return material; } -static void ensure_forward_shaders(WORKBENCH_PrivateData *wpd, int index, bool use_textures, bool is_hair) +static GPUShader *ensure_forward_accum_shaders(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair) { - if (e_data.composite_sh_cache[index] == NULL && !use_textures && !is_hair) { - char *defines = workbench_material_build_defines(wpd, use_textures, is_hair); - char *composite_frag = workbench_build_forward_composite_frag(); - e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); - MEM_freeN(composite_frag); - MEM_freeN(defines); - } - + int index = workbench_material_get_accum_shader_index(wpd, use_textures, is_hair); if (e_data.transparent_accum_sh_cache[index] == NULL) { char *defines = workbench_material_build_defines(wpd, use_textures, is_hair); char *transparent_accum_vert = workbench_build_forward_vert(is_hair); @@ -220,25 +213,29 @@ static void ensure_forward_shaders(WORKBENCH_PrivateData *wpd, int index, bool u MEM_freeN(transparent_accum_frag); MEM_freeN(defines); } + return e_data.transparent_accum_sh_cache[index]; +} + +static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd) +{ + int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0; + if (e_data.composite_sh_cache[index] == NULL) { + char *defines = workbench_material_build_defines(wpd, false, false); + char *composite_frag = workbench_build_forward_composite_frag(); + e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); + MEM_freeN(composite_frag); + MEM_freeN(defines); + } + return e_data.composite_sh_cache[index]; } static void select_forward_shaders(WORKBENCH_PrivateData *wpd) { - int index_solid = workbench_material_get_shader_index(wpd, false, false); - int index_solid_hair = workbench_material_get_shader_index(wpd, false, true); - int index_texture = workbench_material_get_shader_index(wpd, true, false); - int index_texture_hair = workbench_material_get_shader_index(wpd, true, true); - - ensure_forward_shaders(wpd, index_solid, false, false); - ensure_forward_shaders(wpd, index_solid_hair, false, true); - ensure_forward_shaders(wpd, index_texture, true, false); - ensure_forward_shaders(wpd, index_texture_hair, true, true); - - wpd->composite_sh = e_data.composite_sh_cache[index_solid]; - wpd->transparent_accum_sh = e_data.transparent_accum_sh_cache[index_solid]; - wpd->transparent_accum_hair_sh = e_data.transparent_accum_sh_cache[index_solid_hair]; - wpd->transparent_accum_texture_sh = e_data.transparent_accum_sh_cache[index_texture]; - wpd->transparent_accum_texture_hair_sh = e_data.transparent_accum_sh_cache[index_texture_hair]; + wpd->composite_sh = ensure_forward_composite_shaders(wpd); + wpd->transparent_accum_sh = ensure_forward_accum_shaders(wpd, false, false); + wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders(wpd, false, true); + wpd->transparent_accum_texture_sh = ensure_forward_accum_shaders(wpd, true, false); + wpd->transparent_accum_texture_hair_sh = ensure_forward_accum_shaders(wpd, true, true); } /* public functions */ @@ -266,8 +263,8 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata) if (!e_data.next_object_id) { e_data.next_object_id = 1; - memset(e_data.composite_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS); - memset(e_data.transparent_accum_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS); + memset(e_data.composite_sh_cache, 0x00, sizeof(e_data.composite_sh_cache)); + memset(e_data.transparent_accum_sh_cache, 0x00, sizeof(e_data.transparent_accum_sh_cache)); char *defines = workbench_material_build_defines(wpd, false, false); char *defines_texture = workbench_material_build_defines(wpd, true, false); @@ -393,8 +390,10 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata) void workbench_forward_engine_free() { - for (int index = 0; index < MAX_SHADERS; index++) { + for (int index = 0; index < 2; index++) { DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]); + } + for (int index = 0; index < MAX_ACCUM_SHADERS; index++) { DRW_SHADER_FREE_SAFE(e_data.transparent_accum_sh_cache[index]); } DRW_SHADER_FREE_SAFE(e_data.object_outline_sh); @@ -416,11 +415,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O WORKBENCH_StorageList *stl = vedata->stl; WORKBENCH_PassList *psl = vedata->psl; WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (ob == draw_ctx->object_edit) { - return; - } for (ModifierData *md = ob->modifiers.first; md; md = md->next) { if (md->type != eModifierType_ParticleSystem) { continue; @@ -449,15 +444,14 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O ob, psys, md, psl->transparent_accum_pass, shader); - workbench_material_set_normal_world_matrix(shgrp, wpd, e_data.normal_world_matrix); DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo); - workbench_material_shgroup_uniform(wpd, shgrp, material, ob); + workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false); DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3); /* Hairs have lots of layer and can rapidly become the most prominent surface. * So lower their alpha artificially. */ float hair_alpha = XRAY_ALPHA(wpd) * 0.33f; DRW_shgroup_uniform_float_copy(shgrp, "alpha", hair_alpha); - if (STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)) { + if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE); DRW_shgroup_uniform_texture(shgrp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture ); } @@ -492,15 +486,14 @@ static void workbench_forward_cache_populate_hair(WORKBENCH_Data *vedata, Object ? wpd->transparent_accum_hair_sh : wpd->transparent_accum_texture_hair_sh; DRWShadingGroup *shgrp = DRW_shgroup_hair_create(ob, hsys, psl->transparent_accum_pass, shader); - workbench_material_set_normal_world_matrix(shgrp, wpd, e_data.normal_world_matrix); DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo); - workbench_material_shgroup_uniform(wpd, shgrp, material, ob); + workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false); DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3); /* Hairs have lots of layer and can rapidly become the most prominent surface. * So lower their alpha artificially. */ float hair_alpha = wpd->shading.xray_alpha * 0.33f; DRW_shgroup_uniform_float_copy(shgrp, "alpha", hair_alpha); - if (STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)) { + if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE); DRW_shgroup_uniform_texture(shgrp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture ); } @@ -553,33 +546,26 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) const Mesh *me = ob->data; if (me->mloopuv) { const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); - struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - struct GPUBatch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob) : NULL; - if (materials_len > 0 && geom_array) { - for (int i = 0; i < materials_len; i++) { - if (geom_array[i] == NULL) { - continue; - } + struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); + for (int i = 0; i < materials_len; i++) { + Material *mat = give_current_material(ob, i + 1); + Image *image; + ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL); + /* use OB_SOLID when no texture could be determined */ - Material *mat = give_current_material(ob, i + 1); - Image *image; - ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL); + int color_type = wpd->shading.color_type; + if (color_type == V3D_SHADING_TEXTURE_COLOR) { /* use OB_SOLID when no texture could be determined */ - - int color_type = wpd->shading.color_type; - if (color_type == V3D_SHADING_TEXTURE_COLOR) { - /* use OB_SOLID when no texture could be determined */ - if (image == NULL) { - color_type = V3D_SHADING_MATERIAL_COLOR; - } + if (image == NULL) { + color_type = V3D_SHADING_MATERIAL_COLOR; } - - material = get_or_create_material_data(vedata, ob, mat, image, color_type); - 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; + + material = get_or_create_material_data(vedata, ob, mat, image, color_type); + 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; } } diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 2faa9e288f8..5360cf3683b 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -4,24 +4,27 @@ #include "BIF_gl.h" +#include "BKE_image.h" + #include "BLI_dynstr.h" #include "BLI_hash.h" #define HSV_SATURATION 0.5 -#define HSV_VALUE 0.9 +#define HSV_VALUE 0.8 void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, WORKBENCH_MaterialData *data) { /* When V3D_SHADING_TEXTURE_COLOR is active, use V3D_SHADING_MATERIAL_COLOR as fallback when no texture could be determined */ int color_type = wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR ? V3D_SHADING_MATERIAL_COLOR : wpd->shading.color_type; - static float default_diffuse_color[] = {0.8f, 0.8f, 0.8f, 1.0f}; - static float default_specular_color[] = {0.5f, 0.5f, 0.5f, 0.5f}; - copy_v4_v4(data->diffuse_color, default_diffuse_color); - copy_v4_v4(data->specular_color, default_specular_color); - data->roughness = 0.5f; + copy_v3_fl3(data->diffuse_color, 0.8f, 0.8f, 0.8f); + copy_v3_v3(data->base_color, data->diffuse_color); + copy_v3_fl3(data->specular_color, 0.05f, 0.05f, 0.05f); /* Dielectric: 5% reflective. */ + data->metallic = 0.0f; + data->roughness = 0.5f; /* sqrtf(0.25f); */ if (color_type == V3D_SHADING_SINGLE_COLOR) { copy_v3_v3(data->diffuse_color, wpd->shading.single_color); + copy_v3_v3(data->base_color, data->diffuse_color); } else if (color_type == V3D_SHADING_RANDOM_COLOR) { uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); @@ -32,13 +35,23 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Mate float hue = BLI_hash_int_01(hash); float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE}; hsv_to_rgb_v(hsv, data->diffuse_color); + copy_v3_v3(data->base_color, data->diffuse_color); } else { /* V3D_SHADING_MATERIAL_COLOR */ if (mat) { - copy_v3_v3(data->diffuse_color, &mat->r); - copy_v3_v3(data->specular_color, &mat->specr); - data->roughness = mat->roughness; + if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) { + copy_v3_v3(data->base_color, &mat->r); + mul_v3_v3fl(data->diffuse_color, &mat->r, 1.0f - mat->metallic); + mul_v3_v3fl(data->specular_color, &mat->r, mat->metallic); + add_v3_fl(data->specular_color, 0.05f * (1.0f - mat->metallic)); + data->metallic = mat->metallic; + data->roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */ + } + else { + copy_v3_v3(data->base_color, &mat->r); + copy_v3_v3(data->diffuse_color, &mat->r); + } } } } @@ -55,8 +68,8 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool use_text if (wpd->shading.flag & V3D_SHADING_SHADOW) { BLI_dynstr_appendf(ds, "#define V3D_SHADING_SHADOW\n"); } - if (CAVITY_ENABLED(wpd)) { - BLI_dynstr_appendf(ds, "#define V3D_SHADING_CAVITY\n"); + if (SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) { + BLI_dynstr_appendf(ds, "#define WB_CAVITY\n"); } if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) { BLI_dynstr_appendf(ds, "#define V3D_SHADING_SPECULAR_HIGHLIGHT\n"); @@ -70,14 +83,11 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool use_text if (MATCAP_ENABLED(wpd)) { BLI_dynstr_appendf(ds, "#define V3D_LIGHTING_MATCAP\n"); } - if (STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) { - BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_WORLD\n"); - } - if (STUDIOLIGHT_ORIENTATION_CAMERA_ENABLED(wpd)) { - BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_CAMERA\n"); + if (OBJECT_ID_PASS_ENABLED(wpd)) { + BLI_dynstr_appendf(ds, "#define OBJECT_ID_PASS_ENABLED\n"); } - if (STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)) { - BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_VIEWNORMAL\n"); + if (MATDATA_PASS_ENABLED(wpd)) { + BLI_dynstr_appendf(ds, "#define MATDATA_PASS_ENABLED\n"); } if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { BLI_dynstr_appendf(ds, "#define NORMAL_VIEWPORT_PASS_ENABLED\n"); @@ -92,9 +102,6 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool use_text BLI_dynstr_appendf(ds, "#define HAIR_SHADER\n"); } - BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_SH_BANDS %d\n", STUDIOLIGHT_SH_BANDS); - BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_SH_MAX_COMPONENTS %d\n", WORKBENCH_SH_DATA_LEN); - str = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); return str; @@ -128,40 +135,42 @@ uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool return result; } -int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair) +int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd) { - /* NOTE: change MAX_SHADERS accordingly when modifying this function. */ + /* NOTE: change MAX_COMPOSITE_SHADERS accordingly when modifying this function. */ int index = 0; - /* 1 bit V3D_SHADING_TEXTURE_COLOR */ - SET_FLAG_FROM_TEST(index, use_textures, 1 << 0); - /* 2 bits FLAT/STUDIO/MATCAP/SCENE */ - SET_FLAG_FROM_TEST(index, wpd->shading.light, wpd->shading.light << 1); - /* 1 bit V3D_SHADING_SPECULAR_HIGHLIGHT */ - SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT, 1 << 3); - SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 4); - SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 5); - SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 6); - /* 2 bits STUDIOLIGHT_ORIENTATION */ - SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD, 1 << 7); - SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL, 1 << 8); - /* 1 bit for hair */ - SET_FLAG_FROM_TEST(index, is_hair, 1 << 9); + /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */ + index = SPECULAR_HIGHLIGHT_ENABLED(wpd) ? 3 : wpd->shading.light; + SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 2); + SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 3); + SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 4); + SET_FLAG_FROM_TEST(index, MATDATA_PASS_ENABLED(wpd), 1 << 5); return index; } -void workbench_material_set_normal_world_matrix( - DRWShadingGroup *grp, WORKBENCH_PrivateData *wpd, float persistent_matrix[3][3]) +int workbench_material_get_prepass_shader_index( + WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair) { - if (STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) { - float view_matrix_inverse[4][4]; - float rot_matrix[4][4]; - float matrix[4][4]; - axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z); - DRW_viewport_matrix_get(view_matrix_inverse, DRW_MAT_VIEWINV); - mul_m4_m4m4(matrix, rot_matrix, view_matrix_inverse); - copy_m3_m4(persistent_matrix, matrix); - DRW_shgroup_uniform_mat3(grp, "normalWorldMatrix", persistent_matrix); - } + /* NOTE: change MAX_PREPASS_SHADERS accordingly when modifying this function. */ + int index = 0; + SET_FLAG_FROM_TEST(index, is_hair, 1 << 0); + SET_FLAG_FROM_TEST(index, MATDATA_PASS_ENABLED(wpd), 1 << 1); + SET_FLAG_FROM_TEST(index, OBJECT_ID_PASS_ENABLED(wpd), 1 << 2); + SET_FLAG_FROM_TEST(index, NORMAL_VIEWPORT_PASS_ENABLED(wpd), 1 << 3); + SET_FLAG_FROM_TEST(index, MATCAP_ENABLED(wpd), 1 << 4); + SET_FLAG_FROM_TEST(index, use_textures, 1 << 5); + return index; +} + +int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair) +{ + /* NOTE: change MAX_ACCUM_SHADERS accordingly when modifying this function. */ + int index = 0; + /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */ + index = SPECULAR_HIGHLIGHT_ENABLED(wpd) ? 3 : wpd->shading.light; + SET_FLAG_FROM_TEST(index, use_textures, 1 << 2); + SET_FLAG_FROM_TEST(index, is_hair, 1 << 3); + return index; } int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, Image *ima, Object *ob) @@ -174,18 +183,32 @@ int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, Image *i } void workbench_material_shgroup_uniform( - WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material, Object *ob) + WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material, Object *ob, + const bool use_metallic, const bool deferred) { + if (deferred && !MATDATA_PASS_ENABLED(wpd)) { + return; + } + if (workbench_material_determine_color_type(wpd, material->ima, ob) == V3D_SHADING_TEXTURE_COLOR) { + ImBuf *ibuf = BKE_image_acquire_ibuf(material->ima, NULL, NULL); + const bool do_color_correction = (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0); + BKE_image_release_ibuf(material->ima, ibuf, NULL); GPUTexture *tex = GPU_texture_from_blender(material->ima, NULL, GL_TEXTURE_2D, false, 0.0f); DRW_shgroup_uniform_texture(grp, "image", tex); + DRW_shgroup_uniform_bool_copy(grp, "imageSrgb", do_color_correction); } else { - DRW_shgroup_uniform_vec4(grp, "materialDiffuseColor", material->diffuse_color, 1); + DRW_shgroup_uniform_vec3(grp, "materialDiffuseColor", (use_metallic) ? material->base_color : material->diffuse_color, 1); } if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) { - DRW_shgroup_uniform_vec4(grp, "materialSpecularColor", material->specular_color, 1); + if (use_metallic) { + DRW_shgroup_uniform_float(grp, "materialMetallic", &material->metallic, 1); + } + else { + DRW_shgroup_uniform_vec3(grp, "materialSpecularColor", material->specular_color, 1); + } DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1); } } @@ -193,8 +216,10 @@ void workbench_material_shgroup_uniform( void workbench_material_copy(WORKBENCH_MaterialData *dest_material, const WORKBENCH_MaterialData *source_material) { dest_material->object_id = source_material->object_id; - copy_v4_v4(dest_material->diffuse_color, source_material->diffuse_color); - copy_v4_v4(dest_material->specular_color, source_material->specular_color); + copy_v3_v3(dest_material->base_color, source_material->base_color); + copy_v3_v3(dest_material->diffuse_color, source_material->diffuse_color); + copy_v3_v3(dest_material->specular_color, source_material->specular_color); + dest_material->metallic = source_material->metallic; dest_material->roughness = source_material->roughness; dest_material->ima = source_material->ima; } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 93b3bddfb72..080817c7f53 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -40,16 +40,22 @@ #define WORKBENCH_ENGINE "BLENDER_WORKBENCH" #define M_GOLDEN_RATION_CONJUGATE 0.618033988749895 -#define MAX_SHADERS (1 << 10) +#define MAX_COMPOSITE_SHADERS (1 << 6) +#define MAX_PREPASS_SHADERS (1 << 6) +#define MAX_ACCUM_SHADERS (1 << 4) +#define MAX_CAVITY_SHADERS (1 << 3) #define TEXTURE_DRAWING_ENABLED(wpd) (wpd->shading.color_type & V3D_SHADING_TEXTURE_COLOR) #define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT) #define STUDIOLIGHT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_STUDIO) #define MATCAP_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_MATCAP) -#define STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD)) -#define STUDIOLIGHT_ORIENTATION_CAMERA_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_CAMERA)) -#define STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd) (MATCAP_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL)) -#define CAVITY_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_CAVITY) +#define USE_WORLD_ORIENTATION(wpd) ((wpd->shading.flag & V3D_SHADING_WORLD_ORIENTATION) != 0) +#define STUDIOLIGHT_TYPE_WORLD_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_TYPE_WORLD)) +#define STUDIOLIGHT_TYPE_STUDIO_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_TYPE_STUDIO)) +#define STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd) (MATCAP_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_TYPE_MATCAP)) +#define SSAO_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_CAVITY) && ((wpd->shading.cavity_type == V3D_SHADING_CAVITY_SSAO) || (wpd->shading.cavity_type == V3D_SHADING_CAVITY_BOTH))) +#define CURVATURE_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_CAVITY) && ((wpd->shading.cavity_type == V3D_SHADING_CAVITY_CURVATURE) || (wpd->shading.cavity_type == V3D_SHADING_CAVITY_BOTH))) +#define CAVITY_ENABLED(wpd) (CURVATURE_ENABLED(wpd) || SSAO_ENABLED(wpd)) #define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW) #define GHOST_ENABLED(psl) (!DRW_pass_is_empty(psl->ghost_prepass_pass) || !DRW_pass_is_empty(psl->ghost_prepass_hair_pass)) @@ -58,10 +64,12 @@ (IN_RANGE(wpd->user_preferences->gpu_viewport_quality, GPU_VIEWPORT_QUALITY_FXAA, GPU_VIEWPORT_QUALITY_TAA8) || \ ((IS_NAVIGATING(wpd) || wpd->is_playback) && (wpd->user_preferences->gpu_viewport_quality >= GPU_VIEWPORT_QUALITY_TAA8)))) #define TAA_ENABLED(wpd) (DRW_state_is_image_render() || (wpd->user_preferences->gpu_viewport_quality >= GPU_VIEWPORT_QUALITY_TAA8 && !IS_NAVIGATING(wpd) && !wpd->is_playback)) -#define SPECULAR_HIGHLIGHT_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) && (!STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd))) -#define OBJECT_ID_PASS_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) -#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd) || SPECULAR_HIGHLIGHT_ENABLED(wpd)) -#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) || CAVITY_ENABLED(wpd)) +#define SPECULAR_HIGHLIGHT_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) && (!STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd))) +#define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) +#define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) +#define MATDATA_PASS_ENABLED(wpd) (wpd->shading.color_type != V3D_SHADING_SINGLE_COLOR || MATCAP_ENABLED(wpd)) +#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd)) +#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) || SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) #define NORMAL_ENCODING_ENABLED() (true) @@ -76,6 +84,7 @@ typedef struct WORKBENCH_FramebufferList { struct GPUFrameBuffer *ghost_prepass_fb; struct GPUFrameBuffer *cavity_fb; struct GPUFrameBuffer *composite_fb; + struct GPUFrameBuffer *id_clear_fb; struct GPUFrameBuffer *effect_fb; struct GPUFrameBuffer *effect_taa_fb; @@ -113,6 +122,7 @@ typedef struct WORKBENCH_PassList { struct DRWPass *shadow_depth_fail_caps_mani_pass; struct DRWPass *composite_pass; struct DRWPass *composite_shadow_pass; + struct DRWPass *background_pass; struct DRWPass *ghost_resolve_pass; struct DRWPass *effect_aa_pass; struct DRWPass *volume_pass; @@ -133,24 +143,24 @@ typedef struct WORKBENCH_Data { } WORKBENCH_Data; typedef struct WORKBENCH_UBO_Light { - float light_direction_vs[4]; - float specular_color[3]; - float energy; + float light_direction[4]; + float specular_color[3], pad; + float diffuse_color[3], wrapped; } WORKBENCH_UBO_Light; -#define WORKBENCH_SH_DATA_LEN ((STUDIOLIGHT_SH_BANDS == 2) ? 6 : STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN) - typedef struct WORKBENCH_UBO_World { - float spherical_harmonics_coefs[WORKBENCH_SH_DATA_LEN][4]; float background_color_low[4]; float background_color_high[4]; float object_outline_color[4]; float shadow_direction_vs[4]; - WORKBENCH_UBO_Light lights[3]; + WORKBENCH_UBO_Light lights[4]; + float ambient_color[4]; int num_lights; int matcap_orientation; float background_alpha; - int pad[1]; + float curvature_ridge; + float curvature_valley; + int pad[3]; } WORKBENCH_UBO_World; BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16) @@ -162,6 +172,7 @@ typedef struct WORKBENCH_PrivateData { struct GPUShader *prepass_texture_sh; struct GPUShader *prepass_texture_hair_sh; struct GPUShader *composite_sh; + struct GPUShader *background_sh; struct GPUShader *transparent_accum_sh; struct GPUShader *transparent_accum_hair_sh; struct GPUShader *transparent_accum_texture_sh; @@ -212,8 +223,10 @@ typedef struct WORKBENCH_EffectInfo { } WORKBENCH_EffectInfo; typedef struct WORKBENCH_MaterialData { - float diffuse_color[4]; - float specular_color[4]; + float base_color[3]; + float diffuse_color[3]; + float specular_color[3]; + float metallic; float roughness; int object_id; int color_type; @@ -288,15 +301,16 @@ int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, Image *i char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair); void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, WORKBENCH_MaterialData *data); uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost); -int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair); -void workbench_material_set_normal_world_matrix( - DRWShadingGroup *grp, WORKBENCH_PrivateData *wpd, float persistent_matrix[3][3]); +int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd); +int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair); +int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair); void workbench_material_shgroup_uniform( - WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material, Object *ob); + WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material, Object *ob, + const bool use_metallic, const bool deferred); void workbench_material_copy(WORKBENCH_MaterialData *dest_material, const WORKBENCH_MaterialData *source_material); /* workbench_studiolight.c */ -void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd); +void studiolight_update_world(WORKBENCH_PrivateData *wpd, StudioLight *sl, WORKBENCH_UBO_World *wd); void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3]); bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed); float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed); diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c index 901260d0660..52a0e6045c6 100644 --- a/source/blender/draw/engines/workbench/workbench_studiolight.c +++ b/source/blender/draw/engines/workbench/workbench_studiolight.c @@ -32,8 +32,48 @@ #include "BLI_math.h" #include "BKE_global.h" -void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd) +void studiolight_update_world(WORKBENCH_PrivateData *wpd, StudioLight *studiolight, WORKBENCH_UBO_World *wd) { + float view_matrix[4][4], rot_matrix[4][4]; + DRW_viewport_matrix_get(view_matrix, DRW_MAT_VIEW); + + if (USE_WORLD_ORIENTATION(wpd)) { + axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z); + mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix); + swap_v3_v3(rot_matrix[2], rot_matrix[1]); + negate_v3(rot_matrix[2]); + } + else { + unit_m4(rot_matrix); + } + + if (U.edit_studio_light) { + studiolight = BKE_studiolight_studio_edit_get(); + } + + /* Studio Lights. */ + for (int i = 0; i < 4; i++) { + WORKBENCH_UBO_Light *light = &wd->lights[i]; + + SolidLight *sl = &studiolight->light[i]; + if (sl->flag) { + copy_v3_v3(light->light_direction, sl->vec); + mul_mat3_m4_v3(rot_matrix, light->light_direction); + /* We should predivide the power by PI but that makes the lights really dim. */ + copy_v3_v3(light->specular_color, sl->spec); + copy_v3_v3(light->diffuse_color, sl->col); + light->wrapped = sl->smooth; + } + else { + copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f); + copy_v3_fl(light->specular_color, 0.0f); + copy_v3_fl(light->diffuse_color, 0.0f); + } + } + + copy_v3_v3(wd->ambient_color, studiolight->light_ambient); + +#if 0 BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED); #if STUDIOLIGHT_SH_BANDS == 2 @@ -87,6 +127,7 @@ void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd) copy_v3_v3(wd->spherical_harmonics_coefs[i], sl->spherical_harmonics_coefs[i]); } #endif +#endif } static void compute_parallel_lines_nor_and_dist(const float v1[2], const float v2[2], const float v3[2], float r_line[2]) diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index faba85c9b46..89aa55c56b2 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -283,9 +283,9 @@ typedef enum { DRW_STATE_CULL_FRONT = (1 << 9), DRW_STATE_WIRE = (1 << 10), DRW_STATE_POINT = (1 << 11), - DRW_STATE_STIPPLE_2 = (1 << 12), - DRW_STATE_STIPPLE_3 = (1 << 13), - DRW_STATE_STIPPLE_4 = (1 << 14), + DRW_STATE_OFFSET_POSITIVE = (1 << 12), /* Polygon offset. Does not work with lines and points. */ + DRW_STATE_OFFSET_NEGATIVE = (1 << 13), /* Polygon offset. Does not work with lines and points. */ + /* DRW_STATE_STIPPLE_4 = (1 << 14), */ /* Not used */ DRW_STATE_BLEND = (1 << 15), DRW_STATE_ADDITIVE = (1 << 16), DRW_STATE_MULTIPLY = (1 << 17), @@ -296,6 +296,7 @@ typedef enum { DRW_STATE_WIRE_SMOOTH = (1 << 22), DRW_STATE_TRANS_FEEDBACK = (1 << 23), DRW_STATE_BLEND_OIT = (1 << 24), + DRW_STATE_FIRST_VERTEX_CONVENTION = (1 << 25), DRW_STATE_WRITE_STENCIL = (1 << 27), DRW_STATE_WRITE_STENCIL_SHADOW_PASS = (1 << 28), @@ -512,9 +513,13 @@ DrawData *DRW_drawdata_ensure( bool DRW_object_is_renderable(const struct Object *ob); bool DRW_object_is_visible_in_active_context(const struct Object *ob); bool DRW_object_is_flat_normal(const struct Object *ob); +bool DRW_object_use_hide_faces(const struct Object *ob); bool DRW_object_is_visible_psys_in_active_context(const struct Object *object, const struct ParticleSystem *psys); +struct Object *DRW_object_get_dupli_parent(const struct Object *ob); +struct DupliObject *DRW_object_get_dupli(const struct Object *ob); + /* Draw commands */ void DRW_draw_pass(DRWPass *pass); void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group); @@ -552,6 +557,7 @@ bool DRW_state_is_depth(void); bool DRW_state_is_image_render(void); bool DRW_state_is_scene_render(void); bool DRW_state_is_opengl_render(void); +bool DRW_state_is_playback(void); bool DRW_state_show_text(void); bool DRW_state_draw_support(void); bool DRW_state_draw_background(void); diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index aec25274ab1..b8b53fbbb78 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -940,7 +940,7 @@ static void edbo_compute_bbone_child(bArmature *arm) } } -/* A version of b_bone_spline_setup() for previewing editmode curve settings. */ +/* A version of BKE_pchan_bbone_spline_setup() for previewing editmode curve settings. */ static void ebone_spline_preview(EditBone *ebone, float result_array[MAX_BBONE_SUBDIV][4][4]) { BBoneSplineParameters param; @@ -1043,7 +1043,7 @@ static void ebone_spline_preview(EditBone *ebone, float result_array[MAX_BBONE_S param.curveOutX = ebone->curveOutX; param.curveOutY = ebone->curveOutY; - ebone->segments = BKE_compute_b_bone_spline(¶m, (Mat4 *)result_array); + ebone->segments = BKE_pchan_bbone_spline_compute(¶m, (Mat4 *)result_array); } static void draw_bone_update_disp_matrix_bbone(EditBone *eBone, bPoseChannel *pchan) @@ -1086,7 +1086,7 @@ static void draw_bone_update_disp_matrix_bbone(EditBone *eBone, bPoseChannel *pc memcpy(bbones_mat, pchan->runtime.bbone_pose_mats, sizeof(Mat4) * bbone_segments); } else { - b_bone_spline_setup(pchan, false, bbones_mat); + BKE_pchan_bbone_spline_setup(pchan, false, bbones_mat); } for (int i = bbone_segments; i--; bbones_mat++) { diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 4857f4c0bb2..c9be2cb4b31 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -39,6 +39,7 @@ #include "BLI_math.h" #include "BLI_listbase.h" +#include "BKE_object.h" #include "BKE_object_deform.h" #include "GPU_batch.h" @@ -49,6 +50,7 @@ #include "draw_cache.h" #include "draw_cache_impl.h" +#include "draw_manager.h" /* Batch's only (free'd as an array) */ static struct DRWShapeCache { @@ -693,25 +695,21 @@ GPUBatch *DRW_cache_object_edge_detection_get(Object *ob, bool *r_is_manifold) } /* Returns a buffer texture. */ -void DRW_cache_object_face_wireframe_get( - Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count) +GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob) { switch (ob->type) { case OB_MESH: - DRW_cache_mesh_face_wireframe_get(ob, r_vert_tx, r_faceid_tx, r_tri_count); - break; + return DRW_cache_mesh_face_wireframe_get(ob); case OB_CURVE: - DRW_cache_curve_face_wireframe_get(ob, r_vert_tx, r_faceid_tx, r_tri_count); - break; + return DRW_cache_curve_face_wireframe_get(ob); case OB_SURF: - DRW_cache_surf_face_wireframe_get(ob, r_vert_tx, r_faceid_tx, r_tri_count); - break; + return DRW_cache_surf_face_wireframe_get(ob); case OB_FONT: - DRW_cache_text_face_wireframe_get(ob, r_vert_tx, r_faceid_tx, r_tri_count); - break; + return DRW_cache_text_face_wireframe_get(ob); case OB_MBALL: - DRW_cache_mball_face_wireframe_get(ob, r_vert_tx, r_faceid_tx, r_tri_count); - break; + return DRW_cache_mball_face_wireframe_get(ob); + default: + return NULL; } } @@ -720,8 +718,14 @@ GPUBatch *DRW_cache_object_loose_edges_get(struct Object *ob) switch (ob->type) { case OB_MESH: return DRW_cache_mesh_loose_edges_get(ob); - - /* TODO, should match 'DRW_cache_object_surface_get' */ + case OB_CURVE: + return DRW_cache_curve_loose_edges_get(ob); + case OB_SURF: + return DRW_cache_surf_loose_edges_get(ob); + case OB_FONT: + return DRW_cache_text_loose_edges_get(ob); + case OB_MBALL: + /* Cannot have any loose edge */ default: return NULL; } @@ -2988,51 +2992,6 @@ GPUBatch *DRW_cache_single_vert_get(void) /** \name Meshes * \{ */ -GPUBatch *DRW_cache_mesh_surface_overlay_get(Object *ob) -{ - BLI_assert(ob->type == OB_MESH); - Mesh *me = ob->data; - return DRW_mesh_batch_cache_get_all_triangles(me); -} - -void DRW_cache_mesh_wire_overlay_get( - Object *ob, - GPUBatch **r_tris, GPUBatch **r_ledges, GPUBatch **r_lverts, - struct GPUTexture **r_data_tex) -{ - BLI_assert(ob->type == OB_MESH); - - Mesh *me = ob->data; - - *r_tris = DRW_mesh_batch_cache_get_overlay_triangles(me); - *r_ledges = DRW_mesh_batch_cache_get_overlay_loose_edges(me); - *r_lverts = DRW_mesh_batch_cache_get_overlay_loose_verts(me); - *r_data_tex = DRW_mesh_batch_cache_get_overlay_data_tex(me); -} - -void DRW_cache_mesh_normals_overlay_get( - Object *ob, - GPUBatch **r_tris, GPUBatch **r_tris_lnor, GPUBatch **r_ledges, GPUBatch **r_lverts) -{ - BLI_assert(ob->type == OB_MESH); - - Mesh *me = ob->data; - - *r_tris = DRW_mesh_batch_cache_get_overlay_triangles_nor(me); - *r_tris_lnor = DRW_mesh_batch_cache_get_overlay_triangles_lnor(me); - *r_ledges = DRW_mesh_batch_cache_get_overlay_loose_edges_nor(me); - *r_lverts = DRW_mesh_batch_cache_get_overlay_loose_verts(me); -} - -GPUBatch *DRW_cache_face_centers_get(Object *ob) -{ - BLI_assert(ob->type == OB_MESH); - - Mesh *me = ob->data; - - return DRW_mesh_batch_cache_get_overlay_facedots(me); -} - GPUBatch *DRW_cache_mesh_wire_outline_get(Object *ob) { BLI_assert(ob->type == OB_MESH); @@ -3057,64 +3016,36 @@ GPUBatch *DRW_cache_mesh_surface_get(Object *ob) return DRW_mesh_batch_cache_get_triangles_with_normals(me); } -void DRW_cache_mesh_face_wireframe_get( - Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count) +GPUBatch *DRW_cache_mesh_wire_get(Object *ob) { BLI_assert(ob->type == OB_MESH); Mesh *me = ob->data; - DRW_mesh_batch_cache_get_wireframes_face_texbuf(me, r_vert_tx, r_faceid_tx, r_tri_count); + return DRW_mesh_batch_cache_get_wire_loops(me); } -GPUBatch *DRW_cache_mesh_loose_edges_get(Object *ob) +GPUBatch *DRW_cache_mesh_face_wireframe_get(Object *ob) { BLI_assert(ob->type == OB_MESH); Mesh *me = ob->data; - return DRW_mesh_batch_cache_get_loose_edges_with_normals(me); + return DRW_mesh_batch_cache_get_wireframes_face(me); } -GPUBatch *DRW_cache_mesh_surface_weights_get(Object *ob, ToolSettings *ts, bool paint_mode) +GPUBatch *DRW_cache_mesh_loose_edges_get(Object *ob) { BLI_assert(ob->type == OB_MESH); Mesh *me = ob->data; + return DRW_mesh_batch_cache_get_loose_edges_with_normals(me); +} - /* Extract complete vertex weight group selection state and mode flags. */ - struct DRW_MeshWeightState wstate; - memset(&wstate, 0, sizeof(wstate)); - - wstate.defgroup_active = ob->actdef - 1; - wstate.defgroup_len = BLI_listbase_count(&ob->defbase); - - wstate.alert_mode = ts->weightuser; - - if (paint_mode && ts->multipaint) { - /* Multipaint needs to know all selected bones, not just the active group. - * This is actually a relatively expensive operation, but caching would be difficult. */ - wstate.defgroup_sel = BKE_object_defgroup_selected_get(ob, wstate.defgroup_len, &wstate.defgroup_sel_count); - - if (wstate.defgroup_sel_count > 1) { - wstate.flags |= DRW_MESH_WEIGHT_STATE_MULTIPAINT | (ts->auto_normalize ? DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE : 0); - - if (me->editflag & ME_EDIT_MIRROR_X) { - BKE_object_defgroup_mirror_selection( - ob, wstate.defgroup_len, wstate.defgroup_sel, wstate.defgroup_sel, &wstate.defgroup_sel_count); - } - } - /* With only one selected bone Multipaint reverts to regular mode. */ - else { - wstate.defgroup_sel_count = 0; - MEM_SAFE_FREE(wstate.defgroup_sel); - } - } - - /* Generate the weight data using the selection. */ - GPUBatch *batch = DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(me, &wstate); - - DRW_mesh_weight_state_clear(&wstate); +GPUBatch *DRW_cache_mesh_surface_weights_get(Object *ob) +{ + BLI_assert(ob->type == OB_MESH); - return batch; + Mesh *me = ob->data; + return DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(me); } GPUBatch *DRW_cache_mesh_surface_vert_colors_get(Object *ob) @@ -3122,7 +3053,7 @@ GPUBatch *DRW_cache_mesh_surface_vert_colors_get(Object *ob) BLI_assert(ob->type == OB_MESH); Mesh *me = ob->data; - return DRW_mesh_batch_cache_get_triangles_with_normals_and_vert_colors(me); + return DRW_mesh_batch_cache_get_surface_vertpaint(me); } /* Return list of batches */ @@ -3178,30 +3109,6 @@ GPUBatch *DRW_cache_mesh_verts_get(Object *ob) return DRW_mesh_batch_cache_get_all_verts(me); } -GPUBatch *DRW_cache_mesh_edges_paint_overlay_get(Object *ob, bool use_wire, bool use_sel) -{ - BLI_assert(ob->type == OB_MESH); - - Mesh *me = ob->data; - return DRW_mesh_batch_cache_get_weight_overlay_edges(me, use_wire, use_sel); -} - -GPUBatch *DRW_cache_mesh_faces_weight_overlay_get(Object *ob) -{ - BLI_assert(ob->type == OB_MESH); - - Mesh *me = ob->data; - return DRW_mesh_batch_cache_get_weight_overlay_faces(me); -} - -GPUBatch *DRW_cache_mesh_verts_weight_overlay_get(Object *ob) -{ - BLI_assert(ob->type == OB_MESH); - - Mesh *me = ob->data; - return DRW_mesh_batch_cache_get_weight_overlay_verts(me); -} - void DRW_cache_mesh_sculpt_coords_ensure(Object *ob) { BLI_assert(ob->type == OB_MESH); @@ -3222,15 +3129,15 @@ GPUBatch *DRW_cache_curve_edge_wire_get(Object *ob) BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_wire_edge(cu, ob->runtime.curve_cache); + return DRW_curve_batch_cache_get_wire_edge(cu); } -GPUBatch *DRW_cache_curve_edge_normal_get(Object *ob, float normal_size) +GPUBatch *DRW_cache_curve_edge_normal_get(Object *ob) { BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_normal_edge(cu, ob->runtime.curve_cache, normal_size); + return DRW_curve_batch_cache_get_normal_edge(cu); } GPUBatch *DRW_cache_curve_edge_overlay_get(Object *ob) @@ -3238,7 +3145,7 @@ GPUBatch *DRW_cache_curve_edge_overlay_get(Object *ob) BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF)); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_overlay_edges(cu); + return DRW_curve_batch_cache_get_edit_edges(cu); } GPUBatch *DRW_cache_curve_vert_overlay_get(Object *ob, bool handles) @@ -3246,7 +3153,7 @@ GPUBatch *DRW_cache_curve_vert_overlay_get(Object *ob, bool handles) BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF)); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_overlay_verts(cu, handles); + return DRW_curve_batch_cache_get_edit_verts(cu, handles); } GPUBatch *DRW_cache_curve_surface_get(Object *ob) @@ -3254,16 +3161,43 @@ GPUBatch *DRW_cache_curve_surface_get(Object *ob) BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->runtime.curve_cache); + struct Mesh *mesh_eval = ob->runtime.mesh_eval; + if (mesh_eval != NULL) { + return DRW_mesh_batch_cache_get_triangles_with_normals(mesh_eval); + } + else { + return DRW_curve_batch_cache_get_triangles_with_normals(cu); + } +} + +GPUBatch *DRW_cache_curve_loose_edges_get(Object *ob) +{ + BLI_assert(ob->type == OB_CURVE); + + struct Curve *cu = ob->data; + struct Mesh *mesh_eval = ob->runtime.mesh_eval; + if (mesh_eval != NULL) { + return DRW_mesh_batch_cache_get_loose_edges_with_normals(mesh_eval); + } + else { + /* TODO */ + UNUSED_VARS(cu); + return NULL; + } } -void DRW_cache_curve_face_wireframe_get( - Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count) +GPUBatch *DRW_cache_curve_face_wireframe_get(Object *ob) { BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - DRW_curve_batch_cache_get_wireframes_face_texbuf(cu, ob->runtime.curve_cache, r_vert_tx, r_faceid_tx, r_tri_count); + struct Mesh *mesh_eval = ob->runtime.mesh_eval; + if (mesh_eval != NULL) { + return DRW_mesh_batch_cache_get_wireframes_face(mesh_eval); + } + else { + return DRW_curve_batch_cache_get_wireframes_face(cu); + } } /* Return list of batches */ @@ -3273,7 +3207,13 @@ GPUBatch **DRW_cache_curve_surface_shaded_get( BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_surface_shaded(cu, ob->runtime.curve_cache, gpumat_array, gpumat_array_len); + struct Mesh *mesh_eval = ob->runtime.mesh_eval; + if (mesh_eval != NULL) { + return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL); + } + else { + return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len); + } } /** \} */ @@ -3289,11 +3229,10 @@ GPUBatch *DRW_cache_mball_surface_get(Object *ob) return DRW_metaball_batch_cache_get_triangles_with_normals(ob); } -void DRW_cache_mball_face_wireframe_get( - Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count) +GPUBatch *DRW_cache_mball_face_wireframe_get(Object *ob) { BLI_assert(ob->type == OB_MBALL); - return DRW_metaball_batch_cache_get_wireframes_face_texbuf(ob, r_vert_tx, r_faceid_tx, r_tri_count); + return DRW_metaball_batch_cache_get_wireframes_face(ob); } GPUBatch **DRW_cache_mball_surface_shaded_get( @@ -3316,57 +3255,73 @@ GPUBatch *DRW_cache_text_edge_wire_get(Object *ob) BLI_assert(ob->type == OB_FONT); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_wire_edge(cu, ob->runtime.curve_cache); + return DRW_curve_batch_cache_get_wire_edge(cu); } GPUBatch *DRW_cache_text_surface_get(Object *ob) { BLI_assert(ob->type == OB_FONT); struct Curve *cu = ob->data; + struct Mesh *mesh_eval = ob->runtime.mesh_eval; if (cu->editfont && (cu->flag & CU_FAST)) { return NULL; } - return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->runtime.curve_cache); + if (mesh_eval != NULL) { + return DRW_mesh_batch_cache_get_triangles_with_normals(mesh_eval); + } + else { + return DRW_curve_batch_cache_get_triangles_with_normals(cu); + } } -void DRW_cache_text_face_wireframe_get( - Object *ob, - struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count) +GPUBatch *DRW_cache_text_loose_edges_get(Object *ob) { BLI_assert(ob->type == OB_FONT); struct Curve *cu = ob->data; + struct Mesh *mesh_eval = ob->runtime.mesh_eval; if (cu->editfont && (cu->flag & CU_FAST)) { - *r_vert_tx = NULL; - *r_faceid_tx = NULL; - *r_tri_count = 0; - return; + return NULL; + } + if (mesh_eval != NULL) { + return DRW_mesh_batch_cache_get_loose_edges_with_normals(mesh_eval); + } + else { + /* TODO */ + return NULL; } - DRW_curve_batch_cache_get_wireframes_face_texbuf(cu, ob->runtime.curve_cache, r_vert_tx, r_faceid_tx, r_tri_count); } -GPUBatch **DRW_cache_text_surface_shaded_get( - Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len) +GPUBatch *DRW_cache_text_face_wireframe_get(Object *ob) { BLI_assert(ob->type == OB_FONT); struct Curve *cu = ob->data; + struct Mesh *mesh_eval = ob->runtime.mesh_eval; if (cu->editfont && (cu->flag & CU_FAST)) { return NULL; } - return DRW_curve_batch_cache_get_surface_shaded(cu, ob->runtime.curve_cache, gpumat_array, gpumat_array_len); -} - -GPUBatch *DRW_cache_text_cursor_overlay_get(Object *ob) -{ - BLI_assert(ob->type == OB_FONT); - struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_overlay_cursor(cu); + if (mesh_eval != NULL) { + return DRW_mesh_batch_cache_get_wireframes_face(mesh_eval); + } + else { + return DRW_curve_batch_cache_get_wireframes_face(cu); + } } -GPUBatch *DRW_cache_text_select_overlay_get(Object *ob) +GPUBatch **DRW_cache_text_surface_shaded_get( + Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len) { BLI_assert(ob->type == OB_FONT); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_overlay_select(cu); + struct Mesh *mesh_eval = ob->runtime.mesh_eval; + if (cu->editfont && (cu->flag & CU_FAST)) { + return NULL; + } + if (mesh_eval != NULL) { + return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL); + } + else { + return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len); + } } /** \} */ @@ -3381,16 +3336,51 @@ GPUBatch *DRW_cache_surf_surface_get(Object *ob) BLI_assert(ob->type == OB_SURF); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->runtime.curve_cache); + struct Mesh *mesh_eval = ob->runtime.mesh_eval; + if (mesh_eval != NULL) { + return DRW_mesh_batch_cache_get_triangles_with_normals(mesh_eval); + } + else { + return DRW_curve_batch_cache_get_triangles_with_normals(cu); + } +} + +GPUBatch *DRW_cache_surf_edge_wire_get(Object *ob) +{ + BLI_assert(ob->type == OB_SURF); + + struct Curve *cu = ob->data; + return DRW_curve_batch_cache_get_wire_edge(cu); +} + +GPUBatch *DRW_cache_surf_face_wireframe_get(Object *ob) +{ + BLI_assert(ob->type == OB_SURF); + + struct Curve *cu = ob->data; + struct Mesh *mesh_eval = ob->runtime.mesh_eval; + if (mesh_eval != NULL) { + return DRW_mesh_batch_cache_get_wireframes_face(mesh_eval); + } + else { + return DRW_curve_batch_cache_get_wireframes_face(cu); + } } -void DRW_cache_surf_face_wireframe_get( - Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count) +GPUBatch *DRW_cache_surf_loose_edges_get(Object *ob) { BLI_assert(ob->type == OB_SURF); struct Curve *cu = ob->data; - DRW_curve_batch_cache_get_wireframes_face_texbuf(cu, ob->runtime.curve_cache, r_vert_tx, r_faceid_tx, r_tri_count); + struct Mesh *mesh_eval = ob->runtime.mesh_eval; + if (mesh_eval != NULL) { + return DRW_mesh_batch_cache_get_loose_edges_with_normals(mesh_eval); + } + else { + /* TODO */ + UNUSED_VARS(cu); + return NULL; + } } /* Return list of batches */ @@ -3400,7 +3390,13 @@ GPUBatch **DRW_cache_surf_surface_shaded_get( BLI_assert(ob->type == OB_SURF); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_surface_shaded(cu, ob->runtime.curve_cache, gpumat_array, gpumat_array_len); + struct Mesh *mesh_eval = ob->runtime.mesh_eval; + if (mesh_eval != NULL) { + return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL); + } + else { + return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len); + } } /** \} */ @@ -3437,7 +3433,7 @@ GPUBatch *DRW_cache_lattice_vert_overlay_get(Object *ob) BLI_assert(ob->type == OB_LATTICE); struct Lattice *lt = ob->data; - return DRW_lattice_batch_cache_get_overlay_verts(lt); + return DRW_lattice_batch_cache_get_edit_verts(lt); } /** \} */ @@ -3460,9 +3456,10 @@ GPUBatch *DRW_cache_particles_get_dots(Object *object, ParticleSystem *psys) GPUBatch *DRW_cache_particles_get_edit_strands( Object *object, ParticleSystem *psys, - struct PTCacheEdit *edit) + struct PTCacheEdit *edit, + bool use_weight) { - return DRW_particles_batch_cache_get_edit_strands(object, psys, edit); + return DRW_particles_batch_cache_get_edit_strands(object, psys, edit, use_weight); } GPUBatch *DRW_cache_particles_get_edit_inner_points( @@ -3733,3 +3730,95 @@ GPUBatch *DRW_cache_cursor_get(bool crosshair_lines) } return *drw_cursor; } + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Batch Cache Impl. common + * \{ */ + +GPUBatch *DRW_batch_request(GPUBatch **batch) +{ + /* XXX TODO(fclem): We are writting to batch cache here. Need to make this thread safe. */ + if (*batch == NULL) { + *batch = MEM_callocN(sizeof(GPUBatch), "GPUBatch"); + } + return *batch; +} + +bool DRW_batch_requested(GPUBatch *batch, int prim_type) +{ + /* Batch has been requested if it has been created but not initialized. */ + if (batch != NULL && batch->verts[0] == NULL) { + /* HACK. We init without a valid VBO and let the first vbo binding + * fill verts[0]. */ + GPU_batch_init_ex(batch, prim_type, (GPUVertBuf *)1, NULL, 0); + batch->verts[0] = NULL; + return true; + } + return false; +} + +void DRW_ibo_request(GPUBatch *batch, GPUIndexBuf **ibo) +{ + if (*ibo == NULL) { + *ibo = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf"); + } + GPU_batch_vao_cache_clear(batch); + batch->elem = *ibo; +} + +bool DRW_ibo_requested(GPUIndexBuf *ibo) +{ + /* TODO do not rely on data uploaded. This prevents multithreading. + * (need access to a gl context) */ + return (ibo != NULL && ibo->ibo_id == 0 && ibo->data == NULL); +} + +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; + } +} + +bool DRW_vbo_requested(GPUVertBuf *vbo) +{ + return (vbo != NULL && vbo->format.attr_len == 0); +} + +void drw_batch_cache_generate_requested(Object *ob) +{ + struct Mesh *mesh_eval = ob->runtime.mesh_eval; + switch (ob->type) { + case OB_MESH: + DRW_mesh_batch_cache_create_requested(ob, (Mesh *)ob->data); + break; + case OB_CURVE: + case OB_FONT: + case OB_SURF: + if (mesh_eval) { + DRW_mesh_batch_cache_create_requested(ob, mesh_eval); + } + DRW_curve_batch_cache_create_requested(ob); + break; + /* TODO all cases */ + default: + break; + } +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index f3f41e569ed..cbc4ef413ac 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -59,8 +59,7 @@ struct GPUBatch *DRW_cache_object_loose_edges_get(struct Object *ob); struct GPUBatch **DRW_cache_object_surface_material_get( struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len, char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count); -void DRW_cache_object_face_wireframe_get( - Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count); +struct GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob); /* Empties */ struct GPUBatch *DRW_cache_plain_axes_get(void); @@ -127,35 +126,23 @@ struct GPUBatch *DRW_cache_bone_dof_sphere_get(void); struct GPUBatch *DRW_cache_bone_dof_lines_get(void); /* Meshes */ -struct GPUBatch *DRW_cache_mesh_surface_overlay_get(struct Object *ob); -void DRW_cache_mesh_wire_overlay_get( - struct Object *ob, - struct GPUBatch **r_tris, struct GPUBatch **r_ledges, struct GPUBatch **r_lverts, - struct GPUTexture **r_data_tex); -void DRW_cache_mesh_normals_overlay_get( - struct Object *ob, - struct GPUBatch **r_tris, struct GPUBatch **r_tris_lnor, - struct GPUBatch **r_ledges, struct GPUBatch **r_lverts); -struct GPUBatch *DRW_cache_face_centers_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_wire_outline_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_edge_detection_get(struct Object *ob, bool *r_is_manifold); struct GPUBatch *DRW_cache_mesh_surface_get(struct Object *ob); +struct GPUBatch *DRW_cache_mesh_wire_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_loose_edges_get(struct Object *ob); -struct GPUBatch *DRW_cache_mesh_surface_weights_get(struct Object *ob, struct ToolSettings *ts, bool paint_mode); +struct GPUBatch *DRW_cache_mesh_surface_weights_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_vert_colors_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_verts_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_edges_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_verts_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_edges_paint_overlay_get(struct Object *ob, bool use_wire, bool use_sel); -struct GPUBatch *DRW_cache_mesh_faces_weight_overlay_get(struct Object *ob); -struct GPUBatch *DRW_cache_mesh_verts_weight_overlay_get(struct Object *ob); struct GPUBatch **DRW_cache_mesh_surface_shaded_get( struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len, char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count); struct GPUBatch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob); -void DRW_cache_mesh_face_wireframe_get( - Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count); +struct GPUBatch *DRW_cache_mesh_face_wireframe_get(struct Object *ob); void DRW_cache_mesh_sculpt_coords_ensure(struct Object *ob); @@ -164,31 +151,32 @@ struct GPUBatch *DRW_cache_curve_surface_get(struct Object *ob); struct GPUBatch **DRW_cache_curve_surface_shaded_get( struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len); struct GPUBatch *DRW_cache_curve_surface_verts_get(struct Object *ob); +struct GPUBatch *DRW_cache_curve_loose_edges_get(struct Object *ob); struct GPUBatch *DRW_cache_curve_edge_wire_get(struct Object *ob); -void DRW_cache_curve_face_wireframe_get( - Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count); +struct GPUBatch *DRW_cache_curve_face_wireframe_get(Object *ob); /* edit-mode */ -struct GPUBatch *DRW_cache_curve_edge_normal_get(struct Object *ob, float normal_size); +struct GPUBatch *DRW_cache_curve_edge_normal_get(struct Object *ob); struct GPUBatch *DRW_cache_curve_edge_overlay_get(struct Object *ob); struct GPUBatch *DRW_cache_curve_vert_overlay_get(struct Object *ob, bool handles); /* Font */ -struct GPUBatch *DRW_cache_text_edge_wire_get(struct Object *ob); struct GPUBatch *DRW_cache_text_surface_get(struct Object *ob); +struct GPUBatch *DRW_cache_text_loose_edges_get(struct Object *ob); +struct GPUBatch *DRW_cache_text_edge_wire_get(struct Object *ob); struct GPUBatch **DRW_cache_text_surface_shaded_get( struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len); -void DRW_cache_text_face_wireframe_get( - Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count); +struct GPUBatch *DRW_cache_text_face_wireframe_get(Object *ob); /* edit-mode */ struct GPUBatch *DRW_cache_text_cursor_overlay_get(struct Object *ob); struct GPUBatch *DRW_cache_text_select_overlay_get(struct Object *ob); /* Surface */ struct GPUBatch *DRW_cache_surf_surface_get(struct Object *ob); +struct GPUBatch *DRW_cache_surf_edge_wire_get(struct Object *ob); +struct GPUBatch *DRW_cache_surf_loose_edges_get(struct Object *ob); struct GPUBatch **DRW_cache_surf_surface_shaded_get( struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len); -void DRW_cache_surf_face_wireframe_get( - Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count); +struct GPUBatch *DRW_cache_surf_face_wireframe_get(Object *ob); /* Lattice */ struct GPUBatch *DRW_cache_lattice_verts_get(struct Object *ob); @@ -201,7 +189,7 @@ struct GPUBatch *DRW_cache_particles_get_hair( struct GPUBatch *DRW_cache_particles_get_dots( struct Object *object, struct ParticleSystem *psys); struct GPUBatch *DRW_cache_particles_get_edit_strands( - struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit); + struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit, bool use_weight); struct GPUBatch *DRW_cache_particles_get_edit_inner_points( struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit); struct GPUBatch *DRW_cache_particles_get_edit_tip_points( @@ -217,7 +205,6 @@ struct GPUBatch *DRW_cache_hair_get_edit_strands(struct Object *ob, struct HairS /* Metaball */ struct GPUBatch *DRW_cache_mball_surface_get(struct Object *ob); struct GPUBatch **DRW_cache_mball_surface_shaded_get(struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len); -void DRW_cache_mball_face_wireframe_get( - Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count); +struct GPUBatch *DRW_cache_mball_face_wireframe_get(Object *ob); #endif /* __DRAW_CACHE_H__ */ diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index c25b7b74532..1a01184f760 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -69,82 +69,50 @@ void DRW_hair_batch_cache_dirty(struct HairSystem *hsys, int mode); void DRW_hair_batch_cache_free(struct HairSystem *hsys); /* Curve */ -struct GPUBatch *DRW_curve_batch_cache_get_wire_edge(struct Curve *cu, struct CurveCache *ob_curve_cache); -struct GPUBatch *DRW_curve_batch_cache_get_normal_edge( - struct Curve *cu, struct CurveCache *ob_curve_cache, float normal_size); -struct GPUBatch *DRW_curve_batch_cache_get_overlay_edges(struct Curve *cu); -struct GPUBatch *DRW_curve_batch_cache_get_overlay_verts(struct Curve *cu, bool handles); - -struct GPUBatch *DRW_curve_batch_cache_get_triangles_with_normals( - struct Curve *cu, struct CurveCache *ob_curve_cache); +void DRW_curve_batch_cache_create_requested(struct Object *ob); + +struct GPUBatch *DRW_curve_batch_cache_get_wire_edge(struct Curve *cu); +struct GPUBatch *DRW_curve_batch_cache_get_normal_edge(struct Curve *cu); +struct GPUBatch *DRW_curve_batch_cache_get_edit_edges(struct Curve *cu); +struct GPUBatch *DRW_curve_batch_cache_get_edit_verts(struct Curve *cu, bool handles); + +struct GPUBatch *DRW_curve_batch_cache_get_triangles_with_normals(struct Curve *cu); struct GPUBatch **DRW_curve_batch_cache_get_surface_shaded( - struct Curve *cu, struct CurveCache *ob_curve_cache, - struct GPUMaterial **gpumat_array, uint gpumat_array_len); -void DRW_curve_batch_cache_get_wireframes_face_texbuf( - struct Curve *cu, struct CurveCache *ob_curve_cache, - struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count); + struct Curve *cu, struct GPUMaterial **gpumat_array, uint gpumat_array_len); +struct GPUBatch *DRW_curve_batch_cache_get_wireframes_face(struct Curve *cu); /* Metaball */ struct GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(struct Object *ob); struct GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(struct Object *ob, struct MetaBall *mb, struct GPUMaterial **gpumat_array, uint gpumat_array_len); -void DRW_metaball_batch_cache_get_wireframes_face_texbuf( - struct Object *ob, struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count); - -/* Curve (Font) */ -struct GPUBatch *DRW_curve_batch_cache_get_overlay_cursor(struct Curve *cu); -struct GPUBatch *DRW_curve_batch_cache_get_overlay_select(struct Curve *cu); +struct GPUBatch *DRW_metaball_batch_cache_get_wireframes_face(struct Object *ob); /* DispList */ -struct GPUVertBuf *DRW_displist_vertbuf_calc_pos_with_normals(struct ListBase *lb); -struct GPUIndexBuf *DRW_displist_indexbuf_calc_triangles_in_order(struct ListBase *lb); -struct GPUIndexBuf **DRW_displist_indexbuf_calc_triangles_in_order_split_by_material( - struct ListBase *lb, uint gpumat_array_len); -struct GPUBatch **DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material( - struct ListBase *lb, uint gpumat_array_len); -struct GPUVertBuf *DRW_displist_create_edges_overlay_texture_buf(ListBase *lb); +void DRW_displist_vertbuf_create_pos_and_nor(struct ListBase *lb, struct GPUVertBuf *vbo); +void DRW_displist_vertbuf_create_pos_and_nor_and_uv_tess( + struct ListBase *lb, struct GPUVertBuf *vbo_pos_nor, struct GPUVertBuf *vbo_uv); +void DRW_displist_vertbuf_create_wireframe_data_tess(struct ListBase *lb, struct GPUVertBuf *vbo); +void DRW_displist_indexbuf_create_triangles_in_order(struct ListBase *lb, struct GPUIndexBuf *vbo); +void DRW_displist_indexbuf_create_triangles_tess_split_by_material( + struct ListBase *lb, struct GPUIndexBuf **ibo_mat, uint mat_len); /* Lattice */ struct GPUBatch *DRW_lattice_batch_cache_get_all_edges(struct Lattice *lt, bool use_weight, const int actdef); struct GPUBatch *DRW_lattice_batch_cache_get_all_verts(struct Lattice *lt); -struct GPUBatch *DRW_lattice_batch_cache_get_overlay_verts(struct Lattice *lt); - -/* Vertex Group Selection and display options */ -struct DRW_MeshWeightState { - int defgroup_active; - int defgroup_len; - - short flags; - char alert_mode; - - /* Set of all selected bones for Multipaint. */ - bool *defgroup_sel; /* [defgroup_len] */ - int defgroup_sel_count; -}; - -/* DRW_MeshWeightState.flags */ -enum { - DRW_MESH_WEIGHT_STATE_MULTIPAINT = (1 << 0), - DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE = (1 << 1), -}; - -void DRW_mesh_weight_state_clear(struct DRW_MeshWeightState *wstate); -void DRW_mesh_weight_state_copy(struct DRW_MeshWeightState *wstate_dst, const struct DRW_MeshWeightState *wstate_src); -bool DRW_mesh_weight_state_compare(const struct DRW_MeshWeightState *a, const struct DRW_MeshWeightState *b); +struct GPUBatch *DRW_lattice_batch_cache_get_edit_verts(struct Lattice *lt); /* Mesh */ +void DRW_mesh_batch_cache_create_requested(struct Object *ob, struct Mesh *me); + struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded( struct Mesh *me, struct GPUMaterial **gpumat_array, uint gpumat_array_len, char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count); 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_weight_overlay_edges(struct Mesh *me, bool use_wire, bool use_sel); -struct GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_faces(struct Mesh *me); -struct GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_verts(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_wire_loops(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_all_edges(struct Mesh *me); -struct GPUBatch *DRW_mesh_batch_cache_get_all_triangles(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals(struct Mesh *me); -struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(struct Mesh *me, const struct DRW_MeshWeightState *wstate); -struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_vert_colors(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id(struct Mesh *me, bool use_hide, uint select_id_offset); struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_mask(struct Mesh *me, bool use_hide); struct GPUBatch *DRW_mesh_batch_cache_get_loose_edges_with_normals(struct Mesh *me); @@ -152,22 +120,20 @@ struct GPUBatch *DRW_mesh_batch_cache_get_points_with_normals(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_all_verts(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_fancy_edges(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_edge_detection(struct Mesh *me, bool *r_is_manifold); -struct GPUBatch *DRW_mesh_batch_cache_get_overlay_triangles(struct Mesh *me); -struct GPUBatch *DRW_mesh_batch_cache_get_overlay_triangles_nor(struct Mesh *me); -struct GPUBatch *DRW_mesh_batch_cache_get_overlay_triangles_lnor(struct Mesh *me); -struct GPUBatch *DRW_mesh_batch_cache_get_overlay_verts(struct Mesh *me); -struct GPUBatch *DRW_mesh_batch_cache_get_overlay_loose_edges(struct Mesh *me); -struct GPUBatch *DRW_mesh_batch_cache_get_overlay_loose_edges_nor(struct Mesh *me); -struct GPUBatch *DRW_mesh_batch_cache_get_overlay_loose_verts(struct Mesh *me); -struct GPUBatch *DRW_mesh_batch_cache_get_overlay_facedots(struct Mesh *me); -struct GPUTexture *DRW_mesh_batch_cache_get_overlay_data_tex(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_edit_triangles_nor(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_edit_triangles_lnor(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_edit_loose_edges(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_edit_loose_edges_nor(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_edit_loose_verts(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(struct Mesh *me); /* edit-mesh selection (use generic function for faces) */ struct GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(struct Mesh *me, uint select_id_offset); struct GPUBatch *DRW_mesh_batch_cache_get_edges_with_select_id(struct Mesh *me, uint select_id_offset); struct GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(struct Mesh *me, uint select_id_offset); /* Object mode Wireframe overlays */ -void DRW_mesh_batch_cache_get_wireframes_face_texbuf( - struct Mesh *me, struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count); +struct GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(struct Mesh *me); void DRW_mesh_cache_sculpt_coords_ensure(struct Mesh *me); @@ -217,7 +183,7 @@ struct GPUBatch *DRW_particles_batch_cache_get_hair( struct GPUBatch *DRW_particles_batch_cache_get_dots( struct Object *object, struct ParticleSystem *psys); struct GPUBatch *DRW_particles_batch_cache_get_edit_strands( - struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit); + struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit, bool use_weight); struct GPUBatch *DRW_particles_batch_cache_get_edit_inner_points( struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit); struct GPUBatch *DRW_particles_batch_cache_get_edit_tip_points( @@ -229,4 +195,19 @@ struct GPUBatch *DRW_hair_batch_cache_get_edit_follicle_normals(struct Object *o struct GPUBatch *DRW_hair_batch_cache_get_edit_follicle_axes(struct Object *ob, struct HairSystem *hsys); struct GPUBatch *DRW_hair_batch_cache_get_edit_strands(struct Object *ob, struct HairSystem *hsys); +/* Common */ +#define DRW_ADD_FLAG_FROM_VBO_REQUEST(flag, vbo, value) (flag |= DRW_vbo_requested(vbo) ? value : 0) +#define DRW_ADD_FLAG_FROM_IBO_REQUEST(flag, ibo, value) (flag |= DRW_ibo_requested(ibo) ? value : 0) + +/* Test and assign NULL if test fails */ +#define DRW_TEST_ASSIGN_VBO(v) (v = (DRW_vbo_requested(v) ? v : NULL)) +#define DRW_TEST_ASSIGN_IBO(v) (v = (DRW_ibo_requested(v) ? v : NULL)) + +struct GPUBatch *DRW_batch_request(struct GPUBatch **batch); +bool DRW_batch_requested(struct GPUBatch *batch, int prim_type); +void DRW_ibo_request(struct GPUBatch *batch, struct GPUIndexBuf **ibo); +bool DRW_ibo_requested(struct GPUIndexBuf *ibo); +void DRW_vbo_request(struct GPUBatch *batch, struct GPUVertBuf **vbo); +bool DRW_vbo_requested(struct GPUVertBuf *vbo); + #endif /* __DRAW_CACHE_IMPL_H__ */ diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c index f214f722c0b..ecdbdcf094f 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.c +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -35,11 +35,12 @@ #include "DNA_curve_types.h" #include "BKE_curve.h" - +#include "BKE_displist.h" #include "BKE_font.h" #include "GPU_batch.h" #include "GPU_texture.h" +#include "GPU_material.h" #include "UI_resources.h" @@ -99,23 +100,27 @@ static void curve_render_overlay_verts_edges_len_get( static void curve_render_wire_verts_edges_len_get( const CurveCache *ob_curve_cache, - int *r_vert_len, int *r_edge_len) + int *r_curve_len, int *r_vert_len, int *r_edge_len) { BLI_assert(r_vert_len || r_edge_len); int vert_len = 0; int edge_len = 0; + int curve_len = 0; for (const BevList *bl = ob_curve_cache->bev.first; bl; bl = bl->next) { if (bl->nr > 0) { const bool is_cyclic = bl->poly != -1; - - /* verts */ + edge_len += (is_cyclic) ? bl->nr : bl->nr - 1; vert_len += bl->nr; - - /* edges */ - edge_len += bl->nr; - if (!is_cyclic) { - edge_len -= 1; - } + curve_len += 1; + } + } + for (const DispList *dl = ob_curve_cache->disp.first; dl; dl = dl->next) { + if (ELEM(dl->type, DL_SEGM, DL_POLY)) { + BLI_assert(dl->parts == 1); + const bool is_cyclic = dl->type == DL_POLY; + edge_len += (is_cyclic) ? dl->nr : dl->nr - 1; + vert_len += dl->nr; + curve_len += 1; } } if (r_vert_len) { @@ -124,6 +129,9 @@ static void curve_render_wire_verts_edges_len_get( if (r_edge_len) { *r_edge_len = edge_len; } + if (r_curve_len) { + *r_curve_len = curve_len; + } } static int curve_render_normal_len_get(const ListBase *lb, const CurveCache *ob_curve_cache) @@ -159,6 +167,7 @@ typedef struct CurveRenderData { } overlay; struct { + int curve_len; int vert_len; int edge_len; } wire; @@ -216,7 +225,7 @@ static CurveRenderData *curve_render_data_create(Curve *cu, CurveCache *ob_curve if (types & CU_DATATYPE_WIRE) { curve_render_wire_verts_edges_len_get( rdata->ob_curve_cache, - &rdata->wire.vert_len, &rdata->wire.edge_len); + &rdata->wire.curve_len, &rdata->wire.vert_len, &rdata->wire.edge_len); } if (cu->editnurb) { @@ -281,67 +290,112 @@ static int curve_render_data_wire_edges_len_get(const CurveRenderData *rdata) return rdata->wire.edge_len; } +static int curve_render_data_wire_curve_len_get(const CurveRenderData *rdata) +{ + BLI_assert(rdata->types & CU_DATATYPE_WIRE); + return rdata->wire.curve_len; +} + static int curve_render_data_normal_len_get(const CurveRenderData *rdata) { BLI_assert(rdata->types & CU_DATATYPE_NORMAL); return rdata->normal.len; } +static void curve_cd_calc_used_gpu_layers(int *cd_layers, struct GPUMaterial **gpumat_array, int gpumat_array_len) +{ + GPUVertexAttribs gattribs = {{{0}}}; + for (int i = 0; i < gpumat_array_len; i++) { + struct GPUMaterial *gpumat = gpumat_array[i]; + if (gpumat == NULL) { + continue; + } + GPU_material_vertex_attributes(gpumat, &gattribs); + for (int j = 0; j < gattribs.totlayer; j++) { + const char *name = gattribs.layer[j].name; + int type = gattribs.layer[j].type; + + /* Curves cannot have named layers. + * Note: We could relax this assumption later. */ + if (name[0] != '\0') { + continue; + } + + if (type == CD_AUTO_FROM_NAME) { + type = CD_MTFACE; + } + + switch (type) { + case CD_MTFACE: + *cd_layers |= CD_MLOOPUV; + break; + case CD_TANGENT: + /* Currently unsupported */ + // *cd_layers |= CD_TANGENT; + break; + case CD_MCOL: + /* Curve object don't have Color data. */ + break; + case CD_ORCO: + *cd_layers |= CD_ORCO; + break; + } + } + } +} /* ---------------------------------------------------------------------- */ /* Curve GPUBatch Cache */ typedef struct CurveBatchCache { - /* center-line */ struct { - GPUVertBuf *verts; - GPUVertBuf *edges; - GPUBatch *batch; - GPUIndexBuf *elem; - } wire; + GPUVertBuf *pos_nor; + GPUVertBuf *curves_pos; + } ordered; - /* normals */ struct { - GPUVertBuf *verts; - GPUVertBuf *edges; - GPUBatch *batch; - GPUIndexBuf *elem; - } normal; + GPUVertBuf *pos_nor; + GPUVertBuf *uv; - /* control handles and vertices */ - struct { - GPUBatch *edges; - GPUBatch *verts; - GPUBatch *verts_no_handles; - } overlay; + GPUVertBuf *wireframe_data; + } tess; struct { - GPUVertBuf *verts; - GPUIndexBuf *triangles_in_order; - GPUBatch **shaded_triangles; - GPUBatch *batch; - int mat_len; - } surface; - - /* Wireframes */ + /* Curve points. Aligned with ordered.pos_nor */ + GPUVertBuf *curves_nor; + GPUVertBuf *curves_weight; /* TODO. */ + /* Edit points (beztriples and bpoints) */ + GPUVertBuf *pos; + GPUVertBuf *data; + } edit; + struct { - GPUVertBuf *elem_vbo; - GPUTexture *elem_tx; - GPUTexture *verts_tx; - uint tri_count; - } face_wire; + GPUIndexBuf *surfaces_tris; + GPUIndexBuf *curves_lines; + /* Edit mode */ + GPUIndexBuf *edit_verts_points; /* Only control points. Not handles. */ + GPUIndexBuf *edit_lines; + } ibo; - /* 3d text */ struct { - GPUBatch *select; - GPUBatch *cursor; - } text; + GPUBatch *surfaces; + GPUBatch *curves; + /* control handles and vertices */ + GPUBatch *edit_edges; + GPUBatch *edit_verts; + GPUBatch *edit_handles_verts; + GPUBatch *edit_normals; + /* Triangles for object mode wireframe. */ + GPUBatch *wire_triangles; + } batch; + + GPUIndexBuf **surf_per_mat_tris; + GPUBatch **surf_per_mat; + int mat_len; + int cd_used, cd_needed; /* settings to determine if cache is invalid */ bool is_dirty; - - float normal_size; - bool is_editmode; } CurveBatchCache; @@ -355,6 +409,10 @@ static bool curve_batch_cache_valid(Curve *cu) return false; } + if (cache->mat_len != max_ii(1, cu->totcol)) { + return false; + } + if (cache->is_dirty) { return false; } @@ -394,6 +452,17 @@ static void curve_batch_cache_init(Curve *cu) } #endif + cache->cd_used = 0; + cache->mat_len = max_ii(1, cu->totcol); + cache->surf_per_mat_tris = MEM_mallocN(sizeof(*cache->surf_per_mat_tris) * cache->mat_len, __func__); + cache->surf_per_mat = MEM_mallocN(sizeof(*cache->surf_per_mat) * cache->mat_len, __func__); + + /* TODO Might be wiser to alloc in one chunck. */ + for (int i = 0; i < cache->mat_len; ++i) { + cache->surf_per_mat_tris[i] = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf"); + cache->surf_per_mat[i] = MEM_callocN(sizeof(GPUBatch), "GPUBatch"); + } + cache->is_editmode = (cu->editnurb != NULL) || (cu->editfont != NULL); cache->is_dirty = false; @@ -419,14 +488,11 @@ void DRW_curve_batch_cache_dirty_tag(Curve *cu, int mode) cache->is_dirty = true; break; case BKE_CURVE_BATCH_DIRTY_SELECT: - /* editnurb */ - GPU_BATCH_DISCARD_SAFE(cache->overlay.verts_no_handles); - GPU_BATCH_DISCARD_SAFE(cache->overlay.verts); - GPU_BATCH_DISCARD_SAFE(cache->overlay.edges); - - /* editfont */ - GPU_BATCH_DISCARD_SAFE(cache->text.select); - GPU_BATCH_DISCARD_SAFE(cache->text.cursor); + GPU_VERTBUF_DISCARD_SAFE(cache->edit.data); + + GPU_BATCH_DISCARD_SAFE(cache->batch.edit_edges); + GPU_BATCH_DISCARD_SAFE(cache->batch.edit_verts); + GPU_BATCH_DISCARD_SAFE(cache->batch.edit_handles_verts); break; default: BLI_assert(0); @@ -440,36 +506,35 @@ static void curve_batch_cache_clear(Curve *cu) return; } - GPU_BATCH_DISCARD_SAFE(cache->overlay.verts_no_handles); - GPU_BATCH_DISCARD_SAFE(cache->overlay.verts); - GPU_BATCH_DISCARD_SAFE(cache->overlay.edges); - - GPU_VERTBUF_DISCARD_SAFE(cache->surface.verts); - GPU_INDEXBUF_DISCARD_SAFE(cache->surface.triangles_in_order); - - GPU_BATCH_DISCARD_ARRAY_SAFE(cache->surface.shaded_triangles, cache->surface.mat_len); - GPU_BATCH_DISCARD_SAFE(cache->surface.batch); - - GPU_VERTBUF_DISCARD_SAFE(cache->face_wire.elem_vbo); - DRW_TEXTURE_FREE_SAFE(cache->face_wire.elem_tx); - DRW_TEXTURE_FREE_SAFE(cache->face_wire.verts_tx); - cache->face_wire.tri_count = 0; - - /* don't own vbo & elems */ - GPU_BATCH_DISCARD_SAFE(cache->wire.batch); - GPU_VERTBUF_DISCARD_SAFE(cache->wire.verts); - GPU_VERTBUF_DISCARD_SAFE(cache->wire.edges); - GPU_INDEXBUF_DISCARD_SAFE(cache->wire.elem); - - /* don't own vbo & elems */ - GPU_BATCH_DISCARD_SAFE(cache->normal.batch); - GPU_VERTBUF_DISCARD_SAFE(cache->normal.verts); - GPU_VERTBUF_DISCARD_SAFE(cache->normal.edges); - GPU_INDEXBUF_DISCARD_SAFE(cache->normal.elem); + for (int i = 0; i < sizeof(cache->ordered) / sizeof(void *); ++i) { + GPUVertBuf **vbo = (GPUVertBuf **)&cache->ordered; + GPU_VERTBUF_DISCARD_SAFE(vbo[i]); + } + for (int i = 0; i < sizeof(cache->tess) / sizeof(void *); ++i) { + GPUVertBuf **vbo = (GPUVertBuf **)&cache->tess; + GPU_VERTBUF_DISCARD_SAFE(vbo[i]); + } + for (int i = 0; i < sizeof(cache->edit) / sizeof(void *); ++i) { + GPUVertBuf **vbo = (GPUVertBuf **)&cache->edit; + GPU_VERTBUF_DISCARD_SAFE(vbo[i]); + } + for (int i = 0; i < sizeof(cache->ibo) / sizeof(void *); ++i) { + GPUIndexBuf **ibo = (GPUIndexBuf **)&cache->ibo; + GPU_INDEXBUF_DISCARD_SAFE(ibo[i]); + } + for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) { + GPUBatch **batch = (GPUBatch **)&cache->batch; + GPU_BATCH_DISCARD_SAFE(batch[i]); + } - /* 3d text */ - GPU_BATCH_DISCARD_SAFE(cache->text.cursor); - GPU_BATCH_DISCARD_SAFE(cache->text.select); + for (int i = 0; i < cache->mat_len; ++i) { + GPU_INDEXBUF_DISCARD_SAFE(cache->surf_per_mat_tris[i]); + GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]); + } + MEM_SAFE_FREE(cache->surf_per_mat_tris); + MEM_SAFE_FREE(cache->surf_per_mat); + cache->mat_len = 0; + cache->cd_used = 0; } void DRW_curve_batch_cache_free(Curve *cu) @@ -484,460 +549,277 @@ void DRW_curve_batch_cache_free(Curve *cu) * \{ */ /* GPUBatch cache usage. */ -static GPUVertBuf *curve_batch_cache_get_wire_verts(CurveRenderData *rdata, CurveBatchCache *cache) +static void curve_create_curves_pos(CurveRenderData *rdata, GPUVertBuf *vbo_curves_pos) { - BLI_assert(rdata->types & CU_DATATYPE_WIRE); BLI_assert(rdata->ob_curve_cache != NULL); - if (cache->wire.verts == NULL) { - static GPUVertFormat format = { 0 }; - static struct { uint pos; } attr_id; - if (format.attr_len == 0) { - /* initialize vertex format */ - attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - } + static GPUVertFormat format = { 0 }; + static struct { uint pos; } attr_id; + if (format.attr_len == 0) { + attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + } - const int vert_len = curve_render_data_wire_verts_len_get(rdata); + const int vert_len = curve_render_data_wire_verts_len_get(rdata); + GPU_vertbuf_init_with_format(vbo_curves_pos, &format); + GPU_vertbuf_data_alloc(vbo_curves_pos, vert_len); - GPUVertBuf *vbo = cache->wire.verts = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, vert_len); - int vbo_len_used = 0; - for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) { - if (bl->nr > 0) { - const int i_end = vbo_len_used + bl->nr; - for (const BevPoint *bevp = bl->bevpoints; vbo_len_used < i_end; vbo_len_used++, bevp++) { - GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bevp->vec); - } + int v_idx = 0; + for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) { + if (bl->nr <= 0) { + continue; + } + const int i_end = v_idx + bl->nr; + for (const BevPoint *bevp = bl->bevpoints; v_idx < i_end; v_idx++, bevp++) { + GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, bevp->vec); + } + } + for (const DispList *dl = rdata->ob_curve_cache->disp.first; dl; dl = dl->next) { + if (ELEM(dl->type, DL_SEGM, DL_POLY)) { + for (int i = 0; i < dl->nr; v_idx++, i++) { + GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, &((float(*)[3])dl->verts)[i]); } } - BLI_assert(vbo_len_used == vert_len); } - - return cache->wire.verts; + BLI_assert(v_idx == vert_len); } -static GPUIndexBuf *curve_batch_cache_get_wire_edges(CurveRenderData *rdata, CurveBatchCache *cache) +static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_curve_lines) { - BLI_assert(rdata->types & CU_DATATYPE_WIRE); BLI_assert(rdata->ob_curve_cache != NULL); - if (cache->wire.edges == NULL) { - const int vert_len = curve_render_data_wire_verts_len_get(rdata); - const int edge_len = curve_render_data_wire_edges_len_get(rdata); - int edge_len_used = 0; - - GPUIndexBufBuilder elb; - GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len); - - int i = 0; - for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) { - if (bl->nr > 0) { - const bool is_cyclic = bl->poly != -1; - const int i_end = i + (bl->nr); - int i_prev; - if (is_cyclic) { - i_prev = i + (bl->nr - 1); - } - else { - i_prev = i; - i += 1; - } - for (; i < i_end; i_prev = i++) { - GPU_indexbuf_add_line_verts(&elb, i_prev, i); - edge_len_used += 1; - } + const int vert_len = curve_render_data_wire_verts_len_get(rdata); + const int edge_len = curve_render_data_wire_edges_len_get(rdata); + const int curve_len = curve_render_data_wire_curve_len_get(rdata); + /* Count the last vertex or each strip and the primitive restart. */ + const int index_len = edge_len + curve_len * 2; + + GPUIndexBufBuilder elb; + GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, index_len, vert_len, true); + + int v_idx = 0; + for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) { + if (bl->nr <= 0) { + continue; + } + const bool is_cyclic = bl->poly != -1; + if (is_cyclic) { + GPU_indexbuf_add_generic_vert(&elb, v_idx + (bl->nr - 1)); + } + for (int i = 0; i < bl->nr; i++) { + GPU_indexbuf_add_generic_vert(&elb, v_idx + i); + } + GPU_indexbuf_add_primitive_restart(&elb); + v_idx += bl->nr; + } + for (const DispList *dl = rdata->ob_curve_cache->disp.first; dl; dl = dl->next) { + if (ELEM(dl->type, DL_SEGM, DL_POLY)) { + const bool is_cyclic = dl->type == DL_POLY; + if (is_cyclic) { + GPU_indexbuf_add_generic_vert(&elb, v_idx + (dl->nr - 1)); + } + for (int i = 0; i < dl->nr; i++) { + GPU_indexbuf_add_generic_vert(&elb, v_idx + i); } + GPU_indexbuf_add_primitive_restart(&elb); + v_idx += dl->nr; } - cache->wire.elem = GPU_indexbuf_build(&elb); } - - return cache->wire.elem; + GPU_indexbuf_build_in_place(&elb, ibo_curve_lines); } -static GPUVertBuf *curve_batch_cache_get_normal_verts(CurveRenderData *rdata, CurveBatchCache *cache) +static void curve_create_edit_curves_nor(CurveRenderData *rdata, GPUVertBuf *vbo_curves_nor) { - BLI_assert(rdata->types & CU_DATATYPE_NORMAL); - BLI_assert(rdata->ob_curve_cache != NULL); - - if (cache->normal.verts == NULL) { - static GPUVertFormat format = { 0 }; - static struct { uint pos; } attr_id; - if (format.attr_len == 0) { - /* initialize vertex format */ - attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - } - - const int normal_len = curve_render_data_normal_len_get(rdata); - const int vert_len = normal_len * 3; - - GPUVertBuf *vbo = cache->normal.verts = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, vert_len); - int vbo_len_used = 0; + static GPUVertFormat format = { 0 }; + static struct { uint pos, nor, tan, rad; } attr_id; + if (format.attr_len == 0) { + /* initialize vertex formats */ + attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + attr_id.rad = GPU_vertformat_attr_add(&format, "rad", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + attr_id.tan = GPU_vertformat_attr_add(&format, "tan", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + } - const BevList *bl; - const Nurb *nu; + int verts_len_capacity = curve_render_data_normal_len_get(rdata) * 2; + int vbo_len_used = 0; - for (bl = rdata->ob_curve_cache->bev.first, nu = rdata->nurbs->first; - nu && bl; - bl = bl->next, nu = nu->next) - { - const BevPoint *bevp = bl->bevpoints; - int nr = bl->nr; - int skip = nu->resolu / 16; + GPU_vertbuf_init_with_format(vbo_curves_nor, &format); + GPU_vertbuf_data_alloc(vbo_curves_nor, verts_len_capacity); - while (nr-- > 0) { /* accounts for empty bevel lists */ - const float fac = bevp->radius * cache->normal_size; - float vec_a[3]; /* Offset perpendicular to the curve */ - float vec_b[3]; /* Delta along the curve */ + const BevList *bl; + const Nurb *nu; - vec_a[0] = fac; - vec_a[1] = 0.0f; - vec_a[2] = 0.0f; + for (bl = rdata->ob_curve_cache->bev.first, nu = rdata->nurbs->first; + nu && bl; + bl = bl->next, nu = nu->next) + { + const BevPoint *bevp = bl->bevpoints; + int nr = bl->nr; + int skip = nu->resolu / 16; - mul_qt_v3(bevp->quat, vec_a); - madd_v3_v3fl(vec_a, bevp->dir, -fac); + while (nr-- > 0) { /* accounts for empty bevel lists */ + float nor[3] = {1.0f, 0.0f, 0.0f}; + mul_qt_v3(bevp->quat, nor); - reflect_v3_v3v3(vec_b, vec_a, bevp->dir); - negate_v3(vec_b); + GPUPackedNormal pnor = GPU_normal_convert_i10_v3(nor); + GPUPackedNormal ptan = GPU_normal_convert_i10_v3(bevp->dir); - add_v3_v3(vec_a, bevp->vec); - add_v3_v3(vec_b, bevp->vec); + /* Only set attribs for one vertex. */ + GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.pos, vbo_len_used, bevp->vec); + GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.rad, vbo_len_used, &bevp->radius); + GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.nor, vbo_len_used, &pnor); + GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.tan, vbo_len_used, &ptan); + vbo_len_used++; - GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, vec_a); - GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, bevp->vec); - GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, vec_b); + /* Skip the other vertex (it does not need to be offseted). */ + GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.pos, vbo_len_used, bevp->vec); + vbo_len_used++; - bevp += skip + 1; - nr -= skip; - } + bevp += skip + 1; + nr -= skip; } - BLI_assert(vbo_len_used == vert_len); } - - return cache->normal.verts; + BLI_assert(vbo_len_used == verts_len_capacity); } -static GPUIndexBuf *curve_batch_cache_get_normal_edges(CurveRenderData *rdata, CurveBatchCache *cache) +static char beztriple_vflag_get(CurveRenderData *rdata, char flag, char col_id, int v_idx, int nu_id) { - BLI_assert(rdata->types & CU_DATATYPE_NORMAL); - BLI_assert(rdata->ob_curve_cache != NULL); - - if (cache->normal.edges == NULL) { - const int normal_len = curve_render_data_normal_len_get(rdata); - const int vert_len = normal_len * 3; - const int edge_len = normal_len * 2; - - GPUIndexBufBuilder elb; - GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len); - - int vbo_len_used = 0; - for (int i = 0; i < normal_len; i++) { - GPU_indexbuf_add_line_verts(&elb, vbo_len_used + 0, vbo_len_used + 1); - GPU_indexbuf_add_line_verts(&elb, vbo_len_used + 1, vbo_len_used + 2); - vbo_len_used += 3; - } + char vflag = 0; + SET_FLAG_FROM_TEST(vflag, (flag & SELECT), VFLAG_VERTEX_SELECTED); + SET_FLAG_FROM_TEST(vflag, (v_idx == rdata->actvert), VFLAG_VERTEX_ACTIVE); + SET_FLAG_FROM_TEST(vflag, (nu_id == rdata->actnu), ACTIVE_NURB); + /* handle color id */ + vflag |= col_id << 4; /* << 4 because of EVEN_U_BIT */ + return vflag; +} - BLI_assert(vbo_len_used == vert_len); +static char bpoint_vflag_get(CurveRenderData *rdata, char flag, int v_idx, int nu_id, int u) +{ + char vflag = 0; + SET_FLAG_FROM_TEST(vflag, (flag & SELECT), VFLAG_VERTEX_SELECTED); + SET_FLAG_FROM_TEST(vflag, (v_idx == rdata->actvert), VFLAG_VERTEX_ACTIVE); + SET_FLAG_FROM_TEST(vflag, (nu_id == rdata->actnu), ACTIVE_NURB); + SET_FLAG_FROM_TEST(vflag, ((u % 2) == 0), EVEN_U_BIT); + vflag |= COLOR_NURB_ULINE_ID << 4; /* << 4 because of EVEN_U_BIT */ + return vflag; +} - cache->normal.elem = GPU_indexbuf_build(&elb); +static void curve_create_edit_data_and_handles( + CurveRenderData *rdata, + GPUVertBuf *vbo_pos, GPUVertBuf *vbo_data, GPUIndexBuf *ibo_edit_verts_points, GPUIndexBuf *ibo_edit_lines) +{ + static GPUVertFormat format_pos = { 0 }; + static GPUVertFormat format_data = { 0 }; + static struct { uint pos, data; } attr_id; + if (format_pos.attr_len == 0) { + /* initialize vertex formats */ + attr_id.pos = GPU_vertformat_attr_add(&format_pos, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + attr_id.data = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U8, 1, GPU_FETCH_INT); } - return cache->normal.elem; -} + int verts_len_capacity = curve_render_data_overlay_verts_len_get(rdata); + int edges_len_capacity = curve_render_data_overlay_edges_len_get(rdata) * 2; + int vbo_len_used = 0; -static void curve_batch_cache_create_overlay_batches(Curve *cu) -{ - /* Since CU_DATATYPE_OVERLAY is slow to generate, generate them all at once */ - int options = CU_DATATYPE_OVERLAY; + if (DRW_TEST_ASSIGN_VBO(vbo_pos)) { + GPU_vertbuf_init_with_format(vbo_pos, &format_pos); + GPU_vertbuf_data_alloc(vbo_pos, verts_len_capacity); + } + if (DRW_TEST_ASSIGN_VBO(vbo_data)) { + GPU_vertbuf_init_with_format(vbo_data, &format_data); + GPU_vertbuf_data_alloc(vbo_data, verts_len_capacity); + } - CurveBatchCache *cache = curve_batch_cache_get(cu); - CurveRenderData *rdata = curve_render_data_create(cu, NULL, options); - - if (cache->overlay.verts == NULL) { - static GPUVertFormat format = { 0 }; - static struct { uint pos, data; } attr_id; - if (format.attr_len == 0) { - /* initialize vertex format */ - attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - attr_id.data = GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 1, GPU_FETCH_INT); - } + GPUIndexBufBuilder elb_verts, *elbp_verts = NULL; + GPUIndexBufBuilder elb_lines, *elbp_lines = NULL; + if (DRW_TEST_ASSIGN_IBO(ibo_edit_verts_points)) { + elbp_verts = &elb_verts; + GPU_indexbuf_init(elbp_verts, GPU_PRIM_POINTS, verts_len_capacity, verts_len_capacity); + } + if (DRW_TEST_ASSIGN_IBO(ibo_edit_lines)) { + elbp_lines = &elb_lines; + GPU_indexbuf_init(elbp_lines, GPU_PRIM_LINES, edges_len_capacity, verts_len_capacity); + } - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); - const int vbo_len_capacity = curve_render_data_overlay_verts_len_get(rdata); - GPUIndexBufBuilder elb; - GPU_indexbuf_init(&elb, GPU_PRIM_POINTS, vbo_len_capacity, vbo_len_capacity); - int vbo_len_used = 0; - GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); - int i = 0, nu_id = 0; - for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, nu_id++) { - const bool is_active_nurb = (nu_id == cu->actnu); - if (nu->bezt) { - int a = 0; - for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) { - if (bezt->hide == false) { - const bool is_active = (i == rdata->actvert); - GPU_indexbuf_add_point_vert(&elb, vbo_len_used + 1); - for (int j = 0; j < 3; j++) { - char vflag = ((&bezt->f1)[j] & SELECT) ? VFLAG_VERTEX_SELECTED : 0; - vflag |= (is_active) ? VFLAG_VERTEX_ACTIVE : 0; - vflag |= (is_active_nurb) ? ACTIVE_NURB : 0; - /* handle color id */ - char col_id = (&bezt->h1)[j / 2]; - vflag |= col_id << 4; /* << 4 because of EVEN_U_BIT */ - GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[j]); - GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag); - vbo_len_used += 1; - } - } - i += 1; + int v_idx = 0, nu_id = 0; + for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, nu_id++) { + const BezTriple *bezt = nu->bezt; + const BPoint *bp = nu->bp; + if (bezt && bezt->hide == false) { + for (int a = 0; a < nu->pntsu; a++, bezt++) { + if (elbp_verts) { + GPU_indexbuf_add_point_vert(elbp_verts, vbo_len_used + 1); } - } - else if (nu->bp) { - int a = 0; - int pt_len = nu->pntsu * nu->pntsv; - for (const BPoint *bp = nu->bp; a < pt_len; a++, bp++) { - if (bp->hide == false) { - const bool is_active = (i == rdata->actvert); - char vflag = (bp->f1 & SELECT) ? VFLAG_VERTEX_SELECTED : 0; - vflag |= (is_active) ? VFLAG_VERTEX_ACTIVE : 0; - vflag |= (is_active_nurb) ? ACTIVE_NURB : 0; - vflag |= (((a % nu->pntsu) % 2) == 0) ? EVEN_U_BIT : 0; - vflag |= COLOR_NURB_ULINE_ID << 4; /* << 4 because of EVEN_U_BIT */ - GPU_indexbuf_add_point_vert(&elb, vbo_len_used); - GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp->vec); - GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag); - vbo_len_used += 1; + if (elbp_lines) { + GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 1, vbo_len_used + 0); + GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 1, vbo_len_used + 2); + } + if (vbo_data) { + char vflag[3] = { + beztriple_vflag_get(rdata, bezt->f1, bezt->h1, v_idx, nu_id), + beztriple_vflag_get(rdata, bezt->f2, bezt->h1, v_idx, nu_id), + beztriple_vflag_get(rdata, bezt->f3, bezt->h2, v_idx, nu_id) + }; + for (int j = 0; j < 3; j++) { + GPU_vertbuf_attr_set(vbo_data, attr_id.data, vbo_len_used + j, &vflag[j]); } - i += 1; } - } - i += nu->pntsu; - } - if (vbo_len_capacity != vbo_len_used) { - GPU_vertbuf_data_resize(vbo, vbo_len_used); - } - - GPUIndexBuf *ibo = GPU_indexbuf_build(&elb); - - cache->overlay.verts = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); - cache->overlay.verts_no_handles = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, ibo, GPU_BATCH_OWNS_INDEX); - } - - if (cache->overlay.edges == NULL) { - GPUVertBuf *vbo = cache->overlay.verts->verts[0]; - - const int edge_len = curve_render_data_overlay_edges_len_get(rdata); - const int vbo_len_capacity = edge_len * 2; - - GPUIndexBufBuilder elb; - GPU_indexbuf_init(&elb, GPU_PRIM_LINES, vbo_len_capacity, vbo->vertex_len); - - int curr_index = 0; - int i = 0; - for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, i++) { - if (nu->bezt) { - int a = 0; - for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) { - if (bezt->hide == false) { - GPU_indexbuf_add_line_verts(&elb, curr_index + 1, curr_index + 0); - GPU_indexbuf_add_line_verts(&elb, curr_index + 1, curr_index + 2); - curr_index += 3; + if (vbo_pos) { + for (int j = 0; j < 3; j++) { + GPU_vertbuf_attr_set(vbo_pos, attr_id.pos, vbo_len_used + j, bezt->vec[j]); } } + vbo_len_used += 3; + v_idx += 1; } - else if (nu->bp) { - int a = 0; - int next_v_index = curr_index; - for (const BPoint *bp = nu->bp; a < nu->pntsu; a++, bp++) { - if (bp->hide == false) { - next_v_index += 1; - } + } + else if (bp) { + int pt_len = nu->pntsu * nu->pntsv; + for (int a = 0; a < pt_len; a++, bp++) { + int u = (a % nu->pntsu); + int v = (a / nu->pntsu); + /* Use indexed rendering for bezier. + * Specify all points and use indices to hide/show. */ + if (elbp_verts && bp->hide == false) { + GPU_indexbuf_add_point_vert(elbp_verts, vbo_len_used); } - - int pt_len = nu->pntsu * nu->pntsv; - for (a = 0; a < pt_len; a++) { - const BPoint *bp_curr = &nu->bp[a]; - const BPoint *bp_next_u = ((a % nu->pntsu) < (nu->pntsu - 1)) ? &nu->bp[a + 1] : NULL; - const BPoint *bp_next_v = (a < (pt_len - nu->pntsu)) ? &nu->bp[a + nu->pntsu] : NULL; - if (bp_curr->hide == false) { - if (bp_next_u && (bp_next_u->hide == false)) { - GPU_indexbuf_add_line_verts(&elb, curr_index, curr_index + 1); - } - if (bp_next_v && (bp_next_v->hide == false)) { - GPU_indexbuf_add_line_verts(&elb, curr_index, next_v_index); - } - curr_index += 1; + if (elbp_lines && bp->hide == false) { + const BPoint *bp_next_u = (u < (nu->pntsu - 1)) ? &nu->bp[a + 1] : NULL; + const BPoint *bp_next_v = (v < (nu->pntsv - 1)) ? &nu->bp[a + nu->pntsu] : NULL; + if (bp_next_u && (bp_next_u->hide == false)) { + GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used, vbo_len_used + 1); } if (bp_next_v && (bp_next_v->hide == false)) { - next_v_index += 1; + GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used, vbo_len_used + nu->pntsu); } } + if (vbo_data) { + char vflag = bpoint_vflag_get(rdata, bp->f1, v_idx, nu_id, u); + GPU_vertbuf_attr_set(vbo_data, attr_id.data, vbo_len_used, &vflag); + } + if (vbo_pos) { + GPU_vertbuf_attr_set(vbo_pos, attr_id.pos, vbo_len_used, bp->vec); + } + vbo_len_used += 1; + v_idx += 1; } } - - GPUIndexBuf *ibo = GPU_indexbuf_build(&elb); - cache->overlay.edges = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, ibo, GPU_BATCH_OWNS_INDEX); - } - - curve_render_data_free(rdata); -} - -static GPUBatch *curve_batch_cache_get_pos_and_normals(CurveRenderData *rdata, CurveBatchCache *cache) -{ - BLI_assert(rdata->types & CU_DATATYPE_SURFACE); - if (cache->surface.batch == NULL) { - ListBase *lb = &rdata->ob_curve_cache->disp; - - if (cache->surface.verts == NULL) { - cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb); - } - if (cache->surface.triangles_in_order == NULL) { - cache->surface.triangles_in_order = DRW_displist_indexbuf_calc_triangles_in_order(lb); - } - cache->surface.batch = GPU_batch_create( - GPU_PRIM_TRIS, cache->surface.verts, cache->surface.triangles_in_order); } - return cache->surface.batch; -} - -static GPUTexture *curve_batch_cache_get_edges_overlay_texture_buf(CurveRenderData *rdata, CurveBatchCache *cache) -{ - BLI_assert(rdata->types & CU_DATATYPE_SURFACE); - - if (cache->face_wire.elem_tx != NULL) { - return cache->face_wire.elem_tx; + /* Resize & Finish */ + if (elbp_verts != NULL) { + GPU_indexbuf_build_in_place(elbp_verts, ibo_edit_verts_points); } - - ListBase *lb = &rdata->ob_curve_cache->disp; - - /* We need a special index buffer. */ - GPUVertBuf *vbo = cache->face_wire.elem_vbo = DRW_displist_create_edges_overlay_texture_buf(lb); - - /* Upload data early because we need to create the texture for it. */ - GPU_vertbuf_use(vbo); - cache->face_wire.elem_tx = GPU_texture_create_from_vertbuf(vbo); - cache->face_wire.tri_count = vbo->vertex_alloc / 3; - - return cache->face_wire.elem_tx; -} - -static GPUTexture *curve_batch_cache_get_vert_pos_and_nor_in_order_buf(CurveRenderData *rdata, CurveBatchCache *cache) -{ - BLI_assert(rdata->types & CU_DATATYPE_SURFACE); - - if (cache->face_wire.verts_tx == NULL) { - curve_batch_cache_get_pos_and_normals(rdata, cache); - GPU_vertbuf_use(cache->surface.verts); /* Upload early for buffer texture creation. */ - cache->face_wire.verts_tx = GPU_texture_create_buffer(GPU_R32F, cache->surface.verts->vbo_id); - } - - return cache->face_wire.verts_tx; -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name Private Object/Font Cache API - * \{ */ - - -static GPUBatch *curve_batch_cache_get_overlay_select(CurveRenderData *rdata, CurveBatchCache *cache) -{ - BLI_assert(rdata->types & CU_DATATYPE_TEXT_SELECT); - if (cache->text.select == NULL) { - EditFont *ef = rdata->text.edit_font; - static GPUVertFormat format = { 0 }; - static struct { uint pos; } attr_id; - if (format.attr_len == 0) { - attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - } - - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); - const int vbo_len_capacity = ef->selboxes_len * 6; - int vbo_len_used = 0; - GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); - - float box[4][3]; - - /* fill in xy below */ - box[0][2] = box[1][2] = box[2][2] = box[3][2] = 0.001; - - for (int i = 0; i < ef->selboxes_len; i++) { - EditFontSelBox *sb = &ef->selboxes[i]; - - float selboxw; - if (i + 1 != ef->selboxes_len) { - if (ef->selboxes[i + 1].y == sb->y) - selboxw = ef->selboxes[i + 1].x - sb->x; - else - selboxw = sb->w; - } - else { - selboxw = sb->w; - } - - if (sb->rot == 0.0f) { - copy_v2_fl2(box[0], sb->x, sb->y); - copy_v2_fl2(box[1], sb->x + selboxw, sb->y); - copy_v2_fl2(box[2], sb->x + selboxw, sb->y + sb->h); - copy_v2_fl2(box[3], sb->x, sb->y + sb->h); - } - else { - float mat[2][2]; - - angle_to_mat2(mat, sb->rot); - - copy_v2_fl2(box[0], sb->x, sb->y); - - copy_v2_fl2(box[1], selboxw, 0.0f); - mul_m2v2(mat, box[1]); - add_v2_v2(box[1], &sb->x); - - copy_v2_fl2(box[2], selboxw, sb->h); - mul_m2v2(mat, box[2]); - add_v2_v2(box[2], &sb->x); - - copy_v2_fl2(box[3], 0.0f, sb->h); - mul_m2v2(mat, box[3]); - add_v2_v2(box[3], &sb->x); - } - - GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[0]); - GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[1]); - GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[2]); - - GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[0]); - GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[2]); - GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[3]); - } - BLI_assert(vbo_len_used == vbo_len_capacity); - cache->text.select = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO); + if (elbp_lines != NULL) { + GPU_indexbuf_build_in_place(elbp_lines, ibo_edit_lines); } - return cache->text.select; -} - -static GPUBatch *curve_batch_cache_get_overlay_cursor(CurveRenderData *rdata, CurveBatchCache *cache) -{ - BLI_assert(rdata->types & CU_DATATYPE_TEXT_SELECT); - if (cache->text.cursor == NULL) { - static GPUVertFormat format = { 0 }; - static struct { uint pos; } attr_id; - if (format.attr_len == 0) { - attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + if (vbo_len_used != verts_len_capacity) { + if (vbo_pos != NULL) { + GPU_vertbuf_data_resize(vbo_pos, vbo_len_used); } - - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); - const int vbo_len_capacity = 4; - GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); - for (int i = 0; i < 4; i++) { - GPU_vertbuf_attr_set(vbo, attr_id.pos, i, rdata->text.edit_font->textcurs[i]); + if (vbo_data != NULL) { + GPU_vertbuf_data_resize(vbo_data, vbo_len_used); } - cache->text.cursor = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO); } - return cache->text.cursor; } /** \} */ @@ -947,186 +829,209 @@ static GPUBatch *curve_batch_cache_get_overlay_cursor(CurveRenderData *rdata, Cu /** \name Public Object/Curve API * \{ */ -GPUBatch *DRW_curve_batch_cache_get_wire_edge(Curve *cu, CurveCache *ob_curve_cache) +GPUBatch *DRW_curve_batch_cache_get_wire_edge(Curve *cu) { CurveBatchCache *cache = curve_batch_cache_get(cu); - - if (cache->wire.batch == NULL) { - /* create batch from Curve */ - CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_WIRE); - - cache->wire.batch = GPU_batch_create( - GPU_PRIM_LINES, - curve_batch_cache_get_wire_verts(rdata, cache), - curve_batch_cache_get_wire_edges(rdata, cache)); - - curve_render_data_free(rdata); - } - return cache->wire.batch; + return DRW_batch_request(&cache->batch.curves); } -GPUBatch *DRW_curve_batch_cache_get_normal_edge(Curve *cu, CurveCache *ob_curve_cache, float normal_size) +GPUBatch *DRW_curve_batch_cache_get_normal_edge(Curve *cu) { CurveBatchCache *cache = curve_batch_cache_get(cu); - - if (cache->normal.batch != NULL) { - cache->normal_size = normal_size; - if (cache->normal_size != normal_size) { - GPU_BATCH_DISCARD_SAFE(cache->normal.batch); - GPU_VERTBUF_DISCARD_SAFE(cache->normal.edges); - } - } - cache->normal_size = normal_size; - - if (cache->normal.batch == NULL) { - /* create batch from Curve */ - CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_NORMAL); - - cache->normal.batch = GPU_batch_create( - GPU_PRIM_LINES, - curve_batch_cache_get_normal_verts(rdata, cache), - curve_batch_cache_get_normal_edges(rdata, cache)); - - curve_render_data_free(rdata); - cache->normal_size = normal_size; - } - return cache->normal.batch; + return DRW_batch_request(&cache->batch.edit_normals); } -GPUBatch *DRW_curve_batch_cache_get_overlay_edges(Curve *cu) +GPUBatch *DRW_curve_batch_cache_get_edit_edges(Curve *cu) { CurveBatchCache *cache = curve_batch_cache_get(cu); - - if (cache->overlay.edges == NULL) { - curve_batch_cache_create_overlay_batches(cu); - } - - return cache->overlay.edges; + return DRW_batch_request(&cache->batch.edit_edges); } -GPUBatch *DRW_curve_batch_cache_get_overlay_verts(Curve *cu, bool handles) +GPUBatch *DRW_curve_batch_cache_get_edit_verts(Curve *cu, bool handles) { CurveBatchCache *cache = curve_batch_cache_get(cu); - - if (cache->overlay.verts == NULL || cache->overlay.verts_no_handles == NULL) { - curve_batch_cache_create_overlay_batches(cu); + if (handles) { + return DRW_batch_request(&cache->batch.edit_handles_verts); + } + else { + return DRW_batch_request(&cache->batch.edit_verts); } - - return (handles) ? cache->overlay.verts : cache->overlay.verts_no_handles; } -GPUBatch *DRW_curve_batch_cache_get_triangles_with_normals( - struct Curve *cu, struct CurveCache *ob_curve_cache) +GPUBatch *DRW_curve_batch_cache_get_triangles_with_normals(struct Curve *cu) { CurveBatchCache *cache = curve_batch_cache_get(cu); - - if (cache->surface.batch == NULL) { - CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE); - - curve_batch_cache_get_pos_and_normals(rdata, cache); - - curve_render_data_free(rdata); - } - - return cache->surface.batch; + return DRW_batch_request(&cache->batch.surfaces); } GPUBatch **DRW_curve_batch_cache_get_surface_shaded( - struct Curve *cu, struct CurveCache *ob_curve_cache, - struct GPUMaterial **UNUSED(gpumat_array), uint gpumat_array_len) + struct Curve *cu, + struct GPUMaterial **gpumat_array, uint gpumat_array_len) { CurveBatchCache *cache = curve_batch_cache_get(cu); - if (cache->surface.mat_len != gpumat_array_len) { - GPU_BATCH_DISCARD_ARRAY_SAFE(cache->surface.shaded_triangles, cache->surface.mat_len); - } + BLI_assert(gpumat_array_len == cache->mat_len); - if (cache->surface.shaded_triangles == NULL) { - CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE); - ListBase *lb = &rdata->ob_curve_cache->disp; + curve_cd_calc_used_gpu_layers(&cache->cd_needed, gpumat_array, gpumat_array_len); - cache->surface.mat_len = gpumat_array_len; - if (cu->flag & CU_UV_ORCO) { - cache->surface.shaded_triangles = DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material( - lb, gpumat_array_len); - } - else { - cache->surface.shaded_triangles = MEM_mallocN( - sizeof(*cache->surface.shaded_triangles) * gpumat_array_len, __func__); - GPUIndexBuf **el = DRW_displist_indexbuf_calc_triangles_in_order_split_by_material( - lb, gpumat_array_len); - - if (cache->surface.verts == NULL) { - cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb); - } - - for (int i = 0; i < gpumat_array_len; ++i) { - cache->surface.shaded_triangles[i] = GPU_batch_create_ex( - GPU_PRIM_TRIS, cache->surface.verts, el[i], GPU_BATCH_OWNS_INDEX); - } - - MEM_freeN(el); /* Save `el` in cache? */ - } - - curve_render_data_free(rdata); + for (int i = 0; i < cache->mat_len; ++i) { + DRW_batch_request(&cache->surf_per_mat[i]); } - - return cache->surface.shaded_triangles; + return cache->surf_per_mat; } -void DRW_curve_batch_cache_get_wireframes_face_texbuf( - Curve *cu, CurveCache *ob_curve_cache, - GPUTexture **verts_data, GPUTexture **face_indices, int *tri_count) +GPUBatch *DRW_curve_batch_cache_get_wireframes_face(Curve *cu) { CurveBatchCache *cache = curve_batch_cache_get(cu); + return DRW_batch_request(&cache->batch.wire_triangles); +} - if (cache->face_wire.elem_tx == NULL || cache->face_wire.verts_tx == NULL) { - CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE); +/** \} */ - curve_batch_cache_get_edges_overlay_texture_buf(rdata, cache); - curve_batch_cache_get_vert_pos_and_nor_in_order_buf(rdata, cache); +/* -------------------------------------------------------------------- */ +/** \name Grouped batch generation + * \{ */ - curve_render_data_free(rdata); +void DRW_curve_batch_cache_create_requested(Object *ob) +{ + BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)); + + Curve *me = (Curve *)ob->data; + CurveBatchCache *cache = curve_batch_cache_get(me); + + /* Verify that all surface batches have needed attrib layers. */ + /* TODO(fclem): We could be a bit smarter here and only do it per material. */ + for (int i = 0; i < cache->mat_len; ++i) { + if ((cache->cd_used & cache->cd_needed) != cache->cd_needed) { + /* We can't discard batches at this point as they have been + * referenced for drawing. Just clear them in place. */ + GPU_batch_clear(cache->surf_per_mat[i]); + memset(cache->surf_per_mat[i], 0, sizeof(*cache->surf_per_mat[i])); + } + } + if ((cache->cd_used & cache->cd_needed) != cache->cd_needed) { + cache->cd_used |= cache->cd_needed; + cache->cd_needed = 0; } - *tri_count = cache->face_wire.tri_count; - *face_indices = cache->face_wire.elem_tx; - *verts_data = cache->face_wire.verts_tx; -} + /* Init batches and request VBOs & IBOs */ + if (DRW_batch_requested(cache->batch.surfaces, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.surfaces, &cache->ibo.surfaces_tris); + DRW_vbo_request(cache->batch.surfaces, &cache->ordered.pos_nor); + } + if (DRW_batch_requested(cache->batch.curves, GPU_PRIM_LINE_STRIP)) { + DRW_ibo_request(cache->batch.curves, &cache->ibo.curves_lines); + DRW_vbo_request(cache->batch.curves, &cache->ordered.curves_pos); + } + if (DRW_batch_requested(cache->batch.wire_triangles, GPU_PRIM_TRIS)) { + DRW_vbo_request(cache->batch.wire_triangles, &cache->tess.pos_nor); + DRW_vbo_request(cache->batch.wire_triangles, &cache->tess.wireframe_data); + } -/* -------------------------------------------------------------------- */ + /* Edit mode */ + if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) { + DRW_ibo_request(cache->batch.edit_edges, &cache->ibo.edit_lines); + DRW_vbo_request(cache->batch.edit_edges, &cache->edit.pos); + DRW_vbo_request(cache->batch.edit_edges, &cache->edit.data); + } + if (DRW_batch_requested(cache->batch.edit_verts, GPU_PRIM_POINTS)) { + DRW_ibo_request(cache->batch.edit_verts, &cache->ibo.edit_verts_points); + DRW_vbo_request(cache->batch.edit_verts, &cache->edit.pos); + DRW_vbo_request(cache->batch.edit_verts, &cache->edit.data); + } + if (DRW_batch_requested(cache->batch.edit_handles_verts, GPU_PRIM_POINTS)) { + DRW_vbo_request(cache->batch.edit_handles_verts, &cache->edit.pos); + DRW_vbo_request(cache->batch.edit_handles_verts, &cache->edit.data); + } + if (DRW_batch_requested(cache->batch.edit_normals, GPU_PRIM_LINES)) { + DRW_vbo_request(cache->batch.edit_normals, &cache->edit.curves_nor); + } + for (int i = 0; i < cache->mat_len; ++i) { + if (DRW_batch_requested(cache->surf_per_mat[i], GPU_PRIM_TRIS)) { + if (cache->mat_len > 1) { + DRW_ibo_request(cache->surf_per_mat[i], &cache->surf_per_mat_tris[i]); + } + if (cache->cd_used & CD_MLOOPUV) { + DRW_vbo_request(cache->surf_per_mat[i], &cache->tess.uv); + } + DRW_vbo_request(cache->surf_per_mat[i], &cache->tess.pos_nor); + } + } -/** \name Public Object/Font API - * \{ */ + /* Generate MeshRenderData flags */ + int mr_flag = 0; + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.pos_nor, CU_DATATYPE_SURFACE); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.curves_pos, CU_DATATYPE_WIRE); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->tess.pos_nor, CU_DATATYPE_SURFACE); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->tess.uv, CU_DATATYPE_SURFACE); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->tess.wireframe_data, CU_DATATYPE_SURFACE); + DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.surfaces_tris, CU_DATATYPE_SURFACE); + DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.curves_lines, CU_DATATYPE_WIRE); + + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.pos, CU_DATATYPE_OVERLAY); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.data, CU_DATATYPE_OVERLAY); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.curves_nor, CU_DATATYPE_NORMAL); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.curves_weight, CU_DATATYPE_OVERLAY); + DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_verts_points, CU_DATATYPE_OVERLAY); + DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_lines, CU_DATATYPE_OVERLAY); + + for (int i = 0; i < cache->mat_len; ++i) { + DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->surf_per_mat_tris[i], CU_DATATYPE_SURFACE); + } -GPUBatch *DRW_curve_batch_cache_get_overlay_select(Curve *cu) -{ - CurveBatchCache *cache = curve_batch_cache_get(cu); + CurveRenderData *rdata = curve_render_data_create(me, ob->runtime.curve_cache, mr_flag); - if (cache->text.select == NULL) { - CurveRenderData *rdata = curve_render_data_create(cu, NULL, CU_DATATYPE_TEXT_SELECT); + /* DispLists */ + ListBase *lb = &rdata->ob_curve_cache->disp; - curve_batch_cache_get_overlay_select(rdata, cache); + /* Generate VBOs */ + if (DRW_vbo_requested(cache->ordered.pos_nor)) { + DRW_displist_vertbuf_create_pos_and_nor(lb, cache->ordered.pos_nor); + } + if (DRW_vbo_requested(cache->ordered.curves_pos)) { + curve_create_curves_pos(rdata, cache->ordered.curves_pos); + } - curve_render_data_free(rdata); + if (DRW_vbo_requested(cache->tess.pos_nor) || + DRW_vbo_requested(cache->tess.uv)) + { + DRW_displist_vertbuf_create_pos_and_nor_and_uv_tess(lb, cache->tess.pos_nor, cache->tess.uv); + } + if (DRW_vbo_requested(cache->tess.wireframe_data)) { + DRW_displist_vertbuf_create_wireframe_data_tess(lb, cache->tess.wireframe_data); } - return cache->text.select; -} + if (DRW_ibo_requested(cache->surf_per_mat_tris[0])) { + DRW_displist_indexbuf_create_triangles_tess_split_by_material(lb, cache->surf_per_mat_tris, cache->mat_len); + } -GPUBatch *DRW_curve_batch_cache_get_overlay_cursor(Curve *cu) -{ - CurveBatchCache *cache = curve_batch_cache_get(cu); + if (DRW_ibo_requested(cache->ibo.curves_lines)) { + curve_create_curves_lines(rdata, cache->ibo.curves_lines); + } + if (DRW_ibo_requested(cache->ibo.surfaces_tris)) { + DRW_displist_indexbuf_create_triangles_in_order(lb, cache->ibo.surfaces_tris); + } - if (cache->text.cursor == NULL) { - CurveRenderData *rdata = curve_render_data_create(cu, NULL, CU_DATATYPE_TEXT_SELECT); + if (DRW_vbo_requested(cache->edit.pos) || + DRW_vbo_requested(cache->edit.data) || + DRW_ibo_requested(cache->ibo.edit_verts_points) || + DRW_ibo_requested(cache->ibo.edit_lines)) + { + curve_create_edit_data_and_handles(rdata, cache->edit.pos, cache->edit.data, + cache->ibo.edit_verts_points, cache->ibo.edit_lines); + } + if (DRW_vbo_requested(cache->edit.curves_nor)) { + curve_create_edit_curves_nor(rdata, cache->edit.curves_nor); + } - curve_batch_cache_get_overlay_cursor(rdata, cache); + curve_render_data_free(rdata); - curve_render_data_free(rdata); +#ifdef DEBUG + /* Make sure all requested batches have been setup. */ + for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) { + BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); } - - return cache->text.cursor; +#endif } /** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c index d6a57676a8d..9724b1a47a2 100644 --- a/source/blender/draw/intern/draw_cache_impl_displist.c +++ b/source/blender/draw/intern/draw_cache_impl_displist.c @@ -125,7 +125,52 @@ static void displist_indexbufbuilder_set( } } -GPUVertBuf *DRW_displist_vertbuf_calc_pos_with_normals(ListBase *lb) +static int displist_indexbufbuilder_tess_set( + setTriIndicesFn *set_tri_indices, + setTriIndicesFn *set_quad_tri_indices, /* meh, find a better solution. */ + void *thunk, const DispList *dl, const int ofs) +{ + int v_idx = ofs; + if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { + if (dl->type == DL_INDEX3) { + for (int i = 0; i < dl->parts; i++) { + set_tri_indices(thunk, v_idx + 0, v_idx + 1, v_idx + 2); + v_idx += 3; + } + } + else if (dl->type == DL_SURF) { + for (int a = 0; a < dl->parts; a++) { + if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) { + break; + } + int b = (dl->flag & DL_CYCL_U) ? 0 : 1; + for (; b < dl->nr; b++) { + set_quad_tri_indices(thunk, v_idx + 0, v_idx + 1, v_idx + 2); + set_quad_tri_indices(thunk, v_idx + 3, v_idx + 4, v_idx + 5); + v_idx += 6; + } + } + } + else { + BLI_assert(dl->type == DL_INDEX4); + const int *idx = dl->index; + for (int i = 0; i < dl->parts; i++, idx += 4) { + if (idx[2] != idx[3]) { + set_quad_tri_indices(thunk, v_idx + 0, v_idx + 1, v_idx + 2); + set_quad_tri_indices(thunk, v_idx + 3, v_idx + 4, v_idx + 5); + v_idx += 6; + } + else { + set_tri_indices(thunk, v_idx + 0, v_idx + 1, v_idx + 2); + v_idx += 3; + } + } + } + } + return v_idx; +} + +void DRW_displist_vertbuf_create_pos_and_nor(ListBase *lb, GPUVertBuf *vbo) { static GPUVertFormat format = { 0 }; static struct { uint pos, nor; } attr_id; @@ -135,7 +180,7 @@ GPUVertBuf *DRW_displist_vertbuf_calc_pos_with_normals(ListBase *lb) attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); } - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, curve_render_surface_vert_len_get(lb)); BKE_displist_normals_add(lb); @@ -162,11 +207,9 @@ GPUVertBuf *DRW_displist_vertbuf_calc_pos_with_normals(ListBase *lb) } } } - - return vbo; } -GPUIndexBuf *DRW_displist_indexbuf_calc_triangles_in_order(ListBase *lb) +void DRW_displist_indexbuf_create_triangles_in_order(ListBase *lb, GPUIndexBuf *ibo) { const int tri_len = curve_render_surface_tri_len_get(lb); const int vert_len = curve_render_surface_vert_len_get(lb); @@ -182,159 +225,197 @@ GPUIndexBuf *DRW_displist_indexbuf_calc_triangles_in_order(ListBase *lb) ofs += dl_vert_len(dl); } - return GPU_indexbuf_build(&elb); + GPU_indexbuf_build_in_place(&elb, ibo); } -GPUIndexBuf **DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(ListBase *lb, uint gpumat_array_len) +void DRW_displist_indexbuf_create_triangles_tess_split_by_material( + ListBase *lb, + GPUIndexBuf **ibo_mats, uint mat_len) { - GPUIndexBuf **shaded_triangles_in_order = MEM_callocN( - sizeof(*shaded_triangles_in_order) * gpumat_array_len, __func__); - GPUIndexBufBuilder *elb = BLI_array_alloca(elb, gpumat_array_len); + GPUIndexBufBuilder *elb = BLI_array_alloca(elb, mat_len); const int tri_len = curve_render_surface_tri_len_get(lb); - const int vert_len = curve_render_surface_vert_len_get(lb); - int i; /* Init each index buffer builder */ - for (i = 0; i < gpumat_array_len; i++) { - GPU_indexbuf_init(&elb[i], GPU_PRIM_TRIS, tri_len, vert_len); + for (int i = 0; i < mat_len; i++) { + GPU_indexbuf_init(&elb[i], GPU_PRIM_TRIS, tri_len * 3, tri_len * 3); } /* calc each index buffer builder */ - int ofs = 0; + uint v_idx = 0; for (const DispList *dl = lb->first; dl; dl = dl->next) { - displist_indexbufbuilder_set((setTriIndicesFn *)GPU_indexbuf_add_tri_verts, - (setTriIndicesFn *)GPU_indexbuf_add_tri_verts, - &elb[dl->col], dl, ofs); - ofs += dl_vert_len(dl); + v_idx = displist_indexbufbuilder_tess_set((setTriIndicesFn *)GPU_indexbuf_add_tri_verts, + (setTriIndicesFn *)GPU_indexbuf_add_tri_verts, + &elb[dl->col], dl, v_idx); } /* build each indexbuf */ - for (i = 0; i < gpumat_array_len; i++) { - shaded_triangles_in_order[i] = GPU_indexbuf_build(&elb[i]); + for (int i = 0; i < mat_len; i++) { + GPU_indexbuf_build_in_place(&elb[i], ibo_mats[i]); } - - return shaded_triangles_in_order; } typedef struct DRWDisplistWireThunk { - uint index_id, vidx; - short dl_type; + uint wd_id, ofs; + const DispList *dl; GPUVertBuf *vbo; } DRWDisplistWireThunk; static void set_overlay_wires_tri_indices(void *thunk, uint v1, uint v2, uint v3) { DRWDisplistWireThunk *dwt = (DRWDisplistWireThunk *)thunk; - /* Tag real edges. */ - v1 |= (1 << 30); - v2 |= (1 << 30); - v3 |= (1 << 30); - GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v1); - GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v2); - GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v3); + uint indices[3] = {v1, v2, v3}; + + for (int i = 0; i < 3; ++i) { + /* TODO: Compute sharpness. For now, only tag real egdes. */ + uchar sharpness = 0xFF; + GPU_vertbuf_attr_set(dwt->vbo, dwt->wd_id, indices[i], &sharpness); + } } static void set_overlay_wires_quad_tri_indices(void *thunk, uint v1, uint v2, uint v3) { DRWDisplistWireThunk *dwt = (DRWDisplistWireThunk *)thunk; - /* Tag real edges. */ - v2 |= (1 << 30); - v3 |= (1 << 30); - GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v1); - GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v2); - GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v3); + uint indices[3] = {v1, v2, v3}; + + for (int i = 0; i < 3; ++i) { + /* TODO: Compute sharpness. For now, only tag real egdes. */ + uchar sharpness = (i == 0) ? 0x00 : 0xFF; + GPU_vertbuf_attr_set(dwt->vbo, dwt->wd_id, indices[i], &sharpness); + } } -GPUVertBuf *DRW_displist_create_edges_overlay_texture_buf(ListBase *lb) +/* TODO reuse the position and normals from other tesselation vertbuf. */ +void DRW_displist_vertbuf_create_wireframe_data_tess(ListBase *lb, GPUVertBuf *vbo) { - GPUVertFormat format = {0}; - uint index_id = GPU_vertformat_attr_add(&format, "index", GPU_COMP_U32, 1, GPU_FETCH_INT); - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + static DRWDisplistWireThunk thunk; + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + thunk.wd_id = GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_triple_load(&format); + } - GPU_vertbuf_data_alloc(vbo, curve_render_surface_tri_len_get(lb) * 3); + GPU_vertbuf_init_with_format(vbo, &format); + thunk.vbo = vbo; - DRWDisplistWireThunk thunk = {.index_id = index_id, .vbo = vbo, .vidx = 0}; + int vert_len = curve_render_surface_tri_len_get(lb) * 3; + GPU_vertbuf_data_alloc(thunk.vbo, vert_len); - int ofs = 0; + thunk.ofs = 0; for (const DispList *dl = lb->first; dl; dl = dl->next) { - thunk.dl_type = dl->type; + thunk.dl = dl; /* TODO consider non-manifold edges correctly. */ - displist_indexbufbuilder_set(set_overlay_wires_tri_indices, - set_overlay_wires_quad_tri_indices, - &thunk, dl, ofs); - ofs += dl_vert_len(dl); + thunk.ofs = displist_indexbufbuilder_tess_set(set_overlay_wires_tri_indices, + set_overlay_wires_quad_tri_indices, + &thunk, dl, thunk.ofs); } - return vbo; + if (thunk.ofs < vert_len) { + GPU_vertbuf_data_resize(thunk.vbo, thunk.ofs); + } } +static void surf_uv_quad(const DispList *dl, const uint quad[4], float r_uv[4][2]) +{ + int orco_sizeu = dl->nr - 1; + int orco_sizev = dl->parts - 1; + + /* exception as handled in convertblender.c too */ + if (dl->flag & DL_CYCL_U) { + orco_sizeu++; + } + if (dl->flag & DL_CYCL_V) { + orco_sizev++; + } + + for (int i = 0; i < 4; i++) { + /* find uv based on vertex index into grid array */ + r_uv[i][0] = (quad[i] / dl->nr) / (float)orco_sizev; + r_uv[i][1] = (quad[i] % dl->nr) / (float)orco_sizeu; -static void displist_vertbuf_attr_set_tri_pos_normals_and_uv( + /* cyclic correction */ + if ((i == 1 || i == 2) && r_uv[i][0] == 0.0f) { + r_uv[i][0] = 1.0f; + } + if ((i == 0 || i == 1) && r_uv[i][1] == 0.0f) { + r_uv[i][1] = 1.0f; + } + } +} + +static void displist_vertbuf_attr_set_tri_pos_nor_uv( GPUVertBufRaw *pos_step, GPUVertBufRaw *nor_step, GPUVertBufRaw *uv_step, const float v1[3], const float v2[3], const float v3[3], const float n1[3], const float n2[3], const float n3[3], - const float uv1[2], const float uv2[2], const float uv3[2]) + const float uv1[2], const float uv2[2], const float uv3[2], + const bool invert_normal) { - copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v1); - copy_v3_v3(GPU_vertbuf_raw_step(nor_step), n1); - copy_v2_v2(GPU_vertbuf_raw_step(uv_step), uv1); - - copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v2); - copy_v3_v3(GPU_vertbuf_raw_step(nor_step), n2); - copy_v2_v2(GPU_vertbuf_raw_step(uv_step), uv2); + if (pos_step->size != 0) { + copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v1); + copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v2); + copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v3); + + if (invert_normal) { + float neg_n1[3], neg_n2[3], neg_n3[3]; + negate_v3_v3(neg_n1, n1); + negate_v3_v3(neg_n2, n2); + negate_v3_v3(neg_n3, n3); + *(GPUPackedNormal *)GPU_vertbuf_raw_step(nor_step) = GPU_normal_convert_i10_v3(neg_n1); + *(GPUPackedNormal *)GPU_vertbuf_raw_step(nor_step) = GPU_normal_convert_i10_v3(neg_n2); + *(GPUPackedNormal *)GPU_vertbuf_raw_step(nor_step) = GPU_normal_convert_i10_v3(neg_n3); + } + else { + *(GPUPackedNormal *)GPU_vertbuf_raw_step(nor_step) = GPU_normal_convert_i10_v3(n1); + *(GPUPackedNormal *)GPU_vertbuf_raw_step(nor_step) = GPU_normal_convert_i10_v3(n2); + *(GPUPackedNormal *)GPU_vertbuf_raw_step(nor_step) = GPU_normal_convert_i10_v3(n3); + } + } - copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v3); - copy_v3_v3(GPU_vertbuf_raw_step(nor_step), n3); - copy_v2_v2(GPU_vertbuf_raw_step(uv_step), uv3); + if (uv_step->size != 0) { + normal_float_to_short_v2(GPU_vertbuf_raw_step(uv_step), uv1); + normal_float_to_short_v2(GPU_vertbuf_raw_step(uv_step), uv2); + normal_float_to_short_v2(GPU_vertbuf_raw_step(uv_step), uv3); + } } -GPUBatch **DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(ListBase *lb, uint gpumat_array_len) +void DRW_displist_vertbuf_create_pos_and_nor_and_uv_tess( + ListBase *lb, + GPUVertBuf *vbo_pos_nor, GPUVertBuf *vbo_uv) { - static GPUVertFormat shaded_triangles_format = { 0 }; + static GPUVertFormat format_pos_nor = { 0 }; + static GPUVertFormat format_uv = { 0 }; static struct { uint pos, nor, uv; } attr_id; - - if (shaded_triangles_format.attr_len == 0) { + if (format_pos_nor.attr_len == 0) { /* initialize vertex format */ - attr_id.pos = GPU_vertformat_attr_add(&shaded_triangles_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - attr_id.nor = GPU_vertformat_attr_add(&shaded_triangles_format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - attr_id.uv = GPU_vertformat_attr_add(&shaded_triangles_format, "u", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + attr_id.pos = GPU_vertformat_attr_add(&format_pos_nor, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + attr_id.nor = GPU_vertformat_attr_add(&format_pos_nor, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_triple_load(&format_pos_nor); + /* UVs are in [0..1] range. We can compress them. */ + attr_id.uv = GPU_vertformat_attr_add(&format_uv, "u", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT); } - GPUBatch **shaded_triangles = MEM_mallocN(sizeof(*shaded_triangles) * gpumat_array_len, __func__); + int vbo_len_capacity = curve_render_surface_tri_len_get(lb) * 3; - GPUVertBuf **vbo = BLI_array_alloca(vbo, gpumat_array_len); - uint *vbo_len_capacity = BLI_array_alloca(vbo_len_capacity, gpumat_array_len); + GPUVertBufRaw pos_step = {0}; + GPUVertBufRaw nor_step = {0}; + GPUVertBufRaw uv_step = {0}; - GPUVertBufRaw *pos_step, *nor_step, *uv_step; - pos_step = BLI_array_alloca(pos_step, gpumat_array_len); - nor_step = BLI_array_alloca(nor_step, gpumat_array_len); - uv_step = BLI_array_alloca(uv_step, gpumat_array_len); - - /* Create each vertex buffer */ - for (int i = 0; i < gpumat_array_len; i++) { - vbo[i] = GPU_vertbuf_create_with_format(&shaded_triangles_format); - vbo_len_capacity[i] = 0; + if (DRW_TEST_ASSIGN_VBO(vbo_pos_nor)) { + GPU_vertbuf_init_with_format(vbo_pos_nor, &format_pos_nor); + GPU_vertbuf_data_alloc(vbo_pos_nor, vbo_len_capacity); + GPU_vertbuf_attr_get_raw_data(vbo_pos_nor, attr_id.pos, &pos_step); + GPU_vertbuf_attr_get_raw_data(vbo_pos_nor, attr_id.nor, &nor_step); } - - /* Calc `vbo_len_capacity` */ - for (const DispList *dl = lb->first; dl; dl = dl->next) { - vbo_len_capacity[dl->col] += dl_tri_len(dl) * 3; - } - - /* Alloc each vertex buffer and get each raw data */ - for (int i = 0; i < gpumat_array_len; i++) { - GPU_vertbuf_data_alloc(vbo[i], vbo_len_capacity[i]); - GPU_vertbuf_attr_get_raw_data(vbo[i], attr_id.pos, &pos_step[i]); - GPU_vertbuf_attr_get_raw_data(vbo[i], attr_id.nor, &nor_step[i]); - GPU_vertbuf_attr_get_raw_data(vbo[i], attr_id.uv, &uv_step[i]); + if (DRW_TEST_ASSIGN_VBO(vbo_uv)) { + GPU_vertbuf_init_with_format(vbo_uv, &format_uv); + GPU_vertbuf_data_alloc(vbo_uv, vbo_len_capacity); + GPU_vertbuf_attr_get_raw_data(vbo_uv, attr_id.uv, &uv_step); } BKE_displist_normals_add(lb); for (const DispList *dl = lb->first; dl; dl = dl->next) { if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { - const int col = dl->col; const float(*verts)[3] = (float(*)[3])dl->verts; const float(*nors)[3] = (float(*)[3])dl->nors; const int *idx = dl->index; @@ -345,15 +426,17 @@ GPUBatch **DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(List uv[0][1] = uv[1][1] = uv[2][1] = 0.0f; const int i_end = dl->parts; for (int i = 0; i < i_end; i++, idx += 3) { - uv[0][0] = idx[0] / x_max; - uv[1][0] = idx[2] / x_max; - uv[2][0] = idx[1] / x_max; + if (vbo_uv) { + uv[0][0] = idx[0] / x_max; + uv[1][0] = idx[1] / x_max; + uv[2][0] = idx[2] / x_max; + } - displist_vertbuf_attr_set_tri_pos_normals_and_uv( - &pos_step[col], &nor_step[col], &uv_step[col], + displist_vertbuf_attr_set_tri_pos_nor_uv( + &pos_step, &nor_step, &uv_step, verts[idx[0]], verts[idx[2]], verts[idx[1]], dl->nors, dl->nors, dl->nors, - uv[0], uv[1], uv[2]); + uv[0], uv[2], uv[1], false); } } else if (dl->type == DL_SURF) { @@ -384,42 +467,21 @@ GPUBatch **DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(List } for (; b < dl->nr; b++) { - int orco_sizeu = dl->nr - 1; - int orco_sizev = dl->parts - 1; - - /* exception as handled in convertblender.c too */ - if (dl->flag & DL_CYCL_U) { - orco_sizeu++; - } - if (dl->flag & DL_CYCL_V) { - orco_sizev++; + if (vbo_uv) { + surf_uv_quad(dl, quad, uv); } - for (int i = 0; i < 4; i++) { - /* find uv based on vertex index into grid array */ - uv[i][0] = (quad[i] / dl->nr) / (float)orco_sizev; - uv[i][1] = (quad[i] % dl->nr) / (float)orco_sizeu; - - /* cyclic correction */ - if ((i == 1 || i == 2) && uv[i][0] == 0.0f) { - uv[i][0] = 1.0f; - } - if ((i == 0 || i == 1) && uv[i][1] == 0.0f) { - uv[i][1] = 1.0f; - } - } + displist_vertbuf_attr_set_tri_pos_nor_uv( + &pos_step, &nor_step, &uv_step, + verts[quad[2]], verts[quad[0]], verts[quad[1]], + nors[quad[2]], nors[quad[0]], nors[quad[1]], + uv[2], uv[0], uv[1], false); - displist_vertbuf_attr_set_tri_pos_normals_and_uv( - &pos_step[col], &nor_step[col], &uv_step[col], - verts[quad[0]], verts[quad[1]], verts[quad[2]], - nors[quad[0]], nors[quad[1]], nors[quad[2]], - uv[0], uv[1], uv[2]); - - displist_vertbuf_attr_set_tri_pos_normals_and_uv( - &pos_step[col], &nor_step[col], &uv_step[col], + displist_vertbuf_attr_set_tri_pos_nor_uv( + &pos_step, &nor_step, &uv_step, verts[quad[0]], verts[quad[2]], verts[quad[3]], nors[quad[0]], nors[quad[2]], nors[quad[3]], - uv[0], uv[2], uv[3]); + uv[0], uv[2], uv[3], false); quad[2] = quad[1]; quad[1]++; @@ -435,31 +497,34 @@ GPUBatch **DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(List const int i_end = dl->parts; for (int i = 0; i < i_end; i++, idx += 4) { - displist_vertbuf_attr_set_tri_pos_normals_and_uv( - &pos_step[col], &nor_step[col], &uv_step[col], - verts[idx[0]], verts[idx[1]], verts[idx[2]], - nors[idx[0]], nors[idx[1]], nors[idx[2]], - uv[0], uv[1], uv[2]); + displist_vertbuf_attr_set_tri_pos_nor_uv( + &pos_step, &nor_step, &uv_step, + verts[idx[0]], verts[idx[2]], verts[idx[1]], + nors[idx[0]], nors[idx[2]], nors[idx[1]], + uv[0], uv[2], uv[1], true); if (idx[2] != idx[3]) { - displist_vertbuf_attr_set_tri_pos_normals_and_uv( - &pos_step[col], &nor_step[col], &uv_step[col], - verts[idx[0]], verts[idx[2]], verts[idx[3]], - nors[idx[0]], nors[idx[2]], nors[idx[3]], - uv[0], uv[2], uv[3]); + displist_vertbuf_attr_set_tri_pos_nor_uv( + &pos_step, &nor_step, &uv_step, + verts[idx[2]], verts[idx[0]], verts[idx[3]], + nors[idx[2]], nors[idx[0]], nors[idx[3]], + uv[2], uv[0], uv[3], true); } } } } } - - for (int i = 0; i < gpumat_array_len; i++) { - uint vbo_len_used = GPU_vertbuf_raw_used(&pos_step[i]); - if (vbo_len_capacity[i] != vbo_len_used) { - GPU_vertbuf_data_resize(vbo[i], vbo_len_used); + /* Resize and finish. */ + if (pos_step.size != 0) { + int vbo_len_used = GPU_vertbuf_raw_used(&pos_step); + if (vbo_len_used < vbo_len_capacity) { + GPU_vertbuf_data_resize(vbo_pos_nor, vbo_len_used); + } + } + if (uv_step.size != 0) { + int vbo_len_used = GPU_vertbuf_raw_used(&uv_step); + if (vbo_len_used < vbo_len_capacity) { + GPU_vertbuf_data_resize(vbo_uv, vbo_len_used); } - shaded_triangles[i] = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo[i], NULL, GPU_BATCH_OWNS_VBO); } - - return shaded_triangles; } diff --git a/source/blender/draw/intern/draw_cache_impl_lattice.c b/source/blender/draw/intern/draw_cache_impl_lattice.c index b077162b41d..12f80c4e8e9 100644 --- a/source/blender/draw/intern/draw_cache_impl_lattice.c +++ b/source/blender/draw/intern/draw_cache_impl_lattice.c @@ -567,7 +567,7 @@ GPUBatch *DRW_lattice_batch_cache_get_all_verts(Lattice *lt) return cache->all_verts; } -GPUBatch *DRW_lattice_batch_cache_get_overlay_verts(Lattice *lt) +GPUBatch *DRW_lattice_batch_cache_get_edit_verts(Lattice *lt) { LatticeBatchCache *cache = lattice_batch_cache_get(lt); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index a24702368de..b0080c70a0d 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -44,6 +44,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_space_types.h" +#include "DNA_scene_types.h" #include "BKE_customdata.h" #include "BKE_deform.h" @@ -53,16 +54,19 @@ #include "BKE_mesh.h" #include "BKE_mesh_tangent.h" #include "BKE_mesh_runtime.h" +#include "BKE_object.h" +#include "BKE_object_deform.h" #include "BKE_colorband.h" #include "BKE_cdderivedmesh.h" +#include "DEG_depsgraph_query.h" + #include "bmesh.h" #include "GPU_batch.h" #include "GPU_batch_presets.h" #include "GPU_draw.h" #include "GPU_material.h" -#include "GPU_texture.h" #include "DRW_render.h" @@ -72,8 +76,28 @@ #include "draw_cache_impl.h" /* own include */ + static void mesh_batch_cache_clear(Mesh *me); +/* Vertex Group Selection and display options */ +typedef struct DRW_MeshWeightState { + int defgroup_active; + int defgroup_len; + + short flags; + char alert_mode; + + /* Set of all selected bones for Multipaint. */ + bool *defgroup_sel; /* [defgroup_len] */ + int defgroup_sel_count; +} DRW_MeshWeightState; + +/* DRW_MeshWeightState.flags */ +enum { + DRW_MESH_WEIGHT_STATE_MULTIPAINT = (1 << 0), + DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE = (1 << 1), +}; + /* ---------------------------------------------------------------------- */ /** \name Mesh/BMesh Interface (direct access to basic data). @@ -175,6 +199,8 @@ typedef struct MeshRenderData { BMEditMesh *edit_bmesh; struct EditMeshData *edit_data; + Mesh *me; + MVert *mvert; const MEdge *medge; const MLoop *mloop; @@ -247,6 +273,7 @@ typedef struct MeshRenderData { GPUPackedNormal *poly_normals_pack; GPUPackedNormal *vert_normals_pack; bool *edge_select_bool; + bool *edge_visible_bool; } MeshRenderData; enum { @@ -260,6 +287,8 @@ enum { MR_DATATYPE_DVERT = 1 << 7, MR_DATATYPE_LOOPCOL = 1 << 8, MR_DATATYPE_LOOPUV = 1 << 9, + MR_DATATYPE_LOOSE_VERT = 1 << 10, + MR_DATATYPE_LOOSE_EDGE = 1 << 11, }; /** @@ -291,12 +320,60 @@ static bool bm_edge_has_visible_face(const BMEdge *e) return false; } +/* Return true is all layers in _b_ are inside _a_. */ +static bool mesh_cd_layers_type_overlap( + const uchar av[CD_NUMTYPES], const ushort al[CD_NUMTYPES], + const uchar bv[CD_NUMTYPES], const ushort bl[CD_NUMTYPES]) +{ + for (int i = 0; i < CD_NUMTYPES; ++i) { + if ((av[i] & bv[i]) != bv[i]) { + return false; + } + if ((al[i] & bl[i]) != bl[i]) { + return false; + } + } + return true; +} + +static void mesh_cd_layers_type_merge( + uchar av[CD_NUMTYPES], ushort al[CD_NUMTYPES], + uchar bv[CD_NUMTYPES], ushort bl[CD_NUMTYPES]) +{ + for (int i = 0; i < CD_NUMTYPES; ++i) { + av[i] |= bv[i]; + al[i] |= bl[i]; + } +} + +static void mesh_cd_calc_active_uv_layer( + const Mesh *me, ushort cd_lused[CD_NUMTYPES]) +{ + const CustomData *cd_ldata = (me->edit_btmesh) ? &me->edit_btmesh->bm->ldata : &me->ldata; + + int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); + if (layer != -1) { + cd_lused[CD_MLOOPUV] |= (1 << layer); + } +} + +static void mesh_cd_calc_active_vcol_layer( + const Mesh *me, ushort cd_lused[CD_NUMTYPES]) +{ + const CustomData *cd_ldata = (me->edit_btmesh) ? &me->edit_btmesh->bm->ldata : &me->ldata; + + int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL); + if (layer != -1) { + cd_lused[CD_MLOOPCOL] |= (1 << layer); + } +} static void mesh_cd_calc_used_gpu_layers( - CustomData *UNUSED(cd_vdata), uchar cd_vused[CD_NUMTYPES], - CustomData *cd_ldata, ushort cd_lused[CD_NUMTYPES], + const Mesh *me, uchar cd_vused[CD_NUMTYPES], ushort cd_lused[CD_NUMTYPES], struct GPUMaterial **gpumat_array, int gpumat_array_len) { + const CustomData *cd_ldata = (me->edit_btmesh) ? &me->edit_btmesh->bm->ldata : &me->ldata; + /* See: DM_vertex_attributes_from_gpu for similar logic */ GPUVertexAttribs gattribs = {{{0}}}; @@ -417,6 +494,54 @@ static void mesh_render_calc_normals_loop_and_poly(const Mesh *me, const float s rdata->poly_normals = poly_normals; } +static void mesh_cd_extract_auto_layers_names_and_srgb( + Mesh *me, const ushort cd_lused[CD_NUMTYPES], + char **r_auto_layers_names, int **r_auto_layers_srgb, int *r_auto_layers_len) +{ + const CustomData *cd_ldata = (me->edit_btmesh) ? &me->edit_btmesh->bm->ldata : &me->ldata; + + int uv_len_used = count_bits_i(cd_lused[CD_MLOOPUV]); + int vcol_len_used = count_bits_i(cd_lused[CD_MLOOPCOL]); + int uv_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPUV); + int vcol_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPCOL); + + uint auto_names_len = 32 * (uv_len_used + vcol_len_used); + uint auto_ofs = 0; + /* Allocate max, resize later. */ + char *auto_names = MEM_callocN(sizeof(char) * auto_names_len, __func__); + int *auto_is_srgb = MEM_callocN(sizeof(int) * (uv_len_used + vcol_len_used), __func__); + + for (int i = 0; i < uv_len; i++) { + if ((cd_lused[CD_MLOOPUV] & (1 << i)) != 0) { + const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i); + uint hash = BLI_ghashutil_strhash_p(name); + /* +1 to include '\0' terminator. */ + auto_ofs += 1 + BLI_snprintf_rlen(auto_names + auto_ofs, auto_names_len - auto_ofs, "ba%u", hash); + } + } + + uint auto_is_srgb_ofs = uv_len_used; + for (int i = 0; i < vcol_len; i++) { + if ((cd_lused[CD_MLOOPCOL] & (1 << i)) != 0) { + const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i); + /* We only do vcols that are not overridden by a uv layer with same name. */ + if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, name) == -1) { + uint hash = BLI_ghashutil_strhash_p(name); + /* +1 to include '\0' terminator. */ + auto_ofs += 1 + BLI_snprintf_rlen(auto_names + auto_ofs, auto_names_len - auto_ofs, "ba%u", hash); + auto_is_srgb[auto_is_srgb_ofs] = true; + auto_is_srgb_ofs++; + } + } + } + + auto_names = MEM_reallocN(auto_names, sizeof(char) * auto_ofs); + auto_is_srgb = MEM_reallocN(auto_is_srgb, sizeof(int) * auto_is_srgb_ofs); + + *r_auto_layers_names = auto_names; + *r_auto_layers_srgb = auto_is_srgb; + *r_auto_layers_len = auto_is_srgb_ofs; +} /** * TODO(campbell): 'gpumat_array' may include materials linked to the object. @@ -424,8 +549,7 @@ static void mesh_render_calc_normals_loop_and_poly(const Mesh *me, const float s * Although this only impacts the data that's generated, not the materials that display. */ static MeshRenderData *mesh_render_data_create_ex( - Mesh *me, const int types, - struct GPUMaterial **gpumat_array, uint gpumat_array_len) + Mesh *me, const int types, const uchar cd_vused[CD_NUMTYPES], const ushort cd_lused[CD_NUMTYPES]) { MeshRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__); rdata->types = types; @@ -539,8 +663,9 @@ static MeshRenderData *mesh_render_data_create_ex( rdata->tri_len = tottri; } - if (types & MR_DATATYPE_OVERLAY) { - rdata->loose_vert_len = rdata->loose_edge_len = 0; + if (types & MR_DATATYPE_LOOSE_VERT) { + BLI_assert(types & MR_DATATYPE_VERT); + rdata->loose_vert_len = 0; { int *lverts = MEM_mallocN(rdata->vert_len * sizeof(int), __func__); @@ -557,24 +682,9 @@ static MeshRenderData *mesh_render_data_create_ex( rdata->loose_verts = MEM_reallocN(lverts, rdata->loose_vert_len * sizeof(int)); } - { - int *ledges = MEM_mallocN(rdata->edge_len * sizeof(int), __func__); - BLI_assert((bm->elem_table_dirty & BM_EDGE) == 0); - for (int i = 0; i < bm->totedge; i++) { - const BMEdge *eed = BM_edge_at_index(bm, i); - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - /* Loose edge */ - if (eed->l == NULL || !bm_edge_has_visible_face(eed)) { - ledges[rdata->loose_edge_len++] = i; - } - } - } - rdata->loose_edges = MEM_reallocN(ledges, rdata->loose_edge_len * sizeof(int)); - } - if (rdata->mapped.supported) { Mesh *me_cage = embm->mesh_eval_cage; - rdata->mapped.loose_vert_len = rdata->mapped.loose_edge_len = 0; + rdata->mapped.loose_vert_len = 0; if (rdata->loose_vert_len) { int *lverts = MEM_mallocN(me_cage->totvert * sizeof(int), __func__); @@ -593,6 +703,31 @@ static MeshRenderData *mesh_render_data_create_ex( } rdata->mapped.loose_verts = MEM_reallocN(lverts, rdata->mapped.loose_vert_len * sizeof(int)); } + } + } + + if (types & MR_DATATYPE_LOOSE_EDGE) { + BLI_assert(types & MR_DATATYPE_EDGE); + rdata->loose_edge_len = 0; + + { + int *ledges = MEM_mallocN(rdata->edge_len * sizeof(int), __func__); + BLI_assert((bm->elem_table_dirty & BM_EDGE) == 0); + for (int i = 0; i < bm->totedge; i++) { + const BMEdge *eed = BM_edge_at_index(bm, i); + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + /* Loose edge */ + if (eed->l == NULL || !bm_edge_has_visible_face(eed)) { + ledges[rdata->loose_edge_len++] = i; + } + } + } + rdata->loose_edges = MEM_reallocN(ledges, rdata->loose_edge_len * sizeof(int)); + } + + if (rdata->mapped.supported) { + Mesh *me_cage = embm->mesh_eval_cage; + rdata->mapped.loose_edge_len = 0; if (rdata->loose_edge_len) { int *ledges = MEM_mallocN(me_cage->totedge * sizeof(int), __func__); @@ -615,6 +750,8 @@ static MeshRenderData *mesh_render_data_create_ex( } } else { + rdata->me = me; + if (types & (MR_DATATYPE_VERT)) { rdata->vert_len = me->totvert; rdata->mvert = CustomData_get_layer(&me->vdata, CD_MVERT); @@ -658,6 +795,8 @@ static MeshRenderData *mesh_render_data_create_ex( if (types & MR_DATATYPE_SHADING) { CustomData *cd_vdata, *cd_ldata; + BLI_assert(cd_vused != NULL && cd_lused != NULL); + if (me->edit_btmesh) { BMesh *bm = me->edit_btmesh->bm; cd_vdata = &bm->vdata; @@ -668,16 +807,6 @@ static MeshRenderData *mesh_render_data_create_ex( cd_ldata = &me->ldata; } - /* Add edge/poly if we need them */ - uchar cd_vused[CD_NUMTYPES] = {0}; - ushort cd_lused[CD_NUMTYPES] = {0}; - - mesh_cd_calc_used_gpu_layers( - cd_vdata, cd_vused, - cd_ldata, cd_lused, - gpumat_array, gpumat_array_len); - - rdata->cd.layers.uv_active = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); rdata->cd.layers.vcol_active = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL); rdata->cd.layers.tangent_active = rdata->cd.layers.uv_active; @@ -942,6 +1071,21 @@ static MeshRenderData *mesh_render_data_create_ex( return rdata; } +/* Warning replace mesh pointer. */ +#define MBC_GET_FINAL_MESH(me) \ + /* Hack to show the final result. */ \ + const bool _use_em_final = ( \ + (me)->edit_btmesh && \ + (me)->edit_btmesh->mesh_eval_final && \ + ((me)->edit_btmesh->mesh_eval_final->runtime.is_original == false)); \ + Mesh _me_fake; \ + if (_use_em_final) { \ + _me_fake = *(me)->edit_btmesh->mesh_eval_final; \ + _me_fake.mat = (me)->mat; \ + _me_fake.totcol = (me)->totcol; \ + (me) = &_me_fake; \ + } ((void)0) + static void mesh_render_data_free(MeshRenderData *rdata) { if (rdata->is_orco_allocated) { @@ -967,6 +1111,7 @@ static void mesh_render_data_free(MeshRenderData *rdata) MEM_SAFE_FREE(rdata->vert_normals_pack); MEM_SAFE_FREE(rdata->vert_weight); MEM_SAFE_FREE(rdata->edge_select_bool); + MEM_SAFE_FREE(rdata->edge_visible_bool); MEM_SAFE_FREE(rdata->vert_color); MEM_SAFE_FREE(rdata->mapped.loose_verts); @@ -979,12 +1124,11 @@ static void mesh_render_data_free(MeshRenderData *rdata) static MeshRenderData *mesh_render_data_create(Mesh *me, const int types) { - return mesh_render_data_create_ex(me, types, NULL, 0); + return mesh_render_data_create_ex(me, types, NULL, NULL); } /** \} */ - /* ---------------------------------------------------------------------- */ /** \name Accessor Functions @@ -1075,7 +1219,7 @@ static int mesh_render_data_looptri_len_get_maybe_mapped(const MeshRenderData *r return ((rdata->mapped.use == false) ? rdata->tri_len : rdata->mapped.tri_len); } -static int mesh_render_data_mat_len_get(const MeshRenderData *rdata) +static int UNUSED_FUNCTION(mesh_render_data_mat_len_get)(const MeshRenderData *rdata) { BLI_assert(rdata->types & MR_DATATYPE_POLY); return rdata->mat_len; @@ -1103,6 +1247,9 @@ static int mesh_render_data_polys_len_get_maybe_mapped(const MeshRenderData *rda /* ---------------------------------------------------------------------- */ +/* TODO remove prototype. */ +static void mesh_create_edit_facedots(MeshRenderData *rdata, GPUVertBuf *vbo_pos_nor_data_facedots); + /** \name Internal Cache (Lazy Initialization) * \{ */ @@ -1174,7 +1321,7 @@ static void mesh_render_data_ensure_vert_normals_pack(MeshRenderData *rdata) /** Ensure #MeshRenderData.vert_color */ -static void mesh_render_data_ensure_vert_color(MeshRenderData *rdata) +static void UNUSED_FUNCTION(mesh_render_data_ensure_vert_color)(MeshRenderData *rdata) { char (*vcol)[3] = rdata->vert_color; if (vcol == NULL) { @@ -1230,7 +1377,7 @@ fallback: } } -static float evaluate_vertex_weight(const MDeformVert *dvert, const struct DRW_MeshWeightState *wstate) +static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate) { float input = 0.0f; bool show_alert_color = false; @@ -1322,34 +1469,6 @@ fallback: } } - -/** Ensure #MeshRenderData.edge_select_bool */ -static void mesh_render_data_ensure_edge_select_bool(MeshRenderData *rdata, bool use_wire) -{ - bool *edge_select_bool = rdata->edge_select_bool; - if (edge_select_bool == NULL) { - edge_select_bool = rdata->edge_select_bool = - MEM_callocN(sizeof(*edge_select_bool) * rdata->edge_len, __func__); - - for (int i = 0; i < rdata->poly_len; i++) { - const MPoly *poly = &rdata->mpoly[i]; - - if (poly->flag & ME_FACE_SEL) { - for (int j = 0; j < poly->totloop; j++) { - const MLoop *loop = &rdata->mloop[poly->loopstart + j]; - if (use_wire) { - edge_select_bool[loop->e] = true; - } - else { - /* Not totally correct, will cause problems for edges with 3x faces. */ - edge_select_bool[loop->e] = !edge_select_bool[loop->e]; - } - } - } - } - } -} - /** \} */ /* ---------------------------------------------------------------------- */ @@ -1357,75 +1476,6 @@ static void mesh_render_data_ensure_edge_select_bool(MeshRenderData *rdata, bool /** \name Internal Cache Generation * \{ */ -static bool mesh_render_data_pnors_pcenter_select_get( - MeshRenderData *rdata, const int poly, - float r_pnors[3], float r_center[3], bool *r_selected) -{ - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); - - if (rdata->edit_bmesh) { - const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, poly); - if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - return false; - } - if (rdata->edit_data && rdata->edit_data->vertexCos) { - copy_v3_v3(r_center, rdata->edit_data->polyCos[poly]); - copy_v3_v3(r_pnors, rdata->edit_data->polyNos[poly]); - } - else { - BM_face_calc_center_mean(efa, r_center); - copy_v3_v3(r_pnors, efa->no); - } - *r_selected = (BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0) ? true : false; - } - else { - MVert *mvert = rdata->mvert; - const MPoly *mpoly = rdata->mpoly + poly; - const MLoop *mloop = rdata->mloop + mpoly->loopstart; - - BKE_mesh_calc_poly_center(mpoly, mloop, mvert, r_center); - BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, r_pnors); - - *r_selected = false; /* No selection if not in edit mode */ - } - - return true; -} -static bool mesh_render_data_pnors_pcenter_select_get_mapped( - MeshRenderData *rdata, const int poly, - float r_pnors[3], float r_center[3], bool *r_selected) -{ - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); - const int *p_origindex = rdata->mapped.p_origindex; - const int p_orig = p_origindex[poly]; - if (p_orig == ORIGINDEX_NONE) { - return false; - } - BMEditMesh *em = rdata->edit_bmesh; - const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, p_orig); - if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - return false; - } - - Mesh *me_cage = em->mesh_eval_cage; - const MVert *mvert = me_cage->mvert; -#if 0 - const MEdge *medge = me_cage->medge; -#endif - const MLoop *mloop = me_cage->mloop; - const MPoly *mpoly = me_cage->mpoly; - - const MPoly *mp = mpoly + poly; - const MLoop *ml = mloop + mp->loopstart; - - BKE_mesh_calc_poly_center(mp, ml, mvert, r_center); - BKE_mesh_calc_poly_normal(mp, ml, mvert, r_pnors); - - *r_selected = (BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0) ? true : false; - - return true; -} - static bool mesh_render_data_edge_vcos_manifold_pnors( MeshRenderData *rdata, const int edge_index, float **r_vco1, float **r_vco2, float **r_pnor1, float **r_pnor2, bool *r_is_manifold) @@ -1613,46 +1663,52 @@ static uchar mesh_render_data_vertex_flag(MeshRenderData *rdata, const BMVert *e return vflag; } -static void add_overlay_tri( - MeshRenderData *rdata, GPUVertBuf *vbo_pos, GPUVertBuf *vbo_nor, GPUVertBuf *vbo_data, GPUIndexBufBuilder *elb, +static void add_edit_tri( + MeshRenderData *rdata, GPUVertBuf *vbo_pos_nor, GPUVertBuf *vbo_lnor, GPUVertBuf *vbo_data, GPUIndexBufBuilder *elb, const uint pos_id, const uint vnor_id, const uint lnor_id, const uint data_id, const BMLoop **bm_looptri, const int base_vert_idx) { uchar fflag; uchar vflag; - for (int i = 0; i < 3; ++i) { - if (!BM_elem_flag_test(bm_looptri[i]->v, BM_ELEM_TAG)) { - BM_elem_flag_enable(bm_looptri[i]->v, BM_ELEM_TAG); - GPU_indexbuf_add_generic_vert(elb, base_vert_idx + i); + /* Only draw vertices once. */ + if (elb) { + for (int i = 0; i < 3; ++i) { + if (!BM_elem_flag_test(bm_looptri[i]->v, BM_ELEM_TAG)) { + BM_elem_flag_enable(bm_looptri[i]->v, BM_ELEM_TAG); + GPU_indexbuf_add_generic_vert(elb, base_vert_idx + i); + } } } - if (vbo_pos) { + if (vbo_pos_nor) { /* TODO(sybren): deduplicate this and all the other places it's pasted to in this file. */ if (rdata->edit_data && rdata->edit_data->vertexCos) { for (uint i = 0; i < 3; i++) { int vidx = BM_elem_index_get(bm_looptri[i]->v); const float *pos = rdata->edit_data->vertexCos[vidx]; - GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos); + GPU_vertbuf_attr_set(vbo_pos_nor, pos_id, base_vert_idx + i, pos); } } else { for (uint i = 0; i < 3; i++) { const float *pos = bm_looptri[i]->v->co; - GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos); + GPU_vertbuf_attr_set(vbo_pos_nor, pos_id, base_vert_idx + i, pos); } } + + for (uint i = 0; i < 3; i++) { + GPUPackedNormal vnor = GPU_normal_convert_i10_v3(bm_looptri[i]->v->no); + GPU_vertbuf_attr_set(vbo_pos_nor, vnor_id, base_vert_idx + i, &vnor); + } } - if (vbo_nor) { + if (vbo_lnor) { float (*lnors)[3] = rdata->loop_normals; for (uint i = 0; i < 3; i++) { const float *nor = (lnors) ? lnors[BM_elem_index_get(bm_looptri[i])] : bm_looptri[0]->f->no; GPUPackedNormal lnor = GPU_normal_convert_i10_v3(nor); - GPU_vertbuf_attr_set(vbo_nor, lnor_id, base_vert_idx + i, &lnor); - GPUPackedNormal vnor = GPU_normal_convert_i10_v3(bm_looptri[i]->v->no); - GPU_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx + i, &vnor); + GPU_vertbuf_attr_set(vbo_lnor, lnor_id, base_vert_idx + i, &lnor); } } @@ -1673,11 +1729,15 @@ static void add_overlay_tri( } } } -static void add_overlay_tri_mapped( - MeshRenderData *rdata, GPUVertBuf *vbo_pos, GPUVertBuf *vbo_nor, GPUVertBuf *vbo_data, GPUIndexBufBuilder *elb, +static bool add_edit_tri_mapped( + MeshRenderData *rdata, GPUVertBuf *vbo_pos_nor, GPUVertBuf *vbo_lnor, GPUVertBuf *vbo_data, GPUIndexBufBuilder *elb, const uint pos_id, const uint vnor_id, const uint lnor_id, const uint data_id, - BMFace *efa, const MLoopTri *mlt, const float poly_normal[3], const int base_vert_idx) + BMFace *efa, const MLoopTri *mlt, const float (*poly_normals)[3], const float (*loop_normals)[3], const int base_vert_idx) { + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + return false; + } + BMEditMesh *embm = rdata->edit_bmesh; BMesh *bm = embm->bm; Mesh *me_cage = embm->mesh_eval_cage; @@ -1685,19 +1745,9 @@ static void add_overlay_tri_mapped( const MVert *mvert = me_cage->mvert; const MEdge *medge = me_cage->medge; const MLoop *mloop = me_cage->mloop; -#if 0 - const MPoly *mpoly = me_cage->mpoly; -#endif const int *v_origindex = rdata->mapped.v_origindex; const int *e_origindex = rdata->mapped.e_origindex; -#if 0 - const int *l_origindex = rdata->mapped.l_origindex; - const int *p_origindex = rdata->mapped.p_origindex; -#endif - - uchar fflag; - uchar vflag; if (elb) { for (int i = 0; i < 3; ++i) { @@ -1713,40 +1763,35 @@ static void add_overlay_tri_mapped( } } - if (vbo_pos) { + if (vbo_pos_nor) { for (uint i = 0; i < 3; i++) { const float *pos = mvert[mloop[mlt->tri[i]].v].co; - GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos); + GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[mloop[mlt->tri[i]].v].no); + GPU_vertbuf_attr_set(vbo_pos_nor, pos_id, base_vert_idx + i, pos); + GPU_vertbuf_attr_set(vbo_pos_nor, vnor_id, base_vert_idx + i, &vnor); } } - if (vbo_nor) { - float (*lnors)[3] = rdata->loop_normals; + if (vbo_lnor) { for (uint i = 0; i < 3; i++) { - const float *nor = (lnors) ? lnors[mlt->tri[i]] : poly_normal; + const float *nor = loop_normals ? loop_normals[mlt->tri[i]] : poly_normals[mlt->poly]; GPUPackedNormal lnor = GPU_normal_convert_i10_v3(nor); - GPU_vertbuf_attr_set(vbo_nor, lnor_id, base_vert_idx + i, &lnor); - GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[mloop[mlt->tri[i]].v].no); - GPU_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx + i, &vnor); + GPU_vertbuf_attr_set(vbo_lnor, lnor_id, base_vert_idx + i, &lnor); } } if (vbo_data) { - fflag = mesh_render_data_looptri_flag(rdata, efa); + EdgeDrawAttr eattr[3] = {{0}}; /* Importantly VFLAG_VERTEX_EXISTS is not set. */ + uchar fflag = mesh_render_data_looptri_flag(rdata, efa); for (uint i = 0; i < 3; i++) { const int i_next = (i + 1) % 3; const int i_prev = (i + 2) % 3; const int v_orig = v_origindex[mloop[mlt->tri[i]].v]; if (v_orig != ORIGINDEX_NONE) { BMVert *v = BM_vert_at_index(bm, v_orig); - vflag = mesh_render_data_vertex_flag(rdata, v); - } - else { - /* Importantly VFLAG_VERTEX_EXISTS is not set. */ - vflag = 0; + eattr[i].v_flag |= mesh_render_data_vertex_flag(rdata, v); } /* Opposite edge to the vertex at 'i'. */ - EdgeDrawAttr eattr = {0}; const int e_idx = mloop[mlt->tri[i_next]].e; const int e_orig = e_origindex[e_idx]; if (e_orig != ORIGINDEX_NONE) { @@ -1757,41 +1802,50 @@ static void add_overlay_tri_mapped( ((ed->v1 == tri_edge[1]) && (ed->v2 == tri_edge[0]))); if (is_edge_real) { BMEdge *eed = BM_edge_at_index(bm, e_orig); - mesh_render_data_edge_flag(rdata, eed, &eattr); + mesh_render_data_edge_flag(rdata, eed, &eattr[i]); + /* Set vertex selected if both original verts are selected. */ + if (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) && + BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) + { + eattr[i_next].v_flag |= VFLAG_VERTEX_SELECTED; + eattr[i_prev].v_flag |= VFLAG_VERTEX_SELECTED; + } } } - eattr.v_flag = fflag | vflag; - GPU_vertbuf_attr_set(vbo_data, data_id, base_vert_idx + i, &eattr); + } + for (uint i = 0; i < 3; i++) { + eattr[i].v_flag |= fflag; + GPU_vertbuf_attr_set(vbo_data, data_id, base_vert_idx + i, &eattr[i]); } } + + return true; } -static void add_overlay_loose_edge( - MeshRenderData *rdata, GPUVertBuf *vbo_pos, GPUVertBuf *vbo_nor, GPUVertBuf *vbo_data, +static void add_edit_loose_edge( + MeshRenderData *rdata, GPUVertBuf *vbo_pos_nor, GPUVertBuf *vbo_data, const uint pos_id, const uint vnor_id, const uint data_id, const BMEdge *eed, const int base_vert_idx) { - if (vbo_pos) { + if (vbo_pos_nor) { /* TODO(sybren): deduplicate this and all the other places it's pasted to in this file. */ if (rdata->edit_data && rdata->edit_data->vertexCos) { for (uint i = 0; i < 2; i++) { int vidx = BM_elem_index_get((&eed->v1)[i]); const float *pos = rdata->edit_data->vertexCos[vidx]; - GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos); + GPU_vertbuf_attr_set(vbo_pos_nor, pos_id, base_vert_idx + i, pos); } } else { for (int i = 0; i < 2; i++) { const float *pos = (&eed->v1)[i]->co; - GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos); + GPU_vertbuf_attr_set(vbo_pos_nor, pos_id, base_vert_idx + i, pos); } } - } - if (vbo_nor) { for (int i = 0; i < 2; i++) { GPUPackedNormal vnor = GPU_normal_convert_i10_v3((&eed->v1)[i]->no); - GPU_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx + i, &vnor); + GPU_vertbuf_attr_set(vbo_pos_nor, vnor_id, base_vert_idx + i, &vnor); } } @@ -1804,23 +1858,19 @@ static void add_overlay_loose_edge( } } } -static void add_overlay_loose_edge_mapped( - MeshRenderData *rdata, GPUVertBuf *vbo_pos, GPUVertBuf *vbo_nor, GPUVertBuf *vbo_data, +static void add_edit_loose_edge_mapped( + MeshRenderData *rdata, GPUVertBuf *vbo_pos_nor, GPUVertBuf *vbo_data, const uint pos_id, const uint vnor_id, const uint data_id, BMEdge *eed, const MVert *mvert, const MEdge *ed, const int base_vert_idx) { - if (vbo_pos) { + if (vbo_pos_nor) { /* TODO(sybren): deduplicate this and all the other places it's pasted to in this file. */ for (int i = 0; i < 2; i++) { const float *pos = mvert[*(&ed->v1 + i)].co; - GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos); - } - } + GPU_vertbuf_attr_set(vbo_pos_nor, pos_id, base_vert_idx + i, pos); - if (vbo_nor) { - for (int i = 0; i < 2; i++) { GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[*(&ed->v1 + i)].no); - GPU_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx + i, &vnor); + GPU_vertbuf_attr_set(vbo_pos_nor, vnor_id, base_vert_idx + i, &vnor); } } @@ -1835,27 +1885,25 @@ static void add_overlay_loose_edge_mapped( } } -static void add_overlay_loose_vert( - MeshRenderData *rdata, GPUVertBuf *vbo_pos, GPUVertBuf *vbo_nor, GPUVertBuf *vbo_data, +static void add_edit_loose_vert( + MeshRenderData *rdata, GPUVertBuf *vbo_pos_nor, GPUVertBuf *vbo_data, const uint pos_id, const uint vnor_id, const uint data_id, const BMVert *eve, const int base_vert_idx) { - if (vbo_pos) { + if (vbo_pos_nor) { /* TODO(sybren): deduplicate this and all the other places it's pasted to in this file. */ if (rdata->edit_data && rdata->edit_data->vertexCos) { int vidx = BM_elem_index_get(eve); const float *pos = rdata->edit_data->vertexCos[vidx]; - GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx, pos); + GPU_vertbuf_attr_set(vbo_pos_nor, pos_id, base_vert_idx, pos); } else { const float *pos = eve->co; - GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx, pos); + GPU_vertbuf_attr_set(vbo_pos_nor, pos_id, base_vert_idx, pos); } - } - if (vbo_nor) { GPUPackedNormal vnor = GPU_normal_convert_i10_v3(eve->no); - GPU_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx, &vnor); + GPU_vertbuf_attr_set(vbo_pos_nor, vnor_id, base_vert_idx, &vnor); } if (vbo_data) { @@ -1864,19 +1912,17 @@ static void add_overlay_loose_vert( GPU_vertbuf_attr_set(vbo_data, data_id, base_vert_idx, vflag); } } -static void add_overlay_loose_vert_mapped( - MeshRenderData *rdata, GPUVertBuf *vbo_pos, GPUVertBuf *vbo_nor, GPUVertBuf *vbo_data, +static void add_edit_loose_vert_mapped( + MeshRenderData *rdata, GPUVertBuf *vbo_pos_nor, GPUVertBuf *vbo_data, const uint pos_id, const uint vnor_id, const uint data_id, const BMVert *eve, const MVert *mv, const int base_vert_idx) { - if (vbo_pos) { + if (vbo_pos_nor) { const float *pos = mv->co; - GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx, pos); - } + GPU_vertbuf_attr_set(vbo_pos_nor, pos_id, base_vert_idx, pos); - if (vbo_nor) { GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mv->no); - GPU_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx, &vnor); + GPU_vertbuf_attr_set(vbo_pos_nor, vnor_id, base_vert_idx, &vnor); } if (vbo_data) { @@ -1886,6 +1932,84 @@ static void add_overlay_loose_vert_mapped( } } +static bool add_edit_facedot( + MeshRenderData *rdata, GPUVertBuf *vbo, + const uint fdot_pos_id, const uint fdot_nor_flag_id, + const int poly, const int base_vert_idx) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); + float pnor[3], center[3]; + bool selected; + if (rdata->edit_bmesh) { + const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, poly); + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + return false; + } + if (rdata->edit_data && rdata->edit_data->vertexCos) { + copy_v3_v3(center, rdata->edit_data->polyCos[poly]); + copy_v3_v3(pnor, rdata->edit_data->polyNos[poly]); + } + else { + BM_face_calc_center_median(efa, center); + copy_v3_v3(pnor, efa->no); + } + selected = (BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0) ? true : false; + } + else { + MVert *mvert = rdata->mvert; + const MPoly *mpoly = rdata->mpoly + poly; + const MLoop *mloop = rdata->mloop + mpoly->loopstart; + + BKE_mesh_calc_poly_center(mpoly, mloop, mvert, center); + BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, pnor); + + selected = false; /* No selection if not in edit mode */ + } + + GPUPackedNormal nor = GPU_normal_convert_i10_v3(pnor); + nor.w = (selected) ? 1 : 0; + GPU_vertbuf_attr_set(vbo, fdot_nor_flag_id, base_vert_idx, &nor); + GPU_vertbuf_attr_set(vbo, fdot_pos_id, base_vert_idx, center); + + return true; +} +static bool add_edit_facedot_mapped( + MeshRenderData *rdata, GPUVertBuf *vbo, + const uint fdot_pos_id, const uint fdot_nor_flag_id, + const int poly, const int base_vert_idx) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); + float pnor[3], center[3]; + const int *p_origindex = rdata->mapped.p_origindex; + const int p_orig = p_origindex[poly]; + if (p_orig == ORIGINDEX_NONE) { + return false; + } + BMEditMesh *em = rdata->edit_bmesh; + const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, p_orig); + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + return false; + } + + Mesh *me_cage = em->mesh_eval_cage; + const MVert *mvert = me_cage->mvert; + const MLoop *mloop = me_cage->mloop; + const MPoly *mpoly = me_cage->mpoly; + + const MPoly *mp = mpoly + poly; + const MLoop *ml = mloop + mp->loopstart; + + BKE_mesh_calc_poly_center(mp, ml, mvert, center); + BKE_mesh_calc_poly_normal(mp, ml, mvert, pnor); + + GPUPackedNormal nor = GPU_normal_convert_i10_v3(pnor); + nor.w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0) ? 1 : 0; + GPU_vertbuf_attr_set(vbo, fdot_nor_flag_id, base_vert_idx, &nor); + GPU_vertbuf_attr_set(vbo, fdot_pos_id, base_vert_idx, center); + + return true; +} + /** \} */ /* ---------------------------------------------------------------------- */ @@ -1894,7 +2018,7 @@ static void add_overlay_loose_vert_mapped( * \{ */ /** Reset the selection structure, deallocating heap memory as appropriate. */ -void DRW_mesh_weight_state_clear(struct DRW_MeshWeightState *wstate) +static void drw_mesh_weight_state_clear(struct DRW_MeshWeightState *wstate) { MEM_SAFE_FREE(wstate->defgroup_sel); @@ -1904,7 +2028,8 @@ void DRW_mesh_weight_state_clear(struct DRW_MeshWeightState *wstate) } /** Copy selection data from one structure to another, including heap memory. */ -void DRW_mesh_weight_state_copy(struct DRW_MeshWeightState *wstate_dst, const struct DRW_MeshWeightState *wstate_src) +static void drw_mesh_weight_state_copy( + struct DRW_MeshWeightState *wstate_dst, const struct DRW_MeshWeightState *wstate_src) { MEM_SAFE_FREE(wstate_dst->defgroup_sel); @@ -1916,7 +2041,7 @@ void DRW_mesh_weight_state_copy(struct DRW_MeshWeightState *wstate_dst, const st } /** Compare two selection structures. */ -bool DRW_mesh_weight_state_compare(const struct DRW_MeshWeightState *a, const struct DRW_MeshWeightState *b) +static bool drw_mesh_weight_state_compare(const struct DRW_MeshWeightState *a, const struct DRW_MeshWeightState *b) { return a->defgroup_active == b->defgroup_active && a->defgroup_len == b->defgroup_len && @@ -1928,6 +2053,39 @@ bool DRW_mesh_weight_state_compare(const struct DRW_MeshWeightState *a, const st memcmp(a->defgroup_sel, b->defgroup_sel, a->defgroup_len * sizeof(bool)) == 0)); } +static void drw_mesh_weight_state_extract( + Object *ob, Mesh *me, ToolSettings *ts, bool paint_mode, + struct DRW_MeshWeightState *wstate) +{ + /* Extract complete vertex weight group selection state and mode flags. */ + memset(wstate, 0, sizeof(*wstate)); + + wstate->defgroup_active = ob->actdef - 1; + wstate->defgroup_len = BLI_listbase_count(&ob->defbase); + + wstate->alert_mode = ts->weightuser; + + if (paint_mode && ts->multipaint) { + /* Multipaint needs to know all selected bones, not just the active group. + * This is actually a relatively expensive operation, but caching would be difficult. */ + wstate->defgroup_sel = BKE_object_defgroup_selected_get(ob, wstate->defgroup_len, &wstate->defgroup_sel_count); + + if (wstate->defgroup_sel_count > 1) { + wstate->flags |= DRW_MESH_WEIGHT_STATE_MULTIPAINT | (ts->auto_normalize ? DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE : 0); + + if (me->editflag & ME_EDIT_MIRROR_X) { + BKE_object_defgroup_mirror_selection( + ob, wstate->defgroup_len, wstate->defgroup_sel, wstate->defgroup_sel, &wstate->defgroup_sel_count); + } + } + /* With only one selected bone Multipaint reverts to regular mode. */ + else { + wstate->defgroup_sel_count = 0; + MEM_SAFE_FREE(wstate->defgroup_sel); + } + } +} + /** \} */ /* ---------------------------------------------------------------------- */ @@ -1936,19 +2094,89 @@ bool DRW_mesh_weight_state_compare(const struct DRW_MeshWeightState *a, const st * \{ */ typedef struct MeshBatchCache { - GPUVertBuf *pos_in_order; + /* In order buffers: All verts only specified once. + * To be used with a GPUIndexBuf. */ + struct { + /* Vertex data. */ + GPUVertBuf *pos_nor; + GPUVertBuf *weights; + /* Loop data. */ + GPUVertBuf *loop_pos_nor; + GPUVertBuf *loop_uv_tan; + GPUVertBuf *loop_vcol; + } ordered; + + /* Tesselated: (all verts specified for each triangles). + * Indices does not match the CPU data structure's. */ + struct { + GPUVertBuf *pos_nor; + + GPUVertBuf *wireframe_data; + } tess; + + /* Edit Mesh Data: + * Data is also tesselated because of barycentric wireframe rendering. */ + struct { + GPUVertBuf *pos_nor; + GPUVertBuf *pos_nor_ledges; + GPUVertBuf *pos_nor_lverts; + GPUVertBuf *pos_nor_data_facedots; + GPUVertBuf *data; + GPUVertBuf *data_ledges; + GPUVertBuf *data_lverts; + GPUVertBuf *lnor; + } edit; + + /* Index Buffers: + * Only need to be updated when topology changes. */ + struct { + /* Indices to verts. */ + GPUIndexBuf *surf_tris; + /* Indices to vloops. */ + GPUIndexBuf *loops_tris; + GPUIndexBuf *loops_lines; + /* Contains indices to unique edit vertices to not + * draw the same vert multiple times (because of tesselation). */ + GPUIndexBuf *edit_verts_points; + } ibo; + + struct { + /* Surfaces / Render */ + GPUBatch *surface; + GPUBatch *surface_weights; + /* Edit mode */ + GPUBatch *edit_triangles; + GPUBatch *edit_vertices; + GPUBatch *edit_loose_edges; + GPUBatch *edit_loose_verts; + GPUBatch *edit_triangles_nor; + GPUBatch *edit_triangles_lnor; + GPUBatch *edit_loose_edges_nor; + GPUBatch *edit_facedots; + /* Common display / Other */ + GPUBatch *all_verts; + GPUBatch *wire_loops; /* Loops around faces. */ + GPUBatch *wire_triangles; /* Triangles for object mode wireframe. */ + } batch; + + GPUIndexBuf **surf_per_mat_tris; + GPUBatch **surf_per_mat; + + /* OLD BATCH METHOD, thoses needs to be ported and added in the structs above. */ + + /* Indices buffers. */ GPUIndexBuf *edges_in_order; GPUIndexBuf *edges_adjacency; /* Store edges with adjacent vertices. */ GPUIndexBuf *triangles_in_order; GPUIndexBuf *ledges_in_order; - GPUTexture *pos_in_order_tx; /* Depending on pos_in_order */ - - GPUBatch *all_verts; GPUBatch *all_edges; GPUBatch *all_triangles; GPUVertBuf *pos_with_normals; + GPUVertBuf *pos_with_normals_visible_only; + GPUVertBuf *pos_with_normals_edit; + GPUVertBuf *pos_with_normals_visible_only_edit; GPUVertBuf *tri_aligned_uv; /* Active UV layer (mloopuv) */ /** @@ -1970,7 +2198,7 @@ typedef struct MeshBatchCache { GPUBatch *triangles_with_select_id; uint triangles_with_select_id_offset; - GPUBatch *facedot_with_select_id; /* shares vbo with 'overlay_facedots' */ + GPUBatch *facedot_with_select_id; /* shares vbo with 'edit_facedots' */ GPUBatch *edges_with_select_id; GPUBatch *verts_with_select_id; @@ -1983,45 +2211,11 @@ typedef struct MeshBatchCache { GPUBatch *edge_detection; - GPUVertBuf *edges_face_overlay; - GPUTexture *edges_face_overlay_tx; - int edges_face_overlay_tri_count; /* Number of tri in edges_face_overlay(_adj)_tx */ - - /* Maybe have shaded_triangles_data split into pos_nor and uv_tangent - * to minimize data transfer for skinned mesh. */ - GPUVertFormat shaded_triangles_format; - GPUVertBuf *shaded_triangles_data; - GPUIndexBuf **shaded_triangles_in_order; - GPUBatch **shaded_triangles; - /* Texture Paint.*/ /* per-texture batch */ GPUBatch **texpaint_triangles; GPUBatch *texpaint_triangles_single; - /* Edit Cage Mesh buffers */ - GPUVertBuf *ed_tri_pos; - GPUVertBuf *ed_tri_nor; /* LoopNor, VertNor */ - GPUVertBuf *ed_tri_data; - GPUTexture *ed_tri_data_tx; - GPUIndexBuf *ed_tri_verts; - - GPUVertBuf *ed_ledge_pos; - GPUVertBuf *ed_ledge_nor; /* VertNor */ - GPUVertBuf *ed_ledge_data; - - GPUVertBuf *ed_lvert_pos; - GPUVertBuf *ed_lvert_nor; /* VertNor */ - GPUVertBuf *ed_lvert_data; - - GPUBatch *overlay_triangles; - GPUBatch *overlay_triangles_nor; /* GPU_PRIM_POINTS */ - GPUBatch *overlay_triangles_lnor; /* GPU_PRIM_POINTS */ - GPUBatch *overlay_loose_edges; - GPUBatch *overlay_loose_edges_nor; /* GPU_PRIM_POINTS */ - GPUBatch *overlay_loose_verts; - GPUBatch *overlay_facedots; - GPUBatch *overlay_weight_faces; GPUBatch *overlay_weight_verts; GPUBatch *overlay_paint_edges; @@ -2064,6 +2258,11 @@ typedef struct MeshBatchCache { struct DRW_MeshWeightState weight_state; + uchar cd_vused[CD_NUMTYPES]; + uchar cd_vneeded[CD_NUMTYPES]; + ushort cd_lused[CD_NUMTYPES]; + ushort cd_lneeded[CD_NUMTYPES]; + /* XXX, only keep for as long as sculpt mode uses shaded drawing. */ bool is_sculpt_points_tag; @@ -2081,9 +2280,8 @@ static bool mesh_batch_cache_valid(Mesh *me) return false; } - /* XXX find another place for this */ if (cache->mat_len != mesh_render_mat_len_get(me)) { - cache->is_maybe_dirty = true; + return false; } if (cache->is_editmode != (me->edit_btmesh != NULL)) { @@ -2135,11 +2333,19 @@ static void mesh_batch_cache_init(Mesh *me) } cache->mat_len = mesh_render_mat_len_get(me); + cache->surf_per_mat_tris = MEM_callocN(sizeof(*cache->surf_per_mat_tris) * cache->mat_len, __func__); + cache->surf_per_mat = MEM_callocN(sizeof(*cache->surf_per_mat) * cache->mat_len, __func__); + + /* TODO Might be wiser to alloc in one chunck. */ + for (int i = 0; i < cache->mat_len; ++i) { + cache->surf_per_mat_tris[i] = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf"); + cache->surf_per_mat[i] = MEM_callocN(sizeof(GPUBatch), "GPUBatch"); + } cache->is_maybe_dirty = false; cache->is_dirty = false; - DRW_mesh_weight_state_clear(&cache->weight_state); + drw_mesh_weight_state_clear(&cache->weight_state); } static MeshBatchCache *mesh_batch_cache_get(Mesh *me) @@ -2153,38 +2359,41 @@ static MeshBatchCache *mesh_batch_cache_get(Mesh *me) static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, const struct DRW_MeshWeightState *wstate) { - if (!DRW_mesh_weight_state_compare(&cache->weight_state, wstate)) { - GPU_BATCH_DISCARD_SAFE(cache->triangles_with_weights); + if (!drw_mesh_weight_state_compare(&cache->weight_state, wstate)) { + GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights); + GPU_VERTBUF_DISCARD_SAFE(cache->ordered.weights); - DRW_mesh_weight_state_clear(&cache->weight_state); + drw_mesh_weight_state_clear(&cache->weight_state); } } static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) { - GPU_VERTBUF_DISCARD_SAFE(cache->shaded_triangles_data); - if (cache->shaded_triangles_in_order) { - for (int i = 0; i < cache->mat_len; i++) { - GPU_INDEXBUF_DISCARD_SAFE(cache->shaded_triangles_in_order[i]); - } - } - if (cache->shaded_triangles) { + GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_pos_nor); + GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_uv_tan); + GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_vcol); + /* TODO */ + // GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_orco); + + if (cache->surf_per_mat_tris) { for (int i = 0; i < cache->mat_len; i++) { - GPU_BATCH_DISCARD_SAFE(cache->shaded_triangles[i]); + GPU_INDEXBUF_DISCARD_SAFE(cache->surf_per_mat_tris[i]); } } - if (cache->texpaint_triangles) { + MEM_SAFE_FREE(cache->surf_per_mat_tris); + if (cache->surf_per_mat) { for (int i = 0; i < cache->mat_len; i++) { - /* They use shaded_triangles_in_order */ - GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]); + GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]); } } - MEM_SAFE_FREE(cache->shaded_triangles_in_order); - MEM_SAFE_FREE(cache->shaded_triangles); + MEM_SAFE_FREE(cache->surf_per_mat); + MEM_SAFE_FREE(cache->texpaint_triangles); MEM_SAFE_FREE(cache->auto_layer_names); MEM_SAFE_FREE(cache->auto_layer_is_srgb); + + cache->mat_len = 0; } static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache) @@ -2241,26 +2450,34 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) cache->is_maybe_dirty = true; break; case BKE_MESH_BATCH_DIRTY_SELECT: - GPU_VERTBUF_DISCARD_SAFE(cache->ed_tri_data); - GPU_VERTBUF_DISCARD_SAFE(cache->ed_ledge_data); - GPU_VERTBUF_DISCARD_SAFE(cache->ed_lvert_data); - GPU_VERTBUF_DISCARD_SAFE(cache->ed_fcenter_pos_with_nor_and_sel); /* Contains select flag */ + GPU_VERTBUF_DISCARD_SAFE(cache->edit.data); + GPU_VERTBUF_DISCARD_SAFE(cache->edit.data_ledges); + GPU_VERTBUF_DISCARD_SAFE(cache->edit.data_lverts); + GPU_VERTBUF_DISCARD_SAFE(cache->edit.pos_nor_data_facedots); + GPU_BATCH_DISCARD_SAFE(cache->batch.edit_triangles); + GPU_BATCH_DISCARD_SAFE(cache->batch.edit_vertices); + GPU_BATCH_DISCARD_SAFE(cache->batch.edit_loose_verts); + GPU_BATCH_DISCARD_SAFE(cache->batch.edit_loose_edges); + GPU_BATCH_DISCARD_SAFE(cache->batch.edit_facedots); GPU_VERTBUF_DISCARD_SAFE(cache->ed_edge_pos); GPU_VERTBUF_DISCARD_SAFE(cache->ed_vert_pos); - GPU_INDEXBUF_DISCARD_SAFE(cache->ed_tri_verts); - DRW_TEXTURE_FREE_SAFE(cache->ed_tri_data_tx); - - GPU_BATCH_DISCARD_SAFE(cache->overlay_triangles); - GPU_BATCH_DISCARD_SAFE(cache->overlay_loose_verts); - GPU_BATCH_DISCARD_SAFE(cache->overlay_loose_edges); - GPU_BATCH_DISCARD_SAFE(cache->overlay_facedots); - GPU_BATCH_DISCARD_SAFE(cache->overlay_triangles_nor); - GPU_BATCH_DISCARD_SAFE(cache->overlay_triangles_lnor); - GPU_BATCH_DISCARD_SAFE(cache->overlay_loose_edges_nor); /* Edit mode selection. */ GPU_BATCH_DISCARD_SAFE(cache->facedot_with_select_id); GPU_BATCH_DISCARD_SAFE(cache->edges_with_select_id); GPU_BATCH_DISCARD_SAFE(cache->verts_with_select_id); + /* Paint mode selection */ + /* TODO only do that in paint mode. */ + GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_pos_nor); + GPU_BATCH_DISCARD_SAFE(cache->batch.surface); + GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops); + if (cache->surf_per_mat) { + for (int i = 0; i < cache->mat_len; i++) { + GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]); + } + } + GPU_BATCH_DISCARD_SAFE(cache->overlay_paint_edges); + GPU_BATCH_DISCARD_SAFE(cache->overlay_weight_faces); + GPU_BATCH_DISCARD_SAFE(cache->overlay_weight_verts); /* Because visible UVs depends on edit mode selection, discard everything. */ mesh_batch_cache_discard_uvedit(cache); break; @@ -2298,7 +2515,9 @@ static void mesh_batch_cache_clear_selective(Mesh *me, GPUVertBuf *vert) BLI_assert(vert != NULL); - if (cache->pos_with_normals == vert) { + if (ELEM(vert, cache->pos_with_normals, cache->pos_with_normals_visible_only, + cache->pos_with_normals_edit, cache->pos_with_normals_visible_only_edit)) + { GPU_BATCH_DISCARD_SAFE(cache->triangles_with_normals); GPU_BATCH_DISCARD_SAFE(cache->triangles_with_weights); GPU_BATCH_DISCARD_SAFE(cache->triangles_with_vert_colors); @@ -2306,17 +2525,17 @@ static void mesh_batch_cache_clear_selective(Mesh *me, GPUVertBuf *vert) GPU_BATCH_DISCARD_SAFE(cache->triangles_with_select_mask); GPU_BATCH_DISCARD_SAFE(cache->points_with_normals); GPU_BATCH_DISCARD_SAFE(cache->ledges_with_normals); - if (cache->shaded_triangles) { - for (int i = 0; i < cache->mat_len; i++) { - GPU_BATCH_DISCARD_SAFE(cache->shaded_triangles[i]); - } - } - MEM_SAFE_FREE(cache->shaded_triangles); - if (cache->texpaint_triangles) { - for (int i = 0; i < cache->mat_len; i++) { - GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]); - } - } + // if (cache->shaded_triangles) { + // for (int i = 0; i < cache->mat_len; i++) { + // GPU_BATCH_DISCARD_SAFE(cache->shaded_triangles[i]); + // } + // } + // MEM_SAFE_FREE(cache->shaded_triangles); + // if (cache->texpaint_triangles) { + // for (int i = 0; i < cache->mat_len; i++) { + // GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]); + // } + // } MEM_SAFE_FREE(cache->texpaint_triangles); GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single); } @@ -2334,43 +2553,45 @@ static void mesh_batch_cache_clear(Mesh *me) return; } - GPU_BATCH_DISCARD_SAFE(cache->all_verts); + for (int i = 0; i < sizeof(cache->ordered) / sizeof(void *); ++i) { + GPUVertBuf **vbo = (GPUVertBuf **)&cache->ordered; + GPU_VERTBUF_DISCARD_SAFE(vbo[i]); + } + for (int i = 0; i < sizeof(cache->tess) / sizeof(void *); ++i) { + GPUVertBuf **vbo = (GPUVertBuf **)&cache->tess; + GPU_VERTBUF_DISCARD_SAFE(vbo[i]); + } + for (int i = 0; i < sizeof(cache->edit) / sizeof(void *); ++i) { + GPUVertBuf **vbo = (GPUVertBuf **)&cache->edit; + GPU_VERTBUF_DISCARD_SAFE(vbo[i]); + } + for (int i = 0; i < sizeof(cache->ibo) / sizeof(void *); ++i) { + GPUIndexBuf **ibo = (GPUIndexBuf **)&cache->ibo; + GPU_INDEXBUF_DISCARD_SAFE(ibo[i]); + } + for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) { + GPUBatch **batch = (GPUBatch **)&cache->batch; + GPU_BATCH_DISCARD_SAFE(batch[i]); + } + GPU_BATCH_DISCARD_SAFE(cache->all_edges); GPU_BATCH_DISCARD_SAFE(cache->all_triangles); - GPU_VERTBUF_DISCARD_SAFE(cache->pos_in_order); - DRW_TEXTURE_FREE_SAFE(cache->pos_in_order_tx); GPU_INDEXBUF_DISCARD_SAFE(cache->edges_in_order); GPU_INDEXBUF_DISCARD_SAFE(cache->triangles_in_order); GPU_INDEXBUF_DISCARD_SAFE(cache->ledges_in_order); - GPU_VERTBUF_DISCARD_SAFE(cache->ed_tri_pos); - GPU_VERTBUF_DISCARD_SAFE(cache->ed_tri_nor); - GPU_VERTBUF_DISCARD_SAFE(cache->ed_tri_data); - GPU_VERTBUF_DISCARD_SAFE(cache->ed_ledge_pos); - GPU_VERTBUF_DISCARD_SAFE(cache->ed_ledge_nor); - GPU_VERTBUF_DISCARD_SAFE(cache->ed_ledge_data); - GPU_VERTBUF_DISCARD_SAFE(cache->ed_lvert_pos); - GPU_VERTBUF_DISCARD_SAFE(cache->ed_lvert_nor); - GPU_VERTBUF_DISCARD_SAFE(cache->ed_lvert_data); - GPU_INDEXBUF_DISCARD_SAFE(cache->ed_tri_verts); - GPU_BATCH_DISCARD_SAFE(cache->overlay_triangles); - GPU_BATCH_DISCARD_SAFE(cache->overlay_triangles_nor); - GPU_BATCH_DISCARD_SAFE(cache->overlay_triangles_lnor); - GPU_BATCH_DISCARD_SAFE(cache->overlay_loose_verts); - GPU_BATCH_DISCARD_SAFE(cache->overlay_loose_edges); - GPU_BATCH_DISCARD_SAFE(cache->overlay_loose_edges_nor); - DRW_TEXTURE_FREE_SAFE(cache->ed_tri_data_tx); - GPU_BATCH_DISCARD_SAFE(cache->overlay_weight_faces); GPU_BATCH_DISCARD_SAFE(cache->overlay_weight_verts); GPU_BATCH_DISCARD_SAFE(cache->overlay_paint_edges); - GPU_BATCH_DISCARD_SAFE(cache->overlay_facedots); GPU_BATCH_DISCARD_SAFE(cache->triangles_with_normals); GPU_BATCH_DISCARD_SAFE(cache->points_with_normals); GPU_BATCH_DISCARD_SAFE(cache->ledges_with_normals); GPU_VERTBUF_DISCARD_SAFE(cache->pos_with_normals); + GPU_VERTBUF_DISCARD_SAFE(cache->pos_with_normals_visible_only); + GPU_VERTBUF_DISCARD_SAFE(cache->pos_with_normals_edit); + GPU_VERTBUF_DISCARD_SAFE(cache->pos_with_normals_visible_only_edit); GPU_BATCH_DISCARD_SAFE(cache->triangles_with_weights); GPU_BATCH_DISCARD_SAFE(cache->triangles_with_vert_colors); GPU_VERTBUF_DISCARD_SAFE(cache->tri_aligned_uv); @@ -2388,9 +2609,6 @@ static void mesh_batch_cache_clear(Mesh *me) GPU_INDEXBUF_DISCARD_SAFE(cache->edges_adjacency); GPU_BATCH_DISCARD_SAFE(cache->edge_detection); - GPU_VERTBUF_DISCARD_SAFE(cache->edges_face_overlay); - DRW_TEXTURE_FREE_SAFE(cache->edges_face_overlay_tx); - mesh_batch_cache_discard_shaded_tri(cache); mesh_batch_cache_discard_uvedit(cache); @@ -2402,9 +2620,7 @@ static void mesh_batch_cache_clear(Mesh *me) } MEM_SAFE_FREE(cache->texpaint_triangles); - GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single); - - DRW_mesh_weight_state_clear(&cache->weight_state); + drw_mesh_weight_state_clear(&cache->weight_state); } void DRW_mesh_batch_cache_free(Mesh *me) @@ -2415,408 +2631,164 @@ void DRW_mesh_batch_cache_free(Mesh *me) /* GPUBatch cache usage. */ -static GPUVertBuf *mesh_batch_cache_get_tri_shading_data(MeshRenderData *rdata, MeshBatchCache *cache) +static void mesh_create_pos_and_nor_tess(MeshRenderData *rdata, GPUVertBuf *vbo, bool use_hide) { - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); - - if (cache->shaded_triangles_data == NULL) { - const uint uv_len = rdata->cd.layers.uv_len; - const uint tangent_len = rdata->cd.layers.tangent_len; - const uint vcol_len = rdata->cd.layers.vcol_len; - const uint layers_combined_len = uv_len + vcol_len + tangent_len; - cache->auto_layer_len = 0; - - if (layers_combined_len == 0) { - return NULL; - } - - GPUVertFormat *format = &cache->shaded_triangles_format; - - GPU_vertformat_clear(format); - - /* initialize vertex format */ - uint *layers_combined_id = BLI_array_alloca(layers_combined_id, layers_combined_len); - uint *uv_id = layers_combined_id; - uint *tangent_id = uv_id + uv_len; - uint *vcol_id = tangent_id + tangent_len; - - /* Not needed, just for sanity. */ - if (uv_len == 0) { uv_id = NULL; } - if (tangent_len == 0) { tangent_id = NULL; } - if (vcol_len == 0) { vcol_id = NULL; } - - /* Count number of auto layer and allocate big enough name buffer. */ - uint auto_names_len = 0; - uint auto_ofs = 0; - uint auto_id = 0; - for (uint i = 0; i < uv_len; i++) { - const char *attrib_name = mesh_render_data_uv_auto_layer_uuid_get(rdata, i); - auto_names_len += strlen(attrib_name) + 2; /* include null terminator and b prefix. */ - cache->auto_layer_len++; - } - for (uint i = 0; i < vcol_len; i++) { - if (rdata->cd.layers.auto_vcol[i]) { - const char *attrib_name = mesh_render_data_vcol_auto_layer_uuid_get(rdata, i); - auto_names_len += strlen(attrib_name) + 2; /* include null terminator and b prefix. */ - cache->auto_layer_len++; - } - } - auto_names_len += 1; /* add an ultimate '\0' terminator */ - cache->auto_layer_names = MEM_callocN(auto_names_len * sizeof(char), "Auto layer name buf"); - cache->auto_layer_is_srgb = MEM_mallocN(cache->auto_layer_len * sizeof(int), "Auto layer value buf"); - -#define USE_COMP_MESH_DATA - - for (uint i = 0; i < uv_len; i++) { - /* UV */ - const char *attrib_name = mesh_render_data_uv_layer_uuid_get(rdata, i); -#if defined(USE_COMP_MESH_DATA) && 0 /* these are clamped. Maybe use them as an option in the future */ - uv_id[i] = GPU_vertformat_attr_add(format, attrib_name, GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT); -#else - uv_id[i] = GPU_vertformat_attr_add(format, attrib_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT); -#endif - - /* Auto Name */ - attrib_name = mesh_render_data_uv_auto_layer_uuid_get(rdata, i); - GPU_vertformat_alias_add(format, attrib_name); - - /* +1 include null terminator. */ - auto_ofs += 1 + BLI_snprintf_rlen( - cache->auto_layer_names + auto_ofs, auto_names_len - auto_ofs, "b%s", attrib_name); - cache->auto_layer_is_srgb[auto_id++] = 0; /* tag as not srgb */ - - if (i == rdata->cd.layers.uv_active) { - GPU_vertformat_alias_add(format, "u"); - } - } - - for (uint i = 0; i < tangent_len; i++) { - const char *attrib_name = mesh_render_data_tangent_layer_uuid_get(rdata, i); -#ifdef USE_COMP_MESH_DATA - /* Tangents need more precision than 10_10_10 */ - tangent_id[i] = GPU_vertformat_attr_add(format, attrib_name, GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); -#else - tangent_id[i] = GPU_vertformat_attr_add(format, attrib_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT); -#endif + static GPUVertFormat format = { 0 }; + static struct { uint pos, nor; } attr_id; + if (format.attr_len == 0) { + attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_triple_load(&format); + } - if (i == rdata->cd.layers.tangent_active) { - GPU_vertformat_alias_add(format, "t"); - } - } + GPU_vertbuf_init_with_format(vbo, &format); - for (uint i = 0; i < vcol_len; i++) { - const char *attrib_name = mesh_render_data_vcol_layer_uuid_get(rdata, i); - vcol_id[i] = GPU_vertformat_attr_add(format, attrib_name, GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + const int tri_len = mesh_render_data_looptri_len_get_maybe_mapped(rdata); + const int vbo_len_capacity = tri_len * 3; + int vbo_len_used = 0; + GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); - /* Auto layer */ - if (rdata->cd.layers.auto_vcol[i]) { - attrib_name = mesh_render_data_vcol_auto_layer_uuid_get(rdata, i); + GPUVertBufRaw pos_step, nor_step; + GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); + GPU_vertbuf_attr_get_raw_data(vbo, attr_id.nor, &nor_step); - GPU_vertformat_alias_add(format, attrib_name); + if (rdata->mapped.use == false) { + float (*lnors)[3] = rdata->loop_normals; + if (rdata->edit_bmesh) { + GPUPackedNormal *pnors_pack, *vnors_pack; - /* +1 include null terminator. */ - auto_ofs += 1 + BLI_snprintf_rlen( - cache->auto_layer_names + auto_ofs, auto_names_len - auto_ofs, "b%s", attrib_name); - cache->auto_layer_is_srgb[auto_id++] = 1; /* tag as srgb */ - } + if (lnors == NULL) { + mesh_render_data_ensure_poly_normals_pack(rdata); + mesh_render_data_ensure_vert_normals_pack(rdata); - if (i == rdata->cd.layers.vcol_active) { - GPU_vertformat_alias_add(format, "c"); + pnors_pack = rdata->poly_normals_pack; + vnors_pack = rdata->vert_normals_pack; } - } - - const uint tri_len = mesh_render_data_looptri_len_get(rdata); - GPUVertBuf *vbo = cache->shaded_triangles_data = GPU_vertbuf_create_with_format(format); - - const int vbo_len_capacity = tri_len * 3; - int vbo_len_used = 0; - GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); - - GPUVertBufRaw *layers_combined_step = BLI_array_alloca(layers_combined_step, layers_combined_len); - - GPUVertBufRaw *uv_step = layers_combined_step; - GPUVertBufRaw *tangent_step = uv_step + uv_len; - GPUVertBufRaw *vcol_step = tangent_step + tangent_len; - - /* Not needed, just for sanity. */ - if (uv_len == 0) { uv_step = NULL; } - if (tangent_len == 0) { tangent_step = NULL; } - if (vcol_len == 0) { vcol_step = NULL; } - - for (uint i = 0; i < uv_len; i++) { - GPU_vertbuf_attr_get_raw_data(vbo, uv_id[i], &uv_step[i]); - } - for (uint i = 0; i < tangent_len; i++) { - GPU_vertbuf_attr_get_raw_data(vbo, tangent_id[i], &tangent_step[i]); - } - for (uint i = 0; i < vcol_len; i++) { - GPU_vertbuf_attr_get_raw_data(vbo, vcol_id[i], &vcol_step[i]); - } - - /* TODO deduplicate all verts and make use of GPUIndexBuf in - * mesh_batch_cache_get_triangles_in_order_split_by_material. */ - if (rdata->edit_bmesh) { - for (uint i = 0; i < tri_len; i++) { + for (int i = 0; i < tri_len; i++) { const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i]; - if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) { + const BMFace *bm_face = bm_looptri[0]->f; + + /* use_hide always for edit-mode */ + if (BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) { continue; } - /* UVs */ - for (uint j = 0; j < uv_len; j++) { - const uint layer_offset = rdata->cd.offset.uv[j]; + + if (lnors) { for (uint t = 0; t < 3; t++) { - const float *elem = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(bm_looptri[t], layer_offset))->uv; - copy_v2_v2(GPU_vertbuf_raw_step(&uv_step[j]), elem); + const float *nor = lnors[BM_elem_index_get(bm_looptri[t])]; + *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = GPU_normal_convert_i10_v3(nor); } } - /* TANGENTs */ - for (uint j = 0; j < tangent_len; j++) { - float (*layer_data)[4] = rdata->cd.layers.tangent[j]; + else if (BM_elem_flag_test(bm_face, BM_ELEM_SMOOTH)) { for (uint t = 0; t < 3; t++) { - const float *elem = layer_data[BM_elem_index_get(bm_looptri[t])]; -#ifdef USE_COMP_MESH_DATA - normal_float_to_short_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem); -#else - copy_v4_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem); -#endif + *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = vnors_pack[BM_elem_index_get(bm_looptri[t]->v)]; } } - /* VCOLs */ - for (uint j = 0; j < vcol_len; j++) { - const uint layer_offset = rdata->cd.offset.vcol[j]; + else { + const GPUPackedNormal *snor_pack = &pnors_pack[BM_elem_index_get(bm_face)]; for (uint t = 0; t < 3; t++) { - const uchar *elem = &((MLoopCol *)BM_ELEM_CD_GET_VOID_P(bm_looptri[t], layer_offset))->r; - copy_v3_v3_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem); + *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = *snor_pack; } } - } - } - else { - for (uint i = 0; i < tri_len; i++) { - const MLoopTri *mlt = &rdata->mlooptri[i]; - /* UVs */ - for (uint j = 0; j < uv_len; j++) { - const MLoopUV *layer_data = rdata->cd.layers.uv[j]; + /* TODO(sybren): deduplicate this and all the other places it's pasted to in this file. */ + if (rdata->edit_data && rdata->edit_data->vertexCos) { for (uint t = 0; t < 3; t++) { - const float *elem = layer_data[mlt->tri[t]].uv; - copy_v2_v2(GPU_vertbuf_raw_step(&uv_step[j]), elem); + int vidx = BM_elem_index_get(bm_looptri[t]->v); + const float *pos = rdata->edit_data->vertexCos[vidx]; + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), pos); } } - /* TANGENTs */ - for (uint j = 0; j < tangent_len; j++) { - float (*layer_data)[4] = rdata->cd.layers.tangent[j]; - for (uint t = 0; t < 3; t++) { - const float *elem = layer_data[mlt->tri[t]]; -#ifdef USE_COMP_MESH_DATA - normal_float_to_short_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem); -#else - copy_v4_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem); -#endif - } - } - /* VCOLs */ - for (uint j = 0; j < vcol_len; j++) { - const MLoopCol *layer_data = rdata->cd.layers.vcol[j]; + else { for (uint t = 0; t < 3; t++) { - const uchar *elem = &layer_data[mlt->tri[t]].r; - copy_v3_v3_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem); + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), bm_looptri[t]->v->co); } } } } - - vbo_len_used = GPU_vertbuf_raw_used(&layers_combined_step[0]); - -#ifndef NDEBUG - /* Check all layers are write aligned. */ - if (layers_combined_len > 1) { - for (uint i = 1; i < layers_combined_len; i++) { - BLI_assert(vbo_len_used == GPU_vertbuf_raw_used(&layers_combined_step[i])); + else { + if (lnors == NULL) { + /* Use normals from vertex. */ + mesh_render_data_ensure_poly_normals_pack(rdata); } - } -#endif - if (vbo_len_capacity != vbo_len_used) { - GPU_vertbuf_data_resize(vbo, vbo_len_used); - } - } - -#undef USE_COMP_MESH_DATA - - return cache->shaded_triangles_data; -} - -static GPUVertBuf *mesh_batch_cache_get_tri_uv_active( - MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPUV)); - - - if (cache->tri_aligned_uv == NULL) { - const MLoopUV *mloopuv = rdata->mloopuv; - if (mloopuv == NULL) { - return NULL; - } - - uint vidx = 0; - - static GPUVertFormat format = { 0 }; - static struct { uint uv; } attr_id; - if (format.attr_len == 0) { - attr_id.uv = GPU_vertformat_attr_add(&format, "uv", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - } - - const int tri_len = mesh_render_data_looptri_len_get(rdata); - - GPUVertBuf *vbo = cache->tri_aligned_uv = GPU_vertbuf_create_with_format(&format); - - const int vbo_len_capacity = tri_len * 3; - int vbo_len_used = 0; - GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); - - - BMEditMesh *embm = rdata->edit_bmesh; - /* get uv's from active UVMap */ - if (rdata->edit_bmesh) { - /* edit mode */ - BMesh *bm = embm->bm; - - const int layer_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - for (uint i = 0; i < tri_len; i++) { - const BMLoop **bm_looptri = (const BMLoop **)embm->looptris[i]; - if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) { - continue; - } - for (uint t = 0; t < 3; t++) { - const BMLoop *loop = bm_looptri[t]; - const int index = BM_elem_index_get(loop); - if (index != -1) { - const float *elem = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(loop, layer_offset))->uv; - GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx++, elem); - } - } - } - } - else { - /* object mode */ for (int i = 0; i < tri_len; i++) { const MLoopTri *mlt = &rdata->mlooptri[i]; - GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx++, mloopuv[mlt->tri[0]].uv); - GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx++, mloopuv[mlt->tri[1]].uv); - GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx++, mloopuv[mlt->tri[2]].uv); - } - } + const MPoly *mp = &rdata->mpoly[mlt->poly]; - vbo_len_used = vidx; - - BLI_assert(vbo_len_capacity == vbo_len_used); - UNUSED_VARS_NDEBUG(vbo_len_used); - } - - return cache->tri_aligned_uv; -} - -static GPUVertBuf *mesh_batch_cache_get_tri_pos_and_normals_ex( - MeshRenderData *rdata, const bool use_hide, - GPUVertBuf **r_vbo) -{ - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); - - if (*r_vbo == NULL) { - static GPUVertFormat format = { 0 }; - static struct { uint pos, nor; } attr_id; - if (format.attr_len == 0) { - attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - } - - const int tri_len = mesh_render_data_looptri_len_get_maybe_mapped(rdata); - - GPUVertBuf *vbo = *r_vbo = GPU_vertbuf_create_with_format(&format); - - const int vbo_len_capacity = tri_len * 3; - int vbo_len_used = 0; - GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); - - GPUVertBufRaw pos_step, nor_step; - GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); - GPU_vertbuf_attr_get_raw_data(vbo, attr_id.nor, &nor_step); - - if (rdata->mapped.use == false) { - float (*lnors)[3] = rdata->loop_normals; - if (rdata->edit_bmesh) { - GPUPackedNormal *pnors_pack, *vnors_pack; - - if (lnors == NULL) { - mesh_render_data_ensure_poly_normals_pack(rdata); - mesh_render_data_ensure_vert_normals_pack(rdata); - - pnors_pack = rdata->poly_normals_pack; - vnors_pack = rdata->vert_normals_pack; + if (use_hide && (mp->flag & ME_HIDE)) { + continue; } - for (int i = 0; i < tri_len; i++) { - const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i]; - const BMFace *bm_face = bm_looptri[0]->f; - - /* use_hide always for edit-mode */ - if (BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) { - continue; - } + const uint vtri[3] = { + rdata->mloop[mlt->tri[0]].v, + rdata->mloop[mlt->tri[1]].v, + rdata->mloop[mlt->tri[2]].v, + }; - if (lnors) { - for (uint t = 0; t < 3; t++) { - const float *nor = lnors[BM_elem_index_get(bm_looptri[t])]; - *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = GPU_normal_convert_i10_v3(nor); - } + if (lnors) { + for (uint t = 0; t < 3; t++) { + const float *nor = lnors[mlt->tri[t]]; + *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = GPU_normal_convert_i10_v3(nor); } - else if (BM_elem_flag_test(bm_face, BM_ELEM_SMOOTH)) { - for (uint t = 0; t < 3; t++) { - *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = vnors_pack[BM_elem_index_get(bm_looptri[t]->v)]; - } + } + else if (mp->flag & ME_SMOOTH) { + for (uint t = 0; t < 3; t++) { + const MVert *mv = &rdata->mvert[vtri[t]]; + *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = GPU_normal_convert_i10_s3(mv->no); } - else { - const GPUPackedNormal *snor_pack = &pnors_pack[BM_elem_index_get(bm_face)]; - for (uint t = 0; t < 3; t++) { - *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = *snor_pack; - } + } + else { + const GPUPackedNormal *pnors_pack = &rdata->poly_normals_pack[mlt->poly]; + for (uint t = 0; t < 3; t++) { + *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = *pnors_pack; } + } - /* TODO(sybren): deduplicate this and all the other places it's pasted to in this file. */ - if (rdata->edit_data && rdata->edit_data->vertexCos) { - for (uint t = 0; t < 3; t++) { - int vidx = BM_elem_index_get(bm_looptri[t]->v); - const float *pos = rdata->edit_data->vertexCos[vidx]; - copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), pos); - } - } - else { - for (uint t = 0; t < 3; t++) { - copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), bm_looptri[t]->v->co); - } - } + for (uint t = 0; t < 3; t++) { + const MVert *mv = &rdata->mvert[vtri[t]]; + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mv->co); } } - else { - if (lnors == NULL) { - /* Use normals from vertex. */ - mesh_render_data_ensure_poly_normals_pack(rdata); - } + } + } + else { + /* Note: mapped doesn't support lnors yet. */ + BMesh *bm = rdata->edit_bmesh->bm; + Mesh *me_cage = rdata->mapped.me_cage; - for (int i = 0; i < tri_len; i++) { - const MLoopTri *mlt = &rdata->mlooptri[i]; - const MPoly *mp = &rdata->mpoly[mlt->poly]; + /* TODO(campbell): unlike non-mapped modes we don't generate these on demand, just use if they exist. + * this seems like a low priority TODO since mapped meshes typically + * use the final mesh evaluated mesh for showing faces. */ + const float (*lnors)[3] = CustomData_get_layer(&me_cage->ldata, CD_NORMAL); - if (use_hide && (mp->flag & ME_HIDE)) { - continue; - } + /* TODO(campbell): this is quite an expensive operation for something + * that's not used unless 'normal' display option is enabled. */ + if (!CustomData_has_layer(&me_cage->pdata, CD_NORMAL)) { + /* TODO(campbell): this is quite an expensive operation for something + * that's not used unless 'normal' display option is enabled. */ + BKE_mesh_ensure_normals_for_display(me_cage); + } + const float (*polynors)[3] = CustomData_get_layer(&me_cage->pdata, CD_NORMAL); + + const MVert *mvert = rdata->mapped.me_cage->mvert; + const MLoop *mloop = rdata->mapped.me_cage->mloop; + const MPoly *mpoly = rdata->mapped.me_cage->mpoly; + const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage); + for (int i = 0; i < tri_len; i++) { + const MLoopTri *mlt = &mlooptri[i]; + const int p_orig = rdata->mapped.p_origindex[mlt->poly]; + if (p_orig != ORIGINDEX_NONE) { + /* Assume 'use_hide' */ + BMFace *efa = BM_face_at_index(bm, p_orig); + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + const MPoly *mp = &mpoly[mlt->poly]; const uint vtri[3] = { - rdata->mloop[mlt->tri[0]].v, - rdata->mloop[mlt->tri[1]].v, - rdata->mloop[mlt->tri[2]].v, + mloop[mlt->tri[0]].v, + mloop[mlt->tri[1]].v, + mloop[mlt->tri[2]].v, }; if (lnors) { @@ -2827,176 +2799,68 @@ static GPUVertBuf *mesh_batch_cache_get_tri_pos_and_normals_ex( } else if (mp->flag & ME_SMOOTH) { for (uint t = 0; t < 3; t++) { - const MVert *mv = &rdata->mvert[vtri[t]]; + const MVert *mv = &mvert[vtri[t]]; *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = GPU_normal_convert_i10_s3(mv->no); } } else { - const GPUPackedNormal *pnors_pack = &rdata->poly_normals_pack[mlt->poly]; + /* we don't have cached 'rdata->poly_normals_pack'. */ + const GPUPackedNormal pnor = GPU_normal_convert_i10_v3(polynors[mlt->poly]); for (uint t = 0; t < 3; t++) { - *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = *pnors_pack; + *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = pnor; } } for (uint t = 0; t < 3; t++) { - const MVert *mv = &rdata->mvert[vtri[t]]; + const MVert *mv = &mvert[vtri[t]]; copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mv->co); } } } } - else { - /* Note: mapped doesn't support lnors yet. */ - BMesh *bm = rdata->edit_bmesh->bm; - Mesh *me_cage = rdata->mapped.me_cage; - - /* TODO(campbell): unlike non-mapped modes we don't generate these on demand, just use if they exist. - * this seems like a low priority TODO since mapped meshes typically - * use the final mesh evaluated mesh for showing faces. */ - const float (*lnors)[3] = CustomData_get_layer(&me_cage->ldata, CD_NORMAL); - - /* TODO(campbell): this is quite an expensive operation for something - * that's not used unless 'normal' display option is enabled. */ - if (!CustomData_has_layer(&me_cage->pdata, CD_NORMAL)) { - /* TODO(campbell): this is quite an expensive operation for something - * that's not used unless 'normal' display option is enabled. */ - BKE_mesh_ensure_normals_for_display(me_cage); - } - const float (*polynors)[3] = CustomData_get_layer(&me_cage->pdata, CD_NORMAL); - - const MVert *mvert = rdata->mapped.me_cage->mvert; - const MLoop *mloop = rdata->mapped.me_cage->mloop; - const MPoly *mpoly = rdata->mapped.me_cage->mpoly; + } - const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage); - for (int i = 0; i < tri_len; i++) { - const MLoopTri *mlt = &mlooptri[i]; - const int p_orig = rdata->mapped.p_origindex[mlt->poly]; - if (p_orig != ORIGINDEX_NONE) { - /* Assume 'use_hide' */ - BMFace *efa = BM_face_at_index(bm, p_orig); - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - const MPoly *mp = &mpoly[mlt->poly]; - const uint vtri[3] = { - mloop[mlt->tri[0]].v, - mloop[mlt->tri[1]].v, - mloop[mlt->tri[2]].v, - }; - - if (lnors) { - for (uint t = 0; t < 3; t++) { - const float *nor = lnors[mlt->tri[t]]; - *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = GPU_normal_convert_i10_v3(nor); - } - } - else if (mp->flag & ME_SMOOTH) { - for (uint t = 0; t < 3; t++) { - const MVert *mv = &mvert[vtri[t]]; - *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = GPU_normal_convert_i10_s3(mv->no); - } - } - else { - /* we don't have cached 'rdata->poly_normals_pack'. */ - const GPUPackedNormal pnor = GPU_normal_convert_i10_v3(polynors[mlt->poly]); - for (uint t = 0; t < 3; t++) { - *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = pnor; - } - } + vbo_len_used = GPU_vertbuf_raw_used(&pos_step); + BLI_assert(vbo_len_used == GPU_vertbuf_raw_used(&nor_step)); - for (uint t = 0; t < 3; t++) { - const MVert *mv = &mvert[vtri[t]]; - copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mv->co); - } - } - } - } - } + if (vbo_len_capacity != vbo_len_used) { + GPU_vertbuf_data_resize(vbo, vbo_len_used); + } +} - vbo_len_used = GPU_vertbuf_raw_used(&pos_step); - BLI_assert(vbo_len_used == GPU_vertbuf_raw_used(&nor_step)); +static GPUVertBuf *mesh_batch_cache_get_tri_pos_and_normals_ex( + MeshRenderData *rdata, const bool use_hide, + GPUVertBuf **r_vbo) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); - if (vbo_len_capacity != vbo_len_used) { - GPU_vertbuf_data_resize(vbo, vbo_len_used); - } + if (*r_vbo == NULL) { + *r_vbo = GPU_vertbuf_create(GPU_USAGE_STATIC); + mesh_create_pos_and_nor_tess(rdata, *r_vbo, use_hide); } return *r_vbo; } -static GPUVertBuf *mesh_batch_cache_get_tri_pos_and_normals( - MeshRenderData *rdata, MeshBatchCache *cache) -{ - return mesh_batch_cache_get_tri_pos_and_normals_ex( - rdata, false, - &cache->pos_with_normals); -} -static GPUVertBuf *mesh_create_tri_pos_and_normals_visible_only( - MeshRenderData *rdata) +static GPUVertBuf *mesh_batch_cache_get_tri_pos_and_normals_edit( + MeshRenderData *rdata, MeshBatchCache *cache, bool use_hide) { - GPUVertBuf *vbo_dummy = NULL; return mesh_batch_cache_get_tri_pos_and_normals_ex( - rdata, true, - &vbo_dummy); + rdata, use_hide, + use_hide ? &cache->pos_with_normals_visible_only_edit : &cache->pos_with_normals_edit); } +/* DEPRECATED Need to be ported */ static GPUVertBuf *mesh_batch_cache_get_facedot_pos_with_normals_and_flag( MeshRenderData *rdata, MeshBatchCache *cache) { BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); - if (cache->ed_fcenter_pos_with_nor_and_sel == NULL) { - static GPUVertFormat format = { 0 }; - static struct { uint pos, data; } attr_id; - if (format.attr_len == 0) { - attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - attr_id.data = GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - } - const int vbo_len_capacity = mesh_render_data_polys_len_get_maybe_mapped(rdata); - int vidx = 0; - - GPUVertBuf *vbo = cache->ed_fcenter_pos_with_nor_and_sel = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); - - if (rdata->edit_bmesh) { - if (rdata->edit_data && rdata->edit_data->vertexCos != NULL) { - BKE_editmesh_cache_ensure_poly_normals(rdata->edit_bmesh, rdata->edit_data); - BKE_editmesh_cache_ensure_poly_centers(rdata->edit_bmesh, rdata->edit_data); - } - } - - if (rdata->mapped.use == false) { - for (int i = 0; i < vbo_len_capacity; i++) { - float pcenter[3], pnor[3]; - bool selected = false; - if (mesh_render_data_pnors_pcenter_select_get(rdata, i, pnor, pcenter, &selected)) { - GPUPackedNormal nor = GPU_normal_convert_i10_v3(pnor); - nor.w = selected ? 1 : 0; - GPU_vertbuf_attr_set(vbo, attr_id.data, vidx, &nor); - GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx, pcenter); - vidx += 1; - } - } - } - else { - for (int i = 0; i < vbo_len_capacity; i++) { - float pcenter[3], pnor[3]; - bool selected = false; - if (mesh_render_data_pnors_pcenter_select_get_mapped(rdata, i, pnor, pcenter, &selected)) { - GPUPackedNormal nor = GPU_normal_convert_i10_v3(pnor); - nor.w = selected ? 1 : 0; - GPU_vertbuf_attr_set(vbo, attr_id.data, vidx, &nor); - GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx, pcenter); - vidx += 1; - } - } - } - const int vbo_len_used = vidx; - BLI_assert(vbo_len_used <= vbo_len_capacity); - if (vbo_len_used != vbo_len_capacity) { - GPU_vertbuf_data_resize(vbo, vbo_len_used); - } + if (cache->edit.pos_nor_data_facedots == NULL) { + cache->edit.pos_nor_data_facedots = GPU_vertbuf_create(GPU_USAGE_STATIC); + mesh_create_edit_facedots(rdata, cache->edit.pos_nor_data_facedots); } - return cache->ed_fcenter_pos_with_nor_and_sel; + return cache->edit.pos_nor_data_facedots; } static GPUVertBuf *mesh_batch_cache_get_edges_visible( @@ -3327,126 +3191,6 @@ static GPUVertBuf *mesh_create_verts_select_id( return vbo; } -static GPUVertBuf *mesh_create_tri_weights( - MeshRenderData *rdata, bool use_hide, const struct DRW_MeshWeightState *wstate) -{ - BLI_assert( - rdata->types & - (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_DVERT)); - - GPUVertBuf *vbo; - { - uint cidx = 0; - - static GPUVertFormat format = { 0 }; - static struct { uint weight; } attr_id; - if (format.attr_len == 0) { - attr_id.weight = GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - } - - vbo = GPU_vertbuf_create_with_format(&format); - - const int tri_len = mesh_render_data_looptri_len_get(rdata); - const int vbo_len_capacity = tri_len * 3; - int vbo_len_used = 0; - GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); - - mesh_render_data_ensure_vert_weight(rdata, wstate); - const float (*vert_weight) = rdata->vert_weight; - - if (rdata->edit_bmesh) { - for (int i = 0; i < tri_len; i++) { - const BMLoop **ltri = (const BMLoop **)rdata->edit_bmesh->looptris[i]; - /* Assume 'use_hide' */ - if (!BM_elem_flag_test(ltri[0]->f, BM_ELEM_HIDDEN)) { - for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { - const int v_index = BM_elem_index_get(ltri[tri_corner]->v); - GPU_vertbuf_attr_set(vbo, attr_id.weight, cidx++, &vert_weight[v_index]); - } - } - } - } - else { - for (int i = 0; i < tri_len; i++) { - const MLoopTri *mlt = &rdata->mlooptri[i]; - if (!(use_hide && (rdata->mpoly[mlt->poly].flag & ME_HIDE))) { - for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { - const uint v_index = rdata->mloop[mlt->tri[tri_corner]].v; - GPU_vertbuf_attr_set(vbo, attr_id.weight, cidx++, &vert_weight[v_index]); - } - } - } - } - vbo_len_used = cidx; - - if (vbo_len_capacity != vbo_len_used) { - GPU_vertbuf_data_resize(vbo, vbo_len_used); - } - } - - return vbo; -} - -static GPUVertBuf *mesh_create_tri_vert_colors( - MeshRenderData *rdata, bool use_hide) -{ - BLI_assert( - rdata->types & - (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPCOL)); - - GPUVertBuf *vbo; - { - uint cidx = 0; - - static GPUVertFormat format = { 0 }; - static struct { uint col; } attr_id; - if (format.attr_len == 0) { - attr_id.col = GPU_vertformat_attr_add(&format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - } - - const int tri_len = mesh_render_data_looptri_len_get(rdata); - - vbo = GPU_vertbuf_create_with_format(&format); - - const uint vbo_len_capacity = tri_len * 3; - GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); - - mesh_render_data_ensure_vert_color(rdata); - const char (*vert_color)[3] = rdata->vert_color; - - if (rdata->edit_bmesh) { - for (int i = 0; i < tri_len; i++) { - const BMLoop **ltri = (const BMLoop **)rdata->edit_bmesh->looptris[i]; - /* Assume 'use_hide' */ - if (!BM_elem_flag_test(ltri[0]->f, BM_ELEM_HIDDEN)) { - for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { - const int l_index = BM_elem_index_get(ltri[tri_corner]); - GPU_vertbuf_attr_set(vbo, attr_id.col, cidx++, vert_color[l_index]); - } - } - } - } - else { - for (int i = 0; i < tri_len; i++) { - const MLoopTri *mlt = &rdata->mlooptri[i]; - if (!(use_hide && (rdata->mpoly[mlt->poly].flag & ME_HIDE))) { - for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { - const uint l_index = mlt->tri[tri_corner]; - GPU_vertbuf_attr_set(vbo, attr_id.col, cidx++, vert_color[l_index]); - } - } - } - } - const uint vbo_len_used = cidx; - - if (vbo_len_capacity != vbo_len_used) { - GPU_vertbuf_data_resize(vbo, vbo_len_used); - } - } - - return vbo; -} - static GPUVertBuf *mesh_create_tri_select_id( MeshRenderData *rdata, bool use_hide, uint select_id_offset) { @@ -3489,14 +3233,22 @@ static GPUVertBuf *mesh_create_tri_select_id( } } else { + const int *p_origindex = NULL; + if (rdata->me != NULL) { + p_origindex = CustomData_get_layer(&rdata->me->pdata, CD_ORIGINDEX); + } + for (int i = 0; i < tri_len; i++) { const MLoopTri *mlt = &rdata->mlooptri[i]; const int poly_index = mlt->poly; if (!(use_hide && (rdata->mpoly[poly_index].flag & ME_HIDE))) { - int select_id; - GPU_select_index_get(poly_index + select_id_offset, &select_id); - for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { - GPU_vertbuf_attr_set(vbo, attr_id.col, cidx++, &select_id); + int orig_index = p_origindex ? p_origindex[poly_index] : poly_index; + if (orig_index != ORIGINDEX_NONE) { + int select_id; + GPU_select_index_get(orig_index + select_id_offset, &select_id); + for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { + GPU_vertbuf_attr_set(vbo, attr_id.col, cidx++, &select_id); + } } } } @@ -3531,519 +3283,719 @@ static GPUVertBuf *mesh_create_tri_select_id( return vbo; } -static GPUVertBuf *mesh_batch_cache_get_vert_pos_and_nor_in_order( - MeshRenderData *rdata, MeshBatchCache *cache) +static void mesh_create_pos_and_nor(MeshRenderData *rdata, GPUVertBuf *vbo) { - BLI_assert(rdata->types & MR_DATATYPE_VERT); + static GPUVertFormat format = { 0 }; + static struct { uint pos, nor; } attr_id; + if (format.attr_len == 0) { + attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + } - if (cache->pos_in_order == NULL) { - static GPUVertFormat format = { 0 }; - static struct { uint pos, nor; } attr_id; - if (format.attr_len == 0) { - /* Normal is padded so that the vbo can be used as a buffer texture */ - attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertbuf_init_with_format(vbo, &format); + const int vbo_len_capacity = mesh_render_data_verts_len_get_maybe_mapped(rdata); + GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); + + if (rdata->mapped.use == false) { + if (rdata->edit_bmesh) { + BMesh *bm = rdata->edit_bmesh->bm; + BMIter iter; + BMVert *eve; + uint i; + + mesh_render_data_ensure_vert_normals_pack(rdata); + GPUPackedNormal *vnor = rdata->vert_normals_pack; + + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { + GPU_vertbuf_attr_set(vbo, attr_id.pos, i, eve->co); + GPU_vertbuf_attr_set(vbo, attr_id.nor, i, &vnor[i]); + } + BLI_assert(i == vbo_len_capacity); + } + else { + for (int i = 0; i < vbo_len_capacity; i++) { + const MVert *mv = &rdata->mvert[i]; + GPUPackedNormal vnor_pack = GPU_normal_convert_i10_s3(mv->no); + vnor_pack.w = (mv->flag & ME_HIDE) ? -1 : ((mv->flag & SELECT) ? 1 : 0); + GPU_vertbuf_attr_set(vbo, attr_id.pos, i, rdata->mvert[i].co); + GPU_vertbuf_attr_set(vbo, attr_id.nor, i, &vnor_pack); + } + } + } + else { + const MVert *mvert = rdata->mapped.me_cage->mvert; + const int *v_origindex = rdata->mapped.v_origindex; + for (int i = 0; i < vbo_len_capacity; i++) { + const int v_orig = v_origindex[i]; + if (v_orig != ORIGINDEX_NONE) { + const MVert *mv = &mvert[i]; + GPUPackedNormal vnor_pack = GPU_normal_convert_i10_s3(mv->no); + vnor_pack.w = (mv->flag & ME_HIDE) ? -1 : ((mv->flag & SELECT) ? 1 : 0); + GPU_vertbuf_attr_set(vbo, attr_id.pos, i, mv->co); + GPU_vertbuf_attr_set(vbo, attr_id.nor, i, &vnor_pack); + } } + } +} - GPUVertBuf *vbo = cache->pos_in_order = GPU_vertbuf_create_with_format(&format); - const int vbo_len_capacity = mesh_render_data_verts_len_get_maybe_mapped(rdata); - GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); +static void mesh_create_weights(MeshRenderData *rdata, GPUVertBuf *vbo, DRW_MeshWeightState *wstate) +{ + static GPUVertFormat format = { 0 }; + static struct { uint weight; } attr_id; + if (format.attr_len == 0) { + attr_id.weight = GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } - if (rdata->mapped.use == false) { - if (rdata->edit_bmesh) { - BMesh *bm = rdata->edit_bmesh->bm; - BMIter iter; - BMVert *eve; - uint i; + const int vbo_len_capacity = mesh_render_data_verts_len_get_maybe_mapped(rdata); - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - static short no_short[4]; - normal_float_to_short_v3(no_short, eve->no); + mesh_render_data_ensure_vert_weight(rdata, wstate); + const float (*vert_weight) = rdata->vert_weight; - GPU_vertbuf_attr_set(vbo, attr_id.pos, i, eve->co); - GPU_vertbuf_attr_set(vbo, attr_id.nor, i, no_short); - } - BLI_assert(i == vbo_len_capacity); + GPU_vertbuf_init_with_format(vbo, &format); + /* Meh, another allocation / copy for no benefit. + * Needed because rdata->vert_weight is freed afterwards and + * GPU module don't have a GPU_vertbuf_data_from_memory or similar. */ + /* TODO get rid of the extra allocation/copy. */ + GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); + GPU_vertbuf_attr_fill(vbo, attr_id.weight, vert_weight); +} + +static void mesh_create_loop_pos_and_nor(MeshRenderData *rdata, GPUVertBuf *vbo, const bool use_face_sel) +{ + /* TODO deduplicate format creation*/ + static GPUVertFormat format = { 0 }; + static struct { uint pos, nor; } attr_id; + if (format.attr_len == 0) { + attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + const int poly_len = mesh_render_data_polys_len_get(rdata); + const int loop_len = mesh_render_data_loops_len_get(rdata); + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, loop_len); + + GPUVertBufRaw pos_step, nor_step; + GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); + GPU_vertbuf_attr_get_raw_data(vbo, attr_id.nor, &nor_step); + + if (rdata->mapped.use == false) { + if (rdata->edit_bmesh) { + const GPUPackedNormal *vnor, *pnor; + const float (*lnors)[3] = rdata->loop_normals; + BMesh *bm = rdata->edit_bmesh->bm; + BMIter iter_efa, iter_loop; + BMFace *efa; + BMLoop *loop; + uint f; + + if (rdata->loop_normals == NULL) { + mesh_render_data_ensure_poly_normals_pack(rdata); + mesh_render_data_ensure_vert_normals_pack(rdata); + vnor = rdata->vert_normals_pack; + pnor = rdata->poly_normals_pack; } - else { - for (int i = 0; i < vbo_len_capacity; i++) { - GPU_vertbuf_attr_set(vbo, attr_id.pos, i, rdata->mvert[i].co); - GPU_vertbuf_attr_set(vbo, attr_id.nor, i, rdata->mvert[i].no); /* XXX actually reading 4 shorts */ + + BM_ITER_MESH_INDEX (efa, &iter_efa, bm, BM_FACES_OF_MESH, f) { + const bool face_smooth = BM_elem_flag_test(efa, BM_ELEM_SMOOTH); + + BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) { + BLI_assert(GPU_vertbuf_raw_used(&pos_step) == BM_elem_index_get(loop)); + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), loop->v->co); + + if (lnors) { + GPUPackedNormal plnor = GPU_normal_convert_i10_v3(lnors[BM_elem_index_get(loop)]); + *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = plnor; + } + else if (!face_smooth) { + *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = pnor[f]; + } + else { + *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = vnor[BM_elem_index_get(loop->v)]; + } } } + BLI_assert(GPU_vertbuf_raw_used(&pos_step) == loop_len); } else { - const MVert *mvert = rdata->mapped.me_cage->mvert; - const int *v_origindex = rdata->mapped.v_origindex; - for (int i = 0; i < vbo_len_capacity; i++) { - const int v_orig = v_origindex[i]; - if (v_orig != ORIGINDEX_NONE) { - const MVert *mv = &mvert[i]; - GPU_vertbuf_attr_set(vbo, attr_id.pos, i, mv->co); - GPU_vertbuf_attr_set(vbo, attr_id.nor, i, mv->no); /* XXX actually reading 4 shorts */ + const MVert *mvert = rdata->mvert; + const MPoly *mpoly = rdata->mpoly; + + if (rdata->loop_normals == NULL) { + mesh_render_data_ensure_poly_normals_pack(rdata); + } + + for (int a = 0; a < poly_len; a++, mpoly++) { + const MLoop *mloop = rdata->mloop + mpoly->loopstart; + const float *lnors = (rdata->loop_normals) ? rdata->loop_normals[mpoly->loopstart] : NULL; + const GPUPackedNormal *fnor = (mpoly->flag & ME_SMOOTH) ? NULL : &rdata->poly_normals_pack[a]; + for (int b = 0; b < mpoly->totloop; b++, mloop++) { + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop->v].co); + GPUPackedNormal *pnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step); + if (lnors) { + *pnor = GPU_normal_convert_i10_v3(lnors); + } + else if (fnor) { + *pnor = *fnor; + } + else { + *pnor = GPU_normal_convert_i10_s3(mvert[mloop->v].no); + } + if (use_face_sel) { + pnor->w = (mpoly->flag & ME_HIDE) ? -1 : ((mpoly->flag & ME_FACE_SEL) ? 1 : 0); + } } } + + BLI_assert(loop_len == GPU_vertbuf_raw_used(&pos_step)); } } + else { + const int *p_origindex = rdata->mapped.p_origindex; + const MVert *mvert = rdata->mvert; + const MPoly *mpoly = rdata->mpoly; + + if (rdata->loop_normals == NULL) { + mesh_render_data_ensure_poly_normals_pack(rdata); + } - return cache->pos_in_order; + for (int a = 0; a < poly_len; a++, mpoly++) { + const MLoop *mloop = rdata->mloop + mpoly->loopstart; + const float *lnors = (rdata->loop_normals) ? rdata->loop_normals[mpoly->loopstart] : NULL; + const GPUPackedNormal *fnor = (mpoly->flag & ME_SMOOTH) ? NULL : &rdata->poly_normals_pack[a]; + if (p_origindex[a] == ORIGINDEX_NONE) { + continue; + } + for (int b = 0; b < mpoly->totloop; b++, mloop++) { + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop->v].co); + GPUPackedNormal *pnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step); + if (lnors) { + *pnor = GPU_normal_convert_i10_v3(lnors); + } + else if (fnor) { + *pnor = *fnor; + } + else { + *pnor = GPU_normal_convert_i10_s3(mvert[mloop->v].no); + } + } + } + } + + int vbo_len_used = GPU_vertbuf_raw_used(&pos_step); + if (vbo_len_used < loop_len) { + GPU_vertbuf_data_resize(vbo, vbo_len_used); + } } -static GPUVertFormat *edit_mesh_overlay_pos_format(uint *r_pos_id) +static void mesh_create_loop_uv_and_tan(MeshRenderData *rdata, GPUVertBuf *vbo) { - static GPUVertFormat format_pos = { 0 }; - static uint pos_id; - if (format_pos.attr_len == 0) { - pos_id = GPU_vertformat_attr_add(&format_pos, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + const uint loops_len = mesh_render_data_loops_len_get(rdata); + const uint uv_len = rdata->cd.layers.uv_len; + const uint tangent_len = rdata->cd.layers.tangent_len; + const uint layers_combined_len = uv_len + tangent_len; + + GPUVertBufRaw *layers_combined_step = BLI_array_alloca(layers_combined_step, layers_combined_len); + GPUVertBufRaw *uv_step = layers_combined_step; + GPUVertBufRaw *tangent_step = uv_step + uv_len; + + uint *layers_combined_id = BLI_array_alloca(layers_combined_id, layers_combined_len); + uint *uv_id = layers_combined_id; + uint *tangent_id = uv_id + uv_len; + + /* initialize vertex format */ + GPUVertFormat format = { 0 }; + + for (uint i = 0; i < uv_len; i++) { + const char *attrib_name = mesh_render_data_uv_layer_uuid_get(rdata, i); +#if 0 /* these are clamped. Maybe use them as an option in the future */ + uv_id[i] = GPU_vertformat_attr_add(&format, attrib_name, GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT); +#else + uv_id[i] = GPU_vertformat_attr_add(&format, attrib_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT); +#endif + /* Auto Name */ + attrib_name = mesh_render_data_uv_auto_layer_uuid_get(rdata, i); + GPU_vertformat_alias_add(&format, attrib_name); + + if (i == rdata->cd.layers.uv_active) { + GPU_vertformat_alias_add(&format, "u"); + } } - *r_pos_id = pos_id; - return &format_pos; + + for (uint i = 0; i < tangent_len; i++) { + const char *attrib_name = mesh_render_data_tangent_layer_uuid_get(rdata, i); +#ifdef USE_COMP_MESH_DATA + tangent_id[i] = GPU_vertformat_attr_add(&format, attrib_name, GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); +#else + tangent_id[i] = GPU_vertformat_attr_add(&format, attrib_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT); +#endif + if (i == rdata->cd.layers.tangent_active) { + GPU_vertformat_alias_add(&format, "t"); + } + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, loops_len); + + for (uint i = 0; i < uv_len; i++) { + GPU_vertbuf_attr_get_raw_data(vbo, uv_id[i], &uv_step[i]); + } + for (uint i = 0; i < tangent_len; i++) { + GPU_vertbuf_attr_get_raw_data(vbo, tangent_id[i], &tangent_step[i]); + } + + if (rdata->edit_bmesh) { + BMesh *bm = rdata->edit_bmesh->bm; + BMIter iter_efa, iter_loop; + BMFace *efa; + BMLoop *loop; + + BM_ITER_MESH (efa, &iter_efa, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) { + /* UVs */ + for (uint j = 0; j < uv_len; j++) { + const uint layer_offset = rdata->cd.offset.uv[j]; + const float *elem = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(loop, layer_offset))->uv; + copy_v2_v2(GPU_vertbuf_raw_step(&uv_step[j]), elem); + } + /* TANGENTs */ + for (uint j = 0; j < tangent_len; j++) { + float (*layer_data)[4] = rdata->cd.layers.tangent[j]; + const float *elem = layer_data[BM_elem_index_get(loop)]; +#ifdef USE_COMP_MESH_DATA + normal_float_to_short_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem); +#else + copy_v4_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem); +#endif + } + } + } + } + else { + for (uint loop = 0; loop < loops_len; loop++) { + /* UVs */ + for (uint j = 0; j < uv_len; j++) { + const MLoopUV *layer_data = rdata->cd.layers.uv[j]; + const float *elem = layer_data[loop].uv; + copy_v2_v2(GPU_vertbuf_raw_step(&uv_step[j]), elem); + } + /* TANGENTs */ + for (uint j = 0; j < tangent_len; j++) { + float (*layer_data)[4] = rdata->cd.layers.tangent[j]; + const float *elem = layer_data[loop]; +#ifdef USE_COMP_MESH_DATA + normal_float_to_short_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem); +#else + copy_v4_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem); +#endif + } + } + } + +#ifndef NDEBUG + /* Check all layers are write aligned. */ + if (layers_combined_len > 0) { + int vbo_len_used = GPU_vertbuf_raw_used(&layers_combined_step[0]); + for (uint i = 0; i < layers_combined_len; i++) { + BLI_assert(vbo_len_used == GPU_vertbuf_raw_used(&layers_combined_step[i])); + } + } +#endif + +#undef USE_COMP_MESH_DATA } -static GPUVertFormat *edit_mesh_overlay_nor_format(uint *r_vnor_id, uint *r_lnor_id) +static void mesh_create_loop_vcol(MeshRenderData *rdata, GPUVertBuf *vbo) { - static GPUVertFormat format_nor = { 0 }; - static GPUVertFormat format_nor_loop = { 0 }; - static uint vnor_id, vnor_loop_id, lnor_id; - if (format_nor.attr_len == 0) { - vnor_id = GPU_vertformat_attr_add(&format_nor, "vnor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - vnor_loop_id = GPU_vertformat_attr_add(&format_nor_loop, "vnor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - lnor_id = GPU_vertformat_attr_add(&format_nor_loop, "lnor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + const uint loops_len = mesh_render_data_loops_len_get(rdata); + const uint vcol_len = rdata->cd.layers.vcol_len; + + GPUVertBufRaw *vcol_step = BLI_array_alloca(vcol_step, vcol_len); + uint *vcol_id = BLI_array_alloca(vcol_id, vcol_len); + + /* initialize vertex format */ + GPUVertFormat format = { 0 }; + + for (uint i = 0; i < vcol_len; i++) { + const char *attrib_name = mesh_render_data_vcol_layer_uuid_get(rdata, i); + vcol_id[i] = GPU_vertformat_attr_add(&format, attrib_name, GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + /* Auto layer */ + if (rdata->cd.layers.auto_vcol[i]) { + attrib_name = mesh_render_data_vcol_auto_layer_uuid_get(rdata, i); + GPU_vertformat_alias_add(&format, attrib_name); + } + if (i == rdata->cd.layers.vcol_active) { + GPU_vertformat_alias_add(&format, "c"); + } + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, loops_len); + + for (uint i = 0; i < vcol_len; i++) { + GPU_vertbuf_attr_get_raw_data(vbo, vcol_id[i], &vcol_step[i]); } - if (r_lnor_id) { - *r_vnor_id = vnor_loop_id; - *r_lnor_id = lnor_id; - return &format_nor_loop; + + if (rdata->edit_bmesh) { + BMesh *bm = rdata->edit_bmesh->bm; + BMIter iter_efa, iter_loop; + BMFace *efa; + BMLoop *loop; + + BM_ITER_MESH (efa, &iter_efa, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) { + for (uint j = 0; j < vcol_len; j++) { + const uint layer_offset = rdata->cd.offset.vcol[j]; + const uchar *elem = &((MLoopCol *)BM_ELEM_CD_GET_VOID_P(loop, layer_offset))->r; + copy_v3_v3_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem); + } + } + } } else { - *r_vnor_id = vnor_id; - return &format_nor; + for (uint loop = 0; loop < loops_len; loop++) { + for (uint j = 0; j < vcol_len; j++) { + const MLoopCol *layer_data = rdata->cd.layers.vcol[j]; + const uchar *elem = &layer_data[loop].r; + copy_v3_v3_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem); + } + } + } + +#ifndef NDEBUG + /* Check all layers are write aligned. */ + if (vcol_len > 0) { + int vbo_len_used = GPU_vertbuf_raw_used(&vcol_step[0]); + for (uint i = 0; i < vcol_len; i++) { + BLI_assert(vbo_len_used == GPU_vertbuf_raw_used(&vcol_step[i])); + } + } +#endif + +#undef USE_COMP_MESH_DATA +} + +static GPUVertBuf *mesh_batch_cache_get_vert_pos_and_nor_in_order( + MeshRenderData *rdata, MeshBatchCache *cache) +{ + BLI_assert(rdata->types & MR_DATATYPE_VERT); + + if (cache->ordered.pos_nor == NULL) { + cache->ordered.pos_nor = GPU_vertbuf_create(GPU_USAGE_STATIC); + mesh_create_pos_and_nor(rdata, cache->ordered.pos_nor); } + + return cache->ordered.pos_nor; } -static GPUVertFormat *edit_mesh_overlay_data_format(uint *r_data_id) +static GPUVertFormat *edit_mesh_pos_nor_format(uint *r_pos_id, uint *r_nor_id) +{ + static GPUVertFormat format_pos_nor = { 0 }; + static uint pos_id, nor_id; + if (format_pos_nor.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format_pos_nor, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + nor_id = GPU_vertformat_attr_add(&format_pos_nor, "vnor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + *r_pos_id = pos_id; + *r_nor_id = nor_id; + return &format_pos_nor; +} + +static GPUVertFormat *edit_mesh_lnor_format(uint *r_lnor_id) +{ + static GPUVertFormat format_lnor = { 0 }; + static uint lnor_id; + if (format_lnor.attr_len == 0) { + lnor_id = GPU_vertformat_attr_add(&format_lnor, "lnor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + *r_lnor_id = lnor_id; + return &format_lnor; +} + +static GPUVertFormat *edit_mesh_data_format(uint *r_data_id) { static GPUVertFormat format_flag = { 0 }; static uint data_id; if (format_flag.attr_len == 0) { data_id = GPU_vertformat_attr_add(&format_flag, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); + GPU_vertformat_triple_load(&format_flag); } *r_data_id = data_id; return &format_flag; } -static void mesh_batch_cache_create_overlay_tri_buffers( - MeshRenderData *rdata, MeshBatchCache *cache) +static GPUVertFormat *edit_mesh_facedot_format(uint *r_pos_id, uint *r_nor_flag_id) +{ + static GPUVertFormat format_facedots = { 0 }; + static uint pos_id, nor_flag_id; + if (format_facedots.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format_facedots, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + nor_flag_id = GPU_vertformat_attr_add(&format_facedots, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + *r_pos_id = pos_id; + *r_nor_flag_id = nor_flag_id; + return &format_facedots; +} + +static void mesh_create_edit_tris_and_verts( + MeshRenderData *rdata, + GPUVertBuf *vbo_data, GPUVertBuf *vbo_pos_nor, GPUVertBuf *vbo_lnor, GPUIndexBuf *ibo_verts) { - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI)); BMesh *bm = rdata->edit_bmesh->bm; BMIter iter; BMVert *ev; const int tri_len = mesh_render_data_looptri_len_get_maybe_mapped(rdata); - - const int vbo_len_capacity = tri_len * 3; - int vbo_len_used = 0; + int tri_len_used = 0; int points_len = bm->totvert; - - /* Positions */ - GPUVertBuf *vbo_pos = NULL; - static struct { uint pos, vnor, lnor, data; } attr_id; - if (cache->ed_tri_pos == NULL) { - vbo_pos = cache->ed_tri_pos = - GPU_vertbuf_create_with_format(edit_mesh_overlay_pos_format(&attr_id.pos)); - GPU_vertbuf_data_alloc(vbo_pos, vbo_len_capacity); - } - - /* Normals */ - GPUVertBuf *vbo_nor = NULL; - if (cache->ed_tri_nor == NULL) { - vbo_nor = cache->ed_tri_nor = - GPU_vertbuf_create_with_format(edit_mesh_overlay_nor_format(&attr_id.vnor, &attr_id.lnor)); - GPU_vertbuf_data_alloc(vbo_nor, vbo_len_capacity); - } - - /* Data */ - GPUVertBuf *vbo_data = NULL; - if (cache->ed_tri_data == NULL) { - vbo_data = cache->ed_tri_data = - GPU_vertbuf_create_with_format(edit_mesh_overlay_data_format(&attr_id.data)); - GPU_vertbuf_data_alloc(vbo_data, vbo_len_capacity); + int verts_tri_len = tri_len * 3; + struct { uint pos, vnor, lnor, data; } attr_id; + GPUVertFormat *pos_nor_format = edit_mesh_pos_nor_format(&attr_id.pos, &attr_id.vnor); + GPUVertFormat *data_format = edit_mesh_data_format(&attr_id.data); + GPUVertFormat *lnor_format = edit_mesh_lnor_format(&attr_id.lnor); + + /* Positions & Vert Normals */ + if (DRW_TEST_ASSIGN_VBO(vbo_pos_nor)) { + GPU_vertbuf_init_with_format(vbo_pos_nor, pos_nor_format); + GPU_vertbuf_data_alloc(vbo_pos_nor, verts_tri_len); + } + /* Overlay data */ + if (DRW_TEST_ASSIGN_VBO(vbo_data)) { + GPU_vertbuf_init_with_format(vbo_data, data_format); + GPU_vertbuf_data_alloc(vbo_data, verts_tri_len); + } + /* Loop Normals */ + if (DRW_TEST_ASSIGN_VBO(vbo_lnor)) { + GPU_vertbuf_init_with_format(vbo_lnor, lnor_format); + GPU_vertbuf_data_alloc(vbo_lnor, verts_tri_len); } - /* Verts IBO */ GPUIndexBufBuilder elb, *elbp = NULL; - if (cache->ed_tri_verts == NULL) { + if (DRW_TEST_ASSIGN_IBO(ibo_verts)) { elbp = &elb; - GPU_indexbuf_init(elbp, GPU_PRIM_POINTS, points_len, vbo_len_capacity); - } - - /* Clear tag */ - BM_ITER_MESH(ev, &iter, bm, BM_VERTS_OF_MESH) { - BM_elem_flag_disable(ev, BM_ELEM_TAG); + GPU_indexbuf_init(elbp, GPU_PRIM_POINTS, points_len, verts_tri_len); + /* Clear tag */ + BM_ITER_MESH(ev, &iter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_disable(ev, BM_ELEM_TAG); + } } if (rdata->mapped.use == false) { for (int i = 0; i < tri_len; i++) { const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i]; if (!BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) { - add_overlay_tri( - rdata, vbo_pos, vbo_nor, vbo_data, elbp, - attr_id.pos, attr_id.vnor, attr_id.lnor, attr_id.data, - bm_looptri, vbo_len_used); - vbo_len_used += 3; + add_edit_tri(rdata, vbo_pos_nor, vbo_lnor, vbo_data, elbp, + attr_id.pos, attr_id.vnor, attr_id.lnor, attr_id.data, + bm_looptri, tri_len_used); + tri_len_used += 3; } } } else { Mesh *me_cage = rdata->mapped.me_cage; + + /* TODO(fclem): Maybe move data generation to mesh_render_data_create() */ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage); - if (!CustomData_has_layer(&me_cage->pdata, CD_NORMAL)) { - /* TODO(campbell): this is quite an expensive operation for something - * that's not used unless 'normal' display option is enabled. */ + if (vbo_lnor && !CustomData_has_layer(&me_cage->pdata, CD_NORMAL)) { BKE_mesh_ensure_normals_for_display(me_cage); } const float (*polynors)[3] = CustomData_get_layer(&me_cage->pdata, CD_NORMAL); + const float (*loopnors)[3] = CustomData_get_layer(&me_cage->ldata, CD_NORMAL); + for (int i = 0; i < tri_len; i++) { const MLoopTri *mlt = &mlooptri[i]; const int p_orig = rdata->mapped.p_origindex[mlt->poly]; if (p_orig != ORIGINDEX_NONE) { BMFace *efa = BM_face_at_index(bm, p_orig); - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - add_overlay_tri_mapped( - rdata, vbo_pos, vbo_nor, vbo_data, elbp, - attr_id.pos, attr_id.vnor, attr_id.lnor, attr_id.data, - efa, mlt, polynors[mlt->poly], vbo_len_used); - vbo_len_used += 3; + if (add_edit_tri_mapped(rdata, vbo_pos_nor, vbo_lnor, vbo_data, elbp, + attr_id.pos, attr_id.vnor, attr_id.lnor, attr_id.data, + efa, mlt, polynors, loopnors, tri_len_used)) + { + tri_len_used += 3; } } } } + /* Resize & Finish */ if (elbp != NULL) { - cache->ed_tri_verts = GPU_indexbuf_build(elbp); + GPU_indexbuf_build_in_place(elbp, ibo_verts); } - - /* Finish */ - if (vbo_len_used != vbo_len_capacity) { - if (vbo_pos != NULL) { - GPU_vertbuf_data_resize(vbo_pos, vbo_len_used); + if (tri_len_used != verts_tri_len) { + if (vbo_pos_nor != NULL) { + GPU_vertbuf_data_resize(vbo_pos_nor, tri_len_used); } - if (vbo_nor != NULL) { - GPU_vertbuf_data_resize(vbo_nor, vbo_len_used); + if (vbo_lnor != NULL) { + GPU_vertbuf_data_resize(vbo_lnor, tri_len_used); } if (vbo_data != NULL) { - GPU_vertbuf_data_resize(vbo_data, vbo_len_used); + GPU_vertbuf_data_resize(vbo_data, tri_len_used); } } - - /* Upload data early because we need to create the texture for it. */ - GPU_vertbuf_use(vbo_data); - cache->ed_tri_data_tx = GPU_texture_create_from_vertbuf(vbo_data); } -static void mesh_batch_cache_create_overlay_ledge_buffers( - MeshRenderData *rdata, MeshBatchCache *cache) +static void mesh_create_edit_loose_edges( + MeshRenderData *rdata, + GPUVertBuf *vbo_data_ledges, GPUVertBuf *vbo_pos_nor_ledges) { - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI)); - - const int ledge_len = mesh_render_data_loose_edges_len_get_maybe_mapped(rdata); + BMesh *bm = rdata->edit_bmesh->bm; + const int loose_edge_len = mesh_render_data_loose_edges_len_get_maybe_mapped(rdata); + const int verts_ledges_len = loose_edge_len * 2; + int ledges_len_used = 0; - const int vbo_len_capacity = ledge_len * 2; - int vbo_len_used = 0; + struct { uint pos, vnor, data; } attr_id; + GPUVertFormat *pos_nor_format = edit_mesh_pos_nor_format(&attr_id.pos, &attr_id.vnor); + GPUVertFormat *data_format = edit_mesh_data_format(&attr_id.data); - /* Positions */ - GPUVertBuf *vbo_pos = NULL; - static struct { uint pos, vnor, data; } attr_id; - if (cache->ed_ledge_pos == NULL) { - vbo_pos = cache->ed_ledge_pos = - GPU_vertbuf_create_with_format(edit_mesh_overlay_pos_format(&attr_id.pos)); - GPU_vertbuf_data_alloc(vbo_pos, vbo_len_capacity); + /* Positions & Vert Normals */ + if (DRW_TEST_ASSIGN_VBO(vbo_pos_nor_ledges)) { + GPU_vertbuf_init_with_format(vbo_pos_nor_ledges, pos_nor_format); + GPU_vertbuf_data_alloc(vbo_pos_nor_ledges, verts_ledges_len); } - - /* Normals */ - GPUVertBuf *vbo_nor = NULL; - if (cache->ed_ledge_nor == NULL) { - vbo_nor = cache->ed_ledge_nor = - GPU_vertbuf_create_with_format(edit_mesh_overlay_nor_format(&attr_id.vnor, NULL)); - GPU_vertbuf_data_alloc(vbo_nor, vbo_len_capacity); - } - - /* Data */ - GPUVertBuf *vbo_data = NULL; - if (cache->ed_ledge_data == NULL) { - vbo_data = cache->ed_ledge_data = - GPU_vertbuf_create_with_format(edit_mesh_overlay_data_format(&attr_id.data)); - GPU_vertbuf_data_alloc(vbo_data, vbo_len_capacity); + /* Overlay data */ + if (DRW_TEST_ASSIGN_VBO(vbo_data_ledges)) { + GPU_vertbuf_init_with_format(vbo_data_ledges, data_format); + GPU_vertbuf_data_alloc(vbo_data_ledges, verts_ledges_len); } if (rdata->mapped.use == false) { - if (rdata->edit_bmesh) { - BMesh *bm = rdata->edit_bmesh->bm; - for (uint i = 0; i < ledge_len; i++) { - const BMEdge *eed = BM_edge_at_index(bm, rdata->loose_edges[i]); - add_overlay_loose_edge( - rdata, vbo_pos, vbo_nor, vbo_data, - attr_id.pos, attr_id.vnor, attr_id.data, - eed, vbo_len_used); - vbo_len_used += 2; - } + for (uint i = 0; i < loose_edge_len; i++) { + const BMEdge *eed = BM_edge_at_index(bm, rdata->loose_edges[i]); + add_edit_loose_edge(rdata, vbo_pos_nor_ledges, vbo_data_ledges, + attr_id.pos, attr_id.vnor, attr_id.data, + eed, ledges_len_used); + ledges_len_used += 2; } } else { - BMesh *bm = rdata->edit_bmesh->bm; Mesh *me_cage = rdata->mapped.me_cage; const MVert *mvert = me_cage->mvert; const MEdge *medge = me_cage->medge; const int *e_origindex = rdata->mapped.e_origindex; - for (uint i_iter = 0; i_iter < ledge_len; i_iter++) { + + for (uint i_iter = 0; i_iter < loose_edge_len; i_iter++) { const int i = rdata->mapped.loose_edges[i_iter]; const int e_orig = e_origindex[i]; - const MEdge *ed = &medge[i]; BMEdge *eed = BM_edge_at_index(bm, e_orig); - add_overlay_loose_edge_mapped( - rdata, vbo_pos, vbo_nor, vbo_data, - attr_id.pos, attr_id.vnor, attr_id.data, - eed, mvert, ed, vbo_len_used); - vbo_len_used += 2; - } - } - - /* Finish */ - if (vbo_len_used != vbo_len_capacity) { - if (vbo_pos != NULL) { - GPU_vertbuf_data_resize(vbo_pos, vbo_len_used); - } - if (vbo_nor != NULL) { - GPU_vertbuf_data_resize(vbo_nor, vbo_len_used); - } - if (vbo_data != NULL) { - GPU_vertbuf_data_resize(vbo_data, vbo_len_used); + add_edit_loose_edge_mapped(rdata, vbo_pos_nor_ledges, vbo_data_ledges, + attr_id.pos, attr_id.vnor, attr_id.data, + eed, mvert, &medge[i], ledges_len_used); + ledges_len_used += 2; } } + BLI_assert(ledges_len_used == verts_ledges_len); } -static void mesh_batch_cache_create_overlay_lvert_buffers( - MeshRenderData *rdata, MeshBatchCache *cache) +static void mesh_create_edit_loose_verts( + MeshRenderData *rdata, + GPUVertBuf *vbo_data_lverts, GPUVertBuf *vbo_pos_nor_lverts) { - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI)); - BMesh *bm = rdata->edit_bmesh->bm; - const int lvert_len = mesh_render_data_loose_verts_len_get_maybe_mapped(rdata); - - const int vbo_len_capacity = lvert_len; - int vbo_len_used = 0; + const int loose_verts_len = mesh_render_data_loose_verts_len_get_maybe_mapped(rdata); + const int verts_lverts_len = loose_verts_len; + int lverts_len_used = 0; - static struct { uint pos, vnor, data; } attr_id; + struct { uint pos, vnor, data; } attr_id; + GPUVertFormat *pos_nor_format = edit_mesh_pos_nor_format(&attr_id.pos, &attr_id.vnor); + GPUVertFormat *data_format = edit_mesh_data_format(&attr_id.data); - /* Positions */ - GPUVertBuf *vbo_pos = NULL; - if (cache->ed_lvert_pos == NULL) { - vbo_pos = cache->ed_lvert_pos = - GPU_vertbuf_create_with_format(edit_mesh_overlay_pos_format(&attr_id.pos)); - GPU_vertbuf_data_alloc(vbo_pos, vbo_len_capacity); + /* Positions & Vert Normals */ + if (DRW_TEST_ASSIGN_VBO(vbo_pos_nor_lverts)) { + GPU_vertbuf_init_with_format(vbo_pos_nor_lverts, pos_nor_format); + GPU_vertbuf_data_alloc(vbo_pos_nor_lverts, verts_lverts_len); } - - /* Normals */ - GPUVertBuf *vbo_nor = NULL; - if (cache->ed_lvert_nor == NULL) { - vbo_nor = cache->ed_lvert_nor = - GPU_vertbuf_create_with_format(edit_mesh_overlay_nor_format(&attr_id.vnor, NULL)); - GPU_vertbuf_data_alloc(vbo_nor, vbo_len_capacity); - } - - /* Data */ - GPUVertBuf *vbo_data = NULL; - if (cache->ed_lvert_data == NULL) { - vbo_data = cache->ed_lvert_data = - GPU_vertbuf_create_with_format(edit_mesh_overlay_data_format(&attr_id.data)); - GPU_vertbuf_data_alloc(vbo_data, vbo_len_capacity); + /* Overlay data */ + if (DRW_TEST_ASSIGN_VBO(vbo_data_lverts)) { + GPU_vertbuf_init_with_format(vbo_data_lverts, data_format); + GPU_vertbuf_data_alloc(vbo_data_lverts, verts_lverts_len); } if (rdata->mapped.use == false) { - for (uint i = 0; i < lvert_len; i++) { + for (uint i = 0; i < loose_verts_len; i++) { BMVert *eve = BM_vert_at_index(bm, rdata->loose_verts[i]); - add_overlay_loose_vert( - rdata, vbo_pos, vbo_nor, vbo_data, - attr_id.pos, attr_id.vnor, attr_id.data, - eve, vbo_len_used); - vbo_len_used += 1; + add_edit_loose_vert(rdata, vbo_pos_nor_lverts, vbo_data_lverts, + attr_id.pos, attr_id.vnor, attr_id.data, + eve, lverts_len_used); + lverts_len_used += 1; } } else { Mesh *me_cage = rdata->mapped.me_cage; const MVert *mvert = me_cage->mvert; const int *v_origindex = rdata->mapped.v_origindex; - for (uint i_iter = 0; i_iter < lvert_len; i_iter++) { + + for (uint i_iter = 0; i_iter < loose_verts_len; i_iter++) { const int i = rdata->mapped.loose_verts[i_iter]; const int v_orig = v_origindex[i]; - const MVert *mv = &mvert[i]; BMVert *eve = BM_vert_at_index(bm, v_orig); - add_overlay_loose_vert_mapped( - rdata, vbo_pos, vbo_nor, vbo_data, - attr_id.pos, attr_id.vnor, attr_id.data, - eve, mv, vbo_len_used); - vbo_len_used += 1; - } - } - - /* Finish */ - if (vbo_len_used != vbo_len_capacity) { - if (vbo_pos != NULL) { - GPU_vertbuf_data_resize(vbo_pos, vbo_len_used); - } - if (vbo_nor != NULL) { - GPU_vertbuf_data_resize(vbo_nor, vbo_len_used); + add_edit_loose_vert_mapped(rdata, vbo_pos_nor_lverts, vbo_data_lverts, + attr_id.pos, attr_id.vnor, attr_id.data, + eve, &mvert[i], lverts_len_used); + lverts_len_used += 1; } - if (vbo_data != NULL) { - GPU_vertbuf_data_resize(vbo_data, vbo_len_used); - } - } -} - -/* Position */ -static GPUVertBuf *mesh_batch_cache_get_edit_tri_pos( - MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & MR_DATATYPE_VERT); - - if (cache->ed_tri_pos == NULL) { - mesh_batch_cache_create_overlay_tri_buffers(rdata, cache); } - - return cache->ed_tri_pos; + BLI_assert(lverts_len_used == verts_lverts_len); } -static GPUVertBuf *mesh_batch_cache_get_edit_ledge_pos( - MeshRenderData *rdata, MeshBatchCache *cache) +static void mesh_create_edit_facedots( + MeshRenderData *rdata, + GPUVertBuf *vbo_pos_nor_data_facedots) { - BLI_assert(rdata->types & MR_DATATYPE_VERT); + const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata); + const int verts_facedot_len = poly_len; + int facedot_len_used = 0; - if (cache->ed_ledge_pos == NULL) { - if (rdata->mapped.supported) { - rdata->mapped.use = true; - } - mesh_batch_cache_create_overlay_ledge_buffers(rdata, cache); - } - - return cache->ed_ledge_pos; -} + struct { uint fdot_pos, fdot_nor_flag; } attr_id; + GPUVertFormat *facedot_format = edit_mesh_facedot_format(&attr_id.fdot_pos, &attr_id.fdot_nor_flag); -static GPUVertBuf *mesh_batch_cache_get_edit_lvert_pos( - MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & MR_DATATYPE_VERT); - - if (cache->ed_lvert_pos == NULL) { - if (rdata->mapped.supported) { - rdata->mapped.use = true; - } - mesh_batch_cache_create_overlay_lvert_buffers(rdata, cache); - } - - return cache->ed_lvert_pos; -} - -/* Indices */ -static GPUIndexBuf *mesh_batch_cache_get_edit_tri_indices( - MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & MR_DATATYPE_VERT); - - if (cache->ed_tri_verts == NULL) { - mesh_batch_cache_create_overlay_tri_buffers(rdata, cache); - } - - return cache->ed_tri_verts; -} - -/* Normal */ -static GPUVertBuf *mesh_batch_cache_get_edit_tri_nor( - MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & MR_DATATYPE_VERT); - - if (cache->ed_tri_nor == NULL) { - if (rdata->mapped.supported) { - rdata->mapped.use = true; + if (DRW_TEST_ASSIGN_VBO(vbo_pos_nor_data_facedots)) { + GPU_vertbuf_init_with_format(vbo_pos_nor_data_facedots, facedot_format); + GPU_vertbuf_data_alloc(vbo_pos_nor_data_facedots, verts_facedot_len); + /* TODO(fclem): Maybe move data generation to mesh_render_data_create() */ + if (rdata->edit_bmesh) { + if (rdata->edit_data && rdata->edit_data->vertexCos != NULL) { + BKE_editmesh_cache_ensure_poly_normals(rdata->edit_bmesh, rdata->edit_data); + BKE_editmesh_cache_ensure_poly_centers(rdata->edit_bmesh, rdata->edit_data); + } } - mesh_batch_cache_create_overlay_tri_buffers(rdata, cache); } - return cache->ed_tri_nor; -} - -static GPUVertBuf *mesh_batch_cache_get_edit_ledge_nor( - MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & MR_DATATYPE_VERT); - - if (cache->ed_ledge_nor == NULL) { - if (rdata->mapped.supported) { - rdata->mapped.use = true; + if (rdata->mapped.use == false) { + for (int i = 0; i < poly_len; i++) { + if (add_edit_facedot(rdata, vbo_pos_nor_data_facedots, + attr_id.fdot_pos, attr_id.fdot_nor_flag, + i, facedot_len_used)) + { + facedot_len_used += 1; + } } - mesh_batch_cache_create_overlay_ledge_buffers(rdata, cache); } - - return cache->ed_ledge_nor; -} - -static GPUVertBuf *mesh_batch_cache_get_edit_lvert_nor( - MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & MR_DATATYPE_VERT); - - if (cache->ed_lvert_nor == NULL) { - if (rdata->mapped.supported) { - rdata->mapped.use = true; + else { +#if 0 /* TODO(fclem): Mapped facedots are not following the original face. */ + Mesh *me_cage = rdata->mapped.me_cage; + const MVert *mvert = me_cage->mvert; + const MEdge *medge = me_cage->medge; + const int *e_origindex = rdata->mapped.e_origindex; + const int *v_origindex = rdata->mapped.v_origindex; +#endif + for (int i = 0; i < poly_len; i++) { + if (add_edit_facedot_mapped(rdata, vbo_pos_nor_data_facedots, + attr_id.fdot_pos, attr_id.fdot_nor_flag, + i, facedot_len_used)) + { + facedot_len_used += 1; + } } - mesh_batch_cache_create_overlay_lvert_buffers(rdata, cache); } - return cache->ed_lvert_nor; -} - -/* Data */ -static GPUVertBuf *mesh_batch_cache_get_edit_tri_data( - MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & MR_DATATYPE_VERT); - - if (cache->ed_tri_data == NULL) { - mesh_batch_cache_create_overlay_tri_buffers(rdata, cache); - } - - return cache->ed_tri_data; -} - -static GPUVertBuf *mesh_batch_cache_get_edit_ledge_data( - MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & MR_DATATYPE_VERT); - - if (cache->ed_ledge_data == NULL) { - if (rdata->mapped.supported) { - rdata->mapped.use = true; + /* Resize & Finish */ + if (facedot_len_used != verts_facedot_len) { + if (vbo_pos_nor_data_facedots != NULL) { + GPU_vertbuf_data_resize(vbo_pos_nor_data_facedots, facedot_len_used); } - mesh_batch_cache_create_overlay_ledge_buffers(rdata, cache); } - - return cache->ed_ledge_data; } -static GPUVertBuf *mesh_batch_cache_get_edit_lvert_data( - MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & MR_DATATYPE_VERT); - - if (cache->ed_lvert_data == NULL) { - if (rdata->mapped.supported) { - rdata->mapped.use = true; - } - mesh_batch_cache_create_overlay_lvert_buffers(rdata, cache); - } - - return cache->ed_lvert_data; -} +/* Indices */ static GPUIndexBuf *mesh_batch_cache_get_edges_in_order(MeshRenderData *rdata, MeshBatchCache *cache) { @@ -4173,11 +4125,14 @@ static GPUIndexBuf *mesh_batch_cache_get_edges_adjacency(MeshRenderData *rdata, } #undef NO_EDGE -static EdgeHash *create_looptri_edge_adjacency_hash(MeshRenderData *rdata) +static EdgeHash *create_looptri_edge_adjacency_hash(MeshRenderData *rdata, EdgeAdjacentVerts **r_adj_data) { const int tri_len = mesh_render_data_looptri_len_get(rdata); /* Create adjacency info in looptri */ EdgeHash *eh = BLI_edgehash_new_ex(__func__, tri_len * 3); + /* TODO allocate less memory (based on edge count) */ + EdgeAdjacentVerts *adj_data = MEM_mallocN(tri_len * 3 * sizeof(EdgeAdjacentVerts), __func__); + *r_adj_data = adj_data; /* Create edges for each pair of triangles sharing an edge. */ for (int i = 0; i < tri_len; i++) { for (int e = 0; e < 3; e++) { @@ -4202,7 +4157,7 @@ static EdgeHash *create_looptri_edge_adjacency_hash(MeshRenderData *rdata) EdgeAdjacentVerts **eav; bool value_is_init = BLI_edgehash_ensure_p(eh, v1, v2, (void ***)&eav); if (!value_is_init) { - *eav = MEM_mallocN(sizeof(**eav), "EdgeAdjacentVerts"); + *eav = adj_data++; (*eav)->vert_index[0] = v0; (*eav)->vert_index[1] = -1; } @@ -4219,24 +4174,30 @@ static EdgeHash *create_looptri_edge_adjacency_hash(MeshRenderData *rdata) return eh; } -static GPUVertBuf *mesh_batch_cache_create_edges_overlay_texture_buf(MeshRenderData *rdata) +static void mesh_create_wireframe_data_tess(MeshRenderData *rdata, GPUVertBuf *vbo) { - const int tri_len = mesh_render_data_looptri_len_get(rdata); + static uint data_id; + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + data_id = GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_triple_load(&format); + } - GPUVertFormat format = {0}; - uint index_id = GPU_vertformat_attr_add(&format, "index", GPU_COMP_U32, 1, GPU_FETCH_INT); - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_init_with_format(vbo, &format); + const int tri_len = mesh_render_data_looptri_len_get(rdata); int vbo_len_capacity = tri_len * 3; GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); int vidx = 0; EdgeHash *eh = NULL; - eh = create_looptri_edge_adjacency_hash(rdata); + EdgeAdjacentVerts *adj_data = NULL; + eh = create_looptri_edge_adjacency_hash(rdata, &adj_data); for (int i = 0; i < tri_len; i++) { - bool edge_is_real[3]; + uchar vdata[3] = {0, 0, 0}; + const MVert *mvert = rdata->mvert; const MEdge *medge = rdata->medge; const MLoop *mloop = rdata->mloop; const MLoopTri *mlt = rdata->mlooptri + i; @@ -4244,110 +4205,69 @@ static GPUVertBuf *mesh_batch_cache_create_edges_overlay_texture_buf(MeshRenderD int j, j_next; for (j = 2, j_next = 0; j_next < 3; j = j_next++) { const MEdge *ed = &medge[mloop[mlt->tri[j]].e]; - const uint tri_edge[2] = {mloop[mlt->tri[j]].v, mloop[mlt->tri[j_next]].v}; - const bool is_edge_real = ( - ((ed->v1 == tri_edge[0]) && (ed->v2 == tri_edge[1])) || - ((ed->v1 == tri_edge[1]) && (ed->v2 == tri_edge[0]))); - edge_is_real[j] = is_edge_real; - } + const uint tri_edge[2] = {mloop[mlt->tri[j]].v, mloop[mlt->tri[j_next]].v}; - for (int e = 0; e < 3; e++) { - int v0 = mloop[mlt->tri[e]].v; - int v1 = mloop[mlt->tri[(e + 1) % 3]].v; - EdgeAdjacentVerts *eav = BLI_edgehash_lookup(eh, v0, v1); - uint value = (uint)v0; - /* Real edge */ - if (edge_is_real[e]) { - value |= (1 << 30); - } - /* Non-manifold edge */ - if (eav->vert_index[1] == -1) { - value |= (1u << 31); + if ((((ed->v1 == tri_edge[0]) && (ed->v2 == tri_edge[1])) || + ((ed->v1 == tri_edge[1]) && (ed->v2 == tri_edge[0])))) + { + /* Real edge. */ + /* Temp Workaround. If a mesh has a subdiv mod we should not + * compute the edge sharpness. Instead, we just mix both for now. */ + vdata[j] = ((ed->flag & ME_EDGERENDER) != 0) ? 0xFD : 0xFE; } - GPU_vertbuf_attr_set(vbo, index_id, vidx++, &value); } - } - - BLI_edgehash_free(eh, MEM_freeN); - int vbo_len_used = vidx; + /* If at least one edge is real. */ + if (vdata[0] || vdata[1] || vdata[2]) { + float fnor[3]; + normal_tri_v3(fnor, + mvert[mloop[mlt->tri[0]].v].co, + mvert[mloop[mlt->tri[1]].v].co, + mvert[mloop[mlt->tri[2]].v].co); - if (vbo_len_capacity != vbo_len_used) { - GPU_vertbuf_data_resize(vbo, vbo_len_used); - } - - return vbo; -} - -static GPUTexture *mesh_batch_cache_get_edges_overlay_texture_buf(MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI)); - - BLI_assert(rdata->edit_bmesh == NULL); /* Not supported in edit mode */ - - if (cache->edges_face_overlay_tx != NULL) { - return cache->edges_face_overlay_tx; - } - - GPUVertBuf *vbo = cache->edges_face_overlay = mesh_batch_cache_create_edges_overlay_texture_buf(rdata); - - /* Upload data early because we need to create the texture for it. */ - GPU_vertbuf_use(vbo); - cache->edges_face_overlay_tx = GPU_texture_create_from_vertbuf(vbo); - cache->edges_face_overlay_tri_count = vbo->vertex_alloc / 3; - - return cache->edges_face_overlay_tx; -} - -static GPUTexture *mesh_batch_cache_get_vert_pos_and_nor_in_order_buf(MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI)); - - if (cache->pos_in_order_tx == NULL) { - GPUVertBuf *pos_in_order = mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache); - GPU_vertbuf_use(pos_in_order); /* Upload early for buffer texture creation. */ - cache->pos_in_order_tx = GPU_texture_create_buffer(GPU_R32F, pos_in_order->vbo_id); - } - - return cache->pos_in_order_tx; -} - -static GPUIndexBuf *mesh_batch_cache_get_triangles_in_order(MeshRenderData *rdata, MeshBatchCache *cache) -{ - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI)); - - if (cache->triangles_in_order == NULL) { - const int vert_len = mesh_render_data_verts_len_get(rdata); - const int tri_len = mesh_render_data_looptri_len_get(rdata); - - GPUIndexBufBuilder elb; - GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len); - - if (rdata->edit_bmesh) { - for (int i = 0; i < tri_len; i++) { - const BMLoop **ltri = (const BMLoop **)rdata->edit_bmesh->looptris[i]; - if (!BM_elem_flag_test(ltri[0]->f, BM_ELEM_HIDDEN)) { - for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { - GPU_indexbuf_add_generic_vert(&elb, BM_elem_index_get(ltri[tri_corner]->v)); + for (int e = 0; e < 3; e++) { + /* Non-real edge. */ + if (vdata[e] == 0) { + continue; + } + int v0 = mloop[mlt->tri[e]].v; + int v1 = mloop[mlt->tri[(e + 1) % 3]].v; + EdgeAdjacentVerts *eav = BLI_edgehash_lookup(eh, v0, v1); + /* If Non Manifold. */ + if (eav->vert_index[1] == -1) { + vdata[e] = 0xFF; + } + else if (vdata[e] == 0xFD) { + int v2 = mloop[mlt->tri[(e + 2) % 3]].v; + /* Select the right opposite vertex */ + v2 = (eav->vert_index[1] == v2) ? eav->vert_index[0] : eav->vert_index[1]; + float fnor_adj[3]; + normal_tri_v3(fnor_adj, + mvert[v1].co, + mvert[v0].co, + mvert[v2].co); + float fac = dot_v3v3(fnor_adj, fnor); + fac = fac * fac * 50.0f - 49.0f; + CLAMP(fac, 0.0f, 0.999f); + /* Shorten the range to make the non-ME_EDGERENDER fade first. + * Add one because 0x0 is no edges. */ + vdata[e] = (uchar)(0xDF * fac) + 1; + if (vdata[e] < 0.999f) { + /* TODO construct fast face wire index buffer. */ } } } } - else { - for (int i = 0; i < tri_len; i++) { - const MLoopTri *mlt = &rdata->mlooptri[i]; - for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { - GPU_indexbuf_add_generic_vert(&elb, mlt->tri[tri_corner]); - } - } + + for (int e = 0; e < 3; e++) { + GPU_vertbuf_attr_set(vbo, data_id, vidx++, &vdata[e]); } - cache->triangles_in_order = GPU_indexbuf_build(&elb); } - return cache->triangles_in_order; + BLI_edgehash_free(eh, NULL); + MEM_freeN(adj_data); } - static GPUIndexBuf *mesh_batch_cache_get_loose_edges(MeshRenderData *rdata, MeshBatchCache *cache) { BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI)); @@ -4399,244 +4319,179 @@ static GPUIndexBuf *mesh_batch_cache_get_loose_edges(MeshRenderData *rdata, Mesh return cache->ledges_in_order; } -static GPUIndexBuf **mesh_batch_cache_get_triangles_in_order_split_by_material( - MeshRenderData *rdata, MeshBatchCache *cache, - /* Special case when drawing final evaluated mesh in editmode, so hidden faces are ignored. */ - BMesh *bm_mapped, const int *p_origindex_mapped) +static void mesh_create_surf_tris(MeshRenderData *rdata, GPUIndexBuf *ibo, const bool use_hide) { - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_POLY)); - - if (cache->shaded_triangles_in_order == NULL) { - const int poly_len = mesh_render_data_polys_len_get(rdata); - const int tri_len = mesh_render_data_looptri_len_get(rdata); - const int mat_len = mesh_render_data_mat_len_get(rdata); + const int vert_len = mesh_render_data_verts_len_get_maybe_mapped(rdata); + const int tri_len = mesh_render_data_looptri_len_get(rdata); - int *mat_tri_len = MEM_callocN(sizeof(*mat_tri_len) * mat_len, __func__); - cache->shaded_triangles_in_order = MEM_callocN(sizeof(*cache->shaded_triangles) * mat_len, __func__); - GPUIndexBufBuilder *elb = MEM_callocN(sizeof(*elb) * mat_len, __func__); + GPUIndexBufBuilder elb; + GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len * 3); - /* Note that polygons (not triangles) are used here. - * This OK because result is _guaranteed_ to be the same. */ + if (rdata->mapped.use == false) { if (rdata->edit_bmesh) { - BMesh *bm = rdata->edit_bmesh->bm; - BMIter fiter; - BMFace *efa; - - BM_ITER_MESH(efa, &fiter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - const short ma_id = efa->mat_nr < mat_len ? efa->mat_nr : 0; - mat_tri_len[ma_id] += (efa->len - 2); + for (int i = 0; i < tri_len; i++) { + const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i]; + const BMFace *bm_face = bm_looptri[0]->f; + /* use_hide always for edit-mode */ + if (BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) { + continue; } - } - } - else if (bm_mapped == NULL) { - for (uint i = 0; i < poly_len; i++) { - const MPoly *mp = &rdata->mpoly[i]; ; - const short ma_id = mp->mat_nr < mat_len ? mp->mat_nr : 0; - mat_tri_len[ma_id] += (mp->totloop - 2); + GPU_indexbuf_add_tri_verts(&elb, BM_elem_index_get(bm_looptri[0]->v), + BM_elem_index_get(bm_looptri[1]->v), + BM_elem_index_get(bm_looptri[2]->v)); } } else { - BM_mesh_elem_table_ensure(bm_mapped, BM_FACE); - for (uint i = 0; i < poly_len; i++) { - const int p_orig = p_origindex_mapped[i]; - if ((p_orig == ORIGINDEX_NONE) || - !BM_elem_flag_test(BM_face_at_index(bm_mapped, p_orig), BM_ELEM_HIDDEN)) - { - const MPoly *mp = &rdata->mpoly[i]; ; - const short ma_id = mp->mat_nr < mat_len ? mp->mat_nr : 0; - mat_tri_len[ma_id] += (mp->totloop - 2); + const MLoop *loops = rdata->mloop; + for (int i = 0; i < tri_len; i++) { + const MLoopTri *mlt = &rdata->mlooptri[i]; + const MPoly *mp = &rdata->mpoly[mlt->poly]; + if (use_hide && (mp->flag & ME_HIDE)) { + continue; } + GPU_indexbuf_add_tri_verts(&elb, loops[mlt->tri[0]].v, loops[mlt->tri[1]].v, loops[mlt->tri[2]].v); } - } + } + else { + /* Note: mapped doesn't support lnors yet. */ + BMesh *bm = rdata->edit_bmesh->bm; + Mesh *me_cage = rdata->mapped.me_cage; - /* Init ELBs. */ - for (int i = 0; i < mat_len; i++) { - GPU_indexbuf_init(&elb[i], GPU_PRIM_TRIS, mat_tri_len[i], tri_len * 3); + const MLoop *loops = rdata->mloop; + const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage); + for (int i = 0; i < tri_len; i++) { + const MLoopTri *mlt = &mlooptri[i]; + const int p_orig = rdata->mapped.p_origindex[mlt->poly]; + if (p_orig != ORIGINDEX_NONE) { + /* Assume 'use_hide' */ + BMFace *efa = BM_face_at_index(bm, p_orig); + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + GPU_indexbuf_add_tri_verts(&elb, loops[mlt->tri[0]].v, loops[mlt->tri[1]].v, loops[mlt->tri[2]].v); + } + } } + } - /* Populate ELBs. */ - uint nidx = 0; + GPU_indexbuf_build_in_place(&elb, ibo); +} + +static void mesh_create_loops_lines( + MeshRenderData *rdata, GPUIndexBuf *ibo, const bool use_hide) +{ + const int loop_len = mesh_render_data_loops_len_get(rdata); + const int poly_len = mesh_render_data_polys_len_get(rdata); + + GPUIndexBufBuilder elb; + GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, loop_len + poly_len * 2, loop_len, true); + + uint v_index = 0; + if (rdata->mapped.use == false) { if (rdata->edit_bmesh) { BMesh *bm = rdata->edit_bmesh->bm; - BMIter fiter; - BMFace *efa; + BMIter iter; + BMFace *bm_face; - BM_ITER_MESH(efa, &fiter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - const short ma_id = efa->mat_nr < mat_len ? efa->mat_nr : 0; - for (int j = 2; j < efa->len; j++) { - GPU_indexbuf_add_tri_verts(&elb[ma_id], nidx + 0, nidx + 1, nidx + 2); - nidx += 3; + BM_ITER_MESH (bm_face, &iter, bm, BM_FACES_OF_MESH) { + /* use_hide always for edit-mode */ + if (!BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) { + for (int i; i < bm_face->len; i++) { + GPU_indexbuf_add_generic_vert(&elb, v_index + i); } + /* Finish loop and restart primitive. */ + GPU_indexbuf_add_generic_vert(&elb, v_index); + GPU_indexbuf_add_primitive_restart(&elb); } - } - } - else if (bm_mapped == NULL) { - for (uint i = 0; i < poly_len; i++) { - const MPoly *mp = &rdata->mpoly[i]; ; - const short ma_id = mp->mat_nr < mat_len ? mp->mat_nr : 0; - for (int j = 2; j < mp->totloop; j++) { - GPU_indexbuf_add_tri_verts(&elb[ma_id], nidx + 0, nidx + 1, nidx + 2); - nidx += 3; - } + v_index += bm_face->len; } } else { - for (uint i = 0; i < poly_len; i++) { - const int p_orig = p_origindex_mapped[i]; - const MPoly *mp = &rdata->mpoly[i]; - if ((p_orig == ORIGINDEX_NONE) || - !BM_elem_flag_test(BM_face_at_index(bm_mapped, p_orig), BM_ELEM_HIDDEN)) - { - const short ma_id = mp->mat_nr < mat_len ? mp->mat_nr : 0; - for (int j = 2; j < mp->totloop; j++) { - GPU_indexbuf_add_tri_verts(&elb[ma_id], nidx + 0, nidx + 1, nidx + 2); - nidx += 3; + for (int poly = 0; poly < poly_len; poly++) { + const MPoly *mp = &rdata->mpoly[poly]; + if (!(use_hide && (mp->flag & ME_HIDE))) { + const int loopend = mp->loopstart + mp->totloop; + for (int j = mp->loopstart; j < loopend; j++) { + GPU_indexbuf_add_generic_vert(&elb, j); } + /* Finish loop and restart primitive. */ + GPU_indexbuf_add_generic_vert(&elb, mp->loopstart); + GPU_indexbuf_add_primitive_restart(&elb); } - else { - nidx += (mp->totloop - 2) * 3; - } + v_index += mp->totloop; } } - - /* Build ELBs. */ - for (int i = 0; i < mat_len; i++) { - cache->shaded_triangles_in_order[i] = GPU_indexbuf_build(&elb[i]); - } - - MEM_freeN(mat_tri_len); - MEM_freeN(elb); + } + else { + /* Implement ... eventually if needed. */ + BLI_assert(0); } - return cache->shaded_triangles_in_order; + GPU_indexbuf_build_in_place(&elb, ibo); } -static GPUVertBuf *mesh_create_edge_pos_with_sel( - MeshRenderData *rdata, bool use_wire, bool use_select_bool) +static void mesh_create_loops_tris( + MeshRenderData *rdata, GPUIndexBuf **ibo, int ibo_len, const bool use_hide) { - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_POLY | MR_DATATYPE_LOOP)); - BLI_assert(rdata->edit_bmesh == NULL); - - GPUVertBuf *vbo; - { - uint vidx = 0, cidx = 0; - - static GPUVertFormat format = { 0 }; - static struct { uint pos, sel; } attr_id; - if (format.attr_len == 0) { - attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - attr_id.sel = GPU_vertformat_attr_add(&format, "select", GPU_COMP_U8, 1, GPU_FETCH_INT); - } - - const int edge_len = mesh_render_data_edges_len_get(rdata); - - vbo = GPU_vertbuf_create_with_format(&format); - - const int vbo_len_capacity = edge_len * 2; - int vbo_len_used = 0; - GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); + const int loop_len = mesh_render_data_loops_len_get(rdata); + const int tri_len = mesh_render_data_looptri_len_get(rdata); - if (use_select_bool) { - mesh_render_data_ensure_edge_select_bool(rdata, use_wire); - } - bool *edge_select_bool = use_select_bool ? rdata->edge_select_bool : NULL; + GPUIndexBufBuilder *elb = BLI_array_alloca(elb, ibo_len); - for (int i = 0; i < edge_len; i++) { - const MEdge *ed = &rdata->medge[i]; + for (int i = 0; i < ibo_len; ++i) { + /* TODO alloc minmum necessary. */ + GPU_indexbuf_init(&elb[i], GPU_PRIM_TRIS, tri_len, loop_len * 3); + } - uchar edge_vert_sel; - if (use_select_bool && edge_select_bool[i]) { - edge_vert_sel = true; - } - else if (use_wire) { - edge_vert_sel = false; - } - else { - continue; + if (rdata->mapped.use == false) { + if (rdata->edit_bmesh) { + for (int i = 0; i < tri_len; i++) { + const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i]; + const BMFace *bm_face = bm_looptri[0]->f; + /* use_hide always for edit-mode */ + if (BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) { + continue; + } + int mat = (ibo_len > 1) ? bm_face->mat_nr : 0; + GPU_indexbuf_add_tri_verts(&elb[mat], BM_elem_index_get(bm_looptri[0]), + BM_elem_index_get(bm_looptri[1]), + BM_elem_index_get(bm_looptri[2])); } - - GPU_vertbuf_attr_set(vbo, attr_id.sel, cidx++, &edge_vert_sel); - GPU_vertbuf_attr_set(vbo, attr_id.sel, cidx++, &edge_vert_sel); - - GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, rdata->mvert[ed->v1].co); - GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, rdata->mvert[ed->v2].co); } - vbo_len_used = vidx; - - if (vbo_len_capacity != vbo_len_used) { - GPU_vertbuf_data_resize(vbo, vbo_len_used); + else { + for (int i = 0; i < tri_len; i++) { + const MLoopTri *mlt = &rdata->mlooptri[i]; + const MPoly *mp = &rdata->mpoly[mlt->poly]; + if (use_hide && (mp->flag & ME_HIDE)) { + continue; + } + int mat = (ibo_len > 1) ? mp->mat_nr : 0; + GPU_indexbuf_add_tri_verts(&elb[mat], mlt->tri[0], mlt->tri[1], mlt->tri[2]); + } } } + else { + /* Note: mapped doesn't support lnors yet. */ + BMesh *bm = rdata->edit_bmesh->bm; + Mesh *me_cage = rdata->mapped.me_cage; - return vbo; -} - -static GPUIndexBuf *mesh_create_tri_overlay_weight_faces( - MeshRenderData *rdata) -{ - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI)); - - { - const int vert_len = mesh_render_data_verts_len_get(rdata); - const int tri_len = mesh_render_data_looptri_len_get(rdata); - - GPUIndexBufBuilder elb; - GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len); - + const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage); for (int i = 0; i < tri_len; i++) { - const MLoopTri *mlt = &rdata->mlooptri[i]; - if (!(rdata->mpoly[mlt->poly].flag & (ME_FACE_SEL | ME_HIDE))) { - for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { - GPU_indexbuf_add_generic_vert(&elb, rdata->mloop[mlt->tri[tri_corner]].v); + const MLoopTri *mlt = &mlooptri[i]; + const int p_orig = rdata->mapped.p_origindex[mlt->poly]; + if (p_orig != ORIGINDEX_NONE) { + /* Assume 'use_hide' */ + BMFace *efa = BM_face_at_index(bm, p_orig); + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + int mat = (ibo_len > 1) ? efa->mat_nr : 0; + GPU_indexbuf_add_tri_verts(&elb[mat], mlt->tri[0], mlt->tri[1], mlt->tri[2]); } } } - return GPU_indexbuf_build(&elb); } -} -/** - * Non-edit mode vertices (only used for weight-paint mode). - */ -static GPUVertBuf *mesh_create_vert_pos_with_overlay_data( - MeshRenderData *rdata) -{ - BLI_assert(rdata->types & (MR_DATATYPE_VERT)); - BLI_assert(rdata->edit_bmesh == NULL); - - GPUVertBuf *vbo; - { - uint cidx = 0; - - static GPUVertFormat format = { 0 }; - static struct { uint data; } attr_id; - if (format.attr_len == 0) { - attr_id.data = GPU_vertformat_attr_add(&format, "data", GPU_COMP_I8, 1, GPU_FETCH_INT); - } - - const int vert_len = mesh_render_data_verts_len_get(rdata); - - vbo = GPU_vertbuf_create_with_format(&format); - - const int vbo_len_capacity = vert_len; - int vbo_len_used = 0; - GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); - - for (int i = 0; i < vert_len; i++) { - const MVert *mv = &rdata->mvert[i]; - const char data = mv->flag & (SELECT | ME_HIDE); - GPU_vertbuf_attr_set(vbo, attr_id.data, cidx++, &data); - } - vbo_len_used = cidx; - - if (vbo_len_capacity != vbo_len_used) { - GPU_vertbuf_data_resize(vbo, vbo_len_used); - } + for (int i = 0; i < ibo_len; ++i) { + GPU_indexbuf_build_in_place(&elb[i], ibo[i]); } - return vbo; } /** \} */ @@ -4647,6 +4502,12 @@ static GPUVertBuf *mesh_create_vert_pos_with_overlay_data( /** \name Public API * \{ */ +GPUBatch *DRW_mesh_batch_cache_get_all_verts(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + return DRW_batch_request(&cache->batch.all_verts); +} + GPUBatch *DRW_mesh_batch_cache_get_all_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); @@ -4666,40 +4527,10 @@ GPUBatch *DRW_mesh_batch_cache_get_all_edges(Mesh *me) return cache->all_edges; } -GPUBatch *DRW_mesh_batch_cache_get_all_triangles(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->all_triangles == NULL) { - /* create batch from DM */ - const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI; - MeshRenderData *rdata = mesh_render_data_create(me, datatype); - - cache->all_triangles = GPU_batch_create( - GPU_PRIM_TRIS, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache), - mesh_batch_cache_get_triangles_in_order(rdata, cache)); - - mesh_render_data_free(rdata); - } - - return cache->all_triangles; -} - GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->triangles_with_normals == NULL) { - const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY; - MeshRenderData *rdata = mesh_render_data_create(me, datatype); - - cache->triangles_with_normals = GPU_batch_create( - GPU_PRIM_TRIS, mesh_batch_cache_get_tri_pos_and_normals(rdata, cache), NULL); - - mesh_render_data_free(rdata); - } - - return cache->triangles_with_normals; + return DRW_batch_request(&cache->batch.surface); } GPUBatch *DRW_mesh_batch_cache_get_loose_edges_with_normals(Mesh *me) @@ -4723,61 +4554,12 @@ GPUBatch *DRW_mesh_batch_cache_get_loose_edges_with_normals(Mesh *me) return cache->ledges_with_normals; } -GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights( - Mesh *me, const struct DRW_MeshWeightState *wstate) +GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - - mesh_batch_cache_check_vertex_group(cache, wstate); - - if (cache->triangles_with_weights == NULL) { - const bool use_hide = (me->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) != 0; - const int datatype = - MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_DVERT; - MeshRenderData *rdata = mesh_render_data_create(me, datatype); - - cache->triangles_with_weights = GPU_batch_create_ex( - GPU_PRIM_TRIS, mesh_create_tri_weights(rdata, use_hide, wstate), NULL, GPU_BATCH_OWNS_VBO); - - DRW_mesh_weight_state_copy(&cache->weight_state, wstate); - - GPUVertBuf *vbo_tris = use_hide ? - mesh_create_tri_pos_and_normals_visible_only(rdata) : - mesh_batch_cache_get_tri_pos_and_normals(rdata, cache); - - GPU_batch_vertbuf_add_ex(cache->triangles_with_weights, vbo_tris, use_hide); - - mesh_render_data_free(rdata); - } - - return cache->triangles_with_weights; -} - -GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_vert_colors(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->triangles_with_vert_colors == NULL) { - const bool use_hide = (me->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) != 0; - const int datatype = - MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPCOL; - MeshRenderData *rdata = mesh_render_data_create(me, datatype); - - cache->triangles_with_vert_colors = GPU_batch_create_ex( - GPU_PRIM_TRIS, mesh_create_tri_vert_colors(rdata, use_hide), NULL, GPU_BATCH_OWNS_VBO); - - GPUVertBuf *vbo_tris = use_hide ? - mesh_create_tri_pos_and_normals_visible_only(rdata) : - mesh_batch_cache_get_tri_pos_and_normals(rdata, cache); - GPU_batch_vertbuf_add_ex(cache->triangles_with_vert_colors, vbo_tris, use_hide); - - mesh_render_data_free(rdata); - } - - return cache->triangles_with_vert_colors; + return DRW_batch_request(&cache->batch.surface_weights); } - struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id( struct Mesh *me, bool use_hide, uint select_id_offset) { @@ -4799,10 +4581,8 @@ struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id( cache->triangles_with_select_id = GPU_batch_create_ex( GPU_PRIM_TRIS, mesh_create_tri_select_id(rdata, use_hide, select_id_offset), NULL, GPU_BATCH_OWNS_VBO); - GPUVertBuf *vbo_tris = use_hide ? - mesh_create_tri_pos_and_normals_visible_only(rdata) : - mesh_batch_cache_get_tri_pos_and_normals(rdata, cache); - GPU_batch_vertbuf_add_ex(cache->triangles_with_select_id, vbo_tris, use_hide); + GPUVertBuf *vbo_tris = mesh_batch_cache_get_tri_pos_and_normals_edit(rdata, cache, use_hide); + GPU_batch_vertbuf_add(cache->triangles_with_select_id, vbo_tris); mesh_render_data_free(rdata); } @@ -4825,12 +4605,10 @@ struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_mask(struct Mesh rdata->mapped.use = true; } - GPUVertBuf *vbo_tris = use_hide ? - mesh_create_tri_pos_and_normals_visible_only(rdata) : - mesh_batch_cache_get_tri_pos_and_normals(rdata, cache); + GPUVertBuf *vbo_tris = mesh_batch_cache_get_tri_pos_and_normals_edit(rdata, cache, use_hide); - cache->triangles_with_select_mask = GPU_batch_create_ex( - GPU_PRIM_TRIS, vbo_tris, NULL, use_hide ? GPU_BATCH_OWNS_VBO : 0); + cache->triangles_with_select_mask = GPU_batch_create( + GPU_PRIM_TRIS, vbo_tris, NULL); mesh_render_data_free(rdata); } @@ -4847,7 +4625,7 @@ GPUBatch *DRW_mesh_batch_cache_get_points_with_normals(Mesh *me) MeshRenderData *rdata = mesh_render_data_create(me, datatype); cache->points_with_normals = GPU_batch_create( - GPU_PRIM_POINTS, mesh_batch_cache_get_tri_pos_and_normals(rdata, cache), NULL); + GPU_PRIM_POINTS, mesh_batch_cache_get_tri_pos_and_normals_edit(rdata, cache, false), NULL); mesh_render_data_free(rdata); } @@ -4855,23 +4633,6 @@ GPUBatch *DRW_mesh_batch_cache_get_points_with_normals(Mesh *me) return cache->points_with_normals; } -GPUBatch *DRW_mesh_batch_cache_get_all_verts(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->all_verts == NULL) { - /* create batch from DM */ - MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT); - - cache->all_verts = GPU_batch_create( - GPU_PRIM_POINTS, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache), NULL); - - mesh_render_data_free(rdata); - } - - return cache->all_verts; -} - GPUBatch *DRW_mesh_batch_cache_get_fancy_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); @@ -4960,183 +4721,61 @@ GPUBatch *DRW_mesh_batch_cache_get_edge_detection(Mesh *me, bool *r_is_manifold) return cache->edge_detection; } -void DRW_mesh_batch_cache_get_wireframes_face_texbuf( - Mesh *me, GPUTexture **verts_data, GPUTexture **face_indices, int *tri_count) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->edges_face_overlay_tx == NULL || cache->pos_in_order_tx == NULL) { - const int options = MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI; - - MeshRenderData *rdata = mesh_render_data_create(me, options); - - mesh_batch_cache_get_edges_overlay_texture_buf(rdata, cache); - mesh_batch_cache_get_vert_pos_and_nor_in_order_buf(rdata, cache); - - mesh_render_data_free(rdata); - } - - *tri_count = cache->edges_face_overlay_tri_count; - *face_indices = cache->edges_face_overlay_tx; - *verts_data = cache->pos_in_order_tx; -} - -static void mesh_batch_cache_create_overlay_batches(Mesh *me) +GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(Mesh *me) { - BLI_assert(me->edit_btmesh != NULL); - - /* Since MR_DATATYPE_OVERLAY is slow to generate, generate them all at once */ - const int options = - MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | - MR_DATATYPE_LOOPTRI | MR_DATATYPE_OVERLAY; - MeshBatchCache *cache = mesh_batch_cache_get(me); - MeshRenderData *rdata = mesh_render_data_create(me, options); - - if (rdata->mapped.supported) { - rdata->mapped.use = true; - } - - if (cache->overlay_triangles == NULL) { - cache->overlay_triangles = GPU_batch_create( - GPU_PRIM_TRIS, mesh_batch_cache_get_edit_tri_pos(rdata, cache), NULL); - GPU_batch_vertbuf_add(cache->overlay_triangles, mesh_batch_cache_get_edit_tri_nor(rdata, cache)); - GPU_batch_vertbuf_add(cache->overlay_triangles, mesh_batch_cache_get_edit_tri_data(rdata, cache)); - } - - if (cache->overlay_loose_edges == NULL) { - cache->overlay_loose_edges = GPU_batch_create( - GPU_PRIM_LINES, mesh_batch_cache_get_edit_ledge_pos(rdata, cache), NULL); - GPU_batch_vertbuf_add(cache->overlay_loose_edges, mesh_batch_cache_get_edit_ledge_nor(rdata, cache)); - GPU_batch_vertbuf_add(cache->overlay_loose_edges, mesh_batch_cache_get_edit_ledge_data(rdata, cache)); - } - - if (cache->overlay_loose_verts == NULL) { - cache->overlay_loose_verts = GPU_batch_create( - GPU_PRIM_POINTS, mesh_batch_cache_get_edit_lvert_pos(rdata, cache), NULL); - GPU_batch_vertbuf_add(cache->overlay_loose_verts, mesh_batch_cache_get_edit_lvert_nor(rdata, cache)); - GPU_batch_vertbuf_add(cache->overlay_loose_verts, mesh_batch_cache_get_edit_lvert_data(rdata, cache)); - } - - /* Also used for vertices display */ - if (cache->overlay_triangles_nor == NULL) { - cache->overlay_triangles_nor = GPU_batch_create( - GPU_PRIM_POINTS, mesh_batch_cache_get_edit_tri_pos(rdata, cache), - mesh_batch_cache_get_edit_tri_indices(rdata, cache)); - GPU_batch_vertbuf_add(cache->overlay_triangles_nor, mesh_batch_cache_get_edit_tri_nor(rdata, cache)); - GPU_batch_vertbuf_add(cache->overlay_triangles_nor, mesh_batch_cache_get_edit_tri_data(rdata, cache)); - } - - if (cache->overlay_triangles_lnor == NULL) { - cache->overlay_triangles_lnor = GPU_batch_create( - GPU_PRIM_POINTS, mesh_batch_cache_get_edit_tri_pos(rdata, cache), NULL); - GPU_batch_vertbuf_add(cache->overlay_triangles_lnor, mesh_batch_cache_get_edit_tri_nor(rdata, cache)); - GPU_batch_vertbuf_add(cache->overlay_triangles_lnor, mesh_batch_cache_get_edit_tri_data(rdata, cache)); - } - - if (cache->overlay_loose_edges_nor == NULL) { - cache->overlay_loose_edges_nor = GPU_batch_create( - GPU_PRIM_POINTS, mesh_batch_cache_get_edit_ledge_pos(rdata, cache), NULL); - GPU_batch_vertbuf_add(cache->overlay_loose_edges_nor, mesh_batch_cache_get_edit_ledge_nor(rdata, cache)); - GPU_batch_vertbuf_add(cache->overlay_loose_edges_nor, mesh_batch_cache_get_edit_ledge_data(rdata, cache)); - } - - mesh_render_data_free(rdata); + return DRW_batch_request(&cache->batch.wire_triangles); } -GPUBatch *DRW_mesh_batch_cache_get_overlay_triangles(Mesh *me) +GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->overlay_triangles == NULL) { - mesh_batch_cache_create_overlay_batches(me); - } - - return cache->overlay_triangles; + return DRW_batch_request(&cache->batch.edit_triangles); } -GPUTexture *DRW_mesh_batch_cache_get_overlay_data_tex(Mesh *me) +GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->ed_tri_data_tx == NULL) { - mesh_batch_cache_create_overlay_batches(me); - } - - return cache->ed_tri_data_tx; + return DRW_batch_request(&cache->batch.edit_vertices); } -GPUBatch *DRW_mesh_batch_cache_get_overlay_loose_edges(Mesh *me) +GPUBatch *DRW_mesh_batch_cache_get_edit_loose_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->overlay_loose_edges == NULL) { - mesh_batch_cache_create_overlay_batches(me); - } - - return cache->overlay_loose_edges; + return DRW_batch_request(&cache->batch.edit_loose_edges); } -GPUBatch *DRW_mesh_batch_cache_get_overlay_loose_verts(Mesh *me) +GPUBatch *DRW_mesh_batch_cache_get_edit_loose_verts(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->overlay_loose_verts == NULL) { - mesh_batch_cache_create_overlay_batches(me); - } - - return cache->overlay_loose_verts; + return DRW_batch_request(&cache->batch.edit_loose_verts); } -GPUBatch *DRW_mesh_batch_cache_get_overlay_triangles_nor(Mesh *me) +GPUBatch *DRW_mesh_batch_cache_get_edit_triangles_nor(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->overlay_triangles_nor == NULL) { - mesh_batch_cache_create_overlay_batches(me); - } - - return cache->overlay_triangles_nor; + return DRW_batch_request(&cache->batch.edit_triangles_nor); } -GPUBatch *DRW_mesh_batch_cache_get_overlay_triangles_lnor(Mesh *me) +GPUBatch *DRW_mesh_batch_cache_get_edit_triangles_lnor(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->overlay_triangles_lnor == NULL) { - mesh_batch_cache_create_overlay_batches(me); - } - - return cache->overlay_triangles_lnor; + return DRW_batch_request(&cache->batch.edit_triangles_lnor); } -GPUBatch *DRW_mesh_batch_cache_get_overlay_loose_edges_nor(Mesh *me) +GPUBatch *DRW_mesh_batch_cache_get_edit_loose_edges_nor(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->overlay_loose_edges_nor == NULL) { - mesh_batch_cache_create_overlay_batches(me); - } - - return cache->overlay_loose_edges_nor; + return DRW_batch_request(&cache->batch.edit_loose_edges_nor); } -GPUBatch *DRW_mesh_batch_cache_get_overlay_facedots(Mesh *me) +GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->overlay_facedots == NULL) { - MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY); - - cache->overlay_facedots = GPU_batch_create( - GPU_PRIM_POINTS, mesh_batch_cache_get_facedot_pos_with_normals_and_flag(rdata, cache), NULL); - - mesh_render_data_free(rdata); - } - - return cache->overlay_facedots; + return DRW_batch_request(&cache->batch.edit_facedots); } +/* Need to be ported to new getter style. */ GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(Mesh *me, uint select_id_offset) { MeshBatchCache *cache = mesh_batch_cache_get(me); @@ -5225,122 +4864,97 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded( char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count) { MeshBatchCache *cache = mesh_batch_cache_get(me); + uchar cd_vneeded[CD_NUMTYPES] = {0}; + ushort cd_lneeded[CD_NUMTYPES] = {0}; + mesh_cd_calc_used_gpu_layers(me, cd_vneeded, cd_lneeded, gpumat_array, gpumat_array_len); - if (cache->shaded_triangles == NULL) { + BLI_assert(gpumat_array_len == cache->mat_len); - /* Hack to show the final result. */ - BMesh *bm_mapped = NULL; - const int *p_origindex = NULL; - const bool use_em_final = ( - me->edit_btmesh && - me->edit_btmesh->mesh_eval_final && - (me->edit_btmesh->mesh_eval_final->runtime.is_original == false)); - Mesh me_fake; - if (use_em_final) { - /* Pass in mapped args. */ - bm_mapped = me->edit_btmesh->bm; - p_origindex = CustomData_get_layer(&me->edit_btmesh->mesh_eval_final->pdata, CD_ORIGINDEX); - if (p_origindex == NULL) { - bm_mapped = NULL; - } + bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_vused, cache->cd_lused, + cd_vneeded, cd_lneeded); + if (cd_overlap == false) { + /* XXX TODO(fclem): We are writting to batch cache here. Need to make this thread safe. */ + mesh_cd_layers_type_merge(cache->cd_vneeded, cache->cd_lneeded, + cd_vneeded, cd_lneeded); - me_fake = *me->edit_btmesh->mesh_eval_final; - me_fake.mat = me->mat; - me_fake.totcol = me->totcol; - me = &me_fake; - } - - /* create batch from DM */ - const int datatype = - MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI | - MR_DATATYPE_POLY | MR_DATATYPE_SHADING; - MeshRenderData *rdata = mesh_render_data_create_ex(me, datatype, gpumat_array, gpumat_array_len); - - const int mat_len = mesh_render_data_mat_len_get(rdata); - - cache->shaded_triangles = MEM_callocN(sizeof(*cache->shaded_triangles) * mat_len, __func__); - - GPUIndexBuf **el = mesh_batch_cache_get_triangles_in_order_split_by_material( - rdata, cache, - bm_mapped, p_origindex); - - GPUVertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache); - GPUVertBuf *vbo_shading = mesh_batch_cache_get_tri_shading_data(rdata, cache); - - for (int i = 0; i < mat_len; i++) { - cache->shaded_triangles[i] = GPU_batch_create( - GPU_PRIM_TRIS, vbo, el[i]); - if (vbo_shading) { - GPU_batch_vertbuf_add(cache->shaded_triangles[i], vbo_shading); - } - } - - mesh_render_data_free(rdata); + mesh_cd_extract_auto_layers_names_and_srgb(me, + cache->cd_lneeded, + &cache->auto_layer_names, + &cache->auto_layer_is_srgb, + &cache->auto_layer_len); } - if (auto_layer_names) { *auto_layer_names = cache->auto_layer_names; *auto_layer_is_srgb = cache->auto_layer_is_srgb; *auto_layer_count = cache->auto_layer_len; } + for (int i = 0; i < cache->mat_len; ++i) { + DRW_batch_request(&cache->surf_per_mat[i]); + } + return cache->surf_per_mat; +} - return cache->shaded_triangles; +static void texpaint_request_active_uv(MeshBatchCache *cache, Mesh *me) +{ + uchar cd_vneeded[CD_NUMTYPES] = {0}; + ushort cd_lneeded[CD_NUMTYPES] = {0}; + mesh_cd_calc_active_uv_layer(me, cd_lneeded); + if (cd_lneeded[CD_MLOOPUV] == 0) { + /* This should not happen. */ + BLI_assert(!"No uv layer available in texpaint, but batches requested anyway!"); + } + bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_vused, cache->cd_lused, + cd_vneeded, cd_lneeded); + if (cd_overlap == false) { + /* XXX TODO(fclem): We are writting to batch cache here. Need to make this thread safe. */ + mesh_cd_layers_type_merge(cache->cd_vneeded, cache->cd_lneeded, + cd_vneeded, cd_lneeded); + } } GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->texpaint_triangles == NULL) { - /* create batch from DM */ - const int datatype = - MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOPUV; - MeshRenderData *rdata = mesh_render_data_create(me, datatype); - - const int mat_len = mesh_render_data_mat_len_get(rdata); - - cache->texpaint_triangles = MEM_callocN(sizeof(*cache->texpaint_triangles) * mat_len, __func__); - - GPUIndexBuf **el = mesh_batch_cache_get_triangles_in_order_split_by_material(rdata, cache, NULL, NULL); - - GPUVertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache); - for (int i = 0; i < mat_len; i++) { - cache->texpaint_triangles[i] = GPU_batch_create( - GPU_PRIM_TRIS, vbo, el[i]); - GPUVertBuf *vbo_uv = mesh_batch_cache_get_tri_uv_active(rdata, cache); - if (vbo_uv) { - GPU_batch_vertbuf_add(cache->texpaint_triangles[i], vbo_uv); - } - } - mesh_render_data_free(rdata); + texpaint_request_active_uv(cache, me); + for (int i = 0; i < cache->mat_len; ++i) { + DRW_batch_request(&cache->surf_per_mat[i]); } - - return cache->texpaint_triangles; + return cache->surf_per_mat; } GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + texpaint_request_active_uv(cache, me); + return DRW_batch_request(&cache->batch.surface); +} - if (cache->texpaint_triangles_single == NULL) { - /* create batch from DM */ - const int datatype = - MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOPUV; - MeshRenderData *rdata = mesh_render_data_create(me, datatype); - - GPUVertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache); - - cache->texpaint_triangles_single = GPU_batch_create( - GPU_PRIM_TRIS, vbo, NULL); - GPUVertBuf *vbo_uv = mesh_batch_cache_get_tri_uv_active(rdata, cache); - if (vbo_uv) { - GPU_batch_vertbuf_add(cache->texpaint_triangles_single, vbo_uv); - } - mesh_render_data_free(rdata); +static void texpaint_request_active_vcol(MeshBatchCache *cache, Mesh *me) +{ + uchar cd_vneeded[CD_NUMTYPES] = {0}; + ushort cd_lneeded[CD_NUMTYPES] = {0}; + mesh_cd_calc_active_vcol_layer(me, cd_lneeded); + if (cd_lneeded[CD_MLOOPCOL] == 0) { + /* This should not happen. */ + BLI_assert(!"No vcol layer available in vertpaint, but batches requested anyway!"); } - return cache->texpaint_triangles_single; + bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_vused, cache->cd_lused, + cd_vneeded, cd_lneeded); + if (cd_overlap == false) { + /* XXX TODO(fclem): We are writting to batch cache here. Need to make this thread safe. */ + mesh_cd_layers_type_merge(cache->cd_vneeded, cache->cd_lneeded, + cd_vneeded, cd_lneeded); + } +} + +GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + texpaint_request_active_vcol(cache, me); + return DRW_batch_request(&cache->batch.surface); } +/* TODO port to batch request. Is basically batch.wire_loops. */ GPUBatch *DRW_mesh_batch_cache_get_texpaint_loop_wire(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); @@ -5392,61 +5006,10 @@ GPUBatch *DRW_mesh_batch_cache_get_texpaint_loop_wire(Mesh *me) return cache->texpaint_uv_loops; } -GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_edges(Mesh *me, bool use_wire, bool use_sel) +GPUBatch *DRW_mesh_batch_cache_get_wire_loops(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->overlay_paint_edges == NULL) { - /* create batch from Mesh */ - const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_POLY | MR_DATATYPE_LOOP; - MeshRenderData *rdata = mesh_render_data_create(me, datatype); - - cache->overlay_paint_edges = GPU_batch_create_ex( - GPU_PRIM_LINES, mesh_create_edge_pos_with_sel(rdata, use_wire, use_sel), NULL, GPU_BATCH_OWNS_VBO); - - mesh_render_data_free(rdata); - } - - return cache->overlay_paint_edges; -} - -GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_faces(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->overlay_weight_faces == NULL) { - /* create batch from Mesh */ - const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_POLY | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI; - MeshRenderData *rdata = mesh_render_data_create(me, datatype); - - cache->overlay_weight_faces = GPU_batch_create_ex( - GPU_PRIM_TRIS, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache), - mesh_create_tri_overlay_weight_faces(rdata), GPU_BATCH_OWNS_INDEX); - - mesh_render_data_free(rdata); - } - - return cache->overlay_weight_faces; -} - -GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_verts(Mesh *me) -{ - MeshBatchCache *cache = mesh_batch_cache_get(me); - - if (cache->overlay_weight_verts == NULL) { - /* create batch from Mesh */ - MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT); - - cache->overlay_weight_verts = GPU_batch_create( - GPU_PRIM_POINTS, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache), NULL); - - GPU_batch_vertbuf_add_ex( - cache->overlay_weight_verts, - mesh_create_vert_pos_with_overlay_data(rdata), true); - mesh_render_data_free(rdata); - } - - return cache->overlay_weight_verts; + return DRW_batch_request(&cache->batch.wire_loops); } /** @@ -5885,3 +5448,269 @@ void DRW_mesh_cache_uvedit( } /** \} */ + + +/* ---------------------------------------------------------------------- */ + +/** \name Grouped batch generation + * \{ */ + +/* Can be called for any surface type. Mesh *me is the final mesh. */ +void DRW_mesh_batch_cache_create_requested(Object *ob, Mesh *me) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const int mode = CTX_data_mode_enum_ex(draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode); + const bool is_paint_mode = ELEM(mode, CTX_MODE_PAINT_TEXTURE, CTX_MODE_PAINT_VERTEX, CTX_MODE_PAINT_WEIGHT); + const bool use_hide = (ob->type == OB_MESH) && ((is_paint_mode && (ob == draw_ctx->obact)) || + ((mode == CTX_MODE_EDIT_MESH) && BKE_object_is_in_editmode(ob))); + bool use_face_sel = false; + + /* Tex paint face select */ + if (is_paint_mode && (ob->type == OB_MESH) && (draw_ctx->obact == ob)) { + const Mesh *me_orig = DEG_get_original_object(ob)->data; + use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + } + + MeshBatchCache *cache = mesh_batch_cache_get(me); + + /* Check vertex weights. */ + if (cache->batch.surface_weights != 0) { + struct DRW_MeshWeightState wstate; + BLI_assert(ob->type == OB_MESH); + drw_mesh_weight_state_extract(ob, me, draw_ctx->scene->toolsettings, is_paint_mode, &wstate); + mesh_batch_cache_check_vertex_group(cache, &wstate); + drw_mesh_weight_state_copy(&cache->weight_state, &wstate); + drw_mesh_weight_state_clear(&wstate); + } + + /* Verify that all surface batches have needed attrib layers. */ + /* TODO(fclem): We could be a bit smarter here and only do it per material. */ + bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_vused, cache->cd_lused, + cache->cd_vneeded, cache->cd_lneeded); + if (cd_overlap == false) { + for (int type = 0; type < CD_NUMTYPES; ++type) { + if ((cache->cd_vused[type] & cache->cd_vneeded[type]) != cache->cd_vneeded[type]) { + switch (type) { + case CD_MLOOPUV: + case CD_TANGENT: + GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_uv_tan); + break; + case CD_MLOOPCOL: + GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_vcol); + break; + case CD_ORCO: + /* TODO */ + // GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_orco); + break; + } + } + } + /* We can't discard batches at this point as they have been + * referenced for drawing. Just clear them in place. */ + for (int i = 0; i < cache->mat_len; ++i) { + GPU_BATCH_CLEAR_SAFE(cache->surf_per_mat[i]); + } + GPU_BATCH_CLEAR_SAFE(cache->batch.surface); + + mesh_cd_layers_type_merge(cache->cd_vused, cache->cd_lused, + cache->cd_vneeded, cache->cd_lneeded); + + } + + memset(cache->cd_lneeded, 0, sizeof(cache->cd_lneeded)); + memset(cache->cd_vneeded, 0, sizeof(cache->cd_vneeded)); + + /* Init batches and request VBOs & IBOs */ + if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.surface, &cache->ibo.loops_tris); + DRW_vbo_request(cache->batch.surface, &cache->ordered.loop_pos_nor); + /* For paint overlay. Active layer should have been queried. */ + if (cache->cd_lused[CD_MLOOPUV] != 0) { + DRW_vbo_request(cache->batch.surface, &cache->ordered.loop_uv_tan); + } + if (cache->cd_lused[CD_MLOOPCOL] != 0) { + DRW_vbo_request(cache->batch.surface, &cache->ordered.loop_vcol); + } + } + if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) { + DRW_vbo_request(cache->batch.all_verts, &cache->ordered.pos_nor); + } + if (DRW_batch_requested(cache->batch.surface_weights, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.surface_weights, &cache->ibo.surf_tris); + DRW_vbo_request(cache->batch.surface_weights, &cache->ordered.pos_nor); + DRW_vbo_request(cache->batch.surface_weights, &cache->ordered.weights); + } + if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINE_STRIP)) { + DRW_ibo_request(cache->batch.wire_loops, &cache->ibo.loops_lines); + DRW_vbo_request(cache->batch.wire_loops, &cache->ordered.loop_pos_nor); + } + if (DRW_batch_requested(cache->batch.wire_triangles, GPU_PRIM_TRIS)) { + DRW_vbo_request(cache->batch.wire_triangles, &cache->tess.pos_nor); + DRW_vbo_request(cache->batch.wire_triangles, &cache->tess.wireframe_data); + } + + if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) { + DRW_vbo_request(cache->batch.edit_triangles, &cache->edit.pos_nor); + DRW_vbo_request(cache->batch.edit_triangles, &cache->edit.data); + } + if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) { + DRW_ibo_request(cache->batch.edit_vertices, &cache->ibo.edit_verts_points); + DRW_vbo_request(cache->batch.edit_vertices, &cache->edit.pos_nor); + DRW_vbo_request(cache->batch.edit_vertices, &cache->edit.data); + } + if (DRW_batch_requested(cache->batch.edit_loose_edges, GPU_PRIM_LINES)) { + DRW_vbo_request(cache->batch.edit_loose_edges, &cache->edit.pos_nor_ledges); + DRW_vbo_request(cache->batch.edit_loose_edges, &cache->edit.data_ledges); + } + if (DRW_batch_requested(cache->batch.edit_loose_verts, GPU_PRIM_POINTS)) { + DRW_vbo_request(cache->batch.edit_loose_verts, &cache->edit.pos_nor_lverts); + DRW_vbo_request(cache->batch.edit_loose_verts, &cache->edit.data_lverts); + } + if (DRW_batch_requested(cache->batch.edit_triangles_nor, GPU_PRIM_POINTS)) { + DRW_ibo_request(cache->batch.edit_triangles_nor, &cache->ibo.edit_verts_points); + DRW_vbo_request(cache->batch.edit_triangles_nor, &cache->edit.pos_nor); + } + if (DRW_batch_requested(cache->batch.edit_triangles_lnor, GPU_PRIM_POINTS)) { + DRW_vbo_request(cache->batch.edit_triangles_lnor, &cache->edit.pos_nor); + DRW_vbo_request(cache->batch.edit_triangles_lnor, &cache->edit.lnor); + } + if (DRW_batch_requested(cache->batch.edit_loose_edges_nor, GPU_PRIM_POINTS)) { + DRW_vbo_request(cache->batch.edit_loose_edges_nor, &cache->edit.pos_nor_ledges); + } + if (DRW_batch_requested(cache->batch.edit_facedots, GPU_PRIM_POINTS)) { + DRW_vbo_request(cache->batch.edit_facedots, &cache->edit.pos_nor_data_facedots); + } + + for (int i = 0; i < cache->mat_len; ++i) { + if (DRW_batch_requested(cache->surf_per_mat[i], GPU_PRIM_TRIS)) { + if (cache->mat_len > 1) { + DRW_ibo_request(cache->surf_per_mat[i], &cache->surf_per_mat_tris[i]); + } + else { + DRW_ibo_request(cache->surf_per_mat[i], &cache->ibo.loops_tris); + } + DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_pos_nor); + if ((cache->cd_lused[CD_MLOOPUV] != 0) || + (cache->cd_lused[CD_TANGENT] != 0)) + { + DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_uv_tan); + } + if (cache->cd_lused[CD_MLOOPCOL] != 0) { + DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_vcol); + } + /* TODO */ + // if (cache->cd_vused[CD_ORCO] != 0) { + // DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_orco); + // } + } + } + + /* Generate MeshRenderData flags */ + int mr_flag = 0, mr_edit_flag = 0; + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.pos_nor, MR_DATATYPE_VERT); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.weights, MR_DATATYPE_VERT | MR_DATATYPE_DVERT); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.loop_pos_nor, MR_DATATYPE_VERT | MR_DATATYPE_POLY | MR_DATATYPE_LOOP); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.loop_uv_tan, MR_DATATYPE_VERT | MR_DATATYPE_POLY | MR_DATATYPE_LOOP | MR_DATATYPE_SHADING); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.loop_vcol, MR_DATATYPE_VERT | MR_DATATYPE_POLY | MR_DATATYPE_LOOP | MR_DATATYPE_SHADING); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->tess.pos_nor, MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI | MR_DATATYPE_POLY); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->tess.wireframe_data, MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI); + DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.surf_tris, MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI); + DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.loops_tris, MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI); + DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.loops_lines, MR_DATATYPE_LOOP | MR_DATATYPE_POLY); + for (int i = 0; i < cache->mat_len; ++i) { + DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->surf_per_mat_tris[i], MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI); + } + + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.data, MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI | MR_DATATYPE_POLY | MR_DATATYPE_OVERLAY); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.data_ledges, MR_DATATYPE_LOOSE_EDGE | MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_OVERLAY); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.data_lverts, MR_DATATYPE_LOOSE_VERT | MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_OVERLAY); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.pos_nor, MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI | MR_DATATYPE_POLY | MR_DATATYPE_OVERLAY); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.pos_nor_ledges, MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOSE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_OVERLAY); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.pos_nor_lverts, MR_DATATYPE_VERT | MR_DATATYPE_LOOSE_VERT | MR_DATATYPE_OVERLAY); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.pos_nor_data_facedots, MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_OVERLAY); + DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.lnor, MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI | MR_DATATYPE_OVERLAY); + DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_edit_flag, cache->ibo.edit_verts_points, MR_DATATYPE_VERT | MR_DATATYPE_POLY | MR_DATATYPE_LOOPTRI); + + Mesh *me_original = me; + MBC_GET_FINAL_MESH(me); + + if (me_original == me) { + mr_flag |= mr_edit_flag; + } + + MeshRenderData *rdata = mesh_render_data_create_ex(me, mr_flag, cache->cd_vused, cache->cd_lused); + + /* Generate VBOs */ + if (DRW_vbo_requested(cache->ordered.pos_nor)) { + mesh_create_pos_and_nor(rdata, cache->ordered.pos_nor); + } + if (DRW_vbo_requested(cache->ordered.weights)) { + mesh_create_weights(rdata, cache->ordered.weights, &cache->weight_state); + } + if (DRW_vbo_requested(cache->ordered.loop_pos_nor)) { + mesh_create_loop_pos_and_nor(rdata, cache->ordered.loop_pos_nor, use_face_sel); + } + if (DRW_vbo_requested(cache->ordered.loop_uv_tan)) { + mesh_create_loop_uv_and_tan(rdata, cache->ordered.loop_uv_tan); + } + if (DRW_vbo_requested(cache->ordered.loop_vcol)) { + mesh_create_loop_vcol(rdata, cache->ordered.loop_vcol); + } + if (DRW_vbo_requested(cache->tess.wireframe_data)) { + mesh_create_wireframe_data_tess(rdata, cache->tess.wireframe_data); + } + if (DRW_vbo_requested(cache->tess.pos_nor)) { + mesh_create_pos_and_nor_tess(rdata, cache->tess.pos_nor, use_hide); + } + if (DRW_ibo_requested(cache->ibo.surf_tris)) { + mesh_create_surf_tris(rdata, cache->ibo.surf_tris, use_hide); + } + if (DRW_ibo_requested(cache->ibo.loops_lines)) { + mesh_create_loops_lines(rdata, cache->ibo.loops_lines, use_hide); + } + if (DRW_ibo_requested(cache->ibo.loops_tris)) { + mesh_create_loops_tris(rdata, &cache->ibo.loops_tris, 1, use_hide); + } + if (DRW_ibo_requested(cache->surf_per_mat_tris[0])) { + mesh_create_loops_tris(rdata, cache->surf_per_mat_tris, cache->mat_len, use_hide); + } + + /* Use original Mesh* to have the correct edit cage. */ + if (me_original != me) { + mesh_render_data_free(rdata); + rdata = mesh_render_data_create(me_original, mr_edit_flag); + } + + if (rdata->mapped.supported) { + rdata->mapped.use = true; + } + + if (DRW_vbo_requested(cache->edit.data) || + DRW_vbo_requested(cache->edit.pos_nor) || + DRW_vbo_requested(cache->edit.lnor) || + DRW_ibo_requested(cache->ibo.edit_verts_points)) + { + mesh_create_edit_tris_and_verts(rdata, cache->edit.data, cache->edit.pos_nor, + cache->edit.lnor, cache->ibo.edit_verts_points); + } + if (DRW_vbo_requested(cache->edit.data_ledges) || DRW_vbo_requested(cache->edit.pos_nor_ledges)) { + mesh_create_edit_loose_edges(rdata, cache->edit.data_ledges, cache->edit.pos_nor_ledges); + } + if (DRW_vbo_requested(cache->edit.data_lverts) || DRW_vbo_requested(cache->edit.pos_nor_lverts)) { + mesh_create_edit_loose_verts(rdata, cache->edit.data_lverts, cache->edit.pos_nor_lverts); + } + if (DRW_vbo_requested(cache->edit.pos_nor_data_facedots)) { + mesh_create_edit_facedots(rdata, cache->edit.pos_nor_data_facedots); + } + + mesh_render_data_free(rdata); + +#ifdef DEBUG + /* Make sure all requested batches have been setup. */ + for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) { + BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); + } +#endif +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c index 841cb73d9c7..b77268fb0a7 100644 --- a/source/blender/draw/intern/draw_cache_impl_metaball.c +++ b/source/blender/draw/intern/draw_cache_impl_metaball.c @@ -59,10 +59,7 @@ typedef struct MetaBallBatchCache { /* Wireframe */ struct { - GPUVertBuf *elem_vbo; - GPUTexture *elem_tx; - GPUTexture *verts_tx; - int tri_count; + GPUBatch *batch; } face_wire; /* settings to determine if cache is invalid */ @@ -94,10 +91,7 @@ static void metaball_batch_cache_init(MetaBall *mb) cache->shaded_triangles = NULL; cache->is_dirty = false; cache->pos_nor_in_order = NULL; - cache->face_wire.elem_vbo = NULL; - cache->face_wire.elem_tx = NULL; - cache->face_wire.verts_tx = NULL; - cache->face_wire.tri_count = 0; + cache->face_wire.batch = NULL; } static MetaBallBatchCache *metaball_batch_cache_get(MetaBall *mb) @@ -131,10 +125,7 @@ static void metaball_batch_cache_clear(MetaBall *mb) return; } - GPU_VERTBUF_DISCARD_SAFE(cache->face_wire.elem_vbo); - DRW_TEXTURE_FREE_SAFE(cache->face_wire.elem_tx); - DRW_TEXTURE_FREE_SAFE(cache->face_wire.verts_tx); - + GPU_BATCH_DISCARD_SAFE(cache->face_wire.batch); GPU_BATCH_DISCARD_SAFE(cache->batch); GPU_VERTBUF_DISCARD_SAFE(cache->pos_nor_in_order); /* Note: shaded_triangles[0] is already freed by cache->batch */ @@ -152,41 +143,12 @@ static GPUVertBuf *mball_batch_cache_get_pos_and_normals(Object *ob, MetaBallBat { if (cache->pos_nor_in_order == NULL) { ListBase *lb = &ob->runtime.curve_cache->disp; - cache->pos_nor_in_order = DRW_displist_vertbuf_calc_pos_with_normals(lb); + cache->pos_nor_in_order = MEM_callocN(sizeof(GPUVertBuf), __func__); + DRW_displist_vertbuf_create_pos_and_nor(lb, cache->pos_nor_in_order); } return cache->pos_nor_in_order; } -static GPUTexture *mball_batch_cache_get_edges_overlay_texture_buf(Object *ob, MetaBallBatchCache *cache) -{ - if (cache->face_wire.elem_tx != NULL) { - return cache->face_wire.elem_tx; - } - - ListBase *lb = &ob->runtime.curve_cache->disp; - - /* We need a special index buffer. */ - GPUVertBuf *vbo = cache->face_wire.elem_vbo = DRW_displist_create_edges_overlay_texture_buf(lb); - - /* Upload data early because we need to create the texture for it. */ - GPU_vertbuf_use(vbo); - cache->face_wire.elem_tx = GPU_texture_create_from_vertbuf(vbo); - cache->face_wire.tri_count = vbo->vertex_alloc / 3; - - return cache->face_wire.elem_tx; -} - -static GPUTexture *mball_batch_cache_get_vert_pos_and_nor_in_order_buf(Object *ob, MetaBallBatchCache *cache) -{ - if (cache->face_wire.verts_tx == NULL) { - GPUVertBuf *vbo = mball_batch_cache_get_pos_and_normals(ob, cache); - GPU_vertbuf_use(vbo); /* Upload early for buffer texture creation. */ - cache->face_wire.verts_tx = GPU_texture_create_buffer(GPU_R32F, vbo->vbo_id); - } - - return cache->face_wire.verts_tx; -} - /* -------------------------------------------------------------------- */ /** \name Public Object/MetaBall API @@ -203,10 +165,12 @@ GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob) if (cache->batch == NULL) { ListBase *lb = &ob->runtime.curve_cache->disp; + GPUIndexBuf *ibo = MEM_callocN(sizeof(GPUIndexBuf), __func__); + DRW_displist_indexbuf_create_triangles_in_order(lb, ibo); cache->batch = GPU_batch_create_ex( GPU_PRIM_TRIS, mball_batch_cache_get_pos_and_normals(ob, cache), - DRW_displist_indexbuf_calc_triangles_in_order(lb), + ibo, GPU_BATCH_OWNS_INDEX); } @@ -232,26 +196,27 @@ GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(Object *ob, MetaBall *mb, } -void DRW_metaball_batch_cache_get_wireframes_face_texbuf( - Object *ob, struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count) +GPUBatch *DRW_metaball_batch_cache_get_wireframes_face(Object *ob) { if (!BKE_mball_is_basis(ob)) { - *verts_data = NULL; - *face_indices = NULL; - *tri_count = 0; - return; + return NULL; } MetaBall *mb = ob->data; MetaBallBatchCache *cache = metaball_batch_cache_get(mb); - if (cache->face_wire.verts_tx == NULL) { - *verts_data = mball_batch_cache_get_vert_pos_and_nor_in_order_buf(ob, cache); - *face_indices = mball_batch_cache_get_edges_overlay_texture_buf(ob, cache); - } - else { - *verts_data = cache->face_wire.verts_tx; - *face_indices = cache->face_wire.elem_tx; + if (cache->face_wire.batch == NULL) { + ListBase *lb = &ob->runtime.curve_cache->disp; + + GPUVertBuf *vbo_pos_nor = MEM_callocN(sizeof(GPUVertBuf), __func__); + GPUVertBuf *vbo_wireframe_data = MEM_callocN(sizeof(GPUVertBuf), __func__); + + DRW_displist_vertbuf_create_pos_and_nor_and_uv_tess(lb, vbo_pos_nor, NULL); + DRW_displist_vertbuf_create_wireframe_data_tess(lb, vbo_wireframe_data); + + cache->face_wire.batch = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo_pos_nor, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_vertbuf_add_ex(cache->face_wire.batch, vbo_wireframe_data, true); } - *tri_count = cache->face_wire.tri_count; + + return cache->face_wire.batch; } diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index 2eec85807b6..b6c0fa42331 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -80,6 +80,9 @@ typedef struct ParticleBatchCache { /* Control points when in edit mode. */ ParticleHairCache edit_hair; + GPUVertBuf *edit_pos; + GPUBatch *edit_strands; + GPUVertBuf *edit_inner_pos; GPUBatch *edit_inner_points; int edit_inner_point_len; @@ -90,6 +93,7 @@ typedef struct ParticleBatchCache { /* Settings to determine if cache is invalid. */ bool is_dirty; + bool edit_is_weight; } ParticleBatchCache; /* GPUBatch cache management. */ @@ -100,6 +104,25 @@ typedef struct HairAttributeID { uint ind; } HairAttributeID; +typedef struct EditStrandData { + float pos[3]; + uchar color; +} EditStrandData; + +static GPUVertFormat *edit_points_vert_format_get(uint *r_pos_id, uint *r_color_id) +{ + static GPUVertFormat edit_point_format = { 0 }; + static uint pos_id, color_id; + if (edit_point_format.attr_len == 0) { + /* Keep in sync with EditStrandData */ + pos_id = GPU_vertformat_attr_add(&edit_point_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + color_id = GPU_vertformat_attr_add(&edit_point_format, "color", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + *r_pos_id = pos_id; + *r_color_id = color_id; + return &edit_point_format; +} + static bool particle_batch_cache_valid(ParticleSystem *psys) { ParticleBatchCache *cache = psys->batch_cache; @@ -622,6 +645,78 @@ static void particle_batch_cache_fill_segments_proc_pos( } } +static float particle_key_select_ratio(const PTCacheEdit *edit, int strand, float t) +{ + const PTCacheEditPoint *point = &edit->points[strand]; + float edit_key_seg_t = 1.0f / (point->totkey - 1); + if (t == 1.0) { + return (point->keys[point->totkey - 1].flag & PEK_SELECT) ? 1.0f : 0.0; + } + else { + float interp = t / edit_key_seg_t; + int index = (int)interp; + interp -= floorf(interp); /* Time between 2 edit key */ + float s1 = (point->keys[index].flag & PEK_SELECT) ? 1.0f : 0.0; + float s2 = (point->keys[index + 1].flag & PEK_SELECT) ? 1.0f : 0.0; + return s1 + interp * (s2 - s1); + } +} + +static float particle_key_weight(const ParticleData *particle, int strand, float t) +{ + const ParticleData *part = particle + strand; + const HairKey *hkeys = part->hair; + float edit_key_seg_t = 1.0f / (part->totkey - 1); + if (t == 1.0) { + return hkeys[part->totkey - 1].weight; + } + else { + float interp = t / edit_key_seg_t; + int index = (int)interp; + interp -= floorf(interp); /* Time between 2 edit key */ + float s1 = hkeys[index].weight; + float s2 = hkeys[index + 1].weight; + return s1 + interp * (s2 - s1); + } +} + +static int particle_batch_cache_fill_segments_edit( + const PTCacheEdit *edit, /* NULL for weight data */ + const ParticleData *particle, /* NULL for select data */ + ParticleCacheKey **path_cache, + const int start_index, + const int num_path_keys, + GPUIndexBufBuilder *elb, + GPUVertBufRaw *attr_step) +{ + int curr_point = start_index; + for (int i = 0; i < num_path_keys; i++) { + ParticleCacheKey *path = path_cache[i]; + if (path->segments <= 0) { + continue; + } + for (int j = 0; j <= path->segments; j++) { + EditStrandData *seg_data = (EditStrandData *)GPU_vertbuf_raw_step(attr_step); + copy_v3_v3(seg_data->pos, path[j].co); + float strand_t = (float)(j) / path->segments; + if (particle) { + float weight = particle_key_weight(particle, i, strand_t); + /* NaN or unclamped become 0xFF */ + seg_data->color = (uchar)((weight <= 1.0f) ? 0xFE * weight : 0xFF); + } + else { + float selected = particle_key_select_ratio(edit, i, strand_t); + seg_data->color = (uchar)(0xFF * selected); + } + GPU_indexbuf_add_generic_vert(elb, curr_point); + curr_point++; + } + /* Finish the segment and add restart primitive. */ + GPU_indexbuf_add_primitive_restart(elb); + } + return curr_point; +} + static int particle_batch_cache_fill_segments_indices( const ParticleSystem *psys, ParticleCacheKey **path_cache, @@ -1409,22 +1504,71 @@ GPUBatch *DRW_particles_batch_cache_get_dots(Object *object, ParticleSystem *psy return cache->point.points; } +static void particle_batch_cache_ensure_edit_pos_and_seg( + PTCacheEdit *edit, + ParticleSystem *psys, + ModifierData *UNUSED(md), + ParticleHairCache *hair_cache, + bool use_weight) +{ + if (hair_cache->pos != NULL && hair_cache->indices != NULL) { + return; + } + + ParticleData *particle = (use_weight) ? psys->particles : NULL; + + GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos); + GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices); + + GPUVertBufRaw data_step; + GPUIndexBufBuilder elb; + uint pos_id, color_id; + GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id); + + hair_cache->pos = GPU_vertbuf_create_with_format(edit_point_format); + GPU_vertbuf_data_alloc(hair_cache->pos, hair_cache->point_len); + GPU_vertbuf_attr_get_raw_data(hair_cache->pos, pos_id, &data_step); + + GPU_indexbuf_init_ex( + &elb, + GPU_PRIM_LINE_STRIP, + hair_cache->elems_len, hair_cache->point_len, + true); + + if (edit != NULL && edit->pathcache != NULL) { + particle_batch_cache_fill_segments_edit( + edit, particle, edit->pathcache, + 0, edit->totcached, + &elb, &data_step); + } + else { + BLI_assert(!"Hairs are not in edit mode!"); + } + hair_cache->indices = GPU_indexbuf_build(&elb); +} + GPUBatch *DRW_particles_batch_cache_get_edit_strands( Object *object, ParticleSystem *psys, - PTCacheEdit *edit) + PTCacheEdit *edit, + bool use_weight) { ParticleBatchCache *cache = particle_batch_cache_get(psys); + if (cache->edit_is_weight != use_weight) { + GPU_VERTBUF_DISCARD_SAFE(cache->edit_hair.pos); + GPU_BATCH_DISCARD_SAFE(cache->edit_hair.hairs); + } if (cache->edit_hair.hairs != NULL) { return cache->edit_hair.hairs; } drw_particle_update_ptcache_edit(object, psys, edit); ensure_seg_pt_count(edit, psys, &cache->edit_hair); - particle_batch_cache_ensure_pos_and_seg(edit, psys, NULL, &cache->edit_hair); + particle_batch_cache_ensure_edit_pos_and_seg(edit, psys, NULL, &cache->edit_hair, use_weight); cache->edit_hair.hairs = GPU_batch_create( GPU_PRIM_LINE_STRIP, cache->edit_hair.pos, cache->edit_hair.indices); + cache->edit_is_weight = use_weight; return cache->edit_hair.hairs; } @@ -1443,17 +1587,6 @@ static void ensure_edit_inner_points_count( } } -static void edit_colors_get( - PTCacheEdit *edit, - float selected_color[4], - float normal_color[4]) -{ - rgb_uchar_to_float(selected_color, edit->sel_col); - rgb_uchar_to_float(normal_color, edit->nosel_col); - selected_color[3] = 1.0f; - normal_color[3] = 1.0f; -} - static void particle_batch_cache_ensure_edit_inner_pos( PTCacheEdit *edit, ParticleBatchCache *cache) @@ -1462,35 +1595,20 @@ static void particle_batch_cache_ensure_edit_inner_pos( return; } - static GPUVertFormat format = { 0 }; - static uint pos_id, color_id; + uint pos_id, color_id; + GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id); - GPU_VERTBUF_DISCARD_SAFE(cache->edit_inner_pos); - - if (format.attr_len == 0) { - /* initialize vertex format */ - pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - } - - cache->edit_inner_pos = GPU_vertbuf_create_with_format(&format); + cache->edit_inner_pos = GPU_vertbuf_create_with_format(edit_point_format); GPU_vertbuf_data_alloc(cache->edit_inner_pos, cache->edit_inner_point_len); - float selected_color[4], normal_color[4]; - edit_colors_get(edit, selected_color, normal_color); - int global_key_index = 0; for (int point_index = 0; point_index < edit->totpoint; point_index++) { const PTCacheEditPoint *point = &edit->points[point_index]; for (int key_index = 0; key_index < point->totkey - 1; key_index++) { PTCacheEditKey *key = &point->keys[key_index]; + uchar color = (key->flag & PEK_SELECT) ? 0xFF : 0x00; GPU_vertbuf_attr_set(cache->edit_inner_pos, pos_id, global_key_index, key->world_co); - if (key->flag & PEK_SELECT) { - GPU_vertbuf_attr_set(cache->edit_inner_pos, color_id, global_key_index, selected_color); - } - else { - GPU_vertbuf_attr_set(cache->edit_inner_pos, color_id, global_key_index, normal_color); - } + GPU_vertbuf_attr_set(cache->edit_inner_pos, color_id, global_key_index, &color); global_key_index++; } } @@ -1533,33 +1651,18 @@ static void particle_batch_cache_ensure_edit_tip_pos( return; } - static GPUVertFormat format = { 0 }; - static uint pos_id, color_id; - - GPU_VERTBUF_DISCARD_SAFE(cache->edit_tip_pos); + uint pos_id, color_id; + GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id); - if (format.attr_len == 0) { - /* initialize vertex format */ - pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - } - - cache->edit_tip_pos = GPU_vertbuf_create_with_format(&format); + cache->edit_tip_pos = GPU_vertbuf_create_with_format(edit_point_format); GPU_vertbuf_data_alloc(cache->edit_tip_pos, cache->edit_tip_point_len); - float selected_color[4], normal_color[4]; - edit_colors_get(edit, selected_color, normal_color); - for (int point_index = 0; point_index < edit->totpoint; point_index++) { const PTCacheEditPoint *point = &edit->points[point_index]; PTCacheEditKey *key = &point->keys[point->totkey - 1]; + uchar color = (key->flag & PEK_SELECT) ? 0xFF : 0x00; GPU_vertbuf_attr_set(cache->edit_tip_pos, pos_id, point_index, key->world_co); - if (key->flag & PEK_SELECT) { - GPU_vertbuf_attr_set(cache->edit_tip_pos, color_id, point_index, selected_color); - } - else { - GPU_vertbuf_attr_set(cache->edit_tip_pos, color_id, point_index, normal_color); - } + GPU_vertbuf_attr_set(cache->edit_tip_pos, color_id, point_index, &color); } } @@ -1624,6 +1727,5 @@ bool particles_ensure_procedural_data( particle_batch_cache_ensure_procedural_indices(source.edit, source.psys, &cache->hair, thickness_res, subdiv); } - return need_ft_update; } diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index 4d33e6ed802..837b6e5d051 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -87,6 +87,10 @@ void DRW_globals_update(void) UI_GetThemeColor4fv(TH_FACE_DOT, ts.colorFaceDot); UI_GetThemeColor4fv(TH_BACK, ts.colorBackground); + /* Custom median color to slightly affect the edit mesh colors. */ + interp_v4_v4v4(ts.colorEditMeshMiddle, ts.colorVertexSelect, ts.colorWireEdit, 0.35f); + copy_v3_fl(ts.colorEditMeshMiddle, dot_v3v3(ts.colorEditMeshMiddle, (float[3]){0.3333f, 0.3333f, 0.3333f})); /* Desaturate */ + #ifdef WITH_FREESTYLE UI_GetThemeColor4fv(TH_FREESTYLE_EDGE_MARK, ts.colorEdgeFreestyle); UI_GetThemeColor4fv(TH_FREESTYLE_FACE_MARK, ts.colorFaceFreestyle); @@ -159,29 +163,28 @@ void DRW_globals_update(void) DRW_uniformbuffer_update(globals_ubo, &ts); - ColorBand ramp = {0}; - float *colors; - int col_size; + if (!globals_ramp) { + ColorBand ramp = {0}; + float *colors; + int col_size; - ramp.tot = 3; - ramp.data[0].a = 1.0f; - ramp.data[0].b = 1.0f; - ramp.data[0].pos = 0.0f; - ramp.data[1].a = 1.0f; - ramp.data[1].g = 1.0f; - ramp.data[1].pos = 0.5f; - ramp.data[2].a = 1.0f; - ramp.data[2].r = 1.0f; - ramp.data[2].pos = 1.0f; + ramp.tot = 3; + ramp.data[0].a = 1.0f; + ramp.data[0].b = 1.0f; + ramp.data[0].pos = 0.0f; + ramp.data[1].a = 1.0f; + ramp.data[1].g = 1.0f; + ramp.data[1].pos = 0.5f; + ramp.data[2].a = 1.0f; + ramp.data[2].r = 1.0f; + ramp.data[2].pos = 1.0f; - BKE_colorband_evaluate_table_rgba(&ramp, &colors, &col_size); + BKE_colorband_evaluate_table_rgba(&ramp, &colors, &col_size); - if (globals_ramp) { - GPU_texture_free(globals_ramp); - } - globals_ramp = GPU_texture_create_1D(col_size, GPU_RGBA8, colors, NULL); + globals_ramp = GPU_texture_create_1D(col_size, GPU_RGBA8, colors, NULL); - MEM_freeN(colors); + MEM_freeN(colors); + } /* Weight Painting color ramp texture */ bool user_weight_ramp = (U.flag & USER_CUSTOM_RANGE) != 0; @@ -366,7 +369,6 @@ DRWShadingGroup *shgroup_instance_screenspace(DRWPass *pass, struct GPUBatch *ge DRW_shgroup_uniform_float(grp, "size", size, 1); DRW_shgroup_uniform_float(grp, "pixel_size", DRW_viewport_pixelsize_get(), 1); DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); - DRW_shgroup_state_enable(grp, DRW_STATE_STIPPLE_3); return grp; } @@ -876,9 +878,11 @@ int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color * note: no theme yet for 'colindex' */ int theme_id = is_edit ? TH_WIRE_EDIT : TH_WIRE; - if (//(scene->obedit == NULL) && - ((G.moving & G_TRANSFORM_OBJ) != 0) && - ((ob->base_flag & BASE_SELECTED) != 0)) + if (is_edit) { + /* fallback to TH_WIRE */ + } + else if (((G.moving & G_TRANSFORM_OBJ) != 0) && + ((ob->base_flag & BASE_SELECTED) != 0)) { theme_id = TH_TRANSFORM; } diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 90097a6415f..ff276c0e08b 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -84,6 +84,7 @@ typedef struct GlobalsUboStorage { float colorLampNoAlpha[4]; float colorBackground[4]; + float colorEditMeshMiddle[4]; float colorHandleFree[4]; float colorHandleAuto[4]; diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 51943b2f102..9c6b057e1cb 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -41,6 +41,7 @@ #include "DNA_particle_types.h" #include "DNA_customdata_types.h" +#include "BKE_anim.h" #include "BKE_hair.h" #include "BKE_mesh.h" #include "BKE_particle.h" @@ -87,6 +88,12 @@ void DRW_hair_init(void) g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_TRANS_FEEDBACK); } +typedef struct DRWHairInstanceData { + DrawData dd; + + float mat[4][4]; +} DRWHairInstanceData; + void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) { /* TODO more granular update tagging. */ @@ -126,6 +133,15 @@ static DRWShadingGroup *drw_shgroup_create_particle_hair_procedural_ex( /* TODO(fclem): Pass the scene as parameter */ const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; + static float unit_mat[4][4] = { + {1, 0, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 1}, + }; + float (*dupli_mat)[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; @@ -158,10 +174,29 @@ static DRWShadingGroup *drw_shgroup_create_particle_hair_procedural_ex( } } + if (dupli_parent) { + DRWHairInstanceData *hair_inst_data = (DRWHairInstanceData *)DRW_drawdata_ensure( + &object->id, (DrawEngineType *)&drw_shgroup_create_particle_hair_procedural_ex, + sizeof(DRWHairInstanceData), NULL, NULL); + dupli_mat = hair_inst_data->mat; + 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 { + dupli_mat = unit_mat; + } + DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", hair_cache->final[subdiv].proc_tex); DRW_shgroup_uniform_texture(shgrp, "hairIndexBuffer", hair_cache->final[subdiv].hair_index_tex); DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res); DRW_shgroup_uniform_float(shgrp, "hairRadShape", &part->shape, 1); + DRW_shgroup_uniform_mat4(shgrp, "hairDupliMatrix", dupli_mat); DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", part->rad_root * part->rad_scale * 0.5f); DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", part->rad_tip * part->rad_scale * 0.5f); DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", (part->shape_flag & PART_SHAPE_CLOSE_TIP) != 0); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 54693bd95e7..049f58cb509 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -33,6 +33,7 @@ #include "BLF_api.h" +#include "BKE_colortools.h" #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_object.h" @@ -189,6 +190,24 @@ bool DRW_object_is_flat_normal(const Object *ob) return true; } +bool DRW_object_use_hide_faces(const struct Object *ob) +{ + if (ob->type == OB_MESH) { + const Mesh *me = DEG_get_original_object((Object *)ob)->data; + + switch (ob->mode) { + case OB_MODE_TEXTURE_PAINT: + case OB_MODE_VERTEX_PAINT: + return (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + + case OB_MODE_WEIGHT_PAINT: + return (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; + } + } + + return false; +} + bool DRW_object_is_visible_psys_in_active_context( const Object *object, const ParticleSystem *psys) @@ -216,6 +235,16 @@ bool DRW_object_is_visible_psys_in_active_context( return true; } +struct Object *DRW_object_get_dupli_parent(const Object *UNUSED(ob)) +{ + return DST.dupli_parent; +} + +struct DupliObject *DRW_object_get_dupli(const Object *UNUSED(ob)) +{ + return DST.dupli_source; +} + /** \} */ @@ -241,10 +270,19 @@ void DRW_transform_to_display(GPUTexture *tex, bool use_view_settings) if (!(DST.options.is_image_render && !DST.options.is_scene_render)) { Scene *scene = DST.draw_ctx.scene; ColorManagedDisplaySettings *display_settings = &scene->display_settings; - ColorManagedViewSettings *view_settings = (use_view_settings) ? &scene->view_settings : NULL; - + ColorManagedViewSettings *active_view_settings; + ColorManagedViewSettings default_view_settings; + if (use_view_settings) { + active_view_settings = &scene->view_settings; + } + else { + BKE_color_managed_view_settings_init_render( + &default_view_settings, + display_settings); + active_view_settings = &default_view_settings; + } use_ocio = IMB_colormanagement_setup_glsl_draw_from_space( - view_settings, display_settings, NULL, dither, false); + active_view_settings, display_settings, NULL, dither, false); } if (!use_ocio) { @@ -980,6 +1018,10 @@ static void drw_engines_cache_populate(Object *ob) } } + /* TODO: in the future it would be nice to generate once for all viewports. + * But we need threaded DRW manager first. */ + drw_batch_cache_generate_requested(ob); + /* ... and clearing it here too because theses draw data are * from a mempool and must not be free individually by depsgraph. */ drw_drawdata_unlink_dupli((ID *)ob); @@ -1216,10 +1258,10 @@ static void drw_engines_enable_from_mode(int mode) case CTX_MODE_PAINT_VERTEX: case CTX_MODE_PAINT_TEXTURE: case CTX_MODE_OBJECT: - case CTX_MODE_GPENCIL_PAINT: - case CTX_MODE_GPENCIL_EDIT: - case CTX_MODE_GPENCIL_SCULPT: - case CTX_MODE_GPENCIL_WEIGHT: + case CTX_MODE_PAINT_GPENCIL: + case CTX_MODE_EDIT_GPENCIL: + case CTX_MODE_SCULPT_GPENCIL: + case CTX_MODE_WEIGHT_GPENCIL: break; default: BLI_assert(!"Draw mode invalid"); @@ -1427,13 +1469,23 @@ void DRW_draw_render_loop_ex( drw_engines_world_update(scene); const int object_type_exclude_viewport = v3d->object_type_exclude_viewport; - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob) + DEG_OBJECT_ITER_BEGIN(depsgraph, ob, + DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | + DEG_ITER_OBJECT_FLAG_VISIBLE | + DEG_ITER_OBJECT_FLAG_DUPLI) { - if ((object_type_exclude_viewport & (1 << ob->type)) == 0) { - drw_engines_cache_populate(ob); + if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { + continue; } + if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { + continue; + } + DST.dupli_parent = data_.dupli_parent; + DST.dupli_source = data_.dupli_object_current; + drw_engines_cache_populate(ob); } - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; + DEG_OBJECT_ITER_END; drw_engines_cache_finish(); @@ -1481,6 +1533,11 @@ void DRW_draw_render_loop_ex( drw_engines_draw_scene(); +#ifdef __APPLE__ + /* Fix 3D view being "laggy" on macos. (See T56996) */ + GPU_flush(); +#endif + /* annotations - temporary drawing buffer (3d space) */ /* XXX: Or should we use a proper draw/overlay engine for this case? */ if (do_annotations) { @@ -1852,14 +1909,22 @@ void DRW_render_object_iter( DRW_hair_init(); const int object_type_exclude_viewport = draw_ctx->v3d ? draw_ctx->v3d->object_type_exclude_viewport : 0; - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob) + DEG_OBJECT_ITER_BEGIN(depsgraph, ob, + DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | + DEG_ITER_OBJECT_FLAG_VISIBLE | + DEG_ITER_OBJECT_FLAG_DUPLI) { if ((object_type_exclude_viewport & (1 << ob->type)) == 0) { + DST.dupli_parent = data_.dupli_parent; + DST.dupli_source = data_.dupli_object_current; DST.ob_state = NULL; callback(vedata, ob, engine, depsgraph); + + drw_batch_cache_generate_requested(ob); } } - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END + DEG_OBJECT_ITER_END } /* Assume a valid gl context is bound (and that the gl_context_mutex has been acquired). @@ -2046,7 +2111,7 @@ void DRW_draw_select_loop( #if 0 drw_engines_cache_populate(obact); #else - FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, obact->mode, ob_iter) { + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->type, obact->mode, ob_iter) { drw_engines_cache_populate(ob_iter); } FOREACH_OBJECT_IN_MODE_END; @@ -2057,12 +2122,16 @@ void DRW_draw_select_loop( v3d->object_type_exclude_viewport | v3d->object_type_exclude_select ); bool filter_exclude = false; - DEG_OBJECT_ITER_BEGIN( - depsgraph, ob, + DEG_OBJECT_ITER_BEGIN(depsgraph, ob, DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | DEG_ITER_OBJECT_FLAG_VISIBLE | DEG_ITER_OBJECT_FLAG_DUPLI) { + if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { + continue; + } + if ((ob->base_flag & BASE_SELECTABLE) && (object_type_exclude_select & (1 << ob->type)) == 0) { @@ -2083,6 +2152,8 @@ void DRW_draw_select_loop( Object *ob_orig = DEG_get_original_object(ob); DRW_select_load_id(ob_orig->select_color); } + DST.dupli_parent = data_.dupli_parent; + DST.dupli_source = data_.dupli_object_current; drw_engines_cache_populate(ob); } } @@ -2211,7 +2282,9 @@ void DRW_draw_depth_loop( /* Get list of enabled engines */ { drw_engines_enable_basic(); - drw_engines_enable_from_object_mode(); + if (DRW_state_draw_support()) { + drw_engines_enable_from_object_mode(); + } } /* Setup viewport */ @@ -2238,13 +2311,25 @@ void DRW_draw_depth_loop( drw_engines_world_update(scene); const int object_type_exclude_viewport = v3d->object_type_exclude_viewport; - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob) + DEG_OBJECT_ITER_BEGIN(depsgraph, ob, + DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | + DEG_ITER_OBJECT_FLAG_VISIBLE | + DEG_ITER_OBJECT_FLAG_DUPLI) { - if ((object_type_exclude_viewport & (1 << ob->type)) == 0) { - drw_engines_cache_populate(ob); + if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { + continue; + } + + if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { + continue; } + + DST.dupli_parent = data_.dupli_parent; + DST.dupli_source = data_.dupli_object_current; + drw_engines_cache_populate(ob); } - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; + DEG_OBJECT_ITER_END; drw_engines_cache_finish(); @@ -2355,6 +2440,16 @@ bool DRW_state_is_opengl_render(void) return DST.options.is_image_render && !DST.options.is_scene_render; } +bool DRW_state_is_playback(void) +{ + if (DST.draw_ctx.evil_C != NULL) { + struct wmWindowManager *wm = CTX_wm_manager(DST.draw_ctx.evil_C); + return ED_screen_animation_playing(wm) != NULL; + } + return false; +} + + /** * Should text draw in this mode? */ @@ -2423,7 +2518,7 @@ void DRW_engine_register(DrawEngineType *draw_engine_type) void DRW_engines_register(void) { RE_engines_register(&DRW_engine_viewport_eevee_type); - RE_engines_register(&DRW_engine_viewport_opengl_type); + RE_engines_register(&DRW_engine_viewport_workbench_type); DRW_engine_register(&draw_engine_workbench_solid); DRW_engine_register(&draw_engine_workbench_transparent); @@ -2601,7 +2696,7 @@ void DRW_opengl_context_disable_ex(bool restore) #ifdef __APPLE__ /* Need to flush before disabling draw context, otherwise it does not * always finish drawing and viewport can be empty or partially drawn */ - glFlush(); + GPU_flush(); #endif if (BLI_thread_is_main() && restore) { @@ -2638,7 +2733,7 @@ void DRW_opengl_render_context_enable(void *re_gl_context) void DRW_opengl_render_context_disable(void *re_gl_context) { - glFlush(); + GPU_flush(); WM_opengl_context_release(re_gl_context); /* TODO get rid of the blocking. */ BLI_ticket_mutex_unlock(DST.gl_context_mutex); diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index c8a7816c402..9ff34fe79aa 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -319,6 +319,8 @@ typedef struct DRWManager { /* State of the object being evaluated if already allocated. */ DRWCallState *ob_state; uchar state_cache_id; /* Could be larger but 254 view changes is already a lot! */ + struct DupliObject *dupli_source; + struct Object *dupli_parent; /* Rendering state */ GPUShader *shader; @@ -418,4 +420,6 @@ void drw_state_set(DRWState state); void drw_debug_draw(void); void drw_debug_init(void); +void drw_batch_cache_generate_requested(struct Object *ob); + #endif /* __DRAW_MANAGER_H__ */ diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index e9d874bd1ee..5863eb57745 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -122,8 +122,8 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup, const char *name, } if (location == -1) { - if (G.debug & G_DEBUG) - fprintf(stderr, "Pass : %s, Uniform '%s' not found!\n", shgroup->pass_parent->name, name); + if (G.debug & G_DEBUG_GPU) + fprintf(stderr, "Warning: Pass : %s, Uniform '%s' not found!\n", shgroup->pass_parent->name, name); /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ // BLI_assert(0); return; @@ -1040,7 +1040,7 @@ DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup) DRWShadingGroup *shgroup_new = BLI_mempool_alloc(DST.vmempool->shgroups); *shgroup_new = *shgroup; - shgroup_new->uniforms = NULL; /* Not sure about that.. Should we copy them instead? */ + shgroup_new->uniforms = NULL; shgroup_new->calls.first = NULL; shgroup_new->calls.last = NULL; diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 2d56c7e0cfe..88db0f07267 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -282,33 +282,6 @@ void drw_state_set(DRWState state) } } - /* Line Stipple */ - { - int test; - if (CHANGED_ANY_STORE_VAR( - DRW_STATE_STIPPLE_2 | DRW_STATE_STIPPLE_3 | DRW_STATE_STIPPLE_4, - test)) - { - if (test) { - if ((state & DRW_STATE_STIPPLE_2) != 0) { - setlinestyle(2); - } - else if ((state & DRW_STATE_STIPPLE_3) != 0) { - setlinestyle(3); - } - else if ((state & DRW_STATE_STIPPLE_4) != 0) { - setlinestyle(4); - } - else { - BLI_assert(0); - } - } - else { - setlinestyle(0); - } - } - } - /* Stencil */ { DRWState test; @@ -356,6 +329,50 @@ void drw_state_set(DRWState state) } } + /* Provoking Vertex */ + { + int test; + if ((test = CHANGED_TO(DRW_STATE_FIRST_VERTEX_CONVENTION))) { + if (test == 1) { + glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); + } + else { + glProvokingVertex(GL_LAST_VERTEX_CONVENTION); + } + } + } + + /* Polygon Offset */ + { + int test; + if (CHANGED_ANY_STORE_VAR( + DRW_STATE_OFFSET_POSITIVE | + DRW_STATE_OFFSET_NEGATIVE, + test)) + { + if (test) { + glEnable(GL_POLYGON_OFFSET_FILL); + glEnable(GL_POLYGON_OFFSET_LINE); + glEnable(GL_POLYGON_OFFSET_POINT); + /* Stencil Write */ + if ((state & DRW_STATE_OFFSET_POSITIVE) != 0) { + glPolygonOffset(1.0f, 1.0f); + } + else if ((state & DRW_STATE_OFFSET_NEGATIVE) != 0) { + glPolygonOffset(-1.0f, -1.0f); + } + else { + BLI_assert(0); + } + } + else { + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_POLYGON_OFFSET_LINE); + glDisable(GL_POLYGON_OFFSET_POINT); + } + } + } + #undef CHANGED_TO #undef CHANGED_ANY #undef CHANGED_ANY_STORE_VAR diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index bb580695865..e8d693aa7c0 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -47,6 +47,7 @@ extern char datatoc_gpu_shader_2D_vert_glsl[]; extern char datatoc_gpu_shader_3D_vert_glsl[]; +extern char datatoc_gpu_shader_depth_only_frag_glsl[]; extern char datatoc_common_fullscreen_vert_glsl[]; #define USE_DEFERRED_COMPILATION 1 @@ -131,7 +132,7 @@ static void drw_deferred_shader_compilation_exec(void *custom_data, short *stop, *progress = (float)comp->shaders_done / (float)total; *do_update = true; - glFlush(); + GPU_flush(); BLI_mutex_unlock(&comp->compilation_lock); BLI_spin_lock(&comp->list_lock); @@ -295,7 +296,9 @@ GPUShader *DRW_shader_create_with_transform_feedback( const char *vert, const char *geom, const char *defines, const GPUShaderTFBType prim_type, const char **varying_names, const int varying_count) { - return GPU_shader_create_ex(vert, NULL, geom, NULL, defines, + return GPU_shader_create_ex(vert, + datatoc_gpu_shader_depth_only_frag_glsl, + geom, NULL, defines, prim_type, varying_names, varying_count, __func__); } diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c index 607b5e19745..be6e66c339f 100644 --- a/source/blender/draw/intern/draw_manager_texture.c +++ b/source/blender/draw/intern/draw_manager_texture.c @@ -33,9 +33,12 @@ static bool drw_texture_format_supports_framebuffer(GPUTextureFormat format) switch (format) { /* Only add formats that are COMPATIBLE with FB. * Generally they are multiple of 16bit. */ + case GPU_R8: + case GPU_R8UI: case GPU_R16F: case GPU_R16I: case GPU_R16UI: + case GPU_R16: case GPU_R32F: case GPU_R32UI: case GPU_RG8: diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c index 70049a5c345..4c53049e772 100644 --- a/source/blender/draw/intern/draw_view.c +++ b/source/blender/draw/intern/draw_view.c @@ -154,7 +154,7 @@ static bool is_cursor_visible(const DRWContextState *draw_ctx, Scene *scene, Vie /* no exception met? then don't draw cursor! */ return false; } - else if (draw_ctx->object_mode & OB_MODE_GPENCIL_WEIGHT) { + else if (draw_ctx->object_mode & OB_MODE_WEIGHT_GPENCIL) { /* grease pencil hide always in some modes */ return false; } @@ -165,7 +165,6 @@ static bool is_cursor_visible(const DRWContextState *draw_ctx, Scene *scene, Vie void DRW_draw_cursor(void) { const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; ARegion *ar = draw_ctx->ar; Scene *scene = draw_ctx->scene; ViewLayer *view_layer = draw_ctx->view_layer; @@ -176,14 +175,14 @@ void DRW_draw_cursor(void) if (is_cursor_visible(draw_ctx, scene, view_layer)) { int co[2]; - const View3DCursor *cursor = ED_view3d_cursor3d_get(scene, v3d); + const View3DCursor *cursor = &scene->cursor; if (ED_view3d_project_int_global( ar, cursor->location, co, V3D_PROJ_TEST_NOP | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { RegionView3D *rv3d = ar->regiondata; /* Draw nice Anti Aliased cursor. */ - glLineWidth(1.0f); + GPU_line_width(1.0f); glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); @@ -228,6 +227,9 @@ void DRW_draw_cursor(void) immUnbindProgram(); } + float original_proj[4][4]; + GPU_matrix_projection_get(original_proj); + GPU_matrix_push(); ED_region_pixelspace(ar); GPU_matrix_translate_2f(co[0] + 0.5f, co[1] + 0.5f); GPU_matrix_scale_2f(U.widget_unit, U.widget_unit); @@ -240,6 +242,8 @@ void DRW_draw_cursor(void) glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); + GPU_matrix_pop(); + GPU_matrix_projection_set(original_proj); } } } diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c index e5fd199b69a..b3cb2cb3d80 100644 --- a/source/blender/draw/modes/edit_curve_mode.c +++ b/source/blender/draw/modes/edit_curve_mode.c @@ -47,11 +47,13 @@ extern struct GlobalsUboStorage ts; /* draw_common.c */ extern char datatoc_common_globals_lib_glsl[]; extern char datatoc_edit_curve_overlay_loosevert_vert_glsl[]; +extern char datatoc_edit_curve_overlay_normals_vert_glsl[]; extern char datatoc_edit_curve_overlay_handle_vert_glsl[]; extern char datatoc_edit_curve_overlay_handle_geom_glsl[]; extern char datatoc_gpu_shader_point_varying_color_frag_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; +extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; /* *********** LISTS *********** */ /* All lists are per viewport specific datas. @@ -83,6 +85,7 @@ typedef struct EDIT_CURVE_Data { static struct { GPUShader *wire_sh; + GPUShader *wire_normals_sh; GPUShader *overlay_edge_sh; /* handles and nurbs control cage */ GPUShader *overlay_vert_sh; } e_data = {NULL}; /* Engine data */ @@ -90,6 +93,7 @@ static struct { typedef struct EDIT_CURVE_PrivateData { /* resulting curve as 'wire' for curves (and optionally normals) */ DRWShadingGroup *wire_shgrp; + DRWShadingGroup *wire_normals_shgrp; DRWShadingGroup *overlay_edge_shgrp; DRWShadingGroup *overlay_vert_shgrp; @@ -108,6 +112,12 @@ static void EDIT_CURVE_engine_init(void *UNUSED(vedata)) e_data.wire_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); } + if (!e_data.wire_normals_sh) { + e_data.wire_normals_sh = DRW_shader_create( + datatoc_edit_curve_overlay_normals_vert_glsl, NULL, + datatoc_gpu_shader_uniform_color_frag_glsl, NULL); + } + if (!e_data.overlay_edge_sh) { e_data.overlay_edge_sh = DRW_shader_create_with_lib( datatoc_edit_curve_overlay_handle_vert_glsl, @@ -152,6 +162,12 @@ static void EDIT_CURVE_cache_init(void *vedata) DRW_shgroup_uniform_vec4(grp, "color", ts.colorWireEdit, 1); stl->g_data->wire_shgrp = grp; + + grp = DRW_shgroup_create(e_data.wire_normals_sh, psl->wire_pass); + DRW_shgroup_uniform_vec4(grp, "color", ts.colorWireEdit, 1); + DRW_shgroup_uniform_float_copy(grp, "normalSize", v3d->overlay.normals_length); + stl->g_data->wire_normals_shgrp = grp; + psl->overlay_edge_pass = DRW_pass_create( "Curve Handle Overlay", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND); @@ -169,7 +185,6 @@ static void EDIT_CURVE_cache_init(void *vedata) grp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_vert_pass); DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo); - DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); stl->g_data->overlay_vert_shgrp = grp; } } @@ -191,8 +206,9 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob) DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat); if ((cu->flag & CU_3D) && (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_NORMALS) != 0) { - geom = DRW_cache_curve_edge_normal_get(ob, v3d->overlay.normals_length); - DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat); + static uint instance_len = 2; + geom = DRW_cache_curve_edge_normal_get(ob); + DRW_shgroup_call_instances_add(stl->g_data->wire_normals_shgrp, geom, ob->obmat, &instance_len); } geom = DRW_cache_curve_edge_overlay_get(ob); @@ -243,6 +259,7 @@ static void EDIT_CURVE_draw_scene(void *vedata) * Mostly used for freeing shaders */ static void EDIT_CURVE_engine_free(void) { + DRW_SHADER_FREE_SAFE(e_data.wire_normals_sh); DRW_SHADER_FREE_SAFE(e_data.overlay_edge_sh); DRW_SHADER_FREE_SAFE(e_data.overlay_vert_sh); } diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c index fabff950c60..569ec59c93d 100644 --- a/source/blender/draw/modes/edit_mesh_mode.c +++ b/source/blender/draw/modes/edit_mesh_mode.c @@ -38,6 +38,7 @@ #include "edit_mesh_mode_intern.h" /* own include */ +#include "BKE_editmesh.h" #include "BKE_object.h" #include "BLI_dynstr.h" @@ -59,7 +60,6 @@ extern char datatoc_edit_mesh_overlay_geom_edge_glsl[]; extern char datatoc_edit_mesh_overlay_points_vert_glsl[]; extern char datatoc_edit_mesh_overlay_facedot_frag_glsl[]; extern char datatoc_edit_mesh_overlay_facedot_vert_glsl[]; -extern char datatoc_edit_mesh_overlay_ghost_clear_vert_glsl[]; extern char datatoc_edit_mesh_overlay_mix_frag_glsl[]; extern char datatoc_edit_mesh_overlay_facefill_vert_glsl[]; extern char datatoc_edit_mesh_overlay_facefill_frag_glsl[]; @@ -70,6 +70,7 @@ extern char datatoc_common_globals_lib_glsl[]; extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; extern char datatoc_gpu_shader_flat_color_frag_glsl[]; extern char datatoc_gpu_shader_point_varying_color_frag_glsl[]; +extern char datatoc_gpu_shader_depth_only_frag_glsl[]; /* *********** LISTS *********** */ typedef struct EDIT_MESH_PassList { @@ -135,17 +136,14 @@ typedef struct EDIT_MESH_PrivateData { DRWShadingGroup *vnormals_shgrp; DRWShadingGroup *lnormals_shgrp; - DRWShadingGroup *face_overlay_shgrp; - DRWShadingGroup *verts_overlay_shgrp; - DRWShadingGroup *ledges_overlay_shgrp; - DRWShadingGroup *lverts_overlay_shgrp; - DRWShadingGroup *facedot_overlay_shgrp; - - DRWShadingGroup *face_occluded_shgrp; - DRWShadingGroup *verts_occluded_shgrp; - DRWShadingGroup *ledges_occluded_shgrp; - DRWShadingGroup *lverts_occluded_shgrp; - DRWShadingGroup *facedot_occluded_shgrp; + DRWShadingGroup *face_shgrp; + DRWShadingGroup *face_cage_shgrp; + + DRWShadingGroup *verts_shgrp; + DRWShadingGroup *ledges_shgrp; + DRWShadingGroup *lverts_shgrp; + DRWShadingGroup *facedot_shgrp; + DRWShadingGroup *facefill_occluded_shgrp; int data_mask[4]; @@ -329,8 +327,7 @@ static void EDIT_MESH_engine_init(void *vedata) e_data.depth_sh = DRW_shader_create_3D_depth_only(); } if (!e_data.ghost_clear_depth_sh) { - e_data.ghost_clear_depth_sh = DRW_shader_create(datatoc_edit_mesh_overlay_ghost_clear_vert_glsl, - NULL, NULL, NULL); + e_data.ghost_clear_depth_sh = DRW_shader_create_fullscreen(datatoc_gpu_shader_depth_only_frag_glsl, NULL); } } @@ -338,7 +335,8 @@ static void EDIT_MESH_engine_init(void *vedata) static DRWPass *edit_mesh_create_overlay_pass( float *face_alpha, float *edge_width_scale, int *data_mask, bool do_edges, bool xray, DRWState statemod, - DRWShadingGroup **r_face_shgrp, DRWShadingGroup **r_verts_shgrp, DRWShadingGroup **r_ledges_shgrp, + DRWShadingGroup **r_face_shgrp, DRWShadingGroup **r_face_cage_shgrp, + DRWShadingGroup **r_verts_shgrp, DRWShadingGroup **r_ledges_shgrp, DRWShadingGroup **r_lverts_shgrp, DRWShadingGroup **r_facedot_shgrp) { GPUShader *tri_sh, *ledge_sh; @@ -361,12 +359,14 @@ static DRWPass *edit_mesh_create_overlay_pass( DRW_shgroup_uniform_vec2(*r_lverts_shgrp, "viewportSize", DRW_viewport_size_get(), 1); DRW_shgroup_uniform_float(*r_lverts_shgrp, "edgeScale", edge_width_scale, 1); DRW_shgroup_state_enable(*r_lverts_shgrp, DRW_STATE_WRITE_DEPTH); + DRW_shgroup_state_disable(*r_lverts_shgrp, DRW_STATE_BLEND); *r_verts_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, pass); DRW_shgroup_uniform_block(*r_verts_shgrp, "globalsBlock", globals_ubo); DRW_shgroup_uniform_vec2(*r_verts_shgrp, "viewportSize", DRW_viewport_size_get(), 1); DRW_shgroup_uniform_float(*r_verts_shgrp, "edgeScale", edge_width_scale, 1); DRW_shgroup_state_enable(*r_verts_shgrp, DRW_STATE_WRITE_DEPTH); + DRW_shgroup_state_disable(*r_verts_shgrp, DRW_STATE_BLEND); } if ((tsettings->selectmode & SCE_SELECT_FACE) != 0) { @@ -386,6 +386,13 @@ static DRWPass *edit_mesh_create_overlay_pass( if (!fast_mode) { DRW_shgroup_uniform_bool_copy(*r_face_shgrp, "isXray", xray); } + else { + /* To be able to use triple load. */ + DRW_shgroup_state_enable(*r_face_shgrp, DRW_STATE_FIRST_VERTEX_CONVENTION); + } + /* Cage geom needs to be offseted to avoid Z-fighting. */ + *r_face_cage_shgrp = DRW_shgroup_create_sub(*r_face_shgrp); + DRW_shgroup_state_enable(*r_face_cage_shgrp, DRW_STATE_OFFSET_NEGATIVE); *r_ledges_shgrp = DRW_shgroup_create(ledge_sh, pass); DRW_shgroup_uniform_block(*r_ledges_shgrp, "globalsBlock", globals_ubo); @@ -521,22 +528,24 @@ static void EDIT_MESH_cache_init(void *vedata) psl->edit_face_overlay = edit_mesh_create_overlay_pass( &face_mod, &stl->g_data->edge_width_scale, stl->g_data->data_mask, stl->g_data->do_edges, false, DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND, - &stl->g_data->face_overlay_shgrp, - &stl->g_data->verts_overlay_shgrp, - &stl->g_data->ledges_overlay_shgrp, - &stl->g_data->lverts_overlay_shgrp, - &stl->g_data->facedot_overlay_shgrp); + &stl->g_data->face_shgrp, + &stl->g_data->face_cage_shgrp, + &stl->g_data->verts_shgrp, + &stl->g_data->ledges_shgrp, + &stl->g_data->lverts_shgrp, + &stl->g_data->facedot_shgrp); } else { /* We render all wires with depth and opaque to a new fbo and blend the result based on depth values */ psl->edit_face_occluded = edit_mesh_create_overlay_pass( &zero, &stl->g_data->edge_width_scale, stl->g_data->data_mask, stl->g_data->do_edges, true, DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_DEPTH, - &stl->g_data->face_occluded_shgrp, - &stl->g_data->verts_occluded_shgrp, - &stl->g_data->ledges_occluded_shgrp, - &stl->g_data->lverts_occluded_shgrp, - &stl->g_data->facedot_occluded_shgrp); + &stl->g_data->face_shgrp, + &stl->g_data->face_cage_shgrp, + &stl->g_data->verts_shgrp, + &stl->g_data->ledges_shgrp, + &stl->g_data->lverts_shgrp, + &stl->g_data->facedot_shgrp); /* however we loose the front faces value (because we need the depth of occluded wires and * faces are alpha blended ) so we recover them in a new pass. */ @@ -564,40 +573,48 @@ static void EDIT_MESH_cache_init(void *vedata) static void edit_mesh_add_ob_to_pass( Scene *scene, Object *ob, - DRWShadingGroup *face_shgrp, - DRWShadingGroup *verts_shgrp, - DRWShadingGroup *ledges_shgrp, - DRWShadingGroup *lverts_shgrp, + EDIT_MESH_PrivateData *g_data, DRWShadingGroup *facedot_shgrp, DRWShadingGroup *facefill_shgrp) { - struct GPUBatch *geo_ovl_tris, *geo_ovl_verts, *geo_ovl_lnor, *geo_ovl_ledges, *geo_ovl_lverts, *geo_ovl_fcenter; - struct GPUTexture *data_texture; + struct GPUBatch *geom_tris, *geom_verts, *geom_ledges, *geom_ledges_nor, *geom_lverts, *geom_fcenter; ToolSettings *tsettings = scene->toolsettings; - DRW_cache_mesh_wire_overlay_get(ob, &geo_ovl_tris, &geo_ovl_ledges, &geo_ovl_lverts, &data_texture); + bool has_edit_mesh_cage = false; + /* TODO: Should be its own function. */ + Mesh *me = (Mesh *)ob->data; + BMEditMesh *embm = me->edit_btmesh; + if (embm) { + has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final); + } - face_shgrp = DRW_shgroup_create_sub(face_shgrp); - DRW_shgroup_uniform_texture(face_shgrp, "dataBuffer", data_texture); - DRW_shgroup_call_add(face_shgrp, geo_ovl_tris, ob->obmat); + DRWShadingGroup *face_shgrp = (has_edit_mesh_cage) ? g_data->face_cage_shgrp : g_data->face_shgrp; + DRWShadingGroup *verts_shgrp = g_data->verts_shgrp; + DRWShadingGroup *ledges_shgrp = g_data->ledges_shgrp; + DRWShadingGroup *lverts_shgrp = g_data->lverts_shgrp; - DRW_shgroup_call_add(ledges_shgrp, geo_ovl_ledges, ob->obmat); + geom_tris = DRW_mesh_batch_cache_get_edit_triangles(ob->data); + geom_ledges = DRW_mesh_batch_cache_get_edit_loose_edges(ob->data); + DRW_shgroup_call_add(face_shgrp, geom_tris, ob->obmat); + DRW_shgroup_call_add(ledges_shgrp, geom_ledges, ob->obmat); if (facefill_shgrp) { - DRW_shgroup_call_add(facefill_shgrp, geo_ovl_tris, ob->obmat); + DRW_shgroup_call_add(facefill_shgrp, geom_tris, ob->obmat); } if ((tsettings->selectmode & SCE_SELECT_VERTEX) != 0) { /* Thoses are point batches. */ - DRW_cache_mesh_normals_overlay_get(ob, &geo_ovl_verts, &geo_ovl_lnor, &geo_ovl_ledges, &geo_ovl_lverts); - DRW_shgroup_call_add(verts_shgrp, geo_ovl_verts, ob->obmat); - DRW_shgroup_call_add(lverts_shgrp, geo_ovl_ledges, ob->obmat); - DRW_shgroup_call_add(lverts_shgrp, geo_ovl_lverts, ob->obmat); + geom_verts = DRW_mesh_batch_cache_get_edit_vertices(ob->data); + geom_ledges_nor = DRW_mesh_batch_cache_get_edit_loose_edges_nor(ob->data); + geom_lverts = DRW_mesh_batch_cache_get_edit_loose_verts(ob->data); + DRW_shgroup_call_add(verts_shgrp, geom_verts, ob->obmat); + DRW_shgroup_call_add(lverts_shgrp, geom_ledges_nor, ob->obmat); + DRW_shgroup_call_add(lverts_shgrp, geom_lverts, ob->obmat); } if (facedot_shgrp && (tsettings->selectmode & SCE_SELECT_FACE) != 0 ) { - geo_ovl_fcenter = DRW_cache_face_centers_get(ob); - DRW_shgroup_call_add(facedot_shgrp, geo_ovl_fcenter, ob->obmat); + geom_fcenter = DRW_mesh_batch_cache_get_edit_facedots(ob->data); + DRW_shgroup_call_add(facedot_shgrp, geom_fcenter, ob->obmat); } } @@ -640,7 +657,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob) } if (do_show_weight) { - geom = DRW_cache_mesh_surface_weights_get(ob, tsettings, false); + geom = DRW_cache_mesh_surface_weights_get(ob); DRW_shgroup_call_add(stl->g_data->fweights_shgrp, geom, ob->obmat); } @@ -649,44 +666,33 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob) DRW_shgroup_call_add(stl->g_data->depth_shgrp_hidden_wire, geom, ob->obmat); } + if (vnormals_do) { + geom = DRW_mesh_batch_cache_get_edit_triangles_nor(ob->data); + DRW_shgroup_call_add(stl->g_data->vnormals_shgrp, geom, ob->obmat); + geom = DRW_mesh_batch_cache_get_edit_loose_verts(ob->data); + DRW_shgroup_call_add(stl->g_data->vnormals_shgrp, geom, ob->obmat); + geom = DRW_mesh_batch_cache_get_edit_loose_edges_nor(ob->data); + DRW_shgroup_call_add(stl->g_data->vnormals_shgrp, geom, ob->obmat); + } + if (lnormals_do) { + geom = DRW_mesh_batch_cache_get_edit_triangles_lnor(ob->data); + DRW_shgroup_call_add(stl->g_data->lnormals_shgrp, geom, ob->obmat); + } if (fnormals_do) { - geom = DRW_cache_face_centers_get(ob); + geom = DRW_mesh_batch_cache_get_edit_facedots(ob->data); DRW_shgroup_call_add(stl->g_data->fnormals_shgrp, geom, ob->obmat); } - if (vnormals_do || lnormals_do) { - struct GPUBatch *geo_ovl_tris, *geo_ovl_lnor, *geo_ovl_ledges, *geo_ovl_lverts; - DRW_cache_mesh_normals_overlay_get(ob, &geo_ovl_tris, &geo_ovl_lnor, &geo_ovl_ledges, &geo_ovl_lverts); - - if (vnormals_do) { - DRW_shgroup_call_add(stl->g_data->vnormals_shgrp, geo_ovl_tris, ob->obmat); - DRW_shgroup_call_add(stl->g_data->vnormals_shgrp, geo_ovl_ledges, ob->obmat); - DRW_shgroup_call_add(stl->g_data->vnormals_shgrp, geo_ovl_lverts, ob->obmat); - } - - if (lnormals_do) { - DRW_shgroup_call_add(stl->g_data->lnormals_shgrp, geo_ovl_lnor, ob->obmat); - } - } - if (stl->g_data->do_zbufclip) { edit_mesh_add_ob_to_pass( - scene, ob, - stl->g_data->face_occluded_shgrp, - stl->g_data->verts_occluded_shgrp, - stl->g_data->ledges_occluded_shgrp, - stl->g_data->lverts_occluded_shgrp, - stl->g_data->facedot_occluded_shgrp, + scene, ob, stl->g_data, + stl->g_data->facedot_shgrp, (stl->g_data->do_faces) ? stl->g_data->facefill_occluded_shgrp : NULL); } else { edit_mesh_add_ob_to_pass( - scene, ob, - stl->g_data->face_overlay_shgrp, - stl->g_data->verts_overlay_shgrp, - stl->g_data->ledges_overlay_shgrp, - stl->g_data->lverts_overlay_shgrp, - (show_face_dots) ? stl->g_data->facedot_overlay_shgrp : NULL, + scene, ob, stl->g_data, + (show_face_dots) ? stl->g_data->facedot_shgrp : NULL, NULL); } diff --git a/source/blender/draw/modes/edit_mesh_mode_text.c b/source/blender/draw/modes/edit_mesh_mode_text.c index d2bfc75a2bf..0498998b69a 100644 --- a/source/blender/draw/modes/edit_mesh_mode_text.c +++ b/source/blender/draw/modes/edit_mesh_mode_text.c @@ -345,7 +345,7 @@ void DRW_edit_mesh_mode_text_measure_stats( BM_ITER_MESH_INDEX(f, &iter, em->bm, BM_FACES_OF_MESH, i) { if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - BM_face_calc_center_mean(f, v1); + BM_face_calc_center_median(f, v1); mul_m4_v3(ob->obmat, v1); numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i); diff --git a/source/blender/draw/modes/edit_text_mode.c b/source/blender/draw/modes/edit_text_mode.c index d186ee967e5..cb87a015717 100644 --- a/source/blender/draw/modes/edit_text_mode.c +++ b/source/blender/draw/modes/edit_text_mode.c @@ -30,6 +30,8 @@ #include "BIF_glutil.h" +#include "BKE_font.h" + /* If builtin shaders are needed */ #include "GPU_shader.h" #include "GPU_batch.h" @@ -193,6 +195,78 @@ static void EDIT_TEXT_cache_init(void *vedata) } } +/* Use 2D quad corners to create a matrix that set + * a [-1..1] quad at the right position. */ +static void v2_quad_corners_to_mat4(float corners[4][2], float r_mat[4][4]) +{ + unit_m4(r_mat); + sub_v2_v2v2(r_mat[0], corners[1], corners[0]); + sub_v2_v2v2(r_mat[1], corners[3], corners[0]); + mul_v2_fl(r_mat[0], 0.5f); + mul_v2_fl(r_mat[1], 0.5f); + copy_v2_v2(r_mat[3], corners[0]); + add_v2_v2(r_mat[3], r_mat[0]); + add_v2_v2(r_mat[3], r_mat[1]); +} + +static void edit_text_cache_populate_select(void *vedata, Object *ob) +{ + EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl; + const Curve *cu = ob->data; + EditFont *ef = cu->editfont; + float final_mat[4][4], box[4][2]; + struct GPUBatch *geom = DRW_cache_quad_get(); + + for (int i = 0; i < ef->selboxes_len; i++) { + EditFontSelBox *sb = &ef->selboxes[i]; + + float selboxw; + if (i + 1 != ef->selboxes_len) { + if (ef->selboxes[i + 1].y == sb->y) + selboxw = ef->selboxes[i + 1].x - sb->x; + else + selboxw = sb->w; + } + else { + selboxw = sb->w; + } + /* NOTE: v2_quad_corners_to_mat4 don't need the 3rd corner. */ + if (sb->rot == 0.0f) { + copy_v2_fl2(box[0], sb->x, sb->y); + copy_v2_fl2(box[1], sb->x + selboxw, sb->y); + copy_v2_fl2(box[3], sb->x, sb->y + sb->h); + } + else { + float mat[2][2]; + angle_to_mat2(mat, sb->rot); + copy_v2_fl2(box[0], sb->x, sb->y); + mul_v2_v2fl(box[1], mat[0], selboxw); + add_v2_v2(box[1], &sb->x); + mul_v2_v2fl(box[3], mat[1], sb->h); + add_v2_v2(box[3], &sb->x); + } + v2_quad_corners_to_mat4(box, final_mat); + mul_m4_m4m4(final_mat, ob->obmat, final_mat); + + DRW_shgroup_call_add(stl->g_data->overlay_select_shgrp, geom, final_mat); + } +} + +static void edit_text_cache_populate_cursor(void *vedata, Object *ob) +{ + EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl; + const Curve *cu = ob->data; + EditFont *edit_font = cu->editfont; + float (*cursor)[2] = edit_font->textcurs; + float mat[4][4]; + + v2_quad_corners_to_mat4(cursor, mat); + mul_m4_m4m4(mat, ob->obmat, mat); + + struct GPUBatch *geom = DRW_cache_quad_get(); + DRW_shgroup_call_add(stl->g_data->overlay_cursor_shgrp, geom, mat); +} + static void edit_text_cache_populate_boxes(void *vedata, Object *ob) { EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl; @@ -215,7 +289,7 @@ static void edit_text_cache_populate_boxes(void *vedata, Object *ob) DRWShadingGroup *shading_group = shading_groups[is_active ? 0 : 1]; vec[0] = cu->xof + tb->x; - vec[1] = cu->yof + tb->y + cu->fsize; + vec[1] = cu->yof + tb->y + cu->fsize_realtime; vec[2] = 0.001; mul_v3_m4v3(vec1, ob->obmat, vec); @@ -273,16 +347,8 @@ static void EDIT_TEXT_cache_populate(void *vedata, Object *ob) /* object mode draws */ } - geom = DRW_cache_text_select_overlay_get(ob); - if (geom) { - DRW_shgroup_call_add(stl->g_data->overlay_select_shgrp, geom, ob->obmat); - } - - geom = DRW_cache_text_cursor_overlay_get(ob); - if (geom) { - DRW_shgroup_call_add(stl->g_data->overlay_cursor_shgrp, geom, ob->obmat); - } - + edit_text_cache_populate_select(vedata, ob); + edit_text_cache_populate_cursor(vedata, ob); edit_text_cache_populate_boxes(vedata, ob); } } diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index 144609ddb10..b466333fd13 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -95,6 +95,7 @@ extern char datatoc_object_grid_vert_glsl[]; extern char datatoc_object_empty_image_frag_glsl[]; extern char datatoc_object_empty_image_vert_glsl[]; extern char datatoc_object_lightprobe_grid_vert_glsl[]; +extern char datatoc_object_loose_points_frag_glsl[]; extern char datatoc_object_particle_prim_vert_glsl[]; extern char datatoc_object_particle_dot_vert_glsl[]; extern char datatoc_object_particle_dot_frag_glsl[]; @@ -312,6 +313,7 @@ static struct { GPUShader *part_prim_sh; GPUShader *part_axis_sh; GPUShader *lightprobe_grid_sh; + GPUShader *loose_points_sh; float camera_pos[3]; float screenvecs[3][4]; float grid_settings[5]; @@ -463,6 +465,9 @@ static void OBJECT_engine_init(void *vedata) /* Lightprobes */ e_data.lightprobe_grid_sh = DRW_shader_create( datatoc_object_lightprobe_grid_vert_glsl, NULL, datatoc_gpu_shader_flat_id_frag_glsl, NULL); + + /* Loose Points */ + e_data.loose_points_sh = DRW_shader_create_3D(datatoc_object_loose_points_frag_glsl, NULL); } { @@ -692,6 +697,7 @@ static void OBJECT_engine_free(void) DRW_SHADER_FREE_SAFE(e_data.part_axis_sh); DRW_SHADER_FREE_SAFE(e_data.part_dot_sh); DRW_SHADER_FREE_SAFE(e_data.lightprobe_grid_sh); + DRW_SHADER_FREE_SAFE(e_data.loose_points_sh); } static DRWShadingGroup *shgroup_outline(DRWPass *pass, const int *ofs, GPUShader *sh) @@ -716,6 +722,7 @@ static DRWShadingGroup *shgroup_points(DRWPass *pass, const float col[4], GPUSha { DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); DRW_shgroup_uniform_vec4(grp, "color", col, 1); + DRW_shgroup_uniform_vec4(grp, "innerColor", ts.colorEditMeshMiddle, 1); return grp; } @@ -826,14 +833,12 @@ static DRWShadingGroup *shgroup_theme_id_to_point_or( } } -static void image_calc_aspect(Image *ima, ImageUser *iuser, float r_image_aspect[2]) +static void image_calc_aspect(Image *ima, const int size[2], float r_image_aspect[2]) { float ima_x, ima_y; if (ima) { - int w, h; - BKE_image_get_size(ima, iuser, &w, &h); - ima_x = w; - ima_y = h; + ima_x = size[0]; + ima_y = size[1]; } else { /* if no image, make it a 1x1 empty square, honor scale & offset */ @@ -867,15 +872,27 @@ static void DRW_shgroup_empty_image( { /* TODO: 'StereoViews', see draw_empty_image. */ - if (!BKE_image_empty_visible_in_view3d(ob, rv3d)) + if (!BKE_object_empty_image_is_visible_in_view3d(ob, rv3d)) return; - GPUTexture *tex = ob->data ? - GPU_texture_from_blender(ob->data, ob->iuser, GL_TEXTURE_2D, false, 0.0f) : - NULL; + /* Calling 'BKE_image_get_size' may free the texture. Get the size from 'tex' instead, see: T59347 */ + int size[2] = {0}; + + GPUTexture *tex = NULL; + + if (ob->data != NULL) { + tex = GPU_texture_from_blender(ob->data, ob->iuser, GL_TEXTURE_2D, false, 0.0f); + if (tex) { + size[0] = GPU_texture_width(tex); + size[1] = GPU_texture_height(tex); + } + } + + CLAMP_MIN(size[0], 1); + CLAMP_MIN(size[1], 1); float image_aspect[2]; - image_calc_aspect(ob->data, ob->iuser, image_aspect); + image_calc_aspect(ob->data, size, image_aspect); /* OPTI(fclem) We need sorting only for transparent images. If an image as no alpha channel and * ob->col[3] == 1.0f, we could remove it from the sorting pass. */ @@ -901,7 +918,7 @@ static void DRW_shgroup_empty_image( DRW_shgroup_uniform_int_copy(grp, "depthMode", ob->empty_image_depth); DRW_shgroup_uniform_float(grp, "size", &ob->empty_drawsize, 1); DRW_shgroup_uniform_vec2(grp, "offset", ob->ima_ofs, 1); - DRW_shgroup_uniform_vec4(grp, "color", color, 1); + DRW_shgroup_uniform_vec3(grp, "color", color, 1); DRW_shgroup_call_add(grp, DRW_cache_image_plane_wire_get(), ob->obmat); } } @@ -1198,11 +1215,15 @@ static void OBJECT_cache_init(void *vedata) sgl->wire_active = shgroup_wire(sgl->non_meshes, ts.colorActive, sh); /* Points (loose points) */ - sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); + sh = e_data.loose_points_sh; sgl->points = shgroup_points(sgl->non_meshes, ts.colorWire, sh); sgl->points_select = shgroup_points(sgl->non_meshes, ts.colorSelect, sh); sgl->points_transform = shgroup_points(sgl->non_meshes, ts.colorTransform, sh); sgl->points_active = shgroup_points(sgl->non_meshes, ts.colorActive, sh); + DRW_shgroup_state_disable(sgl->points, DRW_STATE_BLEND); + DRW_shgroup_state_disable(sgl->points_select, DRW_STATE_BLEND); + DRW_shgroup_state_disable(sgl->points_transform, DRW_STATE_BLEND); + DRW_shgroup_state_disable(sgl->points_active, DRW_STATE_BLEND); /* Metaballs Handles */ sgl->mball_handle = shgroup_instance_mball_handles(sgl->non_meshes); @@ -2270,7 +2291,7 @@ static void DRW_shgroup_relationship_lines( Object *ob) { if (ob->parent && DRW_object_is_visible_in_active_context(ob->parent)) { - DRW_shgroup_call_dynamic_add(sgl->relationship_lines, ob->parent->obmat[3]); + DRW_shgroup_call_dynamic_add(sgl->relationship_lines, ob->orig); DRW_shgroup_call_dynamic_add(sgl->relationship_lines, ob->obmat[3]); } @@ -2399,31 +2420,30 @@ static void DRW_shgroup_texture_space(OBJECT_ShadingGroupList *sgl, Object *ob, ID *ob_data = ob->data; float *texcoloc = NULL; float *texcosize = NULL; - if (ob->data != NULL) { - switch (GS(ob_data->name)) { - case ID_ME: - BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize); - break; - case ID_CU: - { - Curve *cu = (Curve *)ob_data; - if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { - BKE_curve_texspace_calc(cu); - } - texcoloc = cu->loc; - texcosize = cu->size; - break; - } - case ID_MB: - { - MetaBall *mb = (MetaBall *)ob_data; - texcoloc = mb->loc; - texcosize = mb->size; - break; + + switch (GS(ob_data->name)) { + case ID_ME: + BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize); + break; + case ID_CU: + { + Curve *cu = (Curve *)ob_data; + if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { + BKE_curve_texspace_calc(cu); } - default: - BLI_assert(0); + texcoloc = cu->loc; + texcosize = cu->size; + break; } + case ID_MB: + { + MetaBall *mb = (MetaBall *)ob_data; + texcoloc = mb->loc; + texcosize = mb->size; + break; + } + default: + BLI_assert(0); } float tmp[4][4] = {{0.0f}}, one = 1.0f; @@ -2682,7 +2702,21 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) break; } case OB_SURF: + { + if (hide_object_extra) { + break; + } + struct GPUBatch *geom = DRW_cache_surf_edge_wire_get(ob); + if (geom == NULL) { + break; + } + if (theme_id == TH_UNDEFINED) { + theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + } + DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(sgl, theme_id, sgl->wire); + DRW_shgroup_call_object_add(shgroup, geom, ob); break; + } case OB_LATTICE: { if (ob != draw_ctx->object_edit && !BKE_object_is_in_editmode(ob)) { @@ -2774,7 +2808,9 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) break; case OB_ARMATURE: { - if (v3d->overlay.flag & V3D_OVERLAY_HIDE_BONES) { + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->overlay.flag & V3D_OVERLAY_HIDE_BONES)) + { break; } bArmature *arm = ob->data; @@ -2894,18 +2930,18 @@ static void OBJECT_draw_scene(void *vedata) MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl); - /* This needs to be drawn after the oultine */ DRW_draw_pass(stl->g_data->sgl.spot_shapes); DRW_draw_pass(stl->g_data->sgl.bone_solid); DRW_draw_pass(stl->g_data->sgl.bone_wire); DRW_draw_pass(stl->g_data->sgl.bone_outline); DRW_draw_pass(stl->g_data->sgl.non_meshes); DRW_draw_pass(psl->particle); - DRW_draw_pass(stl->g_data->sgl.image_empties); DRW_draw_pass(stl->g_data->sgl.bone_axes); MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl) + DRW_draw_pass(stl->g_data->sgl.image_empties); + if (DRW_state_is_fbo() && outline_calls > 0) { DRW_stats_group_start("Outlines"); diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c index 460b3d4240a..0c67263bd4f 100644 --- a/source/blender/draw/modes/overlay_mode.c +++ b/source/blender/draw/modes/overlay_mode.c @@ -23,8 +23,10 @@ * \ingroup draw_engine */ +#include "DNA_mesh_types.h" #include "DNA_view3d_types.h" +#include "BKE_editmesh.h" #include "BKE_object.h" #include "GPU_shader.h" @@ -40,9 +42,7 @@ typedef struct OVERLAY_StorageList { typedef struct OVERLAY_PassList { struct DRWPass *face_orientation_pass; - struct DRWPass *flat_wireframe_pass; struct DRWPass *face_wireframe_pass; - struct DRWPass *face_wireframe_full_pass; } OVERLAY_PassList; typedef struct OVERLAY_Data { @@ -55,7 +55,8 @@ typedef struct OVERLAY_Data { typedef struct OVERLAY_PrivateData { DRWShadingGroup *face_orientation_shgrp; - DRWShadingGroup *sculpt_wires_full; + DRWShadingGroup *face_wires; + DRWShadingGroup *flat_wires; DRWShadingGroup *sculpt_wires; View3DOverlay overlay; float wire_step_param[2]; @@ -70,9 +71,7 @@ static struct { /* Wireframe shader */ struct GPUShader *select_wireframe_sh; struct GPUShader *face_wireframe_sh; - struct GPUShader *face_wireframe_pretty_sh; struct GPUShader *face_wireframe_sculpt_sh; - struct GPUShader *face_wireframe_sculpt_pretty_sh; } e_data = {NULL}; /* Shaders */ @@ -82,6 +81,7 @@ extern char datatoc_overlay_face_orientation_vert_glsl[]; extern char datatoc_overlay_face_wireframe_vert_glsl[]; extern char datatoc_overlay_face_wireframe_geom_glsl[]; extern char datatoc_overlay_face_wireframe_frag_glsl[]; +extern char datatoc_gpu_shader_depth_only_frag_glsl[]; extern struct GlobalsUboStorage ts; /* draw_common.c */ @@ -105,45 +105,23 @@ static void overlay_engine_init(void *vedata) } if (!e_data.face_wireframe_sh) { - bool use_geom = GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY); - e_data.select_wireframe_sh = DRW_shader_create( datatoc_overlay_face_wireframe_vert_glsl, datatoc_overlay_face_wireframe_geom_glsl, - datatoc_overlay_face_wireframe_frag_glsl, - "#define SELECT_EDGES\n" - "#define LIGHT_EDGES\n" - "#define USE_GEOM_SHADER\n"); + datatoc_gpu_shader_depth_only_frag_glsl, + "#define SELECT_EDGES\n"); e_data.face_wireframe_sh = DRW_shader_create( datatoc_overlay_face_wireframe_vert_glsl, - use_geom ? datatoc_overlay_face_wireframe_geom_glsl : NULL, - datatoc_overlay_face_wireframe_frag_glsl, - use_geom ? "#define USE_GEOM_SHADER\n" - : NULL); - - e_data.face_wireframe_pretty_sh = DRW_shader_create( - datatoc_overlay_face_wireframe_vert_glsl, - use_geom ? datatoc_overlay_face_wireframe_geom_glsl : NULL, + NULL, datatoc_overlay_face_wireframe_frag_glsl, - use_geom ? "#define USE_GEOM_SHADER\n" - "#define LIGHT_EDGES\n" - : "#define LIGHT_EDGES\n"); + NULL); e_data.face_wireframe_sculpt_sh = DRW_shader_create( datatoc_overlay_face_wireframe_vert_glsl, datatoc_overlay_face_wireframe_geom_glsl, datatoc_overlay_face_wireframe_frag_glsl, - "#define USE_SCULPT\n" - "#define USE_GEOM_SHADER\n"); - - e_data.face_wireframe_sculpt_pretty_sh = DRW_shader_create( - datatoc_overlay_face_wireframe_vert_glsl, - datatoc_overlay_face_wireframe_geom_glsl, - datatoc_overlay_face_wireframe_frag_glsl, - "#define USE_SCULPT\n" - "#define USE_GEOM_SHADER\n" - "#define LIGHT_EDGES\n"); + "#define USE_SCULPT\n"); } } @@ -152,73 +130,68 @@ static void overlay_cache_init(void *vedata) OVERLAY_Data *data = vedata; OVERLAY_PassList *psl = data->psl; OVERLAY_StorageList *stl = data->stl; + OVERLAY_PrivateData *g_data = stl->g_data; const DRWContextState *DCS = DRW_context_state_get(); View3D *v3d = DCS->v3d; if (v3d) { - stl->g_data->overlay = v3d->overlay; - stl->g_data->show_overlays = (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0; + g_data->overlay = v3d->overlay; + g_data->show_overlays = (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0; } else { - memset(&stl->g_data->overlay, 0, sizeof(stl->g_data->overlay)); - stl->g_data->show_overlays = false; + memset(&g_data->overlay, 0, sizeof(g_data->overlay)); + g_data->show_overlays = false; } - if (stl->g_data->show_overlays == false) { - stl->g_data->overlay.flag = 0; + if (g_data->show_overlays == false) { + g_data->overlay.flag = 0; } if (v3d->shading.type == OB_WIRE) { - stl->g_data->overlay.flag |= V3D_OVERLAY_WIREFRAMES; - stl->g_data->show_overlays = true; + g_data->overlay.flag |= V3D_OVERLAY_WIREFRAMES; + g_data->show_overlays = true; } { /* Face Orientation Pass */ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND; psl->face_orientation_pass = DRW_pass_create("Face Orientation", state); - stl->g_data->face_orientation_shgrp = DRW_shgroup_create( + g_data->face_orientation_shgrp = DRW_shgroup_create( e_data.face_orientation_sh, psl->face_orientation_pass); } { /* Wireframe */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND | DRW_STATE_FIRST_VERTEX_CONVENTION; float wire_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f; - psl->flat_wireframe_pass = DRW_pass_create("Flat Object Wires", state | DRW_STATE_WRITE_DEPTH); + const bool use_select = (DRW_state_is_select() || DRW_state_is_depth()); + GPUShader *sculpt_wire_sh = use_select ? e_data.select_wireframe_sh : e_data.face_wireframe_sculpt_sh; + GPUShader *face_wires_sh = use_select ? e_data.select_wireframe_sh : e_data.face_wireframe_sh; + GPUShader *flat_wires_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + + psl->face_wireframe_pass = DRW_pass_create("Face Wires", state); - psl->face_wireframe_full_pass = DRW_pass_create("All Face Wires", state); + g_data->flat_wires = DRW_shgroup_create(flat_wires_sh, psl->face_wireframe_pass); + DRW_shgroup_uniform_vec4(g_data->flat_wires, "color", ts.colorWire, 1); - stl->g_data->sculpt_wires_full = DRW_shgroup_create(e_data.face_wireframe_sculpt_sh, psl->face_wireframe_full_pass); - DRW_shgroup_uniform_float_copy(stl->g_data->sculpt_wires_full, "wireSize", wire_size); + g_data->sculpt_wires = DRW_shgroup_create(sculpt_wire_sh, psl->face_wireframe_pass); - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.face_wireframe_sh, psl->face_wireframe_full_pass); - DRW_shgroup_uniform_float_copy(shgrp, "wireSize", wire_size); + g_data->face_wires = DRW_shgroup_create(face_wires_sh, psl->face_wireframe_pass); + DRW_shgroup_uniform_vec2(g_data->face_wires, "wireStepParam", g_data->wire_step_param, 1); - psl->face_wireframe_pass = DRW_pass_create("Face Wires", state); + if (!use_select) { + DRW_shgroup_uniform_float_copy(g_data->sculpt_wires, "wireSize", wire_size); + DRW_shgroup_uniform_float_copy(g_data->face_wires, "wireSize", wire_size); + } - stl->g_data->sculpt_wires = DRW_shgroup_create(e_data.face_wireframe_sculpt_pretty_sh, psl->face_wireframe_pass); - DRW_shgroup_uniform_vec2(stl->g_data->sculpt_wires, "wireStepParam", stl->g_data->wire_step_param, 1); - DRW_shgroup_uniform_float_copy(stl->g_data->sculpt_wires, "wireSize", wire_size); - - shgrp = DRW_shgroup_create(e_data.face_wireframe_pretty_sh, psl->face_wireframe_pass); - DRW_shgroup_uniform_vec2(shgrp, "wireStepParam", stl->g_data->wire_step_param, 1); - DRW_shgroup_uniform_float_copy(shgrp, "wireSize", wire_size); - - /** - * The wireframe threshold ranges from 0.0 to 1.0 - * When 1.0 we show all the edges, when 0.5 we show as many as 2.7. - * - * If we wanted 0.0 to match 2.7, factor would need to be 0.003f. - * The range controls the falloff effect. If range was 0.0f we would get a hard cut (as in 2.7). - * That said we are using a different algorithm so the results will always differ. - */ - const float factor = 0.0045f; - const float range = 0.00125f; - stl->g_data->wire_step_param[1] = (1.0f - factor) + stl->g_data->overlay.wireframe_threshold * factor; - stl->g_data->wire_step_param[0] = stl->g_data->wire_step_param[1] + range; + /* Control aspect of the falloff. */ + const float sharpness = 4.0f; + /* Scale and bias: Adjust with wiredata encoding. (see mesh_batch_cache_create_edges_wireframe_data) */ + const float decompress = (0xFF / (float)(0xFF - 0x20)); + g_data->wire_step_param[0] = -sharpness * decompress; + g_data->wire_step_param[1] = decompress + sharpness * stl->g_data->overlay.wireframe_threshold; } } @@ -227,35 +200,47 @@ static void overlay_cache_populate(void *vedata, Object *ob) OVERLAY_Data *data = vedata; OVERLAY_StorageList *stl = data->stl; OVERLAY_PrivateData *pd = stl->g_data; - OVERLAY_PassList *psl = data->psl; const DRWContextState *draw_ctx = DRW_context_state_get(); RegionView3D *rv3d = draw_ctx->rv3d; View3D *v3d = draw_ctx->v3d; - if ((!stl->g_data->show_overlays) || + if ((!pd->show_overlays) || (ob->dt < OB_WIRE) || (!DRW_object_is_renderable(ob) && (ob->dt != OB_WIRE))) { return; } - if (DRW_object_is_renderable(ob) && stl->g_data->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION) { + if (DRW_object_is_renderable(ob) && pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION) { struct GPUBatch *geom = DRW_cache_object_surface_get(ob); if (geom) { DRW_shgroup_call_add(pd->face_orientation_shgrp, geom, ob->obmat); } } - if ((stl->g_data->overlay.flag & V3D_OVERLAY_WIREFRAMES) || + if ((pd->overlay.flag & V3D_OVERLAY_WIREFRAMES) || (v3d->shading.type == OB_WIRE) || (ob->dtx & OB_DRAWWIRE) || (ob->dt == OB_WIRE)) { - /* Don't do that in edit Mesh mode. */ - if (((ob != draw_ctx->object_edit) && !BKE_object_is_in_editmode(ob)) || ob->type != OB_MESH) { + const bool is_edit_mode = BKE_object_is_in_editmode(ob); + bool has_edit_mesh_cage = false; + if (ob->type == OB_MESH) { + /* TODO: Should be its own function. */ + Mesh *me = (Mesh *)ob->data; + BMEditMesh *embm = me->edit_btmesh; + if (embm) { + has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final); + } + } + + /* Don't do that in edit Mesh mode, unless there is a modifier preview. */ + if ((((ob != draw_ctx->object_edit) && !is_edit_mode) || has_edit_mesh_cage) || + ob->type != OB_MESH) + { const bool is_active = (ob == draw_ctx->obact); const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0; - const bool all_wires = (stl->g_data->overlay.wireframe_threshold == 1.0f) || + const bool all_wires = (pd->overlay.wireframe_threshold == 1.0f) || (ob->dtx & OB_DRAW_ALL_EDGES); const bool is_wire = (ob->dt < OB_SOLID); const int stencil_mask = (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF; @@ -267,62 +252,47 @@ static void overlay_cache_populate(void *vedata, Object *ob) DRW_object_is_flat(ob, &flat_axis) && DRW_object_axis_orthogonal_to_view(ob, flat_axis); - if (is_sculpt_mode) { - shgrp = (all_wires || DRW_object_is_flat_normal(ob)) - ? stl->g_data->sculpt_wires_full - : stl->g_data->sculpt_wires; - if (is_wire) { - shgrp = DRW_shgroup_create_sub(shgrp); - } - DRW_shgroup_call_sculpt_add(shgrp, ob, ob->obmat); - } - else if (is_flat_object_viewed_from_side) { + if (is_flat_object_viewed_from_side && !is_sculpt_mode) { /* Avoid losing flat objects when in ortho views (see T56549) */ struct GPUBatch *geom = DRW_cache_object_wire_outline_get(ob); if (geom) { - GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); - shgrp = DRW_shgroup_create(sh, psl->flat_wireframe_pass); + shgrp = pd->flat_wires; + shgrp = DRW_shgroup_create_sub(shgrp); DRW_shgroup_stencil_mask(shgrp, stencil_mask); - DRW_shgroup_uniform_vec4(shgrp, "color", ts.colorWire, 1); DRW_shgroup_call_object_add(shgrp, geom, ob); } } else { - int tri_count; - GPUTexture *verts = NULL, *faceids; - DRW_cache_object_face_wireframe_get(ob, &verts, &faceids, &tri_count); - if (verts) { + struct GPUBatch *geom = DRW_cache_object_face_wireframe_get(ob); + if (geom || is_sculpt_mode) { float *rim_col = ts.colorWire; - if ((ob->base_flag & BASE_SELECTED) != 0) { + if (!is_edit_mode && !is_sculpt_mode && !has_edit_mesh_cage && + ((ob->base_flag & BASE_SELECTED) != 0)) + { rim_col = (ob == draw_ctx->obact) ? ts.colorActive : ts.colorSelect; } - DRWPass *pass = (all_wires) ? psl->face_wireframe_full_pass : psl->face_wireframe_pass; - GPUShader *sh = (all_wires) ? e_data.face_wireframe_sh : e_data.face_wireframe_pretty_sh; - - if ((DRW_state_is_select() || DRW_state_is_depth())) { - static float params[2] = {1.2f, 1.0f}; /* Parameters for all wires */ - - sh = e_data.select_wireframe_sh; - shgrp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_vec2(shgrp, "wireStepParam", (all_wires) - ? params - : stl->g_data->wire_step_param, 1); - DRW_shgroup_uniform_texture(shgrp, "vertData", verts); - DRW_shgroup_uniform_texture(shgrp, "faceIds", faceids); - DRW_shgroup_call_object_procedural_triangles_culled_add(shgrp, tri_count, ob); - } - else { - shgrp = DRW_shgroup_create(sh, pass); + shgrp = (is_sculpt_mode) ? pd->sculpt_wires : pd->face_wires; + shgrp = DRW_shgroup_create_sub(shgrp); + + static float all_wires_params[2] = {0.0f, 10.0f}; /* Parameters for all wires */ + DRW_shgroup_uniform_vec2(shgrp, "wireStepParam", (all_wires) + ? all_wires_params + : pd->wire_step_param, 1); + + if (!(DRW_state_is_select() || DRW_state_is_depth())) { DRW_shgroup_stencil_mask(shgrp, stencil_mask); - DRW_shgroup_uniform_texture(shgrp, "vertData", verts); - DRW_shgroup_uniform_texture(shgrp, "faceIds", faceids); DRW_shgroup_uniform_vec3(shgrp, "wireColor", ts.colorWire, 1); DRW_shgroup_uniform_vec3(shgrp, "rimColor", rim_col, 1); - DRW_shgroup_call_object_procedural_triangles_culled_add(shgrp, tri_count, ob); + } + + if (is_sculpt_mode) { + DRW_shgroup_call_sculpt_add(shgrp, ob, ob->obmat); + } + else { + DRW_shgroup_call_add(shgrp, geom, ob->obmat); } } } - if (is_wire && shgrp != NULL) { /* If object is wireframe, don't try to use stencil test. */ DRW_shgroup_state_disable(shgrp, DRW_STATE_STENCIL_EQUAL); @@ -332,7 +302,7 @@ static void overlay_cache_populate(void *vedata, Object *ob) } } else if ((ob->dtx & OB_DRAWXRAY) && shgrp != NULL) { - stl->g_data->ghost_stencil_test = true; + pd->ghost_stencil_test = true; } } } @@ -351,7 +321,6 @@ static void overlay_cache_finish(void *vedata) if (v3d->shading.type == OB_SOLID && (v3d->shading.flag & XRAY_FLAG(v3d)) == 0) { if (stl->g_data->ghost_stencil_test) { DRW_pass_state_add(psl->face_wireframe_pass, DRW_STATE_STENCIL_EQUAL); - DRW_pass_state_add(psl->face_wireframe_full_pass, DRW_STATE_STENCIL_EQUAL); } } } @@ -366,9 +335,7 @@ static void overlay_draw_scene(void *vedata) GPU_framebuffer_bind(dfbl->default_fb); } DRW_draw_pass(psl->face_orientation_pass); - DRW_draw_pass(psl->flat_wireframe_pass); DRW_draw_pass(psl->face_wireframe_pass); - DRW_draw_pass(psl->face_wireframe_full_pass); } static void overlay_engine_free(void) @@ -376,9 +343,7 @@ static void overlay_engine_free(void) DRW_SHADER_FREE_SAFE(e_data.face_orientation_sh); DRW_SHADER_FREE_SAFE(e_data.select_wireframe_sh); DRW_SHADER_FREE_SAFE(e_data.face_wireframe_sh); - DRW_SHADER_FREE_SAFE(e_data.face_wireframe_pretty_sh); DRW_SHADER_FREE_SAFE(e_data.face_wireframe_sculpt_sh); - DRW_SHADER_FREE_SAFE(e_data.face_wireframe_sculpt_pretty_sh); } static const DrawEngineDataSize overlay_data_size = DRW_VIEWPORT_DATA_SIZE(OVERLAY_Data); diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c index 2792c59b805..3386c797765 100644 --- a/source/blender/draw/modes/paint_texture_mode.c +++ b/source/blender/draw/modes/paint_texture_mode.c @@ -38,11 +38,16 @@ #include "DNA_mesh_types.h" +#include "DEG_depsgraph_query.h" + extern char datatoc_common_globals_lib_glsl[]; extern char datatoc_paint_texture_vert_glsl[]; extern char datatoc_paint_texture_frag_glsl[]; extern char datatoc_paint_wire_vert_glsl[]; extern char datatoc_paint_wire_frag_glsl[]; +extern char datatoc_paint_face_vert_glsl[]; + +extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; /* If needed, contains all global/Theme colors * Add needed theme colors / values to DRW_globals_update() and update UBO @@ -128,35 +133,12 @@ typedef struct PAINT_TEXTURE_PrivateData { /* *********** FUNCTIONS *********** */ /* Init Textures, Framebuffers, Storage and Shaders. - * It is called for every frames. - * (Optional) */ -static void PAINT_TEXTURE_engine_init(void *vedata) + * It is called for every frames. */ +static void PAINT_TEXTURE_engine_init(void *UNUSED(vedata)) { - PAINT_TEXTURE_TextureList *txl = ((PAINT_TEXTURE_Data *)vedata)->txl; - PAINT_TEXTURE_FramebufferList *fbl = ((PAINT_TEXTURE_Data *)vedata)->fbl; - PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl; - - UNUSED_VARS(txl, fbl, stl); - - /* Init Framebuffers like this: order is attachment order (for color texs) */ - /* - * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0}, - * {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}}; - */ - - /* DRW_framebuffer_init takes care of checking if - * the framebuffer is valid and has the right size*/ - /* - * float *viewport_size = DRW_viewport_size_get(); - * DRW_framebuffer_init(&fbl->occlude_wire_fb, - * (int)viewport_size[0], (int)viewport_size[1], - * tex, 2); - */ - if (!e_data.fallback_sh) { e_data.fallback_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); - } - if (!e_data.image_sh) { + e_data.image_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); e_data.image_sh = DRW_shader_create_with_lib( @@ -164,18 +146,15 @@ static void PAINT_TEXTURE_engine_init(void *vedata) datatoc_paint_texture_frag_glsl, datatoc_common_globals_lib_glsl, NULL); - } - - if (!e_data.wire_overlay_shader) { e_data.wire_overlay_shader = DRW_shader_create_with_lib( datatoc_paint_wire_vert_glsl, NULL, datatoc_paint_wire_frag_glsl, datatoc_common_globals_lib_glsl, "#define VERTEX_MODE\n"); - } - if (!e_data.face_overlay_shader) { - e_data.face_overlay_shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + e_data.face_overlay_shader = DRW_shader_create( + datatoc_paint_face_vert_glsl, NULL, + datatoc_gpu_shader_uniform_color_frag_glsl, NULL); } } @@ -258,7 +237,7 @@ static void PAINT_TEXTURE_cache_init(void *vedata) { psl->wire_overlay = DRW_pass_create( "Wire Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL); + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_OFFSET_NEGATIVE); stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay); DRW_shgroup_uniform_block(stl->g_data->lwire_shgrp, "globalsBlock", globals_ubo); @@ -288,57 +267,48 @@ static void PAINT_TEXTURE_cache_populate(void *vedata, Object *ob) if ((ob->type == OB_MESH) && (draw_ctx->obact == ob)) { /* Get geometry cache */ const Mesh *me = ob->data; + const Mesh *me_orig = DEG_get_original_object(ob)->data; Scene *scene = draw_ctx->scene; const bool use_surface = draw_ctx->v3d->overlay.texture_paint_mode_opacity != 0.0; //DRW_object_is_mode_shade(ob) == true; const bool use_material_slots = (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_MATERIAL); - bool ok = false; + const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; if (use_surface) { if (me->mloopuv != NULL) { if (use_material_slots) { - struct GPUBatch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob) : NULL; - if ((me->totcol == 0) || (geom_array == NULL)) { - struct GPUBatch *geom = DRW_cache_mesh_surface_get(ob); - DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom, ob->obmat); - ok = true; - } - else { - for (int i = 0; i < me->totcol; i++) { - if (stl->g_data->shgroup_image_array[i]) { - DRW_shgroup_call_add(stl->g_data->shgroup_image_array[i], geom_array[i], ob->obmat); - } - else { - DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom_array[i], ob->obmat); - } - ok = true; + int mat_nr = max_ii(1, me->totcol); + struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); + + for (int i = 0; i < mat_nr; i++) { + const int index = use_material_slots ? i : 0; + if (stl->g_data->shgroup_image_array[index]) { + DRW_shgroup_call_add(stl->g_data->shgroup_image_array[index], geom_array[i], ob->obmat); + } + else { + DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom_array[i], ob->obmat); } } } else { - struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); - if (geom && stl->g_data->shgroup_image_array[0]) { + if (stl->g_data->shgroup_image_array[0]) { + struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); DRW_shgroup_call_add(stl->g_data->shgroup_image_array[0], geom, ob->obmat); - ok = true; } } } - - if (!ok) { + else { struct GPUBatch *geom = DRW_cache_mesh_surface_get(ob); DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom, ob->obmat); } } /* Face Mask */ - const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; if (use_face_sel) { struct GPUBatch *geom; - /* Note: ideally selected faces wouldn't show interior wire. */ - const bool use_wire = true; - geom = DRW_cache_mesh_edges_paint_overlay_get(ob, use_wire, use_face_sel); + geom = DRW_cache_mesh_wire_get(ob); DRW_shgroup_call_add(stl->g_data->lwire_shgrp, geom, ob->obmat); - geom = DRW_cache_mesh_faces_weight_overlay_get(ob); + geom = DRW_cache_mesh_surface_get(ob); DRW_shgroup_call_add(stl->g_data->face_shgrp, geom, ob->obmat); } } @@ -381,6 +351,7 @@ static void PAINT_TEXTURE_engine_free(void) { DRW_SHADER_FREE_SAFE(e_data.image_sh); DRW_SHADER_FREE_SAFE(e_data.wire_overlay_shader); + DRW_SHADER_FREE_SAFE(e_data.face_overlay_shader); } static const DrawEngineDataSize PAINT_TEXTURE_data_size = DRW_VIEWPORT_DATA_SIZE(PAINT_TEXTURE_Data); diff --git a/source/blender/draw/modes/paint_vertex_mode.c b/source/blender/draw/modes/paint_vertex_mode.c index d026e7a7924..7d3aa0f0b20 100644 --- a/source/blender/draw/modes/paint_vertex_mode.c +++ b/source/blender/draw/modes/paint_vertex_mode.c @@ -45,8 +45,11 @@ extern char datatoc_paint_vertex_vert_glsl[]; extern char datatoc_paint_vertex_frag_glsl[]; extern char datatoc_paint_wire_vert_glsl[]; extern char datatoc_paint_wire_frag_glsl[]; +extern char datatoc_paint_face_vert_glsl[]; extern char datatoc_common_globals_lib_glsl[]; +extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; + /* *********** LISTS *********** */ typedef struct PAINT_VERTEX_PassList { @@ -95,7 +98,9 @@ static void PAINT_VERTEX_engine_init(void *UNUSED(vedata)) datatoc_paint_wire_frag_glsl, datatoc_common_globals_lib_glsl, "#define VERTEX_MODE\n"); - e_data.face_overlay_shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + e_data.face_overlay_shader = DRW_shader_create( + datatoc_paint_face_vert_glsl, NULL, + datatoc_gpu_shader_uniform_color_frag_glsl, NULL); } } @@ -124,7 +129,7 @@ static void PAINT_VERTEX_cache_init(void *vedata) { psl->wire_overlay = DRW_pass_create( "Wire Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL); + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_OFFSET_NEGATIVE); stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay); DRW_shgroup_uniform_block(stl->g_data->lwire_shgrp, "globalsBlock", globals_ubo); @@ -149,26 +154,28 @@ static void PAINT_VERTEX_cache_populate(void *vedata, Object *ob) const View3D *v3d = draw_ctx->v3d; if ((ob->type == OB_MESH) && (ob == draw_ctx->obact)) { - /* We're always painting on original, display original data. */ - ob = DEG_get_original_object(ob); const Mesh *me = ob->data; const bool use_wire = (v3d->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE) != 0; const bool use_surface = v3d->overlay.vertex_paint_mode_opacity != 0.0f; const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; struct GPUBatch *geom; + if (me->mloopcol == NULL) { + return; + } + if (use_surface) { geom = DRW_cache_mesh_surface_vert_colors_get(ob); DRW_shgroup_call_add(stl->g_data->fvcolor_shgrp, geom, ob->obmat); } if (use_face_sel || use_wire) { - geom = DRW_cache_mesh_edges_paint_overlay_get(ob, use_wire, use_face_sel); + geom = DRW_cache_mesh_wire_get(ob); DRW_shgroup_call_add(stl->g_data->lwire_shgrp, geom, ob->obmat); } if (use_face_sel) { - geom = DRW_cache_mesh_faces_weight_overlay_get(ob); + geom = DRW_cache_mesh_surface_get(ob); DRW_shgroup_call_add(stl->g_data->face_shgrp, geom, ob->obmat); } } @@ -187,6 +194,7 @@ static void PAINT_VERTEX_engine_free(void) { DRW_SHADER_FREE_SAFE(e_data.vcolor_face_shader); DRW_SHADER_FREE_SAFE(e_data.wire_overlay_shader); + DRW_SHADER_FREE_SAFE(e_data.face_overlay_shader); } static const DrawEngineDataSize PAINT_VERTEX_data_size = DRW_VIEWPORT_DATA_SIZE(PAINT_VERTEX_Data); diff --git a/source/blender/draw/modes/paint_weight_mode.c b/source/blender/draw/modes/paint_weight_mode.c index 9060a97f412..e3993ee177a 100644 --- a/source/blender/draw/modes/paint_weight_mode.c +++ b/source/blender/draw/modes/paint_weight_mode.c @@ -45,6 +45,7 @@ extern struct GlobalsUboStorage ts; /* draw_common.c */ extern struct GPUTexture *globals_weight_ramp; /* draw_common.c */ +extern char datatoc_paint_face_vert_glsl[]; extern char datatoc_paint_weight_vert_glsl[]; extern char datatoc_paint_weight_frag_glsl[]; extern char datatoc_paint_wire_vert_glsl[]; @@ -52,6 +53,8 @@ extern char datatoc_paint_wire_frag_glsl[]; extern char datatoc_paint_vert_frag_glsl[]; extern char datatoc_common_globals_lib_glsl[]; +extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; + /* *********** LISTS *********** */ typedef struct PAINT_WEIGHT_PassList { @@ -99,20 +102,16 @@ static void PAINT_WEIGHT_engine_init(void *UNUSED(vedata)) datatoc_paint_weight_vert_glsl, NULL, datatoc_paint_weight_frag_glsl, datatoc_common_globals_lib_glsl, NULL); - } - if (!e_data.wire_overlay_shader) { e_data.wire_overlay_shader = DRW_shader_create_with_lib( datatoc_paint_wire_vert_glsl, NULL, datatoc_paint_wire_frag_glsl, datatoc_common_globals_lib_glsl, "#define WEIGHT_MODE\n"); - } - if (!e_data.face_overlay_shader) { - e_data.face_overlay_shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); - } + e_data.face_overlay_shader = DRW_shader_create( + datatoc_paint_face_vert_glsl, NULL, + datatoc_gpu_shader_uniform_color_frag_glsl, NULL); - if (!e_data.vert_overlay_shader) { e_data.vert_overlay_shader = DRW_shader_create_with_lib( datatoc_paint_wire_vert_glsl, NULL, datatoc_paint_vert_frag_glsl, @@ -150,7 +149,7 @@ static void PAINT_WEIGHT_cache_init(void *vedata) { psl->wire_overlay = DRW_pass_create( "Wire Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL); + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_OFFSET_NEGATIVE); stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay); DRW_shgroup_uniform_block(stl->g_data->lwire_shgrp, "globalsBlock", globals_ubo); @@ -170,7 +169,7 @@ static void PAINT_WEIGHT_cache_init(void *vedata) { psl->vert_overlay = DRW_pass_create( "Vert Mask Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL); + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_OFFSET_NEGATIVE); stl->g_data->vert_shgrp = DRW_shgroup_create(e_data.vert_overlay_shader, psl->vert_overlay); DRW_shgroup_uniform_block(stl->g_data->vert_shgrp, "globalsBlock", globals_ubo); @@ -184,30 +183,30 @@ static void PAINT_WEIGHT_cache_populate(void *vedata, Object *ob) const View3D *v3d = draw_ctx->v3d; if ((ob->type == OB_MESH) && (ob == draw_ctx->obact)) { - const Mesh *me = ob->data; + const Mesh *me_orig = DEG_get_original_object(ob)->data; const bool use_wire = (v3d->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE) != 0; const bool use_surface = v3d->overlay.weight_paint_mode_opacity != 0.0f; - const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool use_vert_sel = (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; struct GPUBatch *geom; if (use_surface) { - geom = DRW_cache_mesh_surface_weights_get(ob, draw_ctx->scene->toolsettings, true); + geom = DRW_cache_mesh_surface_weights_get(ob); DRW_shgroup_call_add(stl->g_data->fweights_shgrp, geom, ob->obmat); } if (use_face_sel || use_wire) { - geom = DRW_cache_mesh_edges_paint_overlay_get(ob, use_wire, use_face_sel); + geom = DRW_cache_mesh_wire_get(ob); DRW_shgroup_call_add(stl->g_data->lwire_shgrp, geom, ob->obmat); } if (use_face_sel) { - geom = DRW_cache_mesh_faces_weight_overlay_get(ob); + geom = DRW_cache_mesh_surface_get(ob); DRW_shgroup_call_add(stl->g_data->face_shgrp, geom, ob->obmat); } if (use_vert_sel) { - geom = DRW_cache_mesh_verts_weight_overlay_get(ob); + geom = DRW_cache_mesh_verts_get(ob); DRW_shgroup_call_add(stl->g_data->vert_shgrp, geom, ob->obmat); } } @@ -228,6 +227,7 @@ static void PAINT_WEIGHT_engine_free(void) DRW_SHADER_FREE_SAFE(e_data.weight_face_shader); DRW_SHADER_FREE_SAFE(e_data.wire_overlay_shader); DRW_SHADER_FREE_SAFE(e_data.vert_overlay_shader); + DRW_SHADER_FREE_SAFE(e_data.face_overlay_shader); } static const DrawEngineDataSize PAINT_WEIGHT_data_size = DRW_VIEWPORT_DATA_SIZE(PAINT_WEIGHT_Data); diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c index f4879483540..758218fe329 100644 --- a/source/blender/draw/modes/particle_mode.c +++ b/source/blender/draw/modes/particle_mode.c @@ -48,6 +48,9 @@ extern char datatoc_particle_strand_vert_glsl[]; extern char datatoc_particle_strand_frag_glsl[]; +extern char datatoc_common_globals_lib_glsl[]; + +extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */ /* *********** LISTS *********** */ @@ -80,6 +83,7 @@ typedef struct PARTICLE_Data { static struct { struct GPUShader *strands_shader; + struct GPUShader *strands_weight_shader; struct GPUShader *points_shader; } e_data = {NULL}; /* Engine data */ @@ -94,15 +98,26 @@ typedef struct PARTICLE_PrivateData { static void particle_engine_init(void *UNUSED(vedata)) { if (!e_data.strands_shader) { - e_data.strands_shader = DRW_shader_create( + e_data.strands_shader = DRW_shader_create_with_lib( datatoc_particle_strand_vert_glsl, NULL, datatoc_particle_strand_frag_glsl, + datatoc_common_globals_lib_glsl, ""); - } - if (!e_data.points_shader) { - e_data.points_shader = GPU_shader_get_builtin_shader( - GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR); + + e_data.strands_weight_shader = DRW_shader_create_with_lib( + datatoc_particle_strand_vert_glsl, + NULL, + datatoc_particle_strand_frag_glsl, + datatoc_common_globals_lib_glsl, + "#define USE_WEIGHT"); + + e_data.points_shader = DRW_shader_create_with_lib( + datatoc_particle_strand_vert_glsl, + NULL, + datatoc_particle_strand_frag_glsl, + datatoc_common_globals_lib_glsl, + "#define USE_POINTS"); } } @@ -110,6 +125,9 @@ static void particle_cache_init(void *vedata) { PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl; PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + ParticleEditSettings *pset = PE_settings(draw_ctx->scene); + const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT); if (!stl->g_data) { /* Alloc transient pointers */ @@ -124,19 +142,14 @@ static void particle_cache_init(void *vedata) DRW_STATE_WIRE | DRW_STATE_POINT)); - stl->g_data->strands_group = DRW_shgroup_create( - e_data.strands_shader, psl->psys_edit_pass); - stl->g_data->inner_points_group = DRW_shgroup_create( - e_data.points_shader, psl->psys_edit_pass); - stl->g_data->tip_points_group = DRW_shgroup_create( - e_data.points_shader, psl->psys_edit_pass); - - static float size = 5.0f; - static float outline_width = 1.0f; - DRW_shgroup_uniform_float(stl->g_data->inner_points_group, "size", &size, 1); - DRW_shgroup_uniform_float(stl->g_data->inner_points_group, "outlineWidth", &outline_width, 1); - DRW_shgroup_uniform_float(stl->g_data->tip_points_group, "size", &size, 1); - DRW_shgroup_uniform_float(stl->g_data->tip_points_group, "outlineWidth", &outline_width, 1); + GPUShader *strand_shader = (use_weight) ? e_data.strands_weight_shader : e_data.strands_shader; + stl->g_data->strands_group = DRW_shgroup_create(strand_shader, psl->psys_edit_pass); + stl->g_data->inner_points_group = DRW_shgroup_create(e_data.points_shader, psl->psys_edit_pass); + stl->g_data->tip_points_group = DRW_shgroup_create(e_data.points_shader, psl->psys_edit_pass); + + DRW_shgroup_uniform_block(stl->g_data->strands_group, "globalsBlock", globals_ubo); + DRW_shgroup_uniform_block(stl->g_data->inner_points_group, "globalsBlock", globals_ubo); + DRW_shgroup_uniform_block(stl->g_data->tip_points_group, "globalsBlock", globals_ubo); } static void particle_edit_cache_populate(void *vedata, @@ -147,9 +160,10 @@ static void particle_edit_cache_populate(void *vedata, PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); ParticleEditSettings *pset = PE_settings(draw_ctx->scene); + const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT); { struct GPUBatch *strands = - DRW_cache_particles_get_edit_strands(object, psys, edit); + DRW_cache_particles_get_edit_strands(object, psys, edit, use_weight); DRW_shgroup_call_add(stl->g_data->strands_group, strands, NULL); } if (pset->selectmode == SCE_SELECT_POINT) { @@ -225,6 +239,8 @@ static void particle_draw_scene(void *vedata) static void particle_engine_free(void) { DRW_SHADER_FREE_SAFE(e_data.strands_shader); + DRW_SHADER_FREE_SAFE(e_data.strands_weight_shader); + DRW_SHADER_FREE_SAFE(e_data.points_shader); } static const DrawEngineDataSize particle_data_size = diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c index 3c0a8048c9e..6ee6f59e5fa 100644 --- a/source/blender/draw/modes/pose_mode.c +++ b/source/blender/draw/modes/pose_mode.c @@ -195,7 +195,9 @@ static void POSE_cache_populate(void *vedata, Object *ob) * and similar functionalities. For now we handle only pose bones. */ if (ob->type == OB_ARMATURE) { - if (draw_ctx->v3d->overlay.flag & V3D_OVERLAY_HIDE_BONES) { + if ((draw_ctx->v3d->flag2 & V3D_RENDER_OVERRIDE) || + (draw_ctx->v3d->overlay.flag & V3D_OVERLAY_HIDE_BONES)) + { return; } if (DRW_pose_mode_armature(ob, draw_ctx->obact)) { diff --git a/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl b/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl index fc5cc1cdcc3..e5c5ccc97bf 100644 --- a/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl +++ b/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl @@ -6,5 +6,5 @@ out vec4 uvcoordsvar; void main() { uvcoordsvar = vec4(uvs, 0.0, 0.0); - gl_Position = vec4(pos, 0.0, 1.0); + gl_Position = vec4(pos, 1.0, 1.0); } diff --git a/source/blender/draw/modes/shaders/common_globals_lib.glsl b/source/blender/draw/modes/shaders/common_globals_lib.glsl index 69ba304ca24..520b368bbc2 100644 --- a/source/blender/draw/modes/shaders/common_globals_lib.glsl +++ b/source/blender/draw/modes/shaders/common_globals_lib.glsl @@ -36,6 +36,7 @@ layout(std140) uniform globalsBlock { vec4 colorLampNoAlpha; vec4 colorBackground; + vec4 colorEditMeshMiddle; vec4 colorHandleFree; vec4 colorHandleAuto; diff --git a/source/blender/draw/modes/shaders/common_hair_lib.glsl b/source/blender/draw/modes/shaders/common_hair_lib.glsl index ab4ccad9342..a7fe2a23ed0 100644 --- a/source/blender/draw/modes/shaders/common_hair_lib.glsl +++ b/source/blender/draw/modes/shaders/common_hair_lib.glsl @@ -19,6 +19,8 @@ uniform float hairRadTip = 0.0; uniform float hairRadShape = 0.5; uniform bool hairCloseTip = true; +uniform mat4 hairDupliMatrix; + /* -- Per control points -- */ uniform samplerBuffer hairPointBuffer; /* RGBA32F */ #define point_position xyz @@ -146,6 +148,9 @@ void hair_get_pos_tan_binor_time( wtan = wpos - texelFetch(hairPointBuffer, id - 1).point_position; } + wpos = (hairDupliMatrix * vec4(wpos, 1.0)).xyz; + wtan = mat3(hairDupliMatrix) * wtan; + vec3 camera_vec = (is_persp) ? wpos - camera_pos : -camera_z; wbinor = normalize(cross(camera_vec, wtan)); diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_normals_vert.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_normals_vert.glsl new file mode 100644 index 00000000000..06be402d737 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_curve_overlay_normals_vert.glsl @@ -0,0 +1,23 @@ + +/* Draw Curve Normals */ + +uniform mat4 ModelViewProjectionMatrix; +uniform float normalSize; + +in vec3 pos; +in vec3 nor; +in vec3 tan; +in float rad; + +void main() +{ + vec3 final_pos = pos; + + float flip = (gl_InstanceID != 0) ? -1.0 : 1.0; + + if (gl_VertexID % 2 == 0) { + final_pos += normalSize * rad * (flip * nor - tan); + } + + gl_Position = ModelViewProjectionMatrix * vec4(final_pos, 1.0); +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl index 8d7a653c2fe..0d5c76ad790 100644 --- a/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl @@ -144,7 +144,7 @@ void main() #endif #ifdef VERTEX_FACING - FragColor.a *= 1.0 - abs(facing) * 0.4; + FragColor.rgb = mix(colorEditMeshMiddle.rgb, FragColor.rgb, 1.0 - abs(facing) * 0.4); #endif /* don't write depth if not opaque */ diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl index a04494d2ec4..fa2063a40a6 100644 --- a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl @@ -9,7 +9,7 @@ layout(triangles) in; * triangle. Order is important. * TODO diagram */ -layout(triangle_strip, max_vertices=12) out; +layout(triangle_strip, max_vertices=11) out; uniform mat4 ProjectionMatrix; uniform vec2 viewportSize; @@ -92,7 +92,7 @@ void mask_edge_flag(int v, ivec3 eflag) /* Only shade the edge that we are currently drawing. * (fix corner bleeding) */ - flag = eflag & ~EDGE_VERTEX_EXISTS; + flag = eflag; flag[vaf] &= ~EDGE_EXISTS; flag[v] &= ~EDGE_EXISTS; } diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_points_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_points_vert.glsl index 3886213ce49..245cbab92d5 100644 --- a/source/blender/draw/modes/shaders/edit_mesh_overlay_points_vert.glsl +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_points_vert.glsl @@ -38,8 +38,10 @@ void main() ? normalize(vPos.xyz) : vec3(0.0, 0.0, 1.0); float facing = dot(view_vec, view_normal); + facing = 1.0 - abs(facing) * 0.4; - finalColor.a *= 1.0 - abs(facing) * 0.4; + finalColor = mix(colorEditMeshMiddle, finalColor, facing); + finalColor.a = 1.0; #endif if ((data.x & VERTEX_EXISTS) == 0) { diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl index e4268188e09..b78c7a7a476 100644 --- a/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl @@ -8,10 +8,6 @@ uniform mat4 ModelViewMatrix; uniform mat4 ModelViewProjectionMatrix; uniform ivec4 dataMask = ivec4(0xFF); -uniform float ofs = 1e-5; - -uniform isamplerBuffer dataBuffer; - in vec3 pos; #ifdef VERTEX_FACING in vec3 vnor; @@ -29,7 +25,6 @@ out float vFacing; void main() { pPos = ModelViewProjectionMatrix * vec4(pos, 1.0); - pPos.z -= ofs * ((ProjectionMatrix[3][3] == 0.0) ? 1.0 : 0.0); vData = data & dataMask; # ifdef VERTEX_FACING vec4 vpos = ModelViewMatrix * vec4(pos, 1.0); @@ -43,6 +38,13 @@ void main() #else /* EDGE_FIX */ +/* Consecutive data of the nth vertex. + * Only valid for first vertex in the triangle. + * Assuming GL_FRIST_VERTEX_CONVENTION. */ +in ivec4 data0; +in ivec4 data1; +in ivec4 data2; + flat out vec3 edgesCrease; flat out vec3 edgesBweight; flat out vec4 faceColor; @@ -59,18 +61,16 @@ out vec3 barycentric; void main() { gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - gl_Position.z -= ofs * ((ProjectionMatrix[3][3] == 0.0) ? 1.0 : 0.0); int v_0 = (gl_VertexID / 3) * 3; int vidx = gl_VertexID % 3; barycentric = vec3(equal(ivec3(0, 1, 2), ivec3(vidx))); /* Edge */ - ivec4 vData[3], data = ivec4(0); + ivec4 vData[3] = ivec4[3](data0, data1, data2); ivec3 eflag; for (int v = 0; v < 3; ++v) { - data = texelFetch(dataBuffer, v_0 + v); - vData[v] = data & dataMask; + vData[v] = vData[v] & dataMask; flag[v] = eflag[v] = vData[v].y | (vData[v].x << 8); edgesCrease[v] = vData[v].z / 255.0; edgesBweight[v] = vData[v].w / 255.0; @@ -87,7 +87,7 @@ void main() faceColor = colorFace; # ifdef VERTEX_SELECTION - vertexColor = EDIT_MESH_vertex_color(vData[vidx].x).rgb; + vertexColor = EDIT_MESH_vertex_color(data0.x).rgb; # endif # ifdef VERTEX_FACING vec4 vPos = ModelViewMatrix * vec4(pos, 1.0); diff --git a/source/blender/draw/modes/shaders/object_empty_image_vert.glsl b/source/blender/draw/modes/shaders/object_empty_image_vert.glsl index 3469e37358e..1c1525696fb 100644 --- a/source/blender/draw/modes/shaders/object_empty_image_vert.glsl +++ b/source/blender/draw/modes/shaders/object_empty_image_vert.glsl @@ -24,6 +24,7 @@ void main() (pos + offset) * (size * vec2(aspectX, aspectY)), 0.0, 1.0); #ifdef USE_WIRE + gl_Position.z -= 1e-5; finalColor = vec4(color, 1.0); #else texCoord_interp = texCoord; diff --git a/source/blender/draw/modes/shaders/object_grid_vert.glsl b/source/blender/draw/modes/shaders/object_grid_vert.glsl index a346973a597..15b37bb289d 100644 --- a/source/blender/draw/modes/shaders/object_grid_vert.glsl +++ b/source/blender/draw/modes/shaders/object_grid_vert.glsl @@ -53,10 +53,10 @@ void main() /* Used for additional Z axis */ if ((gridFlag & CLIP_Z_POS) != 0) { - realPos.z = max(realPos.z, 0.0); + realPos.z = clamp(realPos.z, 0.0, 1e30); } if ((gridFlag & CLIP_Z_NEG) != 0) { - realPos.z = min(-realPos.z, 0.0); + realPos.z = clamp(realPos.z, -1e30, 0.0); } gl_Position = ViewProjectionMatrix * vec4(realPos, 1.0); diff --git a/source/blender/draw/modes/shaders/object_loose_points_frag.glsl b/source/blender/draw/modes/shaders/object_loose_points_frag.glsl new file mode 100644 index 00000000000..66b3091a41c --- /dev/null +++ b/source/blender/draw/modes/shaders/object_loose_points_frag.glsl @@ -0,0 +1,19 @@ + +uniform vec4 color; +uniform vec4 innerColor; + +out vec4 fragColor; + +void main() +{ + vec2 centered = abs(gl_PointCoord - vec2(0.5)); + float dist = max(centered.x, centered.y); + + float fac = dist * dist * 4.0; + fragColor = mix(innerColor, color, 0.45 + fac * 0.65); + + /* Make the effect more like a fresnel by offsetting + * the depth and creating mini-spheres. + * Disabled as it has performance impact. */ + // gl_FragDepth = gl_FragCoord.z + 1e-6 * fac; +} diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl index 69af4858a48..cefd4eab2e3 100644 --- a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl @@ -1,18 +1,12 @@ -#ifndef SELECT_EDGES uniform vec3 wireColor; uniform vec3 rimColor; in float facing; in vec3 barycentric; - -# ifdef LIGHT_EDGES flat in vec3 edgeSharpness; -# endif out vec4 fragColor; -#endif -float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); } float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); } /* In pixels */ @@ -25,7 +19,6 @@ const float rim_alpha = 0.75; void main() { -#ifndef SELECT_EDGES vec3 dx = dFdx(barycentric); vec3 dy = dFdy(barycentric); vec3 d = vec3( @@ -35,11 +28,7 @@ void main() ); vec3 dist_to_edge = barycentric / d; -# ifdef LIGHT_EDGES vec3 fac = abs(dist_to_edge); -# else - float fac = min_v3(abs(dist_to_edge)); -# endif fac = smoothstep(wireSize + wire_smooth, wireSize, fac); @@ -48,10 +37,5 @@ void main() vec3 final_front_col = mix(rimColor, wireColor, 0.05); fragColor = mix(vec4(rimColor, rim_alpha), vec4(final_front_col, front_alpha), facing_clamped); -# ifdef LIGHT_EDGES fragColor.a *= max_v3(fac * edgeSharpness); -# else - fragColor.a *= fac; -# endif -#endif } diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl index 8abb6ecc737..7a40dd59571 100644 --- a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl @@ -1,6 +1,5 @@ -/* This shader is only used for intel GPU where the Geom shader is faster - * than doing everything thrice in the vertex shader. */ +/* This shader is only used for edge selection & sculpt mode wires (because of indexed drawing). */ layout(triangles) in; #ifdef SELECT_EDGES @@ -9,119 +8,53 @@ layout(line_strip, max_vertices = 6) out; layout(triangle_strip, max_vertices = 3) out; #endif -uniform vec2 wireStepParam; - -in vec2 ssPos[]; -in float facingOut[]; +in float facing_g[]; +in float edgeSharpness_g[]; #ifndef SELECT_EDGES -out vec3 barycentric; out float facing; -#endif - -#ifdef LIGHT_EDGES -in vec3 obPos[]; -in vec3 vNor[]; -in float forceEdge[]; - -# ifndef SELECT_EDGES +out vec3 barycentric; flat out vec3 edgeSharpness; -# endif #endif -#define NO_EDGE vec3(10000.0); - -vec3 get_edge_normal(vec3 n1, vec3 n2, vec3 edge) -{ - edge = normalize(edge); - vec3 n = n1 + n2; - float p = dot(edge, n); - return normalize(n - p * edge); -} - -float get_edge_sharpness(vec3 fnor, vec3 vnor) -{ - float sharpness = abs(dot(fnor, vnor)); - return smoothstep(wireStepParam.x, wireStepParam.y, sharpness); -} - -vec3 get_barycentric(bvec3 do_edge, const int v) -{ - int v_n = v; - int v_n1 = (v + 1) % 3; - int v_n2 = (v + 2) % 3; - vec3 bary; - bary[v_n] = do_edge[v_n] ? 0.0 : 1.0; - bary[v_n1] = 1.0; - bary[v_n2] = do_edge[v_n2] ? 0.0 : 1.0; - return bary; -} - void main(void) { - vec3 facings = vec3(facingOut[0], facingOut[1], facingOut[2]); - bvec3 do_edge = greaterThan(abs(facings), vec3(1.0)); - facings = fract(facings) - clamp(-sign(facings), 0.0, 1.0); - -#ifdef SELECT_EDGES - vec3 edgeSharpness; -#endif - -#ifdef LIGHT_EDGES - vec3 edges[3]; - edges[0] = obPos[1] - obPos[0]; - edges[1] = obPos[2] - obPos[1]; - edges[2] = obPos[0] - obPos[2]; - vec3 fnor = normalize(cross(edges[0], -edges[2])); - - edgeSharpness.x = get_edge_sharpness(fnor, get_edge_normal(vNor[0], vNor[1], edges[0])); - edgeSharpness.y = get_edge_sharpness(fnor, get_edge_normal(vNor[1], vNor[2], edges[1])); - edgeSharpness.z = get_edge_sharpness(fnor, get_edge_normal(vNor[2], vNor[0], edges[2])); - edgeSharpness.x = (forceEdge[0] == 1.0) ? 1.0 : edgeSharpness.x; - edgeSharpness.y = (forceEdge[1] == 1.0) ? 1.0 : edgeSharpness.y; - edgeSharpness.z = (forceEdge[2] == 1.0) ? 1.0 : edgeSharpness.z; -#endif - #ifdef SELECT_EDGES const float edge_select_threshold = 0.3; - if (edgeSharpness.x > edge_select_threshold) { - gl_Position = gl_in[0].gl_Position; - EmitVertex(); - gl_Position = gl_in[1].gl_Position; - EmitVertex(); + if (edgeSharpness_g[0] > edge_select_threshold) { + gl_Position = gl_in[0].gl_Position; EmitVertex(); + gl_Position = gl_in[1].gl_Position; EmitVertex(); EndPrimitive(); } - if (edgeSharpness.y > edge_select_threshold) { - gl_Position = gl_in[1].gl_Position; - EmitVertex(); - gl_Position = gl_in[2].gl_Position; - EmitVertex(); + if (edgeSharpness_g[1] > edge_select_threshold) { + gl_Position = gl_in[1].gl_Position; EmitVertex(); + gl_Position = gl_in[2].gl_Position; EmitVertex(); EndPrimitive(); } - if (edgeSharpness.z > edge_select_threshold) { - gl_Position = gl_in[2].gl_Position; - EmitVertex(); - gl_Position = gl_in[0].gl_Position; - EmitVertex(); + if (edgeSharpness_g[2] > edge_select_threshold) { + gl_Position = gl_in[2].gl_Position; EmitVertex(); + gl_Position = gl_in[0].gl_Position; EmitVertex(); EndPrimitive(); } #else - barycentric = get_barycentric(do_edge, 0); + edgeSharpness = vec3(edgeSharpness_g[0], edgeSharpness_g[1], edgeSharpness_g[2]); + + barycentric = vec3(1.0, 0.0, 0.0); gl_Position = gl_in[0].gl_Position; - facing = facings.x; + facing = facing_g[0]; EmitVertex(); - barycentric = get_barycentric(do_edge, 1); + barycentric = vec3(0.0, 1.0, 0.0); gl_Position = gl_in[1].gl_Position; - facing = facings.y; + facing = facing_g[1]; EmitVertex(); - barycentric = get_barycentric(do_edge, 2); + barycentric = vec3(0.0, 0.0, 1.0); gl_Position = gl_in[2].gl_Position; - facing = facings.z; + facing = facing_g[2]; EmitVertex(); EndPrimitive(); -#endif +#endif /* SELECT_EDGES */ } diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl index 828bc551cad..d5c2bdeefea 100644 --- a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl @@ -1,177 +1,81 @@ uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelViewMatrix; -uniform mat4 ProjectionMatrix; uniform mat3 NormalMatrix; uniform vec2 wireStepParam; -uniform float nearDist; -uniform samplerBuffer vertData; -uniform usamplerBuffer faceIds; - -#ifdef USE_SCULPT -in vec3 pos; -in vec3 nor; -#endif - -float short_to_unit_float(uint s) +vec3 get_edge_sharpness(vec3 wd) { - int value = int(s) & 0x7FFF; - if ((s & 0x8000u) != 0u) { - value |= ~0x7FFF; - } - return float(value) / float(0x7FFF); + bvec3 do_edge = greaterThan(wd, vec3(0.0)); + bvec3 force_edge = equal(wd, vec3(1.0)); + wd = clamp(wireStepParam.x * wd + wireStepParam.y, 0.0, 1.0); + return clamp(wd * vec3(do_edge) + vec3(force_edge), 0.0, 1.0); } -vec3 get_vertex_nor(uint id) +float get_edge_sharpness(float wd) { - int v_id = int(id) * 5; /* See vertex format for explanation. */ - /* Fetch compressed normal as float and unpack them. */ - vec2 data; - data.x = texelFetch(vertData, v_id + 3).r; - data.y = texelFetch(vertData, v_id + 4).r; - - uvec2 udata = floatBitsToUint(data); - - vec3 nor; - nor.x = short_to_unit_float(udata.x & 0xFFFFu); - nor.y = short_to_unit_float(udata.x >> 16u); - nor.z = short_to_unit_float(udata.y & 0xFFFFu); - return nor; + bool do_edge = (wd > 0.0); + bool force_edge = (wd == 1.0); + wd = (wireStepParam.x * wd + wireStepParam.y); + return clamp(wd * float(do_edge) + float(force_edge), 0.0, 1.0); } -vec3 get_vertex_pos(uint id) -{ - int v_id = int(id) * 5; /* See vertex format for explanation. */ - vec3 pos; - pos.x = texelFetch(vertData, v_id).r; - pos.y = texelFetch(vertData, v_id + 1).r; - pos.z = texelFetch(vertData, v_id + 2).r; - return pos; -} +/* Geometry shader version */ +#if defined(SELECT_EDGES) || defined(USE_SCULPT) -vec3 get_edge_normal(vec3 n1, vec3 n2, vec3 edge) -{ - edge = normalize(edge); - vec3 n = n1 + n2; - float p = dot(edge, n); - return normalize(n - p * edge); -} - -float get_edge_sharpness(vec3 fnor, vec3 vnor) -{ - float sharpness = abs(dot(fnor, vnor)); - return smoothstep(wireStepParam.x, wireStepParam.y, sharpness); -} - -#ifdef USE_GEOM_SHADER +in vec3 pos; +in vec3 nor; +in float wd; /* wiredata */ -# ifdef LIGHT_EDGES -out vec3 obPos; -out vec3 vNor; -out float forceEdge; -# endif -out float facingOut; /* abs(facing) > 1.0 if we do edge */ +out float facing_g; +out float edgeSharpness_g; void main() { # ifndef USE_SCULPT - uint v_id = texelFetch(faceIds, gl_VertexID).r; - - bool do_edge = (v_id & (1u << 30u)) != 0u; - bool force_edge = (v_id & (1u << 31u)) != 0u; - v_id = (v_id << 2u) >> 2u; - - vec3 pos = get_vertex_pos(v_id); - vec3 nor = get_vertex_nor(v_id); + edgeSharpness_g = get_edge_sharpness(wd); # else - const bool do_edge = true; - const bool force_edge = false; + /* TODO approximation using normals. */ + edgeSharpness_g = 1.0; # endif - facingOut = normalize(NormalMatrix * nor).z; - facingOut += (do_edge) ? ((facingOut > 0.0) ? 2.0 : -2.0) : 0.0; - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); -# ifdef LIGHT_EDGES - obPos = pos; - vNor = nor; - forceEdge = float(force_edge); /* meh, could try to also encode it in facingOut */ -# endif + facing_g = normalize(NormalMatrix * nor).z; } -#else /* USE_GEOM_SHADER */ +#else /* SELECT_EDGES */ + +/* Consecutive pos of the nth vertex + * Only valid for first vertex in the triangle. + * Assuming GL_FRIST_VERTEX_CONVENTION. */ +in vec3 pos0; +in vec3 pos1; +in vec3 pos2; +in float wd0; /* wiredata */ +in float wd1; +in float wd2; +in vec3 nor; -# ifdef LIGHT_EDGES -flat out vec3 edgeSharpness; -# endif out float facing; out vec3 barycentric; +flat out vec3 edgeSharpness; void main() { - int v_0 = (gl_VertexID / 3) * 3; int v_n = gl_VertexID % 3; - int v_n1 = (gl_VertexID + 1) % 3; - int v_n2 = (gl_VertexID + 2) % 3; - - /* Getting the same positions for each of the 3 verts. */ - uvec3 v_id; - v_id.x = texelFetch(faceIds, v_0).r; - v_id.y = texelFetch(faceIds, v_0 + 1).r; - v_id.z = texelFetch(faceIds, v_0 + 2).r; - - bvec3 do_edge, force_edge; - do_edge.x = (v_id.x & (1u << 30u)) != 0u; - do_edge.y = (v_id.y & (1u << 30u)) != 0u; - do_edge.z = (v_id.z & (1u << 30u)) != 0u; - force_edge.x = (v_id.x & (1u << 31u)) != 0u; - force_edge.y = (v_id.y & (1u << 31u)) != 0u; - force_edge.z = (v_id.z & (1u << 31u)) != 0u; - v_id = (v_id << 2u) >> 2u; - - vec3 pos[3]; - vec4 p_pos[3]; - - pos[v_n] = get_vertex_pos(v_id[v_n]); - gl_Position = p_pos[v_n] = ModelViewProjectionMatrix * vec4(pos[v_n], 1.0); - - bvec3 bary = equal(ivec3(0, 1, 2), ivec3(v_n1)); - /* This is equivalent to component wise : (do_edge ? bary : 1.0) */ - barycentric = vec3(lessThanEqual(ivec3(do_edge), ivec3(bary))); - -# ifndef LIGHT_EDGES - vec3 nor = get_vertex_nor(v_id[v_n]); -# else - p_pos[v_n1] = ModelViewProjectionMatrix * vec4(pos[v_n1], 1.0); - p_pos[v_n2] = ModelViewProjectionMatrix * vec4(pos[v_n2], 1.0); - - pos[v_n1] = get_vertex_pos(v_id[v_n1]); - pos[v_n2] = get_vertex_pos(v_id[v_n2]); - - vec3 edges[3]; - edges[0] = pos[1] - pos[0]; - edges[1] = pos[2] - pos[1]; - edges[2] = pos[0] - pos[2]; - vec3 fnor = normalize(cross(edges[0], -edges[2])); - - vec3 nors[3]; - nors[0] = get_vertex_nor(v_id.x); - nors[1] = get_vertex_nor(v_id.y); - nors[2] = get_vertex_nor(v_id.z); - edgeSharpness.x = get_edge_sharpness(fnor, get_edge_normal(nors[0], nors[1], edges[0])); - edgeSharpness.y = get_edge_sharpness(fnor, get_edge_normal(nors[1], nors[2], edges[1])); - edgeSharpness.z = get_edge_sharpness(fnor, get_edge_normal(nors[2], nors[0], edges[2])); - edgeSharpness.x = force_edge.x ? 1.0 : edgeSharpness.x; - edgeSharpness.y = force_edge.y ? 1.0 : edgeSharpness.y; - edgeSharpness.z = force_edge.z ? 1.0 : edgeSharpness.z; - - vec3 nor = nors[v_n]; -# endif + + barycentric = vec3(equal(ivec3(2, 0, 1), ivec3(v_n))); + + vec3 wb = vec3(wd0, wd1, wd2); + edgeSharpness = get_edge_sharpness(wb); + + /* Don't generate any fragment if there is no edge to draw. */ + vec3 pos = (!any(greaterThan(edgeSharpness, vec3(0.04))) && (v_n == 0)) ? pos1 : pos0; + + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); facing = normalize(NormalMatrix * nor).z; } -#endif /* USE_GEOM_SHADER */ +#endif /* SELECT_EDGES */ diff --git a/source/blender/draw/modes/shaders/paint_face_vert.glsl b/source/blender/draw/modes/shaders/paint_face_vert.glsl new file mode 100644 index 00000000000..437eeb28118 --- /dev/null +++ b/source/blender/draw/modes/shaders/paint_face_vert.glsl @@ -0,0 +1,14 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in vec4 nor; /* select flag on the 4th component */ + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + /* Don't draw faces that are selected. */ + if (nor.w > 0.0) { + gl_Position = vec4(0.0, 0.0, 0.0, 1.0); + } +} diff --git a/source/blender/draw/modes/shaders/paint_texture_vert.glsl b/source/blender/draw/modes/shaders/paint_texture_vert.glsl index 4ce12e048fa..8eae494cc35 100644 --- a/source/blender/draw/modes/shaders/paint_texture_vert.glsl +++ b/source/blender/draw/modes/shaders/paint_texture_vert.glsl @@ -1,7 +1,7 @@ uniform mat4 ModelViewProjectionMatrix; -in vec2 uv; +in vec2 u; /* active uv map */ in vec3 pos; out vec2 uv_interp; @@ -10,6 +10,5 @@ void main() { gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - uv_interp = uv; - + uv_interp = u; } diff --git a/source/blender/draw/modes/shaders/paint_vert_frag.glsl b/source/blender/draw/modes/shaders/paint_vert_frag.glsl index 5ea8c11ff9a..d7f604d5c2c 100644 --- a/source/blender/draw/modes/shaders/paint_vert_frag.glsl +++ b/source/blender/draw/modes/shaders/paint_vert_frag.glsl @@ -1,5 +1,5 @@ -flat in int finalFlag; +flat in vec4 finalColor; out vec4 fragColor; #define VERTEX_SELECTED (1 << 0) @@ -7,10 +7,6 @@ out vec4 fragColor; void main() { - if (bool(finalFlag & VERTEX_HIDE)) { - discard; - } - vec2 centered = gl_PointCoord - vec2(0.5); float dist_squared = dot(centered, centered); const float rad_squared = 0.25; @@ -22,5 +18,5 @@ void main() discard; } - fragColor = bool(finalFlag & VERTEX_SELECTED) ? colSel : colUnsel; + fragColor = finalColor; } diff --git a/source/blender/draw/modes/shaders/paint_vertex_vert.glsl b/source/blender/draw/modes/shaders/paint_vertex_vert.glsl index 178f77c6b9c..e52c17e52d5 100644 --- a/source/blender/draw/modes/shaders/paint_vertex_vert.glsl +++ b/source/blender/draw/modes/shaders/paint_vertex_vert.glsl @@ -2,7 +2,7 @@ uniform mat4 ModelViewProjectionMatrix; in vec3 pos; -in vec3 color; +in vec3 c; /* active color */ out vec3 finalColor; @@ -17,5 +17,5 @@ void main() { gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - finalColor = srgb_to_linear_attrib(color); + finalColor = srgb_to_linear_attrib(c); } diff --git a/source/blender/draw/modes/shaders/paint_wire_frag.glsl b/source/blender/draw/modes/shaders/paint_wire_frag.glsl index b6637fea308..d738ed5ddb2 100644 --- a/source/blender/draw/modes/shaders/paint_wire_frag.glsl +++ b/source/blender/draw/modes/shaders/paint_wire_frag.glsl @@ -1,22 +1,8 @@ -flat in int finalFlag; +flat in vec4 finalColor; out vec4 fragColor; -#define VERTEX_SELECTED (1 << 0) -#define VERTEX_HIDE (1 << 4) - void main() { - if (bool(finalFlag & VERTEX_HIDE)) { - discard; - } - -#ifdef VERTEX_MODE - vec4 colSel = colorEdgeSelect; - colSel.rgb = clamp(colSel.rgb - 0.2, 0.0, 1.0); -#else - const vec4 colSel = vec4(1.0, 1.0, 1.0, 1.0); -#endif - - fragColor = bool(finalFlag & VERTEX_SELECTED) ? colSel : colorWire; + fragColor = finalColor; } diff --git a/source/blender/draw/modes/shaders/paint_wire_vert.glsl b/source/blender/draw/modes/shaders/paint_wire_vert.glsl index 6a800e56d94..a92591b957d 100644 --- a/source/blender/draw/modes/shaders/paint_wire_vert.glsl +++ b/source/blender/draw/modes/shaders/paint_wire_vert.glsl @@ -2,16 +2,30 @@ uniform mat4 ModelViewProjectionMatrix; in vec3 pos; -in int data; +in vec4 nor; /* flag stored in w */ -flat out int finalFlag; +flat out vec4 finalColor; void main() { + bool is_select = (nor.w > 0.0); + bool is_hidden = (nor.w < 0.0); gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + /* Add offset in Z to avoid zfighting and render selected wires on top. */ + /* TODO scale this bias using znear and zfar range. */ + gl_Position.zw -= exp2(-20) * (is_select ? 2.0 : 1.0); - /* Temp hack for william to start using blender 2.8 for icons. Will be removed by T54910 */ - gl_Position.z -= 0.0001; + if (is_hidden) { + gl_Position = vec4(-2.0, -2.0, -2.0, 1.0); + } - finalFlag = data; +#ifdef VERTEX_MODE + vec4 colSel = colorEdgeSelect; + colSel.rgb = clamp(colSel.rgb - 0.2, 0.0, 1.0); +#else + const vec4 colSel = vec4(1.0, 1.0, 1.0, 1.0); +#endif + + finalColor = (is_select) ? colSel : colorWire; + finalColor.a = nor.w; } diff --git a/source/blender/draw/modes/shaders/particle_strand_frag.glsl b/source/blender/draw/modes/shaders/particle_strand_frag.glsl index 7053ca43ae7..8bb213dbd30 100644 --- a/source/blender/draw/modes/shaders/particle_strand_frag.glsl +++ b/source/blender/draw/modes/shaders/particle_strand_frag.glsl @@ -1,12 +1,23 @@ -uniform mat4 ProjectionMatrix; +uniform mat4 ModelViewProjectionMatrix; + +in vec4 finalColor; +#ifdef USE_POINTS +in vec2 radii; +#endif -in vec3 tangent; -in vec3 viewPosition; -flat in float colRand; out vec4 fragColor; void main() { - fragColor.rgb = tangent; - fragColor.a = 1.0; + fragColor = finalColor; + +#ifdef USE_POINTS + float dist = length(gl_PointCoord - vec2(0.5)); + + fragColor.a = mix(finalColor.a, 0.0, smoothstep(radii[1], radii[0], dist)); + + if (fragColor.a == 0.0) { + discard; + } +#endif } diff --git a/source/blender/draw/modes/shaders/particle_strand_vert.glsl b/source/blender/draw/modes/shaders/particle_strand_vert.glsl index d4c35d14182..9db62a581cb 100644 --- a/source/blender/draw/modes/shaders/particle_strand_vert.glsl +++ b/source/blender/draw/modes/shaders/particle_strand_vert.glsl @@ -1,34 +1,73 @@ uniform mat4 ModelViewProjectionMatrix; -uniform mat3 NormalMatrix; -uniform mat4 ModelViewMatrix; in vec3 pos; -in vec3 nor; -in int ind; -out vec3 tangent; -out vec3 viewPosition; -flat out float colRand; +in float color; -float rand(int s) +out vec4 finalColor; +#ifdef USE_POINTS +out vec2 radii; +#endif + +vec3 weight_to_rgb(float weight) { - int seed = s * 1023423; + vec3 r_rgb; + float blend = ((weight / 2.0) + 0.5); - seed = (seed ^ 61) ^ (seed >> 16); - seed *= 9; - seed = seed ^ (seed >> 4); - seed *= 0x27d4eb2d; - seed = seed ^ (seed >> 15); + if (weight <= 0.25) { /* blue->cyan */ + r_rgb[0] = 0.0; + r_rgb[1] = blend * weight * 4.0; + r_rgb[2] = blend; + } + else if (weight <= 0.50) { /* cyan->green */ + r_rgb[0] = 0.0; + r_rgb[1] = blend; + r_rgb[2] = blend * (1.0 - ((weight - 0.25) * 4.0)); + } + else if (weight <= 0.75) { /* green->yellow */ + r_rgb[0] = blend * ((weight - 0.50) * 4.0); + r_rgb[1] = blend; + r_rgb[2] = 0.0; + } + else if (weight <= 1.0) { /* yellow->red */ + r_rgb[0] = blend; + r_rgb[1] = blend * (1.0 - ((weight - 0.75) * 4.0)); + r_rgb[2] = 0.0; + } + else { + /* exceptional value, unclamped or nan, + * avoid uninitialized memory use */ + r_rgb[0] = 1.0; + r_rgb[1] = 0.0; + r_rgb[2] = 1.0; + } - float value = float(seed); - value *= 1.0 / 42596.0; - return fract(value); + return r_rgb; } +#define DECOMPRESS_RANGE 1.0039 + void main() { gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - tangent = normalize(NormalMatrix * nor); - viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz; - colRand = rand(ind); + +#ifdef USE_WEIGHT + finalColor = vec4(weight_to_rgb(color * DECOMPRESS_RANGE), 1.0); +#else + finalColor = mix(colorWire, colorEdgeSelect, color); +#endif + +#ifdef USE_POINTS + gl_PointSize = sizeVertex; + + /* calculate concentric radii in pixels */ + float radius = 0.5 * sizeVertex; + + /* start at the outside and progress toward the center */ + radii[0] = radius; + radii[1] = radius - 1.0; + + /* convert to PointCoord units */ + radii /= sizeVertex; +#endif } |