diff options
Diffstat (limited to 'source/blender/draw')
66 files changed, 3935 insertions, 1959 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index a26c150cb51..1ddae11999b 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -214,6 +214,7 @@ data_to_c_simple(engines/eevee/shaders/effect_downsample_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_downsample_cube_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_gtao_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_velocity_resolve_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/effect_velocity_tile_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_minmaxz_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_mist_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC) @@ -224,6 +225,8 @@ data_to_c_simple(engines/eevee/shaders/effect_temporal_aa.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl SRC) +data_to_c_simple(engines/eevee/shaders/object_motion_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/object_motion_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/prepass_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/prepass_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/shadow_accum_frag.glsl SRC) @@ -310,6 +313,7 @@ data_to_c_simple(engines/basic/shaders/depth_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/antialiasing_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/antialiasing_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/armature_dof_vert.glsl SRC) +data_to_c_simple(engines/overlay/shaders/armature_dof_solid_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/armature_envelope_outline_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_vert.glsl SRC) diff --git a/source/blender/draw/DRW_select_buffer.h b/source/blender/draw/DRW_select_buffer.h index 6ebc30d0382..66dee3a9aa9 100644 --- a/source/blender/draw/DRW_select_buffer.h +++ b/source/blender/draw/DRW_select_buffer.h @@ -56,16 +56,16 @@ struct ObjectOffsets { uint vert; }; -struct SELECTID_Context { +typedef struct SELECTID_Context { /* All context objects */ struct Object **objects; - uint objects_len; /* Array with only drawn objects. When a new object is found within the rect, * it is added to the end of the list. * The list is reset to any viewport or context update. */ - struct ObjectOffsets *index_offsets; struct Object **objects_drawn; + struct ObjectOffsets *index_offsets; + uint objects_len; uint objects_drawn_len; /** Total number of element indices `index_offsets[object_drawn_len - 1].vert`. */ @@ -73,13 +73,13 @@ struct SELECTID_Context { short select_mode; + /* rect is used to check which objects whose indexes need to be drawn. */ + rcti last_rect; + /* To check for updates. */ float persmat[4][4]; bool is_dirty; - - /* rect is used to check which objects whose indexes need to be drawn. */ - rcti last_rect; -}; +} SELECTID_Context; /* draw_select_buffer.c */ bool DRW_select_buffer_elem_get(const uint sel_id, diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index bbc3c407f14..0dd3cc14234 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -131,7 +131,7 @@ static void basic_cache_init(void *vedata) stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); } - /* Twice for normal and infront objects. */ + /* Twice for normal and in front objects. */ for (int i = 0; i < 2; i++) { DRWState clip_state = (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? DRW_STATE_CLIP_PLANES : 0; DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0; diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index a19af77124f..a4aa0e10198 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -24,11 +24,153 @@ #include "DRW_render.h" +#include "BLI_ghash.h" #include "BLI_memblock.h" +#include "BKE_duplilist.h" + +#include "DEG_depsgraph_query.h" + +#include "GPU_vertex_buffer.h" + #include "eevee_lightcache.h" #include "eevee_private.h" +/* Motion Blur data. */ + +static void eevee_motion_blur_mesh_data_free(void *val) +{ + EEVEE_GeometryMotionData *geom_mb = (EEVEE_GeometryMotionData *)val; + switch (geom_mb->type) { + case EEVEE_HAIR_GEOM_MOTION_DATA: + for (int i = 0; i < ARRAY_SIZE(geom_mb->vbo); i++) { + GPU_VERTBUF_DISCARD_SAFE(geom_mb->hair_pos[i]); + DRW_TEXTURE_FREE_SAFE(geom_mb->hair_pos_tx[i]); + } + break; + + case EEVEE_MESH_GEOM_MOTION_DATA: + for (int i = 0; i < ARRAY_SIZE(geom_mb->vbo); i++) { + GPU_VERTBUF_DISCARD_SAFE(geom_mb->vbo[i]); + } + break; + } + MEM_freeN(val); +} + +static uint eevee_object_key_hash(const void *key) +{ + EEVEE_ObjectKey *ob_key = (EEVEE_ObjectKey *)key; + uint hash = BLI_ghashutil_ptrhash(ob_key->ob); + hash = BLI_ghashutil_combine_hash(hash, BLI_ghashutil_ptrhash(ob_key->parent)); + for (int i = 0; i < 16; i++) { + if (ob_key->id[i] != 0) { + hash = BLI_ghashutil_combine_hash(hash, BLI_ghashutil_inthash(ob_key->id[i])); + } + else { + break; + } + } + return hash; +} + +/* Return false if equal. */ +static bool eevee_object_key_cmp(const void *a, const void *b) +{ + EEVEE_ObjectKey *key_a = (EEVEE_ObjectKey *)a; + EEVEE_ObjectKey *key_b = (EEVEE_ObjectKey *)b; + + if (key_a->ob != key_b->ob) { + return true; + } + if (key_a->parent != key_b->parent) { + return true; + } + if (memcmp(key_a->id, key_b->id, sizeof(key_a->id)) != 0) { + return true; + } + return false; +} + +void EEVEE_motion_blur_data_init(EEVEE_MotionBlurData *mb) +{ + if (mb->object == NULL) { + mb->object = BLI_ghash_new(eevee_object_key_hash, eevee_object_key_cmp, "EEVEE Object Motion"); + } + if (mb->geom == NULL) { + mb->geom = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EEVEE Mesh Motion"); + } +} + +void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb) +{ + if (mb->object) { + BLI_ghash_free(mb->object, MEM_freeN, MEM_freeN); + mb->object = NULL; + } + if (mb->geom) { + BLI_ghash_free(mb->geom, NULL, eevee_motion_blur_mesh_data_free); + mb->geom = NULL; + } +} + +EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, + Object *ob, + bool hair) +{ + if (mb->object == NULL) { + return NULL; + } + + EEVEE_ObjectKey key, *key_p; + /* Small hack to avoid another comparisson. */ + key.ob = (Object *)((char *)ob + hair); + DupliObject *dup = DRW_object_get_dupli(ob); + if (dup) { + key.parent = DRW_object_get_dupli_parent(ob); + memcpy(key.id, dup->persistent_id, sizeof(key.id)); + } + else { + key.parent = key.ob; + memset(key.id, 0, sizeof(key.id)); + } + + EEVEE_ObjectMotionData *ob_step = BLI_ghash_lookup(mb->object, &key); + if (ob_step == NULL) { + key_p = MEM_mallocN(sizeof(*key_p), __func__); + memcpy(key_p, &key, sizeof(*key_p)); + + ob_step = MEM_callocN(sizeof(EEVEE_ObjectMotionData), __func__); + + BLI_ghash_insert(mb->object, key_p, ob_step); + } + return ob_step; +} + +EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_MotionBlurData *mb, + Object *ob, + bool hair) +{ + if (mb->geom == NULL) { + return NULL; + } + + /* Use original data as key to ensure matching accross update. */ + Object *ob_orig = DEG_get_original_object(ob); + + void *key = (char *)ob_orig->data + hair; + EEVEE_GeometryMotionData *geom_step = BLI_ghash_lookup(mb->geom, key); + if (geom_step == NULL) { + geom_step = MEM_callocN(sizeof(EEVEE_GeometryMotionData), __func__); + geom_step->type = (hair) ? EEVEE_HAIR_GEOM_MOTION_DATA : EEVEE_MESH_GEOM_MOTION_DATA; + BLI_ghash_insert(mb->geom, key, geom_step); + } + + return geom_step; +} + +/* View Layer data. */ + void EEVEE_view_layer_data_free(void *storage) { EEVEE_ViewLayerData *sldata = (EEVEE_ViewLayerData *)storage; @@ -105,6 +247,8 @@ static void eevee_object_data_init(DrawData *dd) { EEVEE_ObjectEngineData *eevee_data = (EEVEE_ObjectEngineData *)dd; eevee_data->shadow_caster_id = -1; + eevee_data->need_update = false; + eevee_data->geom_update = false; } EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob) diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index ab846fe0f11..8c48ae65d9b 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -153,7 +153,7 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, effects->enabled_effects = 0; effects->enabled_effects |= (G.debug_value == 9) ? EFFECT_VELOCITY_BUFFER : 0; - effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata, camera); + effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata); effects->enabled_effects |= EEVEE_bloom_init(sldata, vedata); effects->enabled_effects |= EEVEE_depth_of_field_init(sldata, vedata, camera); effects->enabled_effects |= EEVEE_temporal_sampling_init(sldata, vedata); @@ -225,10 +225,13 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, */ if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) { effects->velocity_tx = DRW_texture_pool_query_2d( - size_fs[0], size_fs[1], GPU_RG16, &draw_engine_eevee_type); + size_fs[0], size_fs[1], GPU_RGBA16, &draw_engine_eevee_type); - /* TODO output objects velocity during the mainpass. */ - // GPU_framebuffer_texture_attach(fbl->main_fb, effects->velocity_tx, 1, 0); + GPU_framebuffer_ensure_config(&fbl->velocity_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(effects->velocity_tx), + }); GPU_framebuffer_ensure_config( &fbl->velocity_resolve_fb, @@ -328,14 +331,18 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) { + EEVEE_MotionBlurData *mb_data = &effects->motion_blur; + /* This pass compute camera motions to the non moving objects. */ DRW_PASS_CREATE(psl->velocity_resolve, DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(EEVEE_shaders_velocity_resolve_sh_get(), psl->velocity_resolve); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); - DRW_shgroup_uniform_mat4(grp, "currPersinv", effects->velocity_curr_persinv); - DRW_shgroup_uniform_mat4(grp, "pastPersmat", effects->velocity_past_persmat); + + DRW_shgroup_uniform_mat4(grp, "prevViewProjMatrix", mb_data->camera[MB_PREV].persmat); + DRW_shgroup_uniform_mat4(grp, "currViewProjMatrixInv", mb_data->camera[MB_CURR].persinv); + DRW_shgroup_uniform_mat4(grp, "nextViewProjMatrix", mb_data->camera[MB_NEXT].persmat); DRW_shgroup_call(grp, quad, NULL); } } @@ -501,17 +508,19 @@ static void EEVEE_velocity_resolve(EEVEE_Data *vedata) EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - struct DRWView *view = effects->taa_view; if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) { DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); e_data.depth_src = dtxl->depth; - DRW_view_persmat_get(view, effects->velocity_curr_persinv, true); GPU_framebuffer_bind(fbl->velocity_resolve_fb); DRW_draw_pass(psl->velocity_resolve); + + if (psl->velocity_object) { + GPU_framebuffer_bind(fbl->velocity_fb); + DRW_draw_pass(psl->velocity_object); + } } - DRW_view_persmat_get(view, effects->velocity_past_persmat, false); } void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) @@ -529,6 +538,7 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) effects->target_buffer = fbl->effect_color_fb; /* next target to render to */ /* Post process stack (order matters) */ + EEVEE_velocity_resolve(vedata); EEVEE_motion_blur_draw(vedata); EEVEE_depth_of_field_draw(vedata); @@ -537,7 +547,6 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) * Velocity resolve use a hack to exclude lookdev * spheres from creating shimmering re-projection vectors. */ EEVEE_lookdev_draw(vedata); - EEVEE_velocity_resolve(vedata); EEVEE_temporal_sampling_draw(vedata); EEVEE_bloom_draw(vedata); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index b698574f9d7..bac96ab1079 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -166,7 +166,9 @@ static void eevee_cache_finish(void *vedata) EEVEE_materials_cache_finish(sldata, vedata); EEVEE_lights_cache_finish(sldata, vedata); EEVEE_lightprobes_cache_finish(sldata, vedata); + EEVEE_renderpasses_cache_finish(sldata, vedata); + EEVEE_subsurface_draw_init(sldata, vedata); EEVEE_effects_draw_init(sldata, vedata); EEVEE_volumes_draw_init(sldata, vedata); @@ -213,6 +215,10 @@ static void eevee_draw_scene(void *vedata) loop_len = MAX2(1, scene->eevee.taa_samples); } + if (stl->effects->bypass_drawing) { + loop_len = 0; + } + while (loop_len--) { float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float clear_depth = 1.0f; @@ -351,11 +357,18 @@ static void eevee_draw_scene(void *vedata) EEVEE_renderpasses_draw(sldata, vedata); } + if (stl->effects->bypass_drawing) { + /* Restore the depth from sample 1. */ + GPU_framebuffer_blit(fbl->double_buffer_depth_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT); + } + EEVEE_renderpasses_draw_debug(vedata); EEVEE_volumes_free_smoke_textures(); stl->g_data->view_updated = false; + + DRW_view_set_active(NULL); } static void eevee_view_update(void *vedata) @@ -370,7 +383,7 @@ static void eevee_id_object_update(void *UNUSED(vedata), Object *object) { EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object); if (ped != NULL && ped->dd.recalc != 0) { - ped->need_update = (ped->dd.recalc & (ID_RECALC_TRANSFORM)) != 0; + ped->need_update = (ped->dd.recalc & ID_RECALC_TRANSFORM) != 0; ped->dd.recalc = 0; } EEVEE_LightEngineData *led = EEVEE_light_data_get(object); @@ -381,6 +394,7 @@ static void eevee_id_object_update(void *UNUSED(vedata), Object *object) EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object); if (oedata != NULL && oedata->dd.recalc != 0) { oedata->need_update = true; + oedata->geom_update = (oedata->dd.recalc & (ID_RECALC_GEOMETRY)) != 0; oedata->dd.recalc = 0; } } @@ -390,6 +404,11 @@ static void eevee_id_world_update(void *vedata, World *wo) EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; LightCache *lcache = stl->g_data->light_cache; + if (lcache == NULL || lcache == stl->lookdev_lightcache) { + /* Avoid Lookdev viewport clearing the update flag (see T67741). */ + return; + } + EEVEE_WorldEngineData *wedata = EEVEE_world_data_ensure(wo); if (wedata != NULL && wedata->dd.recalc != 0) { @@ -400,7 +419,7 @@ static void eevee_id_world_update(void *vedata, World *wo) } } -static void eevee_id_update(void *vedata, ID *id) +void eevee_id_update(void *vedata, ID *id) { /* Handle updates based on ID type. */ switch (GS(id->name)) { @@ -416,23 +435,129 @@ static void eevee_id_update(void *vedata, ID *id) } } +static void eevee_render_reset_passes(EEVEE_Data *vedata) +{ + /* Reset passlist. This is safe as they are stored into managed memory chunks. */ + memset(vedata->psl, 0, sizeof(*vedata->psl)); +} + static void eevee_render_to_image(void *vedata, RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect) { + EEVEE_Data *ved = (EEVEE_Data *)vedata; const DRWContextState *draw_ctx = DRW_context_state_get(); + Depsgraph *depsgraph = draw_ctx->depsgraph; + Scene *scene = DEG_get_evaluated_scene(depsgraph); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + const bool do_motion_blur = (scene->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) != 0; + const bool do_motion_blur_fx = do_motion_blur && (scene->eevee.motion_blur_max > 0); - if (!EEVEE_render_init(vedata, engine, draw_ctx->depsgraph)) { + if (!EEVEE_render_init(vedata, engine, depsgraph)) { return; } + EEVEE_PrivateData *g_data = ved->stl->g_data; + + int steps = max_ii(1, scene->eevee.motion_blur_steps); + int time_steps_tot = (do_motion_blur) ? steps : 1; + g_data->render_tot_samples = divide_ceil_u(scene->eevee.taa_render_samples, time_steps_tot); + /* Centered on frame for now. */ + float time = CFRA - scene->eevee.motion_blur_shutter / 2.0f; + float time_step = scene->eevee.motion_blur_shutter / time_steps_tot; + for (int i = 0; i < time_steps_tot && !RE_engine_test_break(engine); i++) { + float time_prev = time; + float time_curr = time + time_step * 0.5f; + float time_next = time + time_step; + time += time_step; + + /* Previous motion step. */ + if (do_motion_blur_fx) { + if (i > 0) { + /* The previous step of this iteration N is exactly the next step of iteration N - 1. + * So we just swap the resources to avoid too much re-evaluation. */ + EEVEE_motion_blur_swap_data(vedata); + } + else { + EEVEE_motion_blur_step_set(ved, MB_PREV); + RE_engine_frame_set(engine, floorf(time_prev), fractf(time_prev)); + + EEVEE_render_view_sync(vedata, engine, depsgraph); + EEVEE_render_cache_init(sldata, vedata); + + DRW_render_object_iter(vedata, engine, depsgraph, EEVEE_render_cache); + + EEVEE_motion_blur_cache_finish(vedata); + EEVEE_materials_cache_finish(sldata, vedata); + eevee_render_reset_passes(vedata); + } + } + + /* Next motion step. */ + if (do_motion_blur_fx) { + EEVEE_motion_blur_step_set(ved, MB_NEXT); + RE_engine_frame_set(engine, floorf(time_next), fractf(time_next)); - DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, EEVEE_render_cache); + EEVEE_render_view_sync(vedata, engine, depsgraph); + EEVEE_render_cache_init(sldata, vedata); - /* Actually do the rendering. */ - EEVEE_render_draw(vedata, engine, render_layer, rect); + DRW_render_object_iter(vedata, engine, depsgraph, EEVEE_render_cache); + + EEVEE_motion_blur_cache_finish(vedata); + EEVEE_materials_cache_finish(sldata, vedata); + eevee_render_reset_passes(vedata); + } + + /* Current motion step. */ + { + if (do_motion_blur) { + EEVEE_motion_blur_step_set(ved, MB_CURR); + RE_engine_frame_set(engine, floorf(time_curr), fractf(time_curr)); + } + + EEVEE_render_view_sync(vedata, engine, depsgraph); + EEVEE_render_cache_init(sldata, vedata); + + DRW_render_object_iter(vedata, engine, depsgraph, EEVEE_render_cache); + + EEVEE_motion_blur_cache_finish(vedata); + EEVEE_volumes_cache_finish(sldata, vedata); + EEVEE_materials_cache_finish(sldata, vedata); + EEVEE_lights_cache_finish(sldata, vedata); + EEVEE_lightprobes_cache_finish(sldata, vedata); + EEVEE_renderpasses_cache_finish(sldata, vedata); + + EEVEE_subsurface_draw_init(sldata, vedata); + EEVEE_effects_draw_init(sldata, vedata); + EEVEE_volumes_draw_init(sldata, vedata); + } + + /* Actual drawing. */ + { + EEVEE_renderpasses_output_init(sldata, vedata, g_data->render_tot_samples * time_steps_tot); + + EEVEE_temporal_sampling_create_view(vedata); + EEVEE_render_draw(vedata, engine, render_layer, rect); + + if (i < time_steps_tot - 1) { + /* Don't reset after the last loop. Since EEVEE_render_read_result + * might need some DRWPasses. */ + DRW_cache_restart(); + } + } + } EEVEE_volumes_free_smoke_textures(); + EEVEE_motion_blur_data_free(&ved->stl->effects->motion_blur); + + if (RE_engine_test_break(engine)) { + return; + } + + EEVEE_render_read_result(vedata, engine, render_layer, rect); + + /* Restore original viewport size. */ + DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]}); } static void eevee_engine_free(void) diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 4cdd166f09c..78d50a02fc7 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -849,6 +849,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb /* Disable volumetrics when baking. */ stl->effects->enabled_effects &= ~EFFECT_VOLUMETRIC; + EEVEE_subsurface_draw_init(sldata, vedata); EEVEE_effects_draw_init(sldata, vedata); EEVEE_volumes_draw_init(sldata, vedata); diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 83b2a9bb6d4..71c8294d123 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -957,8 +957,8 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us /* Slight modification: we handle refraction as normal * shading and don't do SSRefraction. */ - DRW_draw_pass(psl->depth_ps); - DRW_draw_pass(psl->depth_refract_ps); + DRW_draw_pass(psl->depth_clip_ps); + DRW_draw_pass(psl->depth_refract_clip_ps); DRW_draw_pass(psl->probe_background); EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index cfc70baaf01..8537ad0e532 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -801,6 +801,8 @@ static void eevee_hair_cache_populate(EEVEE_Data *vedata, *matcache.shadow_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.shadow_grp); *cast_shadow = true; } + + EEVEE_motion_blur_hair_cache_populate(sldata, vedata, ob, psys, md); } #define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \ @@ -851,8 +853,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, */ bool use_volume_material = (matcache[0].shading_gpumat && GPU_material_has_volume_output(matcache[0].shading_gpumat)); - - if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) { + if ((ob->dt >= OB_SOLID) || DRW_state_is_scene_render()) { if (use_sculpt_pbvh) { struct DRWShadingGroup **shgrps_array = BLI_array_alloca(shgrps_array, materials_len); @@ -901,6 +902,9 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, } } } + + /* Motion Blur Vectors. */ + EEVEE_motion_blur_cache_populate(sldata, vedata, ob); } /* Volumetrics */ @@ -946,17 +950,15 @@ void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata, eevee_hair_cache_populate(vedata, sldata, ob, NULL, NULL, HAIR_MATERIAL_NR, cast_shadow); } -void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_PrivateData *pd = vedata->stl->g_data; EEVEE_EffectsInfo *effects = vedata->stl->effects; BLI_ghash_free(pd->material_hash, NULL, NULL); + pd->material_hash = NULL; SET_FLAG_FROM_TEST(effects->enabled_effects, effects->sss_surface_count > 0, EFFECT_SSS); - - /* TODO(fclem) this is not really clean. Init should not be done in cache finish. */ - EEVEE_subsurface_draw_init(sldata, vedata); } void EEVEE_materials_free(void) @@ -1015,7 +1017,7 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, /* Should be enough precision for many samples. */ const eGPUTextureFormat texture_format = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F; - const bool do_clear = DRW_state_is_image_render() || (effects->taa_current_sample == 1); + const bool do_clear = (effects->taa_current_sample == 1); /* Create FrameBuffer. */ GPU_framebuffer_ensure_config(&fbl->material_accum_fb, {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE}); diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c index 7b942784ee9..1cedd334d67 100644 --- a/source/blender/draw/engines/eevee/eevee_mist.c +++ b/source/blender/draw/engines/eevee/eevee_mist.c @@ -75,7 +75,7 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->mist_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->mist_accum_fb); GPU_framebuffer_clear_color(fbl->mist_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index a6e6b30a6b1..586ee780f1d 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -24,12 +24,19 @@ #include "DRW_render.h" +#include "BLI_rand.h" +#include "BLI_string_utils.h" + #include "BKE_animsys.h" #include "BKE_camera.h" #include "BKE_object.h" +#include "BKE_screen.h" #include "DNA_anim_types.h" #include "DNA_camera_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_particle_types.h" #include "DNA_screen_types.h" #include "ED_screen.h" @@ -37,172 +44,517 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "GPU_batch.h" #include "GPU_texture.h" #include "eevee_private.h" static struct { /* Motion Blur */ struct GPUShader *motion_blur_sh; + struct GPUShader *motion_blur_object_sh; + struct GPUShader *motion_blur_hair_sh; + struct GPUShader *velocity_tiles_sh; + struct GPUShader *velocity_tiles_expand_sh; } e_data = {NULL}; /* Engine data */ +extern char datatoc_effect_velocity_tile_frag_glsl[]; extern char datatoc_effect_motion_blur_frag_glsl[]; +extern char datatoc_object_motion_frag_glsl[]; +extern char datatoc_object_motion_vert_glsl[]; +extern char datatoc_common_hair_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; -static void eevee_motion_blur_camera_get_matrix_at_time(Scene *scene, - ARegion *region, - RegionView3D *rv3d, - View3D *v3d, - Object *camera, - float time, - float r_mat[4][4]) -{ - float obmat[4][4]; +#define EEVEE_VELOCITY_TILE_SIZE 32 - /* HACK */ - Object cam_cpy = *camera; - Camera camdata_cpy = *(Camera *)(camera->data); - cam_cpy.data = &camdata_cpy; +static void eevee_create_shader_motion_blur(void) +{ + e_data.motion_blur_sh = DRW_shader_create_fullscreen( + datatoc_effect_motion_blur_frag_glsl, + "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n"); + e_data.motion_blur_object_sh = DRW_shader_create_with_lib(datatoc_object_motion_vert_glsl, + NULL, + datatoc_object_motion_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); + e_data.velocity_tiles_sh = DRW_shader_create_fullscreen( + datatoc_effect_velocity_tile_frag_glsl, + "#define TILE_GATHER\n" + "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n"); + e_data.velocity_tiles_expand_sh = DRW_shader_create_fullscreen( + datatoc_effect_velocity_tile_frag_glsl, + "#define TILE_EXPANSION\n" + "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n"); + + char *vert = BLI_string_joinN(datatoc_common_hair_lib_glsl, datatoc_object_motion_vert_glsl); + e_data.motion_blur_hair_sh = DRW_shader_create_with_lib( + vert, NULL, datatoc_object_motion_frag_glsl, datatoc_common_view_lib_glsl, "#define HAIR\n"); + MEM_freeN(vert); +} - /* Reset original pointers, so direct evaluation does not attempt to flush - * animation back to the original object: otherwise viewport with motion - * blur enabled will always loose non-keyed changes. */ - cam_cpy.id.orig_id = NULL; - camdata_cpy.id.orig_id = NULL; +int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_EffectsInfo *effects = stl->effects; const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; - /* Past matrix */ - /* FIXME : This is a temporal solution that does not take care of parent animations */ - /* Recalc Anim manually */ - BKE_animsys_evaluate_animdata(&camdata_cpy.id, camdata_cpy.adt, time, ADT_RECALC_ALL, false); - BKE_object_where_is_calc_time(draw_ctx->depsgraph, scene, &cam_cpy, time); + /* Viewport not supported for now. */ + if (!DRW_state_is_scene_render()) { + return 0; + } + + effects->motion_blur_max = max_ii(0, scene->eevee.motion_blur_max); + + if ((effects->motion_blur_max > 0) && (scene->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED)) { + if (!e_data.motion_blur_sh) { + eevee_create_shader_motion_blur(); + } - /* Compute winmat */ - CameraParams params; - BKE_camera_params_init(¶ms); + if (DRW_state_is_scene_render()) { + int mb_step = effects->motion_blur_step; + DRW_view_viewmat_get(NULL, effects->motion_blur.camera[mb_step].viewmat, false); + DRW_view_persmat_get(NULL, effects->motion_blur.camera[mb_step].persmat, false); + DRW_view_persmat_get(NULL, effects->motion_blur.camera[mb_step].persinv, true); + } - if (v3d != NULL) { - BKE_camera_params_from_view3d(¶ms, draw_ctx->depsgraph, v3d, rv3d); - BKE_camera_params_compute_viewplane(¶ms, region->winx, region->winy, 1.0f, 1.0f); + const float *fs_size = DRW_viewport_size_get(); + int tx_size[2] = {1 + ((int)fs_size[0] / EEVEE_VELOCITY_TILE_SIZE), + 1 + ((int)fs_size[1] / EEVEE_VELOCITY_TILE_SIZE)}; + + effects->velocity_tiles_x_tx = DRW_texture_pool_query_2d( + tx_size[0], fs_size[1], GPU_RGBA16, &draw_engine_eevee_type); + GPU_framebuffer_ensure_config(&fbl->velocity_tiles_fb[0], + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->velocity_tiles_x_tx), + }); + + effects->velocity_tiles_tx = DRW_texture_pool_query_2d( + tx_size[0], tx_size[1], GPU_RGBA16, &draw_engine_eevee_type); + GPU_framebuffer_ensure_config(&fbl->velocity_tiles_fb[1], + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->velocity_tiles_tx), + }); + + return EFFECT_MOTION_BLUR | EFFECT_POST_BUFFER | EFFECT_VELOCITY_BUFFER; } - else { - BKE_camera_params_from_object(¶ms, &cam_cpy); - BKE_camera_params_compute_viewplane( - ¶ms, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp); + return 0; +} + +void EEVEE_motion_blur_step_set(EEVEE_Data *vedata, int step) +{ + BLI_assert(step < 3); + vedata->stl->effects->motion_blur_step = step; +} + +static void eevee_motion_blur_sync_camera(EEVEE_Data *vedata) +{ + EEVEE_EffectsInfo *effects = vedata->stl->effects; + if (DRW_state_is_scene_render()) { + int mb_step = effects->motion_blur_step; + DRW_view_viewmat_get(NULL, effects->motion_blur.camera[mb_step].viewmat, false); + DRW_view_persmat_get(NULL, effects->motion_blur.camera[mb_step].persmat, false); + DRW_view_persmat_get(NULL, effects->motion_blur.camera[mb_step].persinv, true); } - BKE_camera_params_compute_matrix(¶ms); + effects->motion_blur_near_far[0] = fabsf(DRW_view_near_distance_get(NULL)); + effects->motion_blur_near_far[1] = fabsf(DRW_view_far_distance_get(NULL)); +} + +void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_MotionBlurData *mb_data = &effects->motion_blur; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + + if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { + const float *fs_size = DRW_viewport_size_get(); + int tx_size[2] = {GPU_texture_width(effects->velocity_tiles_tx), + GPU_texture_height(effects->velocity_tiles_tx)}; + + eevee_motion_blur_sync_camera(vedata); + + DRWShadingGroup *grp; + { + DRW_PASS_CREATE(psl->velocity_tiles_x, DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->velocity_tiles, DRW_STATE_WRITE_COLOR); + + /* Create max velocity tiles in 2 passes. One for X and one for Y */ + GPUShader *sh = e_data.velocity_tiles_sh; + grp = DRW_shgroup_create(sh, psl->velocity_tiles_x); + DRW_shgroup_uniform_texture(grp, "velocityBuffer", effects->velocity_tx); + DRW_shgroup_uniform_ivec2_copy(grp, "velocityBufferSize", (int[2]){fs_size[0], fs_size[1]}); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_vec2(grp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_uniform_ivec2_copy(grp, "gatherStep", (int[2]){1, 0}); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + grp = DRW_shgroup_create(sh, psl->velocity_tiles); + DRW_shgroup_uniform_texture(grp, "velocityBuffer", effects->velocity_tiles_x_tx); + DRW_shgroup_uniform_ivec2_copy(grp, "velocityBufferSize", (int[2]){tx_size[0], fs_size[1]}); + DRW_shgroup_uniform_ivec2_copy(grp, "gatherStep", (int[2]){0, 1}); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + /* Expand max tiles by keeping the max tile in each tile neighborhood. */ + DRW_PASS_CREATE(psl->velocity_tiles_expand[0], DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->velocity_tiles_expand[1], DRW_STATE_WRITE_COLOR); + for (int i = 0; i < 2; i++) { + GPUTexture *tile_tx = (i == 0) ? effects->velocity_tiles_tx : effects->velocity_tiles_x_tx; + GPUShader *sh_expand = e_data.velocity_tiles_expand_sh; + grp = DRW_shgroup_create(sh_expand, psl->velocity_tiles_expand[i]); + DRW_shgroup_uniform_ivec2_copy(grp, "velocityBufferSize", tx_size); + DRW_shgroup_uniform_texture(grp, "velocityBuffer", tile_tx); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_vec2(grp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + } + { + DRW_PASS_CREATE(psl->motion_blur, DRW_STATE_WRITE_COLOR); + eGPUSamplerState state = 0; + int expand_steps = 1 + (max_ii(0, effects->motion_blur_max - 1) / EEVEE_VELOCITY_TILE_SIZE); + GPUTexture *tile_tx = (expand_steps & 1) ? effects->velocity_tiles_x_tx : + effects->velocity_tiles_tx; + + grp = DRW_shgroup_create(e_data.motion_blur_sh, psl->motion_blur); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_texture_ref_ex(grp, "colorBuffer", &effects->source_buffer, state); + DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &dtxl->depth, state); + DRW_shgroup_uniform_texture_ref_ex(grp, "velocityBuffer", &effects->velocity_tx, state); + DRW_shgroup_uniform_texture(grp, "tileMaxBuffer", tile_tx); + DRW_shgroup_uniform_float_copy(grp, "depthScale", scene->eevee.motion_blur_depth_scale); + DRW_shgroup_uniform_vec2(grp, "nearFar", effects->motion_blur_near_far, 1); + DRW_shgroup_uniform_bool_copy(grp, "isPerspective", DRW_view_is_persp_get(NULL)); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_vec2(grp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_uniform_ivec2_copy(grp, "tileBufferSize", tx_size); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + { + DRW_PASS_CREATE(psl->velocity_object, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + + grp = DRW_shgroup_create(e_data.motion_blur_object_sh, psl->velocity_object); + DRW_shgroup_uniform_mat4(grp, "prevViewProjMatrix", mb_data->camera[MB_PREV].persmat); + DRW_shgroup_uniform_mat4(grp, "currViewProjMatrix", mb_data->camera[MB_CURR].persmat); + DRW_shgroup_uniform_mat4(grp, "nextViewProjMatrix", mb_data->camera[MB_NEXT].persmat); + + DRW_PASS_CREATE(psl->velocity_hair, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + + mb_data->hair_grp = grp = DRW_shgroup_create(e_data.motion_blur_hair_sh, psl->velocity_hair); + DRW_shgroup_uniform_mat4(grp, "prevViewProjMatrix", mb_data->camera[MB_PREV].persmat); + DRW_shgroup_uniform_mat4(grp, "currViewProjMatrix", mb_data->camera[MB_CURR].persmat); + DRW_shgroup_uniform_mat4(grp, "nextViewProjMatrix", mb_data->camera[MB_NEXT].persmat); + + DRW_pass_link(psl->velocity_object, psl->velocity_hair); + } - /* FIXME Should be done per view (MULTIVIEW) */ - normalize_m4_m4(obmat, cam_cpy.obmat); - invert_m4(obmat); - mul_m4_m4m4(r_mat, params.winmat, obmat); + EEVEE_motion_blur_data_init(mb_data); + } + else { + psl->motion_blur = NULL; + psl->velocity_object = NULL; + psl->velocity_hair = NULL; + } } -static void eevee_create_shader_motion_blur(void) +void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_Data *vedata, + Object *ob, + ParticleSystem *psys, + ModifierData *md) { - e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL); + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + DRWShadingGroup *grp = NULL; + + if (!DRW_state_is_scene_render() || psl->velocity_hair == NULL) { + return; + } + + /* For now we assume hair objects are always moving. */ + EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get( + &effects->motion_blur, ob, true); + + if (mb_data) { + int mb_step = effects->motion_blur_step; + /* Store transform */ + DRW_hair_duplimat_get(ob, psys, md, mb_data->obmat[mb_step]); + + EEVEE_GeometryMotionData *mb_geom = EEVEE_motion_blur_geometry_data_get( + &effects->motion_blur, ob, true); + + if (mb_step == MB_CURR) { + /* Fill missing matrices if the object was hidden in previous or next frame. */ + if (is_zero_m4(mb_data->obmat[MB_PREV])) { + copy_m4_m4(mb_data->obmat[MB_PREV], mb_data->obmat[MB_CURR]); + } + if (is_zero_m4(mb_data->obmat[MB_NEXT])) { + copy_m4_m4(mb_data->obmat[MB_NEXT], mb_data->obmat[MB_CURR]); + } + + grp = DRW_shgroup_hair_create_sub(ob, psys, md, effects->motion_blur.hair_grp); + DRW_shgroup_uniform_mat4(grp, "prevModelMatrix", mb_data->obmat[MB_PREV]); + DRW_shgroup_uniform_mat4(grp, "currModelMatrix", mb_data->obmat[MB_CURR]); + DRW_shgroup_uniform_mat4(grp, "nextModelMatrix", mb_data->obmat[MB_NEXT]); + DRW_shgroup_uniform_texture(grp, "prvBuffer", mb_geom->hair_pos_tx[MB_PREV]); + DRW_shgroup_uniform_texture(grp, "nxtBuffer", mb_geom->hair_pos_tx[MB_NEXT]); + DRW_shgroup_uniform_bool(grp, "useDeform", &mb_geom->use_deform, 1); + } + else { + /* Store vertex position buffer. */ + mb_geom->hair_pos[mb_step] = DRW_hair_pos_buffer_get(ob, psys, md); + mb_geom->use_deform = true; + } + } } -int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera) +void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_Data *vedata, + Object *ob) { + EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; + DRWShadingGroup *grp = NULL; - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - Scene *scene = draw_ctx->scene; + if (!DRW_state_is_scene_render() || psl->velocity_object == NULL) { + return; + } - View3D *v3d = draw_ctx->v3d; - RegionView3D *rv3d = draw_ctx->rv3d; - ARegion *region = draw_ctx->region; + const bool is_dupli = (ob->base_flag & BASE_FROM_DUPLI) != 0; + /* For now we assume dupli objects are moving. */ + const bool object_moves = is_dupli || BKE_object_moves_in_time(ob, true); + const bool is_deform = BKE_object_is_deform_modified(DRW_context_state_get()->scene, ob); - if (scene_eval->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) { - /* Update Motion Blur Matrices */ - if (camera && (camera->type == OB_CAMERA) && (camera->data != NULL)) { - float persmat[4][4]; - float ctime = DEG_get_ctime(draw_ctx->depsgraph); - float delta = scene_eval->eevee.motion_blur_shutter; - Object *ob_camera_eval = DEG_get_evaluated_object(draw_ctx->depsgraph, camera); + if (!(object_moves || is_deform)) { + return; + } - /* Viewport Matrix */ - /* Note: This does not have TAA jitter applied. */ - DRW_view_persmat_get(NULL, persmat, false); + EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get( + &effects->motion_blur, ob, false); - bool view_is_valid = (stl->g_data->view_updated == false); + if (mb_data) { + int mb_step = effects->motion_blur_step; + /* Store transform */ + copy_m4_m4(mb_data->obmat[mb_step], ob->obmat); + + EEVEE_GeometryMotionData *mb_geom = EEVEE_motion_blur_geometry_data_get( + &effects->motion_blur, ob, false); + + if (mb_step == MB_CURR) { + GPUBatch *batch = DRW_cache_object_surface_get(ob); + if (batch == NULL) { + return; + } - if (draw_ctx->evil_C != NULL) { - struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); - view_is_valid = view_is_valid && (ED_screen_animation_no_scrub(wm) == NULL); + /* Fill missing matrices if the object was hidden in previous or next frame. */ + if (is_zero_m4(mb_data->obmat[MB_PREV])) { + copy_m4_m4(mb_data->obmat[MB_PREV], mb_data->obmat[MB_CURR]); + } + if (is_zero_m4(mb_data->obmat[MB_NEXT])) { + copy_m4_m4(mb_data->obmat[MB_NEXT], mb_data->obmat[MB_CURR]); } - /* The view is jittered by the oglrenderer. So avoid testing in this case. */ - if (!DRW_state_is_image_render()) { - view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN); - /* WATCH: assume TAA init code runs last. */ - if (scene_eval->eevee.taa_samples == 1) { - /* Only if TAA is disabled. If not, TAA will update prev_drw_persmat itself. */ - copy_m4_m4(effects->prev_drw_persmat, persmat); + grp = DRW_shgroup_create(e_data.motion_blur_object_sh, psl->velocity_object); + DRW_shgroup_uniform_mat4(grp, "prevModelMatrix", mb_data->obmat[MB_PREV]); + DRW_shgroup_uniform_mat4(grp, "currModelMatrix", mb_data->obmat[MB_CURR]); + DRW_shgroup_uniform_mat4(grp, "nextModelMatrix", mb_data->obmat[MB_NEXT]); + DRW_shgroup_uniform_bool(grp, "useDeform", &mb_geom->use_deform, 1); + + DRW_shgroup_call(grp, batch, ob); + + if (mb_geom->use_deform) { + EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob); + if (!oedata->geom_update) { + /* FIXME(fclem) There can be false positive where the actual mesh is not updated. + * This avoids a crash but removes the motion blur from some object. + * Maybe an issue with depsgraph tagging. */ + mb_geom->use_deform = false; + oedata->geom_update = false; + + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]); + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_NEXT]); } + /* Keep to modify later (after init). */ + mb_geom->batch = batch; } + } + else if (is_deform) { + /* Store vertex position buffer. */ + mb_geom->vbo[mb_step] = DRW_cache_object_pos_vertbuf_get(ob); + mb_geom->use_deform = (mb_geom->vbo[mb_step] != NULL); + } + else { + mb_geom->vbo[mb_step] = NULL; + mb_geom->use_deform = false; + } + } +} + +void EEVEE_motion_blur_cache_finish(EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + GHashIterator ghi; - effects->motion_blur_mat_cached = view_is_valid && !DRW_state_is_image_render(); + if ((effects->enabled_effects & EFFECT_MOTION_BLUR) == 0) { + return; + } - /* Current matrix */ - if (effects->motion_blur_mat_cached == false) { - eevee_motion_blur_camera_get_matrix_at_time( - scene, region, rv3d, v3d, ob_camera_eval, ctime, effects->current_world_to_ndc); - } + int mb_step = effects->motion_blur_step; + + if (mb_step != MB_CURR) { + /* Push instances attributes to the GPU. */ + DRW_render_instance_buffer_finish(); + + /* Need to be called after DRW_render_instance_buffer_finish() */ + /* Also we weed to have a correct fbo bound for DRW_hair_update */ + GPU_framebuffer_bind(vedata->fbl->main_fb); + DRW_hair_update(); - /* Only continue if camera is not being keyed */ - if (DRW_state_is_image_render() || - compare_m4m4(persmat, effects->current_world_to_ndc, 0.0001f)) { - /* Past matrix */ - if (effects->motion_blur_mat_cached == false) { - eevee_motion_blur_camera_get_matrix_at_time( - scene, region, rv3d, v3d, ob_camera_eval, ctime - delta, effects->past_world_to_ndc); - -#if 0 /* for future high quality blur */ - /* Future matrix */ - eevee_motion_blur_camera_get_matrix_at_time( - scene, region, rv3d, v3d, ob_camera_eval, ctime + delta, effects->future_world_to_ndc); -#endif - invert_m4_m4(effects->current_ndc_to_world, effects->current_world_to_ndc); + DRW_cache_restart(); + } + + for (BLI_ghashIterator_init(&ghi, effects->motion_blur.geom); + BLI_ghashIterator_done(&ghi) == false; + BLI_ghashIterator_step(&ghi)) { + EEVEE_GeometryMotionData *mb_geom = BLI_ghashIterator_getValue(&ghi); + + if (!mb_geom->use_deform) { + continue; + } + + switch (mb_geom->type) { + case EEVEE_HAIR_GEOM_MOTION_DATA: + if (mb_step == MB_CURR) { + /* TODO(fclem) Check if vertex count mismatch. */ + mb_geom->use_deform = true; } + else { + mb_geom->hair_pos[mb_step] = GPU_vertbuf_duplicate(mb_geom->hair_pos[mb_step]); - effects->motion_blur_mat_cached = true; - effects->motion_blur_samples = scene_eval->eevee.motion_blur_samples; + /* Create vbo immediately to bind to texture buffer. */ + GPU_vertbuf_use(mb_geom->hair_pos[mb_step]); - if (!e_data.motion_blur_sh) { - eevee_create_shader_motion_blur(); + mb_geom->hair_pos_tx[mb_step] = GPU_texture_create_from_vertbuf( + mb_geom->hair_pos[mb_step]); + } + break; + + case EEVEE_MESH_GEOM_MOTION_DATA: + if (mb_step == MB_CURR) { + /* Modify batch to have data from adjacent frames. */ + GPUBatch *batch = mb_geom->batch; + for (int i = 0; i < MB_CURR; i++) { + GPUVertBuf *vbo = mb_geom->vbo[i]; + if (vbo && batch) { + if (vbo->vertex_len != batch->verts[0]->vertex_len) { + /* Vertex count mismatch, disable deform motion blur. */ + mb_geom->use_deform = false; + } + + if (mb_geom->use_deform == false) { + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]); + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_NEXT]); + break; + } + else { + /* Modify the batch to include the previous & next position. */ + if (i == MB_PREV) { + GPU_batch_vertbuf_add_ex(batch, vbo, true); + mb_geom->vbo[i] = NULL; + } + else { + /* This VBO can be reuse by next time step. Don't pass ownership. */ + GPU_batch_vertbuf_add_ex(batch, vbo, false); + } + } + } + } + } + else { + GPUVertBuf *vbo = mb_geom->vbo[mb_step]; + /* If this assert fails, it means that different EEVEE_GeometryMotionDatas + * has been used for each motion blur step. */ + BLI_assert(vbo); + if (vbo) { + /* Use the vbo to perform the copy on the GPU. */ + GPU_vertbuf_use(vbo); + /* Perform a copy to avoid loosing it after RE_engine_frame_set(). */ + mb_geom->vbo[mb_step] = vbo = GPU_vertbuf_duplicate(vbo); + /* Find and replace "pos" attrib name. */ + int attrib_id = GPU_vertformat_attr_id_get(&vbo->format, "pos"); + GPU_vertformat_attr_rename( + &vbo->format, attrib_id, (mb_step == MB_PREV) ? "prv" : "nxt"); + } } + break; - return EFFECT_MOTION_BLUR | EFFECT_POST_BUFFER; - } + default: + BLI_assert(0); + break; } } - - return 0; } -void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_motion_blur_swap_data(EEVEE_Data *vedata) { - EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); + GHashIterator ghi; - if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { - DRW_PASS_CREATE(psl->motion_blur, DRW_STATE_WRITE_COLOR); + BLI_assert((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.motion_blur_sh, psl->motion_blur); - DRW_shgroup_uniform_int(grp, "samples", &effects->motion_blur_samples, 1); - DRW_shgroup_uniform_mat4(grp, "currInvViewProjMatrix", effects->current_ndc_to_world); - DRW_shgroup_uniform_mat4(grp, "pastViewProjMatrix", effects->past_world_to_ndc); - DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_call(grp, quad, NULL); + /* Camera Data. */ + effects->motion_blur.camera[MB_PREV] = effects->motion_blur.camera[MB_CURR]; + + /* Object Data. */ + for (BLI_ghashIterator_init(&ghi, effects->motion_blur.object); + BLI_ghashIterator_done(&ghi) == false; + BLI_ghashIterator_step(&ghi)) { + EEVEE_ObjectMotionData *mb_data = BLI_ghashIterator_getValue(&ghi); + + copy_m4_m4(mb_data->obmat[MB_PREV], mb_data->obmat[MB_NEXT]); + } + + /* Deformation Data. */ + for (BLI_ghashIterator_init(&ghi, effects->motion_blur.geom); + BLI_ghashIterator_done(&ghi) == false; + BLI_ghashIterator_step(&ghi)) { + EEVEE_GeometryMotionData *mb_geom = BLI_ghashIterator_getValue(&ghi); + + switch (mb_geom->type) { + case EEVEE_HAIR_GEOM_MOTION_DATA: + GPU_VERTBUF_DISCARD_SAFE(mb_geom->hair_pos[MB_PREV]); + DRW_TEXTURE_FREE_SAFE(mb_geom->hair_pos_tx[MB_PREV]); + mb_geom->hair_pos[MB_PREV] = mb_geom->hair_pos[MB_NEXT]; + mb_geom->hair_pos_tx[MB_PREV] = mb_geom->hair_pos_tx[MB_NEXT]; + break; + + case EEVEE_MESH_GEOM_MOTION_DATA: + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]); + mb_geom->vbo[MB_PREV] = mb_geom->vbo[MB_NEXT]; + + if (mb_geom->vbo[MB_NEXT]) { + GPUVertBuf *vbo = mb_geom->vbo[MB_NEXT]; + int attrib_id = GPU_vertformat_attr_id_get(&vbo->format, "nxt"); + GPU_vertformat_attr_rename(&vbo->format, attrib_id, "prv"); + } + break; + + default: + BLI_assert(0); + break; + } } } @@ -216,6 +568,30 @@ void EEVEE_motion_blur_draw(EEVEE_Data *vedata) /* Motion Blur */ if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { + /* Create velocity max tiles in 2 passes. One for each dimension. */ + GPU_framebuffer_bind(fbl->velocity_tiles_fb[0]); + DRW_draw_pass(psl->velocity_tiles_x); + + GPU_framebuffer_bind(fbl->velocity_tiles_fb[1]); + DRW_draw_pass(psl->velocity_tiles); + + /* Expand the tiles by reading the neighborhood. Do as many passes as required. */ + int buf = 0; + for (int i = effects->motion_blur_max; i > 0; i -= EEVEE_VELOCITY_TILE_SIZE) { + GPU_framebuffer_bind(fbl->velocity_tiles_fb[buf]); + + /* Change viewport to avoid invoking more pixel shaders than necessary since in one of the + * buffer the texture is way bigger in height. This avoid creating another texture and + * reduce VRAM usage. */ + int w = GPU_texture_width(effects->velocity_tiles_tx); + int h = GPU_texture_height(effects->velocity_tiles_tx); + GPU_framebuffer_viewport_set(fbl->velocity_tiles_fb[buf], 0, 0, w, h); + + DRW_draw_pass(psl->velocity_tiles_expand[buf]); + + buf = buf ? 0 : 1; + } + GPU_framebuffer_bind(effects->target_buffer); DRW_draw_pass(psl->motion_blur); SWAP_BUFFERS(); @@ -225,4 +601,8 @@ void EEVEE_motion_blur_draw(EEVEE_Data *vedata) void EEVEE_motion_blur_free(void) { DRW_SHADER_FREE_SAFE(e_data.motion_blur_sh); + DRW_SHADER_FREE_SAFE(e_data.motion_blur_object_sh); + DRW_SHADER_FREE_SAFE(e_data.motion_blur_hair_sh); + DRW_SHADER_FREE_SAFE(e_data.velocity_tiles_sh); + DRW_SHADER_FREE_SAFE(e_data.velocity_tiles_expand_sh); } diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index f5ebbe08dd1..a075210967c 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -155,7 +155,7 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ao_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->ao_accum_fb); GPU_framebuffer_clear_color(fbl->ao_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 40008c5c364..5005c5a8ba9 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -29,6 +29,8 @@ #include "DNA_lightprobe_types.h" +#include "BKE_camera.h" + struct EEVEE_ShadowCasterBuffer; struct GPUFrameBuffer; struct Object; @@ -256,7 +258,12 @@ typedef struct EEVEE_PassList { struct DRWPass *sss_translucency_ps; struct DRWPass *color_downsample_ps; struct DRWPass *color_downsample_cube_ps; + struct DRWPass *velocity_object; + struct DRWPass *velocity_hair; struct DRWPass *velocity_resolve; + struct DRWPass *velocity_tiles_x; + struct DRWPass *velocity_tiles; + struct DRWPass *velocity_tiles_expand[2]; struct DRWPass *taa_resolve; struct DRWPass *alpha_checker; @@ -327,6 +334,8 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *renderpass_fb; struct GPUFrameBuffer *ao_accum_fb; struct GPUFrameBuffer *velocity_resolve_fb; + struct GPUFrameBuffer *velocity_fb; + struct GPUFrameBuffer *velocity_tiles_fb[2]; struct GPUFrameBuffer *update_noise_fb; @@ -556,6 +565,58 @@ enum { PROBE_UPDATE_ALL = 0xFFFFFF, }; +/* ************** MOTION BLUR ************ */ + +#define MB_PREV 0 +#define MB_NEXT 1 +#define MB_CURR 2 + +typedef struct EEVEE_MotionBlurData { + struct GHash *object; + struct GHash *geom; + struct { + float viewmat[4][4]; + float persmat[4][4]; + float persinv[4][4]; + } camera[3]; + DRWShadingGroup *hair_grp; +} EEVEE_MotionBlurData; + +typedef struct EEVEE_ObjectKey { + /** Object or source object for duplis */ + struct Object *ob; + /** Parent object for duplis */ + struct Object *parent; + /** Dupli objects recursive unique identifier */ + int id[16]; /* 2*MAX_DUPLI_RECUR */ +} EEVEE_ObjectKey; + +typedef struct EEVEE_ObjectMotionData { + float obmat[3][4][4]; +} EEVEE_ObjectMotionData; + +typedef enum eEEVEEMotionData { + EEVEE_MESH_GEOM_MOTION_DATA = 0, + EEVEE_HAIR_GEOM_MOTION_DATA, +} eEEVEEMotionData; + +typedef struct EEVEE_GeometryMotionData { + eEEVEEMotionData type; + int use_deform; /* To disable deform mb if vertcount mismatch. */ + union { + struct { + /* Mesh */ + struct GPUBatch *batch; /* Batch for time = t. */ + struct GPUVertBuf *vbo[2]; /* Vbo for time = t +/- step. */ + }; + struct { + /* Hair */ + struct GPUVertBuf *hair_pos[2]; /* Position buffer for time = t +/- step. */ + struct GPUTexture *hair_pos_tx[2]; /* Buffer Texture of the corresponding VBO. */ + }; + }; +} EEVEE_GeometryMotionData; + /* ************ EFFECTS DATA ************* */ typedef enum EEVEE_EffectsFlag { @@ -607,9 +668,10 @@ typedef struct EEVEE_EffectsInfo { int taa_render_sample; int taa_total_sample; float taa_alpha; + bool bypass_drawing; bool prev_drw_support; bool prev_is_navigating; - float prev_drw_persmat[4][4]; + float prev_drw_persmat[4][4]; /* Used for checking view validity and reprojection. */ struct DRWView *taa_view; /* Ambient Occlusion */ int ao_depth_layer; @@ -617,15 +679,24 @@ typedef struct EEVEE_EffectsInfo { struct GPUTexture *gtao_horizons; /* Textures from pool */ struct GPUTexture *gtao_horizons_debug; /* Motion Blur */ - float current_world_to_ndc[4][4]; float current_ndc_to_world[4][4]; + float current_world_to_ndc[4][4]; + float current_world_to_view[4][4]; float past_world_to_ndc[4][4]; - int motion_blur_samples; - bool motion_blur_mat_cached; + float past_world_to_view[4][4]; + CameraParams past_cam_params; + CameraParams current_cam_params; + char motion_blur_step; /* Which step we are evaluating. */ + int motion_blur_max; /* Maximum distance in pixels a motion blured pixel can cover. */ + float motion_blur_near_far[2]; /* Camera near/far clip distances (positive). */ + bool cam_params_init; + /* TODO(fclem) Only used in render mode for now. + * This is because we are missing a per scene persistent place to hold this. */ + struct EEVEE_MotionBlurData motion_blur; /* Velocity Pass */ - float velocity_curr_persinv[4][4]; - float velocity_past_persmat[4][4]; struct GPUTexture *velocity_tx; /* Texture from pool */ + struct GPUTexture *velocity_tiles_x_tx; + struct GPUTexture *velocity_tiles_tx; /* Depth Of Field */ float dof_near_far[2]; float dof_params[2]; @@ -805,6 +876,7 @@ typedef struct EEVEE_ObjectEngineData { bool ob_vis, ob_vis_dirty; bool need_update; + bool geom_update; uint shadow_caster_id; } EEVEE_ObjectEngineData; @@ -880,15 +952,25 @@ typedef struct EEVEE_PrivateData { struct DRWView *world_views[6]; /** For rendering planar reflections. */ struct DRWView *planar_views[MAX_PLANAR]; + + int render_tot_samples; } EEVEE_PrivateData; /* Transient data */ /* eevee_data.c */ +void EEVEE_motion_blur_data_init(EEVEE_MotionBlurData *mb); +void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb); void EEVEE_view_layer_data_free(void *sldata); EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void); EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_layer); EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void); EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob); EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob); +EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, + Object *ob, + bool hair); +EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_MotionBlurData *mb, + Object *ob, + bool hair); EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob); EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob); EEVEE_LightEngineData *EEVEE_light_data_get(Object *ob); @@ -896,6 +978,8 @@ EEVEE_LightEngineData *EEVEE_light_data_ensure(Object *ob); EEVEE_WorldEngineData *EEVEE_world_data_get(World *wo); EEVEE_WorldEngineData *EEVEE_world_data_ensure(World *wo); +void eevee_id_update(void *vedata, ID *id); + /* eevee_materials.c */ struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, @@ -1112,8 +1196,17 @@ void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data void EEVEE_subsurface_free(void); /* eevee_motion_blur.c */ -int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera); +int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_motion_blur_step_set(EEVEE_Data *vedata, int step); void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *ob); +void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + Object *ob, + struct ParticleSystem *psys, + struct ModifierData *md); +void EEVEE_motion_blur_swap_data(EEVEE_Data *vedata); +void EEVEE_motion_blur_cache_finish(EEVEE_Data *vedata); void EEVEE_motion_blur_draw(EEVEE_Data *vedata); void EEVEE_motion_blur_free(void); @@ -1127,6 +1220,7 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata); void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples); +void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, bool post_effect); @@ -1140,6 +1234,7 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata); /* eevee_temporal_sampling.c */ void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata); +void EEVEE_temporal_sampling_create_view(EEVEE_Data *vedata); int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_temporal_sampling_offset_calc(const double ht_point[2], const float filter_size, @@ -1183,6 +1278,10 @@ void EEVEE_effects_free(void); bool EEVEE_render_init(EEVEE_Data *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph); +void EEVEE_render_view_sync(EEVEE_Data *vedata, + struct RenderEngine *engine, + struct Depsgraph *depsgraph); +void EEVEE_render_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_render_cache(void *vedata, struct Object *ob, struct RenderEngine *engine, @@ -1191,6 +1290,10 @@ void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *engine, struct RenderLayer *render_layer, const struct rcti *rect); +void EEVEE_render_read_result(EEVEE_Data *vedata, + struct RenderEngine *engine, + struct RenderLayer *rl, + const rcti *rect); void EEVEE_render_update_passes(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer); diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 89a5ad2198a..f903fa905e8 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -131,6 +131,29 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * &sldata->common_data); } + EEVEE_render_view_sync(vedata, engine, depsgraph); + + /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */ + struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); + + DRWView *view = (DRWView *)DRW_view_default_get(); + DRW_view_camtexco_set(view, camtexcofac); + + /* `EEVEE_renderpasses_init` will set the active render passes used by `EEVEE_effects_init`. + * `EEVEE_effects_init` needs to go second for TAA. */ + EEVEE_renderpasses_init(vedata); + EEVEE_effects_init(sldata, vedata, ob_camera_eval, false); + EEVEE_materials_init(sldata, vedata, stl, fbl); + EEVEE_shadows_init(sldata); + EEVEE_lightprobes_init(sldata, vedata); + + return true; +} + +void EEVEE_render_view_sync(EEVEE_Data *vedata, RenderEngine *engine, struct Depsgraph *depsgraph) +{ + EEVEE_PrivateData *g_data = vedata->stl->g_data; + /* Set the pers & view matrix. */ float winmat[4][4], viewmat[4][4], viewinv[4][4]; /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */ @@ -143,19 +166,13 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * invert_m4_m4(viewmat, viewinv); DRWView *view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); - DRW_view_camtexco_set(view, camtexcofac); + DRW_view_reset(); DRW_view_default_set(view); DRW_view_set_active(view); +} - /* `EEVEE_renderpasses_init` will set the active render passes used by `EEVEE_effects_init`. - * `EEVEE_effects_init` needs to go second for TAA. */ - EEVEE_renderpasses_init(vedata); - EEVEE_effects_init(sldata, vedata, ob_camera_eval, false); - EEVEE_materials_init(sldata, vedata, stl, fbl); - EEVEE_shadows_init(sldata); - EEVEE_lightprobes_init(sldata, vedata); - - /* INIT CACHE */ +void EEVEE_render_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ EEVEE_bloom_cache_init(sldata, vedata); EEVEE_depth_of_field_cache_init(sldata, vedata); EEVEE_effects_cache_init(sldata, vedata); @@ -168,8 +185,6 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * EEVEE_subsurface_cache_init(sldata, vedata); EEVEE_temporal_sampling_cache_init(sldata, vedata); EEVEE_volumes_cache_init(sldata, vedata); - - return true; } /* Used by light cache. in this case engine is NULL. */ @@ -182,6 +197,8 @@ void EEVEE_render_cache(void *vedata, EEVEE_LightProbesInfo *pinfo = sldata->probes; bool cast_shadow = false; + eevee_id_update(vedata, &ob->id); + if (pinfo->vis_data.collection) { /* Used for rendering probe with visibility groups. */ bool ob_vis = BKE_collection_has_object_recursive(pinfo->vis_data.collection, ob); @@ -478,27 +495,12 @@ static void eevee_render_draw_background(EEVEE_Data *vedata) void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl, const rcti *rect) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); const char *viewname = RE_GetActiveRenderView(engine->re); EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); - EEVEE_PrivateData *g_data = stl->g_data; - - /* FINISH CACHE */ - EEVEE_volumes_cache_finish(sldata, vedata); - EEVEE_materials_cache_finish(sldata, vedata); - EEVEE_lights_cache_finish(sldata, vedata); - EEVEE_lightprobes_cache_finish(sldata, vedata); - - EEVEE_effects_draw_init(sldata, vedata); - EEVEE_volumes_draw_init(sldata, vedata); - - /* Sort transparents before the loop. */ - DRW_pass_sort_shgroup_z(psl->transparent_pass); /* Push instances attributes to the GPU. */ DRW_render_instance_buffer_finish(); @@ -508,20 +510,17 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl GPU_framebuffer_bind(fbl->main_fb); DRW_hair_update(); - uint tot_sample = scene_eval->eevee.taa_render_samples; + /* Sort transparents before the loop. */ + DRW_pass_sort_shgroup_z(psl->transparent_pass); + + uint tot_sample = stl->g_data->render_tot_samples; uint render_samples = 0; /* SSR needs one iteration to start properly. */ - if (stl->effects->enabled_effects & EFFECT_SSR) { + if ((stl->effects->enabled_effects & EFFECT_SSR) && !stl->effects->ssr_was_valid_double_buffer) { tot_sample += 1; } - EEVEE_renderpasses_output_init(sldata, vedata, tot_sample); - - if (RE_engine_test_break(engine)) { - return; - } - while (render_samples < tot_sample && !RE_engine_test_break(engine)) { float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float clear_depth = 1.0f; @@ -617,6 +616,15 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl RE_engine_update_progress(engine, (float)(render_samples++) / (float)tot_sample); } +} + +void EEVEE_render_read_result(EEVEE_Data *vedata, + RenderEngine *engine, + RenderLayer *rl, + const rcti *rect) +{ + const char *viewname = RE_GetActiveRenderView(engine->re); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); eevee_render_result_combined(rl, viewname, rect, vedata, sldata); eevee_render_result_mist(rl, viewname, rect, vedata, sldata); @@ -631,9 +639,6 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl eevee_render_result_bloom(rl, viewname, rect, vedata, sldata); eevee_render_result_volume_scatter(rl, viewname, rect, vedata, sldata); eevee_render_result_volume_transmittance(rl, viewname, rect, vedata, sldata); - - /* Restore original viewport size. */ - DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]}); } void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 9a47ca19e7b..be771d7cf42 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -136,24 +136,13 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; - EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; EEVEE_PrivateData *g_data = stl->g_data; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); const bool needs_post_processing = (g_data->render_passes & EEVEE_RENDERPASSES_WITH_POST_PROCESSING) > 0; if (needs_post_processing) { - if (e_data.postprocess_sh == NULL) { - char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_common_uniforms_lib_glsl, - datatoc_bsdf_common_lib_glsl, - datatoc_renderpass_postprocess_frag_glsl); - e_data.postprocess_sh = DRW_shader_create_fullscreen(frag_str, NULL); - MEM_freeN(frag_str); - } - /* Create FrameBuffer. */ /* Should be enough to store the data needs for a single pass. @@ -188,29 +177,51 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, EEVEE_volumes_output_init(sldata, vedata, tot_samples); } - /* Create Pass. */ - DRW_PASS_CREATE(psl->renderpass_pass, DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.postprocess_sh, psl->renderpass_pass); /* We set a default texture as not all post processes uses the inputBuffer. */ g_data->renderpass_input = txl->color; g_data->renderpass_col_input = txl->color; g_data->renderpass_light_input = txl->color; + } + else { + /* Free unneeded memory */ + DRW_TEXTURE_FREE_SAFE(txl->renderpass); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->renderpass_fb); + } +} + +void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_PrivateData *g_data = vedata->stl->g_data; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + const bool needs_post_processing = (g_data->render_passes & + EEVEE_RENDERPASSES_WITH_POST_PROCESSING) > 0; + if (needs_post_processing) { + if (e_data.postprocess_sh == NULL) { + char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_renderpass_postprocess_frag_glsl); + e_data.postprocess_sh = DRW_shader_create_fullscreen(frag_str, NULL); + MEM_freeN(frag_str); + } + + DRW_PASS_CREATE(psl->renderpass_pass, DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.postprocess_sh, psl->renderpass_pass); DRW_shgroup_uniform_texture_ref(grp, "inputBuffer", &g_data->renderpass_input); DRW_shgroup_uniform_texture_ref(grp, "inputColorBuffer", &g_data->renderpass_col_input); DRW_shgroup_uniform_texture_ref( grp, "inputSecondLightBuffer", &g_data->renderpass_light_input); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_uniform_block_ref(grp, "common_block", &sldata->common_ubo); + DRW_shgroup_uniform_block_ref(grp, "renderpass_block", &sldata->renderpass_ubo.combined); DRW_shgroup_uniform_int(grp, "currentSample", &g_data->renderpass_current_sample, 1); DRW_shgroup_uniform_int(grp, "renderpassType", &g_data->renderpass_type, 1); DRW_shgroup_uniform_int(grp, "postProcessType", &g_data->renderpass_postprocess, 1); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } else { - /* Free unneeded memory */ - DRW_TEXTURE_FREE_SAFE(txl->renderpass); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->renderpass_fb); psl->renderpass_pass = NULL; } } diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index cece67334c5..32d758dba4b 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -358,7 +358,7 @@ void EEVEE_reflection_output_init(EEVEE_ViewLayerData *UNUSED(sldata), {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ssr_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->ssr_accum_fb); GPU_framebuffer_clear_color(fbl->ssr_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c index 84c50a22ae6..d0e430e115f 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows.c +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -412,7 +412,7 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->shadow_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->shadow_accum_fb); GPU_framebuffer_clear_color(fbl->shadow_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 7674148f76a..ef4588f4aca 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -75,18 +75,8 @@ static void eevee_create_shader_subsurface(void) MEM_freeN(frag_str); } -void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *UNUSED(vedata)) { - EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - - effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2; - effects->sss_surface_count = 0; - common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold; } void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) @@ -197,22 +187,31 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), * already higher than one. This is noticeable when loading a file that has the diffuse light * pass in look dev mode active. `texture_created` will make sure that newly created textures * are cleared. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1 || texture_created) { + if (effects->taa_current_sample == 1 || texture_created) { float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; GPU_framebuffer_bind(fbl->sss_accum_fb); GPU_framebuffer_clear_color(fbl->sss_accum_fb, clear); } } -void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + EEVEE_EffectsInfo *effects = vedata->stl->effects; EEVEE_PassList *psl = vedata->psl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); + /* Shaders */ if (!e_data.sss_sh[0]) { eevee_create_shader_subsurface(); } + effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2; + effects->sss_surface_count = 0; + common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold; + /** Screen Space SubSurface Scattering overview * TODO */ diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index d57048f2c4e..714481c39f1 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -186,6 +186,18 @@ void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata) vedata->stl->effects->taa_current_sample = 1; } +void EEVEE_temporal_sampling_create_view(EEVEE_Data *vedata) +{ + EEVEE_EffectsInfo *effects = vedata->stl->effects; + /* Create a sub view to disable clipping planes (if any). */ + const DRWView *default_view = DRW_view_default_get(); + float viewmat[4][4], winmat[4][4]; + DRW_view_viewmat_get(default_view, viewmat, false); + DRW_view_winmat_get(default_view, winmat, false); + effects->taa_view = DRW_view_create_sub(default_view, viewmat, winmat); + DRW_view_clip_planes_set(effects->taa_view, NULL, 0); +} + int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; @@ -201,15 +213,9 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data * we accumulate the redraw inside the drawing loop in eevee_draw_scene(). **/ effects->taa_render_sample = 1; - effects->taa_view = NULL; + effects->bypass_drawing = false; - /* Create a sub view to disable clipping planes (if any). */ - const DRWView *default_view = DRW_view_default_get(); - float viewmat[4][4], winmat[4][4]; - DRW_view_viewmat_get(default_view, viewmat, false); - DRW_view_winmat_get(default_view, winmat, false); - effects->taa_view = DRW_view_create_sub(default_view, viewmat, winmat); - DRW_view_clip_planes_set(effects->taa_view, NULL, 0); + EEVEE_temporal_sampling_create_view(vedata); const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); @@ -241,7 +247,6 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data DRW_view_persmat_get(NULL, persmat, false); view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN); - copy_m4_m4(effects->prev_drw_persmat, persmat); /* Prevent ghosting from probe data. */ view_is_valid = view_is_valid && (effects->prev_drw_support == DRW_state_draw_support()) && @@ -251,7 +256,7 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data if (((effects->taa_total_sample == 0) || (effects->taa_current_sample < effects->taa_total_sample)) || - DRW_state_is_image_render()) { + (!view_is_valid) || DRW_state_is_image_render()) { if (view_is_valid) { /* Viewport rendering updates the matrices in `eevee_draw_scene` */ if (!DRW_state_is_image_render()) { @@ -264,7 +269,7 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data } } else { - effects->taa_current_sample = 1; + effects->bypass_drawing = true; } return repro_flag | EFFECT_TAA | EFFECT_DOUBLE_BUFFER | EFFECT_DEPTH_DOUBLE_BUFFER | @@ -283,7 +288,7 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; - if ((effects->enabled_effects & (EFFECT_TAA | EFFECT_TAA_REPROJECT)) != 0) { + if (effects->enabled_effects & EFFECT_TAA) { struct GPUShader *sh = EEVEE_shaders_taa_resolve_sh_get(effects->enabled_effects); DRW_PASS_CREATE(psl->taa_resolve, DRW_STATE_WRITE_COLOR); @@ -295,8 +300,9 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); if (effects->enabled_effects & EFFECT_TAA_REPROJECT) { - // DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - DRW_shgroup_uniform_texture_ref(grp, "velocityBuffer", &effects->velocity_tx); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_mat4(grp, "prevViewProjectionMatrix", effects->prev_drw_persmat); } else { DRW_shgroup_uniform_float(grp, "alpha", &effects->taa_alpha, 1); @@ -359,10 +365,13 @@ void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata) effects->taa_current_sample += 1; } else { - if ((effects->taa_total_sample == 0) || - (effects->taa_current_sample < effects->taa_total_sample)) { + if (!DRW_state_is_playback() && + ((effects->taa_total_sample == 0) || + (effects->taa_current_sample < effects->taa_total_sample))) { DRW_viewport_request_redraw(); } } + + DRW_view_persmat_get(NULL, effects->prev_drw_persmat, false); } } diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 90860e94270..17f53113939 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -894,7 +894,7 @@ void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->volumetric_accum_fb); GPU_framebuffer_clear_color(fbl->volumetric_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 402d306df45..393ecaf1fc5 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -877,6 +877,14 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac) { Closure cl; cl.holdout = mix(cl1.holdout, cl2.holdout, fac); + + if (FLAG_TEST(cl1.flag, CLOSURE_HOLDOUT_FLAG)) { + fac = 1.0; + } + else if (FLAG_TEST(cl2.flag, CLOSURE_HOLDOUT_FLAG)) { + fac = 0.0; + } + cl.transmittance = mix(cl1.transmittance, cl2.transmittance, fac); cl.radiance = mix(cl1.radiance, cl2.radiance, fac); cl.flag = cl1.flag | cl2.flag; @@ -958,7 +966,7 @@ void main() { Closure cl = nodetree_exec(); - float holdout = 1.0 - saturate(cl.holdout); + float holdout = saturate(1.0 - cl.holdout); float transmit = saturate(avg(cl.transmittance)); float alpha = 1.0 - transmit; @@ -972,8 +980,9 @@ void main() * Since we do that using the blending pipeline we need to account for material transmittance. */ vol_scatter -= vol_scatter * cl.transmittance; - outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, alpha * holdout); - outTransmittance = vec4(cl.transmittance, transmit * holdout); + cl.radiance = cl.radiance * holdout * vol_transmit + vol_scatter; + outRadiance = vec4(cl.radiance, alpha * holdout); + outTransmittance = vec4(cl.transmittance, transmit) * holdout; # else outRadiance = vec4(cl.radiance, holdout); ssrNormals = cl.ssr_normal; diff --git a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl index b7935235d06..fbf507a2e40 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl @@ -1,64 +1,235 @@ +/* + * Based on: + * A Fast and Stable Feature-Aware Motion Blur Filter + * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai + * + * With modification from the presentation: + * Next Generation Post Processing in Call of Duty Advanced Warfare + * by Jorge Jimenez + */ uniform sampler2D colorBuffer; uniform sampler2D depthBuffer; +uniform sampler2D velocityBuffer; +uniform sampler2D tileMaxBuffer; -/* current frame */ -uniform mat4 currInvViewProjMatrix; +#define KERNEL 8 -/* past frame frame */ -uniform mat4 pastViewProjMatrix; +/* TODO(fclem) deduplicate this code. */ +uniform sampler2DArray utilTex; +#define LUT_SIZE 64 +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) + +uniform float depthScale; +uniform ivec2 tileBufferSize; +uniform vec2 viewportSize; +uniform vec2 viewportSizeInv; +uniform bool isPerspective; +uniform vec2 nearFar; /* Near & far view depths values */ + +#define linear_depth(z) \ + ((isPerspective) ? (nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) : \ + z * (nearFar.y - nearFar.x) + nearFar.x) /* Only true for camera view! */ in vec4 uvcoordsvar; -out vec4 FragColor; +out vec4 fragColor; -#define MAX_SAMPLE 64 +#define saturate(a) clamp(a, 0.0, 1.0) -uniform int samples; +vec2 spread_compare(float center_motion_length, float sample_motion_length, float offset_length) +{ + return saturate(vec2(center_motion_length, sample_motion_length) - offset_length + 1.0); +} -float wang_hash_noise(uint s) +vec2 depth_compare(float center_depth, float sample_depth) { - uint seed = (uint(gl_FragCoord.x) * 1664525u + uint(gl_FragCoord.y)) + s; + return saturate(0.5 + vec2(depthScale, -depthScale) * (sample_depth - center_depth)); +} - seed = (seed ^ 61u) ^ (seed >> 16u); - seed *= 9u; - seed = seed ^ (seed >> 4u); - seed *= 0x27d4eb2du; - seed = seed ^ (seed >> 15u); +/* Kill contribution if not going the same direction. */ +float dir_compare(vec2 offset, vec2 sample_motion, float sample_motion_length) +{ + if (sample_motion_length < 0.5) { + return 1.0; + } + return (dot(offset, sample_motion) > 0.0) ? 1.0 : 0.0; +} - float value = float(seed); - value *= 1.0 / 4294967296.0; - return fract(value); +/* Return background (x) and foreground (y) weights. */ +vec2 sample_weights(float center_depth, + float sample_depth, + float center_motion_length, + float sample_motion_length, + float offset_length) +{ + /* Clasify foreground/background. */ + vec2 depth_weight = depth_compare(center_depth, sample_depth); + /* Weight if sample is overlapping or under the center pixel. */ + vec2 spread_weight = spread_compare(center_motion_length, sample_motion_length, offset_length); + return depth_weight * spread_weight; } -void main() +vec4 decode_velocity(vec4 velocity) { - vec3 ndc_pos; - ndc_pos.xy = uvcoordsvar.xy; - ndc_pos.z = texture(depthBuffer, uvcoordsvar.xy).x; + velocity = velocity * 2.0 - 1.0; + /* Needed to match cycles. Can't find why... (fclem) */ + velocity *= 0.5; + /* Transpose to pixelspace. */ + velocity *= viewportSize.xyxy; + return velocity; +} - float inv_samples = 1.0 / float(samples); - float noise = 2.0 * wang_hash_noise(0u) * inv_samples; +vec4 sample_velocity(vec2 uv) +{ + vec4 data = texture(velocityBuffer, uv); + return decode_velocity(data); +} - /* Normalize Device Coordinates are [-1, +1]. */ - ndc_pos = ndc_pos * 2.0 - 1.0; +vec2 sample_velocity(vec2 uv, const bool next) +{ + vec4 data = sample_velocity(uv); + data.xy = (next ? data.zw : data.xy); + return data.xy; +} - vec4 p = currInvViewProjMatrix * vec4(ndc_pos, 1.0); - vec3 world_pos = p.xyz / p.w; /* Perspective divide */ +void gather_sample(vec2 screen_uv, + float center_depth, + float center_motion_len, + vec2 offset, + float offset_len, + const bool next, + inout vec4 accum, + inout vec4 accum_bg, + inout vec3 w_accum) +{ + vec2 sample_uv = screen_uv - offset * viewportSizeInv; + vec2 sample_motion = sample_velocity(sample_uv, next); + float sample_motion_len = length(sample_motion); + float sample_depth = linear_depth(texture(depthBuffer, sample_uv).r); + vec4 col = textureLod(colorBuffer, sample_uv, 0.0); + + vec3 weights; + weights.xy = sample_weights( + center_depth, sample_depth, center_motion_len, sample_motion_len, offset_len); + weights.z = dir_compare(offset, sample_motion, sample_motion_len); + weights.xy *= weights.z; + + accum += col * weights.y; + accum_bg += col * weights.x; + w_accum += weights; +} - /* Now find where was this pixel position - * inside the past camera viewport */ - vec4 old_ndc = pastViewProjMatrix * vec4(world_pos, 1.0); - old_ndc.xyz /= old_ndc.w; /* Perspective divide */ +void gather_blur(vec2 screen_uv, + vec2 center_motion, + float center_depth, + vec2 max_motion, + float ofs, + const bool next, + inout vec4 accum, + inout vec4 accum_bg, + inout vec3 w_accum) +{ + float center_motion_len = length(center_motion); + float max_motion_len = length(max_motion); + + /* Tile boundaries randomization can fetch a tile where there is less motion than this pixel. + * Fix this by overriding the max_motion. */ + if (max_motion_len < center_motion_len) { + max_motion_len = center_motion_len; + max_motion = center_motion; + } - vec2 motion = (ndc_pos.xy - old_ndc.xy) * 0.25; /* 0.25 fit cycles ref */ + if (max_motion_len < 0.5) { + return; + } - float inc = 2.0 * inv_samples; - float i = -1.0 + noise; + int i; + float t, inc = 1.0 / float(KERNEL); + for (i = 0, t = ofs * inc; i < KERNEL; i++, t += inc) { + gather_sample(screen_uv, + center_depth, + center_motion_len, + max_motion * t, + max_motion_len * t, + next, + accum, + accum_bg, + w_accum); + } - FragColor = vec4(0.0); - for (int j = 0; j < samples && j < MAX_SAMPLE; j++) { - FragColor += textureLod(colorBuffer, uvcoordsvar.xy + motion * i, 0.0) * inv_samples; - i += inc; + if (center_motion_len < 0.5) { + return; } + + for (i = 0, t = ofs * inc; i < KERNEL; i++, t += inc) { + /* Also sample in center motion direction. + * Allow to recover motion where there is conflicting + * motion between foreground and background. */ + gather_sample(screen_uv, + center_depth, + center_motion_len, + center_motion * t, + center_motion_len * t, + next, + accum, + accum_bg, + w_accum); + } +} + +void main() +{ + vec2 uv = uvcoordsvar.xy; + + /* Data of the center pixel of the gather (target). */ + float center_depth = linear_depth(texture(depthBuffer, uv).r); + vec4 center_motion = sample_velocity(uv); + vec4 center_color = textureLod(colorBuffer, uv, 0.0); + + vec2 rand = texelfetch_noise_tex(gl_FragCoord.xy).xy; + + /* Randomize tile boundary to avoid ugly discontinuities. Randomize 1/4th of the tile. + * Note this randomize only in one direction but in practice it's enough. */ + rand.x = rand.x * 2.0 - 1.0; + ivec2 tile = ivec2(gl_FragCoord.xy + rand.x * float(EEVEE_VELOCITY_TILE_SIZE) * 0.25) / + EEVEE_VELOCITY_TILE_SIZE; + tile = clamp(tile, ivec2(0), tileBufferSize - 1); + vec4 max_motion = decode_velocity(texelFetch(tileMaxBuffer, tile, 0)); + + /* First (center) sample: time = T */ + /* x: Background, y: Foreground, z: dir. */ + vec3 w_accum = vec3(0.0, 0.0, 1.0); + vec4 accum_bg = vec4(0.0); + vec4 accum = vec4(0.0); + /* First linear gather. time = [T - delta, T] */ + gather_blur( + uv, center_motion.xy, center_depth, max_motion.xy, rand.y, false, accum, accum_bg, w_accum); + /* Second linear gather. time = [T, T + delta] */ + gather_blur( + uv, center_motion.zw, center_depth, max_motion.zw, rand.y, true, accum, accum_bg, w_accum); + +#if 1 + /* Avoid division by 0.0. */ + float w = 1.0 / (50.0 * float(KERNEL) * 4.0); + accum_bg += center_color * w; + w_accum.x += w; + /* Note: In Jimenez's presentation, they used center sample. + * We use background color as it contains more informations for foreground + * elements that have not enough weights. + * Yield beter blur in complex motion. */ + center_color = accum_bg / w_accum.x; +#endif + /* Merge background. */ + accum += accum_bg; + w_accum.y += w_accum.x; + /* Balance accumulation for failled samples. + * We replace the missing foreground by the background. */ + float blend_fac = saturate(1.0 - w_accum.y / w_accum.z); + fragColor = (accum / w_accum.z) + center_color * blend_fac; + +#if 0 /* For debugging. */ + fragColor.rgb = fragColor.ggg; + fragColor.rg += max_motion.xy; +#endif } diff --git a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl index 428318e3c68..b44645174bd 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl @@ -1,6 +1,6 @@ uniform sampler2D colorHistoryBuffer; -uniform sampler2D velocityBuffer; +uniform mat4 prevViewProjectionMatrix; out vec4 FragColor; @@ -38,16 +38,19 @@ vec3 clip_to_aabb(vec3 color, vec3 minimum, vec3 maximum, vec3 average) */ void main() { + vec2 screen_res = vec2(textureSize(colorBuffer, 0).xy); + vec2 uv = gl_FragCoord.xy / screen_res; ivec2 texel = ivec2(gl_FragCoord.xy); - vec2 motion = texelFetch(velocityBuffer, texel, 0).rg; - - /* Decode from unsigned normalized 16bit texture. */ - motion = motion * 2.0 - 1.0; /* Compute pixel position in previous frame. */ - vec2 screen_res = vec2(textureSize(colorBuffer, 0).xy); - vec2 uv = gl_FragCoord.xy / screen_res; - vec2 uv_history = uv - motion; + float depth = textureLod(depthBuffer, uv, 0.0).r; + vec3 pos = get_world_space_from_depth(uv, depth); + vec2 uv_history = project_point(prevViewProjectionMatrix, pos).xy * 0.5 + 0.5; + + /* HACK: Reject lookdev spheres from TAA reprojection. */ + if (depth == 0.0) { + uv_history = uv; + } ivec2 texel_history = ivec2(uv_history * screen_res); vec4 color_history = textureLod(colorHistoryBuffer, uv_history, 0.0); diff --git a/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl index 7d701bce5cb..d927fd78d30 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl @@ -1,8 +1,9 @@ -uniform mat4 currPersinv; -uniform mat4 pastPersmat; +uniform mat4 prevViewProjMatrix; +uniform mat4 currViewProjMatrixInv; +uniform mat4 nextViewProjMatrix; -out vec2 outData; +out vec4 outData; void main() { @@ -12,13 +13,12 @@ void main() float depth = texelFetch(depthBuffer, texel, 0).r; - vec3 world_position = project_point(currPersinv, vec3(uv, depth) * 2.0 - 1.0); - vec2 uv_history = project_point(pastPersmat, world_position).xy * 0.5 + 0.5; + vec3 world_position = project_point(currViewProjMatrixInv, vec3(uv, depth) * 2.0 - 1.0); + vec2 uv_prev = project_point(prevViewProjMatrix, world_position).xy * 0.5 + 0.5; + vec2 uv_next = project_point(nextViewProjMatrix, world_position).xy * 0.5 + 0.5; - outData = uv - uv_history; - - /* HACK: Reject lookdev spheres from TAA reprojection. */ - outData = (depth > 0.0) ? outData : vec2(0.0); + outData.xy = uv_prev - uv; + outData.zw = uv_next - uv; /* Encode to unsigned normalized 16bit texture. */ outData = outData * 0.5 + 0.5; diff --git a/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl new file mode 100644 index 00000000000..0eb598521af --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl @@ -0,0 +1,151 @@ +/** + * Shaders that down-sample velocity buffer, + * + * Based on: + * A Fast and Stable Feature-Aware Motion Blur Filter + * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai + * + * Adapted from G3D Innovation Engine implementation. + */ + +uniform sampler2D velocityBuffer; +uniform vec2 viewportSize; +uniform vec2 viewportSizeInv; +uniform ivec2 velocityBufferSize; + +out vec4 tileMaxVelocity; + +vec4 sample_velocity(ivec2 texel) +{ + texel = clamp(texel, ivec2(0), velocityBufferSize - 1); + vec4 data = texelFetch(velocityBuffer, texel, 0); + /* Decode data. */ + return (data * 2.0 - 1.0) * viewportSize.xyxy; +} + +vec4 encode_velocity(vec4 velocity) +{ + return velocity * viewportSizeInv.xyxy * 0.5 + 0.5; +} + +#ifdef TILE_GATHER + +uniform ivec2 gatherStep; + +void main() +{ + vec4 max_motion = vec4(0.0); + float max_motion_len_sqr_prev = 0.0; + float max_motion_len_sqr_next = 0.0; + ivec2 texel = ivec2(gl_FragCoord.xy); + texel = texel * gatherStep.yx + texel * EEVEE_VELOCITY_TILE_SIZE * gatherStep; + + for (int i = 0; i < EEVEE_VELOCITY_TILE_SIZE; ++i) { + vec4 motion = sample_velocity(texel + i * gatherStep); + float motion_len_sqr_prev = dot(motion.xy, motion.xy); + float motion_len_sqr_next = dot(motion.zw, motion.zw); + + if (motion_len_sqr_prev > max_motion_len_sqr_prev) { + max_motion_len_sqr_prev = motion_len_sqr_prev; + max_motion.xy = motion.xy; + } + if (motion_len_sqr_next > max_motion_len_sqr_next) { + max_motion_len_sqr_next = motion_len_sqr_next; + max_motion.zw = motion.zw; + } + } + + tileMaxVelocity = encode_velocity(max_motion); +} + +#else /* TILE_EXPANSION */ + +bool neighbor_affect_this_tile(ivec2 offset, vec2 velocity) +{ + /* Manhattan distance to the tiles, which is used for + * differentiating corners versus middle blocks */ + float displacement = float(abs(offset.x) + abs(offset.y)); + /** + * Relative sign on each axis of the offset compared + * to the velocity for that tile. In order for a tile + * to affect the center tile, it must have a + * neighborhood velocity in which x and y both have + * identical or both have opposite signs relative to + * offset. If the offset coordinate is zero then + * velocity is irrelevant. + **/ + vec2 point = sign(offset * velocity); + + float dist = (point.x + point.y); + /** + * Here's an example of the logic for this code. + * In this diagram, the upper-left tile has offset = (-1, -1). + * V1 is velocity = (1, -2). point in this case = (-1, 1), and therefore dist = 0, + * so the upper-left tile does not affect the center. + * + * Now, look at another case. V2 = (-1, -2). point = (1, 1), so dist = 2 and the tile + * does affect the center. + * + * V2(-1,-2) V1(1, -2) + * \ / + * \ / + * \/___ ____ ____ + * (-1, -1)| | | | + * |____|____|____| + * | | | | + * |____|____|____| + * | | | | + * |____|____|____| + **/ + return (abs(dist) == displacement); +} + +/** + * Only gather neighborhood velocity into tiles that could be affected by it. + * In the general case, only six of the eight neighbors contribute: + * + * This tile can't possibly be affected by the center one + * | + * v + * ____ ____ ____ + * | | ///|/// | + * |____|////|//__| + * | |////|/ | + * |___/|////|____| + * | //|////| | <--- This tile can't possibly be affected by the center one + * |_///|///_|____| + **/ +void main() +{ + vec4 max_motion = vec4(0.0); + float max_motion_len_sqr_prev = -1.0; + float max_motion_len_sqr_next = -1.0; + + ivec2 tile = ivec2(gl_FragCoord.xy); + ivec2 offset = ivec2(0); + for (offset.y = -1; offset.y <= 1; ++offset.y) { + for (offset.x = -1; offset.x <= 1; ++offset.x) { + vec4 motion = sample_velocity(tile + offset); + float motion_len_sqr_prev = dot(motion.xy, motion.xy); + float motion_len_sqr_next = dot(motion.zw, motion.zw); + + if (motion_len_sqr_prev > max_motion_len_sqr_prev) { + if (neighbor_affect_this_tile(offset, motion.xy)) { + max_motion_len_sqr_prev = motion_len_sqr_prev; + max_motion.xy = motion.xy; + } + } + + if (motion_len_sqr_next > max_motion_len_sqr_next) { + if (neighbor_affect_this_tile(offset, motion.zw)) { + max_motion_len_sqr_next = motion_len_sqr_next; + max_motion.zw = motion.zw; + } + } + } + } + + tileMaxVelocity = encode_velocity(max_motion); +} + +#endif
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/object_motion_frag.glsl b/source/blender/draw/engines/eevee/shaders/object_motion_frag.glsl new file mode 100644 index 00000000000..66b098ef6c5 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/object_motion_frag.glsl @@ -0,0 +1,27 @@ + +uniform mat4 prevViewProjMatrix; +uniform mat4 currViewProjMatrix; +uniform mat4 nextViewProjMatrix; + +in vec3 prevWorldPos; +in vec3 currWorldPos; +in vec3 nextWorldPos; + +out vec4 outData; + +void main() +{ + vec4 prev_wpos = prevViewProjMatrix * vec4(prevWorldPos, 1.0); + vec4 curr_wpos = currViewProjMatrix * vec4(currWorldPos, 1.0); + vec4 next_wpos = nextViewProjMatrix * vec4(nextWorldPos, 1.0); + + vec2 prev_uv = (prev_wpos.xy / prev_wpos.w); + vec2 curr_uv = (curr_wpos.xy / curr_wpos.w); + vec2 next_uv = (next_wpos.xy / next_wpos.w); + + outData.xy = prev_uv - curr_uv; + outData.zw = next_uv - curr_uv; + + /* Encode to unsigned normalized 16bit texture. */ + outData = outData * 0.5 + 0.5; +} diff --git a/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl b/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl new file mode 100644 index 00000000000..95cd69ba310 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl @@ -0,0 +1,54 @@ + +uniform mat4 currModelMatrix; +uniform mat4 prevModelMatrix; +uniform mat4 nextModelMatrix; +uniform bool useDeform; + +#ifdef HAIR +uniform samplerBuffer prvBuffer; /* RGBA32F */ +uniform samplerBuffer nxtBuffer; /* RGBA32F */ +#else +in vec3 pos; +in vec3 prv; /* Previous frame position. */ +in vec3 nxt; /* Next frame position. */ +#endif + +out vec3 currWorldPos; +out vec3 prevWorldPos; +out vec3 nextWorldPos; + +void main() +{ +#ifdef HAIR + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + float time, thick_time, thickness; + vec3 tan, binor; + vec3 wpos; + + hair_get_pos_tan_binor_time(is_persp, + ModelMatrixInverse, + ViewMatrixInverse[3].xyz, + ViewMatrixInverse[2].xyz, + wpos, + tan, + binor, + time, + thickness, + thick_time); + + int id = hair_get_base_id(); + vec3 pos = texelFetch(hairPointBuffer, id).point_position; + vec3 prv = texelFetch(prvBuffer, id).point_position; + vec3 nxt = texelFetch(nxtBuffer, id).point_position; +#endif + prevWorldPos = (prevModelMatrix * vec4(useDeform ? prv : pos, 1.0)).xyz; + currWorldPos = (currModelMatrix * vec4(pos, 1.0)).xyz; + nextWorldPos = (nextModelMatrix * vec4(useDeform ? nxt : pos, 1.0)).xyz; + /* Use jittered projmatrix to be able to match exact sample depth (depth equal test). + * Note that currModelMatrix needs to also be equal to ModelMatrix for the samples to match. */ +#ifndef HAIR + gl_Position = ViewProjectionMatrix * vec4(currWorldPos, 1.0); +#else + gl_Position = ViewProjectionMatrix * vec4(wpos, 1.0); +#endif +} diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index 2f448b784ed..3ef20dbe9ec 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -97,8 +97,6 @@ typedef struct EXTERNAL_PrivateData { /* Do we need to update the depth or can we reuse the last calculated texture. */ bool need_depth; bool update_depth; - - float last_persmat[4][4]; } EXTERNAL_PrivateData; /* Transient data */ /* Functions */ diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 2b811f1d52e..d97bf9255d2 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -159,7 +159,7 @@ void gpencil_object_cache_sort(GPENCIL_PrivateData *pd) } } - /* Join both lists, adding infront. */ + /* Join both lists, adding in front. */ if (pd->tobjects_infront.first != NULL) { if (pd->tobjects.last != NULL) { pd->tobjects.last->next = pd->tobjects_infront.first; @@ -265,8 +265,10 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, GPENCIL_VERTEX_MODE(gpd) || pd->is_render; bool is_masked = (gpl->flag & GP_LAYER_USE_MASK) && !BLI_listbase_is_empty(&gpl->mask_layers); - float vert_col_opacity = (overide_vertcol) ? (is_vert_col_mode ? 1.0f : 0.0f) : - gpl->vertex_paint_opacity; + float vert_col_opacity = (overide_vertcol) ? + (is_vert_col_mode ? pd->vertex_paint_opacity : 0.0f) : + pd->is_render ? gpl->vertex_paint_opacity : + pd->vertex_paint_opacity; /* Negate thickness sign to tag that strokes are in screen space. * Convert to world units (by default, 1 meter = 2000 px). */ float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / GPENCIL_PIXEL_FACTOR); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 495de7ef10b..dded83bacf1 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -224,6 +224,7 @@ void GPENCIL_cache_init(void *ved) const bool is_fade_layer = ((!hide_overlay) && (!pd->is_render) && (draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS)); pd->fade_layer_opacity = (is_fade_layer) ? draw_ctx->v3d->overlay.gpencil_fade_layer : -1.0f; + pd->vertex_paint_opacity = draw_ctx->v3d->overlay.gpencil_vertex_paint_opacity; /* Fade GPencil Objects. */ const bool is_fade_object = ((!hide_overlay) && (!pd->is_render) && (draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS) && @@ -383,7 +384,7 @@ static void gpencil_drawcall_flush(gpIterPopulateData *iter) } /* Group drawcalls that are consecutive and with the same type. Reduces GPU driver overhead. */ -static void gp_drawcall_add( +static void gpencil_drawcall_add( gpIterPopulateData *iter, struct GPUBatch *geom, bool instancing, int v_first, int v_count) { #if DISABLE_BATCHING @@ -413,7 +414,7 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, bGPDstroke *gps, void *thunk); -static void gp_sbuffer_cache_populate(gpIterPopulateData *iter) +static void gpencil_sbuffer_cache_populate(gpIterPopulateData *iter) { iter->do_sbuffer_call = DRAW_NOW; /* In order to draw the sbuffer stroke correctly mixed with other strokes, @@ -450,7 +451,7 @@ static void gpencil_layer_cache_populate(bGPDlayer *gpl, gpencil_drawcall_flush(iter); if (iter->do_sbuffer_call) { - gp_sbuffer_cache_populate(iter); + gpencil_sbuffer_cache_populate(iter); } else { iter->do_sbuffer_call = !pd->do_fast_drawing && (gpd == pd->sbuffer_gpd) && @@ -492,8 +493,10 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, (!iter->pd->simplify_fill) && ((gps->flag & GP_STROKE_NOFILL) == 0); bool only_lines = gpl && gpf && gpl->actframe != gpf && iter->pd->use_multiedit_lines_only; + bool hide_onion = gpl && gpf && gpf->runtime.onion_id != 0 && + ((gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN) != 0); - if (hide_material || (!show_stroke && !show_fill) || only_lines) { + if (hide_material || (!show_stroke && !show_fill) || only_lines || hide_onion) { return; } @@ -537,7 +540,7 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, DRW_cache_gpencil_fills_get(iter->ob, iter->pd->cfra); int vfirst = gps->runtime.fill_start * 3; int vcount = gps->tot_triangles * 3; - gp_drawcall_add(iter, geom, false, vfirst, vcount); + gpencil_drawcall_add(iter, geom, false, vfirst, vcount); } if (show_stroke) { @@ -547,13 +550,13 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, int vfirst = gps->runtime.stroke_start - 1; /* Include "potential" cyclic vertex and start adj vertex (see shader). */ int vcount = gps->totpoints + 1 + 1; - gp_drawcall_add(iter, geom, true, vfirst, vcount); + gpencil_drawcall_add(iter, geom, true, vfirst, vcount); } iter->stroke_index_last = gps->runtime.stroke_start + gps->totpoints + 1; } -static void gp_sbuffer_cache_populate_fast(GPENCIL_Data *vedata, gpIterPopulateData *iter) +static void gpencil_sbuffer_cache_populate_fast(GPENCIL_Data *vedata, gpIterPopulateData *iter) { bGPdata *gpd = (bGPdata *)iter->ob->data; if (gpd != iter->pd->sbuffer_gpd) { @@ -630,13 +633,13 @@ void GPENCIL_cache_populate(void *ved, Object *ob) gpencil_drawcall_flush(&iter); if (iter.do_sbuffer_call) { - gp_sbuffer_cache_populate(&iter); + gpencil_sbuffer_cache_populate(&iter); } gpencil_vfx_cache_populate(vedata, ob, iter.tgp_ob); if (pd->do_fast_drawing) { - gp_sbuffer_cache_populate_fast(vedata, &iter); + gpencil_sbuffer_cache_populate_fast(vedata, &iter); } } diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index cedd75af813..7baca28dca3 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -363,6 +363,8 @@ typedef struct GPENCIL_PrivateData { float xray_alpha; /* Mask invert uniform. */ int mask_invert; + /* Vertex Paint opacity. */ + float vertex_paint_opacity; } GPENCIL_PrivateData; /* geometry batch cache functions */ diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c index 7ce7a726bb7..cf6e78f4702 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -262,6 +262,8 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat mul_v3_m4v3(ob_center, persmat, ob->obmat[3]); mul_v3_fl(ob_center, 1.0f / w); + const bool use_antialiasing = ((fx->flag & FX_PIXEL_FILTER_NEAREST) == 0); + /* Convert to uvs. */ mul_v2_fl(ob_center, 0.5f); add_v2_fl(ob_center, 0.5f); @@ -285,7 +287,8 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat DRW_shgroup_uniform_vec2_copy(grp, "targetPixelSize", pixsize_uniform); DRW_shgroup_uniform_vec2_copy(grp, "targetPixelOffset", ob_center); DRW_shgroup_uniform_vec2_copy(grp, "accumOffset", (float[2]){pixel_size[0], 0.0f}); - DRW_shgroup_uniform_int_copy(grp, "sampCount", (pixel_size[0] / vp_size_inv[0] > 3.0) ? 2 : 1); + int samp_count = (pixel_size[0] / vp_size_inv[0] > 3.0) ? 2 : 1; + DRW_shgroup_uniform_int_copy(grp, "sampCount", use_antialiasing ? samp_count : 0); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } @@ -294,7 +297,8 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat grp = gpencil_vfx_pass_create("Fx Pixelize Y", state, iter, sh); DRW_shgroup_uniform_vec2_copy(grp, "targetPixelSize", pixsize_uniform); DRW_shgroup_uniform_vec2_copy(grp, "accumOffset", (float[2]){0.0f, pixel_size[1]}); - DRW_shgroup_uniform_int_copy(grp, "sampCount", (pixel_size[1] / vp_size_inv[1] > 3.0) ? 2 : 1); + int samp_count = (pixel_size[1] / vp_size_inv[1] > 3.0) ? 2 : 1; + DRW_shgroup_uniform_int_copy(grp, "sampCount", use_antialiasing ? samp_count : 0); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } } diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index 481dec340ba..7ccb5d5a753 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -228,11 +228,12 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) { format = formats->instance_extra; - sh = OVERLAY_shader_armature_degrees_of_freedom(); + sh = OVERLAY_shader_armature_degrees_of_freedom_wire(); grp = DRW_shgroup_create(sh, armature_ps); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get()); + sh = OVERLAY_shader_armature_degrees_of_freedom_solid(); grp = DRW_shgroup_create(sh, armature_transp_ps); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); cb->dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get()); @@ -2167,7 +2168,8 @@ static void armature_context_setup(ArmatureDrawContext *ctx, ctx->do_relations = !DRW_state_is_select() && pd->armature.show_relations && (is_edit_mode | is_pose_mode); ctx->const_color = DRW_state_is_select() ? select_const_color : const_color; - ctx->const_wire = (((ob->base_flag & BASE_SELECTED) || (arm->drawtype == ARM_WIRE)) ? + ctx->const_wire = ((((ob->base_flag & BASE_SELECTED) && (pd->v3d_flag & V3D_SELECT_OUTLINE)) || + (arm->drawtype == ARM_WIRE)) ? 1.5f : ((!is_filled || is_transparent) ? 1.0f : 0.0f)); } diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.c b/source/blender/draw/engines/overlay/overlay_edit_text.c index c4d020adc11..4ee936f5ce6 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_text.c +++ b/source/blender/draw/engines/overlay/overlay_edit_text.c @@ -53,13 +53,22 @@ void OVERLAY_edit_text_cache_init(OVERLAY_Data *vedata) DRW_shgroup_uniform_vec4_copy(grp, "color", G_draw.block.colorWire); } { - state = DRW_STATE_WRITE_COLOR | DRW_STATE_LOGIC_INVERT; + state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; DRW_PASS_CREATE(psl->edit_text_overlay_ps, state | pd->clipping_state); sh = OVERLAY_shader_uniform_color(); pd->edit_text_overlay_grp = grp = DRW_shgroup_create(sh, psl->edit_text_overlay_ps); - DRW_shgroup_uniform_vec4_copy(grp, "color", (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); + DRW_shgroup_uniform_vec4(grp, "color", pd->edit_text.overlay_color, 1); + + state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL | DRW_STATE_DEPTH_GREATER_EQUAL | + pd->clipping_state; + DRW_PASS_INSTANCE_CREATE(psl->edit_text_darken_ps, psl->edit_text_overlay_ps, state); + } + { + /* Create view which will render everything (hopefully) behind the text geometry. */ + DRWView *default_view = (DRWView *)DRW_view_default_get(); + pd->view_edit_text = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, -5.0f); } } @@ -193,16 +202,24 @@ void OVERLAY_edit_text_cache_populate(OVERLAY_Data *vedata, Object *ob) void OVERLAY_edit_text_draw(OVERLAY_Data *vedata) { + OVERLAY_PrivateData *pd = vedata->stl->pd; OVERLAY_PassList *psl = vedata->psl; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + OVERLAY_FramebufferList *fbl = vedata->fbl; if (DRW_state_is_fbo()) { - /* Text overlay need final color for color inversion. */ - GPU_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_bind(fbl->overlay_default_fb); } DRW_draw_pass(psl->edit_text_wire_ps[0]); DRW_draw_pass(psl->edit_text_wire_ps[1]); + DRW_view_set_active(pd->view_edit_text); + + /* Alpha blended. */ + copy_v4_fl4(pd->edit_text.overlay_color, 0.8f, 0.8f, 0.8f, 0.5f); DRW_draw_pass(psl->edit_text_overlay_ps); + + /* Multiply previous result where depth test fail. */ + copy_v4_fl4(pd->edit_text.overlay_color, 0.0f, 0.0f, 0.0f, 1.0f); + DRW_draw_pass(psl->edit_text_darken_ps); } diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index 61337ac8d1d..e76b3c82c1d 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -423,7 +423,7 @@ static void OVERLAY_cache_finish(void *vedata) { /* TODO(fclem) Only do this when really needed. */ { - /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */ + /* HACK we allocate the in front depth here to avoid the overhead when if is not needed. */ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index 15bf26a5fa8..e591f54c750 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -1318,7 +1318,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, else { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); - if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) { + if ((cti && cti->get_constraint_targets) && (curcon->ui_expand_flag && (1 << 0))) { ListBase targets = {NULL, NULL}; bConstraintTarget *ct; diff --git a/source/blender/draw/engines/overlay/overlay_grid.c b/source/blender/draw/engines/overlay/overlay_grid.c index 5ed32de6d93..e3079870d8f 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.c +++ b/source/blender/draw/engines/overlay/overlay_grid.c @@ -41,6 +41,7 @@ enum { CLIP_ZPOS = (1 << 7), CLIP_ZNEG = (1 << 8), GRID_BACK = (1 << 9), + GRID_CAMERA = (1 << 10), }; void OVERLAY_grid_init(OVERLAY_Data *vedata) @@ -145,6 +146,9 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata) if (rv3d->persp == RV3D_CAMOB && v3d->camera && v3d->camera->type == OB_CAMERA) { Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera); dist = ((Camera *)(camera_object->data))->clip_end; + shd->grid_flag |= GRID_CAMERA; + shd->zneg_flag |= GRID_CAMERA; + shd->zpos_flag |= GRID_CAMERA; } else { dist = v3d->clip_end; diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index ed0a9cf6981..59fa58c0c03 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -71,6 +71,7 @@ typedef struct OVERLAY_PassList { DRWPass *edit_mesh_normals_ps; DRWPass *edit_particle_ps; DRWPass *edit_text_overlay_ps; + DRWPass *edit_text_darken_ps; DRWPass *edit_text_wire_ps[2]; DRWPass *extra_ps[2]; DRWPass *extra_blend_ps; @@ -264,6 +265,7 @@ typedef struct OVERLAY_PrivateData { DRWView *view_edit_faces_cage; DRWView *view_edit_edges; DRWView *view_edit_verts; + DRWView *view_edit_text; DRWView *view_reference_images; /** TODO get rid of this. */ @@ -300,6 +302,9 @@ typedef struct OVERLAY_PrivateData { int handle_display; } edit_curve; struct { + float overlay_color[4]; + } edit_text; + struct { int ghost_ob; int edit_ob; bool do_zbufclip; @@ -563,7 +568,8 @@ void OVERLAY_wireframe_draw(OVERLAY_Data *vedata); void OVERLAY_wireframe_in_front_draw(OVERLAY_Data *vedata); GPUShader *OVERLAY_shader_antialiasing(void); -GPUShader *OVERLAY_shader_armature_degrees_of_freedom(void); +GPUShader *OVERLAY_shader_armature_degrees_of_freedom_wire(void); +GPUShader *OVERLAY_shader_armature_degrees_of_freedom_solid(void); GPUShader *OVERLAY_shader_armature_envelope(bool use_outline); GPUShader *OVERLAY_shader_armature_shape(bool use_outline); GPUShader *OVERLAY_shader_armature_shape_wire(void); diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c index 0610b8397a1..edf91c99531 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ b/source/blender/draw/engines/overlay/overlay_shader.c @@ -31,6 +31,7 @@ extern char datatoc_antialiasing_frag_glsl[]; extern char datatoc_antialiasing_vert_glsl[]; extern char datatoc_armature_dof_vert_glsl[]; +extern char datatoc_armature_dof_solid_frag_glsl[]; extern char datatoc_armature_envelope_distance_frag_glsl[]; extern char datatoc_armature_envelope_outline_vert_glsl[]; extern char datatoc_armature_envelope_solid_frag_glsl[]; @@ -130,7 +131,8 @@ extern char datatoc_common_view_lib_glsl[]; typedef struct OVERLAY_Shaders { GPUShader *antialiasing; - GPUShader *armature_dof; + GPUShader *armature_dof_wire; + GPUShader *armature_dof_solid; GPUShader *armature_envelope_outline; GPUShader *armature_envelope_solid; GPUShader *armature_shape_outline; @@ -473,13 +475,13 @@ GPUShader *OVERLAY_shader_armature_stick(void) return sh_data->armature_stick; } -GPUShader *OVERLAY_shader_armature_degrees_of_freedom(void) +GPUShader *OVERLAY_shader_armature_degrees_of_freedom_wire(void) { const DRWContextState *draw_ctx = DRW_context_state_get(); const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->armature_dof) { - sh_data->armature_dof = GPU_shader_create_from_arrays({ + if (!sh_data->armature_dof_wire) { + sh_data->armature_dof_wire = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg->lib, datatoc_common_globals_lib_glsl, datatoc_common_view_lib_glsl, @@ -487,10 +489,31 @@ GPUShader *OVERLAY_shader_armature_degrees_of_freedom(void) NULL}, .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_armature_wire_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, "#define EDGE\n", NULL}, + }); + } + return sh_data->armature_dof_wire; +} + +GPUShader *OVERLAY_shader_armature_degrees_of_freedom_solid(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->armature_dof_solid) { + sh_data->armature_dof_solid = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_armature_dof_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_armature_dof_solid_frag_glsl, + NULL}, .defs = (const char *[]){sh_cfg->def, NULL}, }); } - return sh_data->armature_dof; + return sh_data->armature_dof_solid; } GPUShader *OVERLAY_shader_armature_wire(void) diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c index eebfc88fdce..ea45ad5190c 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.c +++ b/source/blender/draw/engines/overlay/overlay_wireframe.c @@ -76,7 +76,8 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; DRWPass *pass; - GPUTexture **depth_tx = ((pd->xray_enabled || pd->xray_opacity > 0.0f) && DRW_state_is_fbo()) ? + GPUTexture **depth_tx = ((!pd->xray_enabled || pd->xray_opacity > 0.0f) && + DRW_state_is_fbo()) ? &txl->temp_depth_tx : &txl->dummy_depth_tx; diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl new file mode 100644 index 00000000000..e511aab69c1 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl @@ -0,0 +1,11 @@ + +flat in vec4 finalColor; + +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 lineOutput; + +void main() +{ + fragColor = finalColor; + lineOutput = vec4(0.0); +} diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl index b15554bbb6a..18a80fc1fb4 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl @@ -8,8 +8,10 @@ in vec4 color; in mat4 inst_obmat; flat out vec4 finalColor; +#ifdef EDGE flat out vec2 edgeStart; noperspective out vec2 edgePos; +#endif vec3 sphere_project(float ax, float az) { @@ -35,7 +37,9 @@ void main() gl_Position = point_world_to_ndc(world_pos); finalColor = color; +#ifdef EDGE edgeStart = edgePos = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; +#endif #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl index 203f6cb1901..2cefab56722 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl @@ -83,7 +83,7 @@ void main() finalColor = EDIT_MESH_facedot_color(norAndFlag.w); /* Bias Facedot Z position in clipspace. */ - gl_Position.z -= 0.00035; + gl_Position.z -= (ProjectionMatrix[3][3] == 0.0) ? 0.00035 : 1e-6; gl_PointSize = sizeFaceDot; bool occluded = test_occlusion(); diff --git a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl index 9743f918ce3..317e9fe0447 100644 --- a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl @@ -28,7 +28,8 @@ uniform float gridSteps[STEPS_LEN] = float[](0.001, 0.01, 0.1, 1.0, 10.0, 100.0, #define PLANE_XY (1 << 4) #define PLANE_XZ (1 << 5) #define PLANE_YZ (1 << 6) -#define GRID_BACK (1 << 9) /* grid is behind objects */ +#define GRID_BACK (1 << 9) /* grid is behind objects */ +#define GRID_CAMERA (1 << 10) /* In camera view */ #define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */ @@ -104,7 +105,9 @@ void main() fade *= 1.0 - smoothstep(0.0, gridDistance, dist - gridDistance); } else { - dist = abs(gl_FragCoord.z * 2.0 - 1.0); + dist = gl_FragCoord.z * 2.0 - 1.0; + /* Avoid fading in +Z direction in camera view (see T70193). */ + dist = ((gridFlag & GRID_CAMERA) != 0) ? clamp(dist, 0.0, 1.0) : abs(dist); fade = 1.0 - smoothstep(0.0, 0.5, dist - 0.5); dist = 1.0; /* avoid branch after */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl index 87d04144cde..d8cb4f86f7b 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl @@ -23,7 +23,7 @@ void cavity_compute(vec2 screenco, float depth = texture(depthBuffer, screenco).x; - /* Early out if background and infront. */ + /* Early out if background and in front. */ if (depth == 1.0 || depth == 0.0) { return; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index 0c2b7850f94..2920a504062 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -107,7 +107,6 @@ void volume_properties(vec3 ls_pos, out vec3 scattering, out float extinction) #ifdef USE_COBA float val = sample_volume_texture(densityTexture, co).r; vec4 tval = texture(transferTexture, val) * densityScale; - tval.rgb = pow(tval.rgb, vec3(2.2)); scattering = tval.rgb * 1500.0; extinction = max(1e-4, tval.a * 50.0); #else @@ -127,7 +126,7 @@ void volume_properties(vec3 ls_pos, out vec3 scattering, out float extinction) # ifdef VOLUME_SMOKE /* 800 is arbitrary and here to mimic old viewport. TODO make it a parameter */ - scattering += pow(emission.rgb, vec3(2.2)) * emission.a * 800.0; + scattering += emission.rgb * emission.a * 800.0; # endif #endif } diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 828a9127fb1..c8dde4d513b 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -174,8 +174,19 @@ static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd, color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR); if (use_single_drawcall) { - struct GPUBatch *geom = (use_vcol) ? DRW_cache_mesh_surface_vertpaint_get(ob) : - DRW_cache_object_surface_get(ob); + struct GPUBatch *geom; + if (use_vcol) { + if (ob->mode & OB_MODE_VERTEX_PAINT) { + geom = DRW_cache_mesh_surface_vertpaint_get(ob); + } + else { + geom = DRW_cache_mesh_surface_sculptcolors_get(ob); + } + } + else { + geom = DRW_cache_object_surface_get(ob); + } + if (geom) { DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, r_transp); DRW_shgroup_call(grp, geom, ob); @@ -240,15 +251,19 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd, const bool is_texpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_TEXTURE); const bool is_vertpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_VERTEX); - if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (ob->dt < OB_TEXTURE)) { - color_type = V3D_SHADING_MATERIAL_COLOR; - } - /* Disable color mode if data layer is unavailable. */ - if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (me == NULL || me->mloopuv == NULL)) { - color_type = V3D_SHADING_MATERIAL_COLOR; + if (color_type == V3D_SHADING_TEXTURE_COLOR) { + if (ob->dt < OB_TEXTURE) { + color_type = V3D_SHADING_MATERIAL_COLOR; + } + else if ((me == NULL) || (me->mloopuv == NULL)) { + /* Disable color mode if data layer is unavailable. */ + color_type = V3D_SHADING_MATERIAL_COLOR; + } } - if ((color_type == V3D_SHADING_VERTEX_COLOR) && (me == NULL || me->mloopcol == NULL)) { - color_type = V3D_SHADING_OBJECT_COLOR; + else if (color_type == V3D_SHADING_VERTEX_COLOR) { + if ((me == NULL) || !CustomData_has_layer(&me->vdata, CD_PROP_COLOR)) { + color_type = V3D_SHADING_OBJECT_COLOR; + } } if (r_sculpt_pbvh) { @@ -379,7 +394,7 @@ void workbench_cache_finish(void *ved) /* TODO(fclem) Only do this when really needed. */ { - /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */ + /* HACK we allocate the in front depth here to avoid the overhead when if is not needed. */ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 0b2d508fee5..d6d3ff8610b 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -57,7 +57,7 @@ void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd, case V3D_SHADING_RANDOM_COLOR: { uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); if (ob->id.lib) { - hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name); + hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->filepath); } float hue = BLI_hash_int_01(hash); float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE}; diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 20b6d368ac0..ee9960ea0ef 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -293,7 +293,7 @@ typedef struct WORKBENCH_PrivateData { /** Object IDs buffer for curvature & outline. */ struct GPUTexture *object_id_tx; - /** Prepass infos for each draw types [transparent][infront][hair]. */ + /** Pre-pass information for each draw types [transparent][infront][hair]. */ WORKBENCH_Prepass prepass[2][2][2]; /* Materials */ diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c index 5fd8229304a..1c40a350300 100644 --- a/source/blender/draw/engines/workbench/workbench_transparent.c +++ b/source/blender/draw/engines/workbench/workbench_transparent.c @@ -157,7 +157,7 @@ void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data) WORKBENCH_FramebufferList *fbl = data->fbl; WORKBENCH_PassList *psl = data->psl; - const bool do_xray_depth_pass = XRAY_ALPHA(wpd) > 0.0f; + const bool do_xray_depth_pass = !XRAY_FLAG_ENABLED(wpd) || XRAY_ALPHA(wpd) > 0.0f; const bool do_transparent_depth_pass = psl->outline_ps || wpd->dof_enabled || do_xray_depth_pass; if (do_transparent_depth_pass) { @@ -165,14 +165,14 @@ void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data) if (!DRW_pass_is_empty(psl->transp_accum_ps)) { GPU_framebuffer_bind(fbl->opaque_fb); - /* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */ + /* TODO(fclem) Disable writing to first two buffers. Unnecessary waste of bandwidth. */ DRW_pass_state_set(psl->transp_accum_ps, state | wpd->cull_state | wpd->clip_state); DRW_draw_pass(psl->transp_accum_ps); } if (!DRW_pass_is_empty(psl->transp_accum_infront_ps)) { GPU_framebuffer_bind(fbl->opaque_infront_fb); - /* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */ + /* TODO(fclem) Disable writing to first two buffers. Unnecessary waste of bandwidth. */ DRW_pass_state_set(psl->transp_accum_infront_ps, state | wpd->cull_state | wpd->clip_state); DRW_draw_pass(psl->transp_accum_infront_ps); } diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 89dd6fa210c..555043ab408 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -462,6 +462,10 @@ void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex, eGPUSamplerState sampler_state); +void DRW_shgroup_uniform_texture_ref_ex(DRWShadingGroup *shgroup, + const char *name, + GPUTexture **tex, + eGPUSamplerState sampler_state); void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex); @@ -569,7 +573,7 @@ void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float w const DRWView *DRW_view_default_get(void); void DRW_view_default_set(DRWView *view); - +void DRW_view_reset(void); void DRW_view_set_active(DRWView *view); void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len); @@ -626,6 +630,8 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, void (*callback)(void *vedata, void *user_data), void *user_data); +void DRW_cache_restart(void); + /* ViewLayers */ void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type); void **DRW_view_layer_engine_data_ensure_ex(struct ViewLayer *view_layer, diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index af5b9cd05dd..9f30cd85957 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -888,6 +888,32 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob) } } +/* Returns the vertbuf used by shaded surface batch. */ +GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob) +{ + Mesh *me = BKE_object_get_evaluated_mesh(ob); + short type = (me != NULL) ? OB_MESH : ob->type; + + switch (type) { + case OB_MESH: + return DRW_mesh_batch_cache_pos_vertbuf_get((me != NULL) ? me : ob->data); + case OB_CURVE: + case OB_SURF: + case OB_FONT: + return DRW_curve_batch_cache_pos_vertbuf_get(ob->data); + case OB_MBALL: + return DRW_mball_batch_cache_pos_vertbuf_get(ob); + case OB_HAIR: + return NULL; + case OB_POINTCLOUD: + return NULL; + case OB_VOLUME: + return NULL; + default: + return NULL; + } +} + int DRW_cache_object_material_count_get(struct Object *ob) { Mesh *me = BKE_object_get_evaluated_mesh(ob); @@ -2844,6 +2870,12 @@ GPUBatch *DRW_cache_mesh_surface_vertpaint_get(Object *ob) return DRW_mesh_batch_cache_get_surface_vertpaint(ob->data); } +GPUBatch *DRW_cache_mesh_surface_sculptcolors_get(Object *ob) +{ + BLI_assert(ob->type == OB_MESH); + return DRW_mesh_batch_cache_get_surface_sculpt(ob->data); +} + GPUBatch *DRW_cache_mesh_surface_weights_get(Object *ob) { BLI_assert(ob->type == OB_MESH); diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 221fb89612f..2f289bf4110 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -63,6 +63,8 @@ struct GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob, struct GPUBatch *DRW_cache_object_face_wireframe_get(struct Object *ob); int DRW_cache_object_material_count_get(struct Object *ob); +struct GPUVertBuf *DRW_cache_object_pos_vertbuf_get(struct Object *ob); + /* Empties */ struct GPUBatch *DRW_cache_plain_axes_get(void); struct GPUBatch *DRW_cache_single_arrow_get(void); @@ -134,6 +136,7 @@ struct GPUBatch **DRW_cache_mesh_surface_shaded_get(struct Object *ob, struct GPUBatch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_vertpaint_get(struct Object *ob); +struct GPUBatch *DRW_cache_mesh_surface_sculptcolors_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_weights_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_mesh_analysis_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_face_wireframe_get(struct Object *ob); diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index f203c2ff1ea..302f9a0d3a8 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -53,6 +53,7 @@ typedef struct DRW_MeshCDMask { uint32_t uv : 8; uint32_t tan : 8; uint32_t vcol : 8; + uint32_t sculpt_vcol : 8; uint32_t orco : 1; uint32_t tan_orco : 1; /** Edit uv layer is from the base edit mesh as @@ -62,7 +63,7 @@ typedef struct DRW_MeshCDMask { typedef enum eMRIterType { MR_ITER_LOOPTRI = 1 << 0, - MR_ITER_LOOP = 1 << 1, + MR_ITER_POLY = 1 << 1, MR_ITER_LEDGE = 1 << 2, MR_ITER_LVERT = 1 << 3, } eMRIterType; diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c index f3dc8f0fd2a..c92722fad7e 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh.c @@ -128,7 +128,7 @@ typedef struct MeshRenderData { BMEdge *eed_act; BMFace *efa_act; BMFace *efa_act_uv; - /* Data created on-demand (usually not for bmesh-based data). */ + /* Data created on-demand (usually not for #BMesh based data). */ MLoopTri *mlooptri; float (*loop_normals)[3]; float (*poly_normals)[3]; @@ -145,17 +145,17 @@ static void mesh_render_data_update_loose_geom(MeshRenderData *mr, mr->vert_loose_len = 0; mr->edge_loose_len = 0; - BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, "lvert map"); + BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__); mr->ledges = MEM_mallocN(mr->edge_len * sizeof(int), __func__); - const MEdge *medge = mr->medge; - for (int e = 0; e < mr->edge_len; e++, medge++) { - if (medge->flag & ME_LOOSEEDGE) { - mr->ledges[mr->edge_loose_len++] = e; + const MEdge *med = mr->medge; + for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) { + if (med->flag & ME_LOOSEEDGE) { + mr->ledges[mr->edge_loose_len++] = med_index; } /* Tag verts as not loose. */ - BLI_BITMAP_ENABLE(lvert_map, medge->v1); - BLI_BITMAP_ENABLE(lvert_map, medge->v2); + BLI_BITMAP_ENABLE(lvert_map, med->v1); + BLI_BITMAP_ENABLE(lvert_map, med->v2); } if (mr->edge_loose_len < mr->edge_len) { mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges)); @@ -173,11 +173,11 @@ static void mesh_render_data_update_loose_geom(MeshRenderData *mr, MEM_freeN(lvert_map); - mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2; + mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2); } } else { - /* BMesh */ + /* #BMesh */ BMesh *bm = mr->bm; if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) { int elem_id; @@ -212,7 +212,9 @@ static void mesh_render_data_update_loose_geom(MeshRenderData *mr, } } -/* Part of the creation of the MeshRenderData that happens in a thread. */ +/** + * Part of the creation of the #MeshRenderData that happens in a thread. + */ static void mesh_render_data_update_looptris(MeshRenderData *mr, const eMRIterType iter_type, const eMRDataType data_flag) @@ -227,7 +229,7 @@ static void mesh_render_data_update_looptris(MeshRenderData *mr, } } else { - /* BMesh */ + /* #BMesh */ if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { /* Edit mode ensures this is valid, no need to calculate. */ BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL)); @@ -278,9 +280,9 @@ static void mesh_render_data_update_normals(MeshRenderData *mr, } } else { - /* BMesh */ + /* #BMesh */ if (data_flag & MR_DATA_POLY_NOR) { - /* Use bmface->no instead. */ + /* Use #BMFace.no instead. */ } if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { @@ -295,7 +297,7 @@ static void mesh_render_data_update_normals(MeshRenderData *mr, } mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__); - int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); + const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); BM_loops_calc_normal_vcos(mr->bm, vert_coords, vert_normals, @@ -419,7 +421,7 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); } else { - /* BMesh */ + /* #BMesh */ BMesh *bm = mr->bm; mr->vert_len = bm->totvert; @@ -486,7 +488,7 @@ BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *e } else { UNUSED_VARS(mr); - return eve->co; + return eve->no; } } @@ -505,48 +507,283 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Mesh Elements Extract Iter +/** \name Mesh Elements Extract: Loop Triangles + * \{ */ + +typedef struct ExtractTriBMesh_Params { + BMLoop *(*looptris)[3]; + int tri_range[2]; +} ExtractTriBMesh_Params; +typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, + const ExtractTriBMesh_Params *params, + void *data); + +#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elem_tri, index_tri, params) \ + CHECK_TYPE(params, const ExtractTriBMesh_Params *); \ + { \ + const int _tri_index_end = (params)->tri_range[1]; \ + BMLoop **elem_tri = (params)->looptris[(params)->tri_range[0]]; \ + for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \ + index_tri += 1, elem_tri += 3) +#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END } + +typedef struct ExtractTriMesh_Params { + const MLoopTri *mlooptri; + int tri_range[2]; +} ExtractTriMesh_Params; +typedef void(ExtractTriMeshFn)(const MeshRenderData *mr, + const ExtractTriMesh_Params *params, + void *data); + +#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(elem_tri, index_tri, params) \ + CHECK_TYPE(params, const ExtractTriMesh_Params *); \ + { \ + const int _tri_index_end = (params)->tri_range[1]; \ + const MLoopTri *elem_tri = &(params)->mlooptri[(params)->tri_range[0]]; \ + for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \ + index_tri += 1, elem_tri += 1) +#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END } + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract: Polygons, Loops + * \{ */ + +typedef struct ExtractPolyBMesh_Params { + BMLoop *(*looptris)[3]; + int poly_range[2]; +} ExtractPolyBMesh_Params; +typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data); + +#define EXTRACT_POLY_FOREACH_BM_BEGIN(elem_poly, index_poly, params, mr) \ + CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \ + { \ + BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \ + BMFace **_ftable = mr->bm->ftable; \ + const int _poly_index_end = (params)->poly_range[1]; \ + for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ + index_poly += 1) { \ + BMFace *elem_poly = _ftable[index_poly]; \ + (void)elem_poly; + +#define EXTRACT_POLY_FOREACH_BM_END \ + } \ + } + +/* Iterate over polygon and loop. */ +#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(elem_loop, index_loop, params, mr) \ + CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \ + { \ + BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \ + BMFace **_ftable = mr->bm->ftable; \ + const int _poly_index_end = (params)->poly_range[1]; \ + for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ + index_poly += 1) { \ + BMFace *elem_face = _ftable[index_poly]; \ + BMLoop *elem_loop, *l_first; \ + elem_loop = l_first = BM_FACE_FIRST_LOOP(elem_face); \ + do { \ + const int index_loop = BM_elem_index_get(elem_loop); \ + (void)index_loop; /* Quiet warning when unused. */ + +#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(elem_loop) \ + } \ + while ((elem_loop = elem_loop->next) != l_first) \ + ; \ + } \ + } + +typedef struct ExtractPolyMesh_Params { + int poly_range[2]; +} ExtractPolyMesh_Params; +typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data); + +#define EXTRACT_POLY_FOREACH_MESH_BEGIN(elem_poly, index_poly, params, mr) \ + CHECK_TYPE(params, const ExtractPolyMesh_Params *); \ + { \ + const MPoly *_mpoly = mr->mpoly; \ + const int _poly_index_end = (params)->poly_range[1]; \ + for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ + index_poly += 1) { \ + const MPoly *elem_poly = &_mpoly[index_poly]; \ + (void)elem_poly; + +#define EXTRACT_POLY_FOREACH_MESH_END \ + } \ + } + +/* Iterate over polygon and loop. */ +#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN( \ + elem_poly, index_poly, elem_loop, index_loop, params, mr) \ + CHECK_TYPE(params, const ExtractPolyMesh_Params *); \ + { \ + const MPoly *_mpoly = mr->mpoly; \ + const MLoop *_mloop = mr->mloop; \ + const int _poly_index_end = (params)->poly_range[1]; \ + for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ + index_poly += 1) { \ + const MPoly *elem_poly = &_mpoly[index_poly]; \ + const int _index_end = elem_poly->loopstart + elem_poly->totloop; \ + for (int index_loop = elem_poly->loopstart; index_loop < _index_end; index_loop += 1) { \ + const MLoop *elem_loop = &_mloop[index_loop]; \ + (void)elem_loop; + +#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END \ + } \ + } \ + } + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract: Loose Edges + * \{ */ + +typedef struct ExtractLEdgeBMesh_Params { + const int *ledge; + int ledge_range[2]; +} ExtractLEdgeBMesh_Params; +typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *data); + +#define EXTRACT_LEDGE_FOREACH_BM_BEGIN(elem_edge, index_ledge, params) \ + CHECK_TYPE(params, const ExtractLEdgeBMesh_Params *); \ + { \ + BLI_assert((mr->bm->elem_table_dirty & BM_EDGE) == 0); \ + BMEdge **_etable = mr->bm->etable; \ + const int *_ledge = (params)->ledge; \ + const int _ledge_index_end = (params)->ledge_range[1]; \ + for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \ + index_ledge += 1) { \ + BMEdge *elem_edge = _etable[_ledge[index_ledge]]; \ + (void)elem_edge; /* Quiet warning when unused. */ \ + { +#define EXTRACT_LEDGE_FOREACH_BM_END \ + } \ + } \ + } + +typedef struct ExtractLEdgeMesh_Params { + const int *ledge; + int ledge_range[2]; +} ExtractLEdgeMesh_Params; +typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *data); + +#define EXTRACT_LEDGE_FOREACH_MESH_BEGIN(elem_edge, index_ledge, params, mr) \ + CHECK_TYPE(params, const ExtractLEdgeMesh_Params *); \ + { \ + const MEdge *_medge = mr->medge; \ + const int *_ledge = (params)->ledge; \ + const int _ledge_index_end = (params)->ledge_range[1]; \ + for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \ + index_ledge += 1) { \ + const MEdge *elem_edge = &_medge[_ledge[index_ledge]]; \ + (void)elem_edge; /* Quiet warning when unused. */ \ + { +#define EXTRACT_LEDGE_FOREACH_MESH_END \ + } \ + } \ + } + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract: Loose Vertices + * \{ */ + +typedef struct ExtractLVertBMesh_Params { + const int *lvert; + int lvert_range[2]; +} ExtractLVertBMesh_Params; +typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *data); + +#define EXTRACT_LVERT_FOREACH_BM_BEGIN(elem_vert, index_lvert, params) \ + CHECK_TYPE(params, const ExtractLVertBMesh_Params *); \ + { \ + BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \ + BMVert **vtable = mr->bm->vtable; \ + const int *lverts = (params)->lvert; \ + const int _lvert_index_end = (params)->lvert_range[1]; \ + for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \ + index_lvert += 1) { \ + BMVert *elem_vert = vtable[lverts[index_lvert]]; \ + (void)elem_vert; /* Quiet warning when unused. */ \ + { +#define EXTRACT_LVERT_FOREACH_BM_END \ + } \ + } \ + } + +typedef struct ExtractLVertMesh_Params { + const int *lvert; + int lvert_range[2]; +} ExtractLVertMesh_Params; +typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *data); + +#define EXTRACT_LVERT_FOREACH_MESH_BEGIN(elem, index_lvert, params, mr) \ + CHECK_TYPE(params, const ExtractLVertMesh_Params *); \ + { \ + const MVert *mvert = mr->mvert; \ + const int *lverts = (params)->lvert; \ + const int _lvert_index_end = (params)->lvert_range[1]; \ + for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \ + index_lvert += 1) { \ + const MVert *elem = &mvert[lverts[index_lvert]]; \ + (void)elem; /* Quiet warning when unused. */ \ + { +#define EXTRACT_LVERT_FOREACH_MESH_END \ + } \ + } \ + } + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract Struct * \{ */ typedef void *(ExtractInitFn)(const MeshRenderData *mr, void *buffer); -typedef void(ExtractEditTriFn)(const MeshRenderData *mr, int t, BMLoop **e, void *data); -typedef void(ExtractEditLoopFn)(const MeshRenderData *mr, int l, BMLoop *el, void *data); -typedef void(ExtractEditLedgeFn)(const MeshRenderData *mr, int e, BMEdge *ed, void *data); -typedef void(ExtractEditLvertFn)(const MeshRenderData *mr, int v, BMVert *ev, void *data); -typedef void(ExtractTriFn)(const MeshRenderData *mr, int t, const MLoopTri *mlt, void *data); -typedef void(ExtractLoopFn)( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data); -typedef void(ExtractLedgeFn)(const MeshRenderData *mr, int e, const MEdge *medge, void *data); -typedef void(ExtractLvertFn)(const MeshRenderData *mr, int v, const MVert *mvert, void *data); typedef void(ExtractFinishFn)(const MeshRenderData *mr, void *buffer, void *data); typedef struct MeshExtract { - /** Executed on main thread and return user data for iter functions. */ + /** Executed on main thread and return user data for iteration functions. */ ExtractInitFn *init; /** Executed on one (or more if use_threading) worker thread(s). */ - ExtractEditTriFn *iter_looptri_bm; - ExtractTriFn *iter_looptri; - ExtractEditLoopFn *iter_loop_bm; - ExtractLoopFn *iter_loop; - ExtractEditLedgeFn *iter_ledge_bm; - ExtractLedgeFn *iter_ledge; - ExtractEditLvertFn *iter_lvert_bm; - ExtractLvertFn *iter_lvert; + ExtractTriBMeshFn *iter_looptri_bm; + ExtractTriMeshFn *iter_looptri_mesh; + ExtractPolyBMeshFn *iter_poly_bm; + ExtractPolyMeshFn *iter_poly_mesh; + ExtractLEdgeBMeshFn *iter_ledge_bm; + ExtractLEdgeMeshFn *iter_ledge_mesh; + ExtractLVertBMeshFn *iter_lvert_bm; + ExtractLVertMeshFn *iter_lvert_mesh; /** Executed on one worker thread after all elements iterations. */ ExtractFinishFn *finish; /** Used to request common data. */ const eMRDataType data_flag; - /** Used to know if the element callbacks are threadsafe and can be parallelized. */ + /** Used to know if the element callbacks are thread-safe and can be parallelized. */ const bool use_threading; } MeshExtract; BLI_INLINE eMRIterType mesh_extract_iter_type(const MeshExtract *ext) { eMRIterType type = 0; - SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri), MR_ITER_LOOPTRI); - SET_FLAG_FROM_TEST(type, (ext->iter_loop_bm || ext->iter_loop), MR_ITER_LOOP); - SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge), MR_ITER_LEDGE); - SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert), MR_ITER_LVERT); + SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI); + SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY); + SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE); + SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert_mesh), MR_ITER_LVERT); return type; } @@ -583,15 +820,15 @@ static void *extract_tris_init(const MeshRenderData *mr, void *UNUSED(ibo)) } } else { - const MPoly *mpoly = mr->mpoly; - for (int p = 0; p < mr->poly_len; p++, mpoly++) { - if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) { - int mat = min_ii(mpoly->mat_nr, mr->mat_len - 1); - mat_tri_len[mat] += mpoly->totloop - 2; + const MPoly *mp = mr->mpoly; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + int mat = min_ii(mp->mat_nr, mr->mat_len - 1); + mat_tri_len[mat] += mp->totloop - 2; } } } - /* Accumulate tri len per mat to have correct offsets. */ + /* Accumulate triangle lengths per material to have correct offsets. */ int ofs = mat_tri_len[0]; mat_tri_len[0] = 0; for (int i = 1; i < mr->mat_len; i++) { @@ -608,51 +845,59 @@ static void *extract_tris_init(const MeshRenderData *mr, void *UNUSED(ibo)) return data; } -static void extract_tris_looptri_bmesh(const MeshRenderData *mr, - int UNUSED(t), - BMLoop **elt, - void *_data) +static void extract_tris_iter_looptri_bm(const MeshRenderData *mr, + const struct ExtractTriBMesh_Params *params, + void *_data) { - if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { - MeshExtract_Tri_Data *data = _data; - int *mat_tri_ofs = data->tri_mat_end; - int mat = min_ii(elt[0]->f->mat_nr, mr->mat_len - 1); - GPU_indexbuf_set_tri_verts(&data->elb, - mat_tri_ofs[mat]++, - BM_elem_index_get(elt[0]), - BM_elem_index_get(elt[1]), - BM_elem_index_get(elt[2])); + MeshExtract_Tri_Data *data = _data; + const int mat_last = mr->mat_len - 1; + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params) + { + if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { + int *mat_tri_ofs = data->tri_mat_end; + const int mat = min_ii(elt[0]->f->mat_nr, mat_last); + GPU_indexbuf_set_tri_verts(&data->elb, + mat_tri_ofs[mat]++, + BM_elem_index_get(elt[0]), + BM_elem_index_get(elt[1]), + BM_elem_index_get(elt[2])); + } } + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; } -static void extract_tris_looptri_mesh(const MeshRenderData *mr, - int UNUSED(t), - const MLoopTri *mlt, - void *_data) +static void extract_tris_iter_looptri_mesh(const MeshRenderData *mr, + const struct ExtractTriMesh_Params *params, + void *_data) { - const MPoly *mpoly = &mr->mpoly[mlt->poly]; - if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) { - MeshExtract_Tri_Data *data = _data; - int *mat_tri_ofs = data->tri_mat_end; - int mat = min_ii(mpoly->mat_nr, mr->mat_len - 1); - GPU_indexbuf_set_tri_verts( - &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]); + MeshExtract_Tri_Data *data = _data; + const int mat_last = mr->mat_len - 1; + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params) + { + const MPoly *mp = &mr->mpoly[mlt->poly]; + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + int *mat_tri_ofs = data->tri_mat_end; + const int mat = min_ii(mp->mat_nr, mat_last); + GPU_indexbuf_set_tri_verts( + &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]); + } } + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; } static void extract_tris_finish(const MeshRenderData *mr, void *ibo, void *_data) { MeshExtract_Tri_Data *data = _data; GPU_indexbuf_build_in_place(&data->elb, ibo); - /* HACK Create ibo subranges and assign them to each GPUBatch. */ + /* HACK: Create ibo sub-ranges and assign them to each #GPUBatch. */ if (mr->use_final_mesh && mr->cache->surface_per_mat && mr->cache->surface_per_mat[0]) { BLI_assert(mr->cache->surface_per_mat[0]->elem == ibo); for (int i = 0; i < mr->mat_len; i++) { /* Multiply by 3 because these are triangle indices. */ - int start = data->tri_mat_start[i] * 3; - int len = data->tri_mat_end[i] * 3 - data->tri_mat_start[i] * 3; + const int start = data->tri_mat_start[i] * 3; + const int len = data->tri_mat_end[i] * 3 - data->tri_mat_start[i] * 3; GPUIndexBuf *sub_ibo = GPU_indexbuf_create_subrange(ibo, start, len); - /* WARNING: We modify the GPUBatch here! */ + /* WARNING: We modify the #GPUBatch here! */ GPU_batch_elembuf_set(mr->cache->surface_per_mat[i], sub_ibo, true); } } @@ -662,18 +907,12 @@ static void extract_tris_finish(const MeshRenderData *mr, void *ibo, void *_data } static const MeshExtract extract_tris = { - extract_tris_init, - extract_tris_looptri_bmesh, - extract_tris_looptri_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_tris_finish, - 0, - false, + .init = extract_tris_init, + .iter_looptri_bm = extract_tris_iter_looptri_bm, + .iter_looptri_mesh = extract_tris_iter_looptri_mesh, + .finish = extract_tris_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -691,71 +930,113 @@ static void *extract_lines_init(const MeshRenderData *mr, void *UNUSED(buf)) return elb; } -static void extract_lines_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *elb) -{ - if (!BM_elem_flag_test(loop->e, BM_ELEM_HIDDEN)) { - GPU_indexbuf_set_line_verts(elb, BM_elem_index_get(loop->e), l, BM_elem_index_get(loop->next)); - } - else { - GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(loop->e)); - } -} - -static void extract_lines_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *elb) -{ - const MEdge *medge = &mr->medge[mloop->e]; - if (!((mr->use_hide && (medge->flag & ME_HIDE)) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[mloop->e] == ORIGINDEX_NONE)))) { - int loopend = mpoly->totloop + mpoly->loopstart - 1; - int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1); - GPU_indexbuf_set_line_verts(elb, mloop->e, l, other_loop); +static void extract_lines_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *elb) +{ + /* Using poly & loop iterator would complicate accessing the adjacent loop. */ + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + BMLoop *l_iter, *l_first; + /* Use #BMLoop.prev to match mesh order (to avoid minor differences in data extraction). */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f)->prev; + do { + if (!BM_elem_flag_test(l_iter->e, BM_ELEM_HIDDEN)) { + GPU_indexbuf_set_line_verts(elb, + BM_elem_index_get(l_iter->e), + BM_elem_index_get(l_iter), + BM_elem_index_get(l_iter->next)); + } + else { + GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(l_iter->e)); + } + } while ((l_iter = l_iter->next) != l_first); + } + EXTRACT_POLY_FOREACH_BM_END; +} + +static void extract_lines_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *elb) +{ + /* Using poly & loop iterator would complicate accessing the adjacent loop. */ + const MLoop *mloop = mr->mloop; + const MEdge *medge = mr->medge; + if (mr->use_hide || (mr->extract_type == MR_EXTRACT_MAPPED) || (mr->e_origindex != NULL)) { + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + const int ml_index_last = mp->loopstart + (mp->totloop - 1); + int ml_index = ml_index_last, ml_index_next = mp->loopstart; + do { + const MLoop *ml = &mloop[ml_index]; + const MEdge *med = &medge[ml->e]; + if (!((mr->use_hide && (med->flag & ME_HIDE)) || + ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && + (mr->e_origindex[ml->e] == ORIGINDEX_NONE)))) { + GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next); + } + else { + GPU_indexbuf_set_line_restart(elb, ml->e); + } + } while ((ml_index = ml_index_next++) != ml_index_last); + } + EXTRACT_POLY_FOREACH_MESH_END; } else { - GPU_indexbuf_set_line_restart(elb, mloop->e); + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + const int ml_index_last = mp->loopstart + (mp->totloop - 1); + int ml_index = ml_index_last, ml_index_next = mp->loopstart; + do { + const MLoop *ml = &mloop[ml_index]; + GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next); + } while ((ml_index = ml_index_next++) != ml_index_last); + } + EXTRACT_POLY_FOREACH_MESH_END; } } -static void extract_lines_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *elb) +static void extract_lines_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *elb) { - int ledge_idx = mr->edge_len + e; - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - int l = mr->loop_len + e * 2; - GPU_indexbuf_set_line_verts(elb, ledge_idx, l, l + 1); - } - else { - GPU_indexbuf_set_line_restart(elb, ledge_idx); + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + const int l_index_offset = mr->edge_len + ledge_index; + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + const int l_index = mr->loop_len + ledge_index * 2; + GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1); + } + else { + GPU_indexbuf_set_line_restart(elb, l_index_offset); + } + /* Don't render the edge twice. */ + GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed)); } - /* Don't render the edge twice. */ - GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed)); + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_lines_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *medge, - void *elb) +static void extract_lines_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *elb) { - int ledge_idx = mr->edge_len + e; - int edge_idx = mr->ledges[e]; - if (!((mr->use_hide && (medge->flag & ME_HIDE)) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[edge_idx] == ORIGINDEX_NONE)))) { - int l = mr->loop_len + e * 2; - GPU_indexbuf_set_line_verts(elb, ledge_idx, l, l + 1); - } - else { - GPU_indexbuf_set_line_restart(elb, ledge_idx); + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + const int l_index_offset = mr->edge_len + ledge_index; + const int e_index = mr->ledges[ledge_index]; + if (!((mr->use_hide && (med->flag & ME_HIDE)) || + ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && + (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) { + const int l_index = mr->loop_len + ledge_index * 2; + GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1); + } + else { + GPU_indexbuf_set_line_restart(elb, l_index_offset); + } + /* Don't render the edge twice. */ + GPU_indexbuf_set_line_restart(elb, e_index); } - /* Don't render the edge twice. */ - GPU_indexbuf_set_line_restart(elb, edge_idx); + EXTRACT_LEDGE_FOREACH_MESH_END; } static void extract_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb) @@ -765,18 +1046,14 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, vo } static const MeshExtract extract_lines = { - extract_lines_init, - NULL, - NULL, - extract_lines_loop_bmesh, - extract_lines_loop_mesh, - extract_lines_ledge_bmesh, - extract_lines_ledge_mesh, - NULL, - NULL, - extract_lines_finish, - 0, - false, + .init = extract_lines_init, + .iter_poly_bm = extract_lines_iter_poly_bm, + .iter_poly_mesh = extract_lines_iter_poly_mesh, + .iter_ledge_bm = extract_lines_iter_ledge_bm, + .iter_ledge_mesh = extract_lines_iter_ledge_mesh, + .finish = extract_lines_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -803,18 +1080,14 @@ static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr, void } static const MeshExtract extract_lines_with_lines_loose = { - extract_lines_init, - NULL, - NULL, - extract_lines_loop_bmesh, - extract_lines_loop_mesh, - extract_lines_ledge_bmesh, - extract_lines_ledge_mesh, - NULL, - NULL, - extract_lines_with_lines_loose_finish, - 0, - false, + .init = extract_lines_init, + .iter_poly_bm = extract_lines_iter_poly_bm, + .iter_poly_mesh = extract_lines_iter_poly_mesh, + .iter_ledge_bm = extract_lines_iter_ledge_bm, + .iter_ledge_mesh = extract_lines_iter_ledge_mesh, + .finish = extract_lines_with_lines_loose_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -830,77 +1103,101 @@ static void *extract_points_init(const MeshRenderData *mr, void *UNUSED(buf)) return elb; } -BLI_INLINE void vert_set_bmesh(GPUIndexBufBuilder *elb, BMVert *eve, int loop) +BLI_INLINE void vert_set_bm(GPUIndexBufBuilder *elb, BMVert *eve, int l_index) { - int vert_idx = BM_elem_index_get(eve); + const int v_index = BM_elem_index_get(eve); if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - GPU_indexbuf_set_point_vert(elb, vert_idx, loop); + GPU_indexbuf_set_point_vert(elb, v_index, l_index); } else { - GPU_indexbuf_set_point_restart(elb, vert_idx); + GPU_indexbuf_set_point_restart(elb, v_index); } } BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb, const MeshRenderData *mr, - int vert_idx, - int loop) + const int v_index, + const int l_index) { - const MVert *mvert = &mr->mvert[vert_idx]; - if (!((mr->use_hide && (mvert->flag & ME_HIDE)) || + const MVert *mv = &mr->mvert[v_index]; + if (!((mr->use_hide && (mv->flag & ME_HIDE)) || ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && - (mr->v_origindex[vert_idx] == ORIGINDEX_NONE)))) { - GPU_indexbuf_set_point_vert(elb, vert_idx, loop); + (mr->v_origindex[v_index] == ORIGINDEX_NONE)))) { + GPU_indexbuf_set_point_vert(elb, v_index, l_index); } else { - GPU_indexbuf_set_point_restart(elb, vert_idx); + GPU_indexbuf_set_point_restart(elb, v_index); } } -static void extract_points_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *elb) +static void extract_points_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *elb) { - vert_set_bmesh(elb, loop->v, l); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + vert_set_bm(elb, l->v, l_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_points_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *elb) +static void extract_points_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *elb) { - vert_set_mesh(elb, mr, mloop->v, l); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + vert_set_mesh(elb, mr, ml->v, ml_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_points_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *elb) +static void extract_points_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *elb) { - vert_set_bmesh(elb, eed->v1, mr->loop_len + e * 2); - vert_set_bmesh(elb, eed->v2, mr->loop_len + e * 2 + 1); + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + vert_set_bm(elb, eed->v1, mr->loop_len + (ledge_index * 2)); + vert_set_bm(elb, eed->v2, mr->loop_len + (ledge_index * 2) + 1); + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_points_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *medge, - void *elb) +static void extract_points_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *elb) { - vert_set_mesh(elb, mr, medge->v1, mr->loop_len + e * 2); - vert_set_mesh(elb, mr, medge->v2, mr->loop_len + e * 2 + 1); + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + vert_set_mesh(elb, mr, med->v1, mr->loop_len + (ledge_index * 2)); + vert_set_mesh(elb, mr, med->v2, mr->loop_len + (ledge_index * 2) + 1); + } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_points_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *elb) +static void extract_points_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *elb) { - vert_set_bmesh(elb, eve, mr->loop_len + mr->edge_loose_len * 2 + v); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + vert_set_bm(elb, eve, offset + lvert_index); + } + EXTRACT_LVERT_FOREACH_BM_END; } -static void extract_points_lvert_mesh(const MeshRenderData *mr, - int v, - const MVert *UNUSED(mvert), - void *elb) +static void extract_points_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *elb) { - vert_set_mesh(elb, mr, mr->lverts[v], mr->loop_len + mr->edge_loose_len * 2 + v); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) + { + vert_set_mesh(elb, mr, mr->lverts[lvert_index], offset + lvert_index); + } + EXTRACT_LVERT_FOREACH_MESH_END; } static void extract_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb) @@ -910,18 +1207,16 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, v } static const MeshExtract extract_points = { - extract_points_init, - NULL, - NULL, - extract_points_loop_bmesh, - extract_points_loop_mesh, - extract_points_ledge_bmesh, - extract_points_ledge_mesh, - extract_points_lvert_bmesh, - extract_points_lvert_mesh, - extract_points_finish, - 0, - false, + .init = extract_points_init, + .iter_poly_bm = extract_points_iter_poly_bm, + .iter_poly_mesh = extract_points_iter_poly_mesh, + .iter_ledge_bm = extract_points_iter_ledge_bm, + .iter_ledge_mesh = extract_points_iter_ledge_mesh, + .iter_lvert_bm = extract_points_iter_lvert_bm, + .iter_lvert_mesh = extract_points_iter_lvert_mesh, + .finish = extract_points_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -937,34 +1232,51 @@ static void *extract_fdots_init(const MeshRenderData *mr, void *UNUSED(buf)) return elb; } -static void extract_fdots_loop_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(l), - BMLoop *loop, - void *elb) +static void extract_fdots_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *elb) { - int face_idx = BM_elem_index_get(loop->f); - if (!BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN)) { - GPU_indexbuf_set_point_vert(elb, face_idx, face_idx); - } - else { - GPU_indexbuf_set_point_restart(elb, face_idx); + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + GPU_indexbuf_set_point_vert(elb, f_index, f_index); + } + else { + GPU_indexbuf_set_point_restart(elb, f_index); + } } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_fdots_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *mloop, - int p, - const MPoly *mpoly, - void *elb) +static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *elb) { - const MVert *mvert = &mr->mvert[mloop->v]; - if ((!mr->use_subsurf_fdots || (mvert->flag & ME_VERT_FACEDOT)) && - !(mr->use_hide && (mpoly->flag & ME_HIDE))) { - GPU_indexbuf_set_point_vert(elb, p, p); + if (mr->use_subsurf_fdots) { + /* Check #ME_VERT_FACEDOT. */ + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MVert *mv = &mr->mvert[ml->v]; + if ((mv->flag & ME_VERT_FACEDOT) && !(mr->use_hide && (mp->flag & ME_HIDE))) { + GPU_indexbuf_set_point_vert(elb, mp_index, mp_index); + } + else { + GPU_indexbuf_set_point_restart(elb, mp_index); + } + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } else { - GPU_indexbuf_set_point_restart(elb, p); + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + GPU_indexbuf_set_point_vert(elb, mp_index, mp_index); + } + else { + GPU_indexbuf_set_point_restart(elb, mp_index); + } + } + EXTRACT_POLY_FOREACH_MESH_END; } } @@ -975,18 +1287,12 @@ static void extract_fdots_finish(const MeshRenderData *UNUSED(mr), void *ibo, vo } static const MeshExtract extract_fdots = { - extract_fdots_init, - NULL, - NULL, - extract_fdots_loop_bmesh, - extract_fdots_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_fdots_finish, - 0, - false, + .init = extract_fdots_init, + .iter_poly_bm = extract_fdots_iter_poly_bm, + .iter_poly_mesh = extract_fdots_iter_poly_mesh, + .finish = extract_fdots_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1009,66 +1315,60 @@ static void *extract_lines_paint_mask_init(const MeshRenderData *mr, void *UNUSE return data; } -static void extract_lines_paint_mask_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *_data) -{ - MeshExtract_LinePaintMask_Data *data = (MeshExtract_LinePaintMask_Data *)_data; - const int edge_idx = mloop->e; - const MEdge *medge = &mr->medge[edge_idx]; - if (!((mr->use_hide && (medge->flag & ME_HIDE)) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[edge_idx] == ORIGINDEX_NONE)))) { - - int loopend = mpoly->totloop + mpoly->loopstart - 1; - int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1); - if (mpoly->flag & ME_FACE_SEL) { - if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, edge_idx)) { - /* Hide edge as it has more than 2 selected loop. */ - GPU_indexbuf_set_line_restart(&data->elb, edge_idx); +static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) +{ + MeshExtract_LinePaintMask_Data *data = _data; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const int e_index = ml->e; + const MEdge *me = &mr->medge[e_index]; + if (!((mr->use_hide && (me->flag & ME_HIDE)) || + ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && + (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) { + + const int ml_index_last = mp->totloop + mp->loopstart - 1; + const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1); + if (mp->flag & ME_FACE_SEL) { + if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, e_index)) { + /* Hide edge as it has more than 2 selected loop. */ + GPU_indexbuf_set_line_restart(&data->elb, e_index); + } + else { + /* First selected loop. Set edge visible, overwriting any unselected loop. */ + GPU_indexbuf_set_line_verts(&data->elb, e_index, ml_index, ml_index_other); + } } else { - /* First selected loop. Set edge visible, overwritting any unsel loop. */ - GPU_indexbuf_set_line_verts(&data->elb, edge_idx, l, other_loop); + /* Set theses unselected loop only if this edge has no other selected loop. */ + if (!BLI_BITMAP_TEST(data->select_map, e_index)) { + GPU_indexbuf_set_line_verts(&data->elb, e_index, ml_index, ml_index_other); + } } } else { - /* Set theses unselected loop only if this edge has no other selected loop. */ - if (!BLI_BITMAP_TEST(data->select_map, edge_idx)) { - GPU_indexbuf_set_line_verts(&data->elb, edge_idx, l, other_loop); - } + GPU_indexbuf_set_line_restart(&data->elb, e_index); } } - else { - GPU_indexbuf_set_line_restart(&data->elb, edge_idx); - } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *_data) { - MeshExtract_LinePaintMask_Data *data = (MeshExtract_LinePaintMask_Data *)_data; + MeshExtract_LinePaintMask_Data *data = _data; GPU_indexbuf_build_in_place(&data->elb, ibo); MEM_freeN(data); } static const MeshExtract extract_lines_paint_mask = { - extract_lines_paint_mask_init, - NULL, - NULL, - NULL, - extract_lines_paint_mask_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_lines_paint_mask_finish, - 0, - false, + .init = extract_lines_paint_mask_init, + .iter_poly_mesh = extract_lines_paint_mask_iter_poly_mesh, + .finish = extract_lines_paint_mask_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1090,7 +1390,7 @@ typedef struct MeshExtract_LineAdjacency_Data { static void *extract_lines_adjacency_init(const MeshRenderData *mr, void *UNUSED(buf)) { /* Similar to poly_to_tri_count(). - * There is always loop + tri - 1 edges inside a polygon. + * There is always (loop + triangle - 1) edges inside a polygon. * Accumulate for all polys and you get : */ uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len; @@ -1107,7 +1407,7 @@ BLI_INLINE void lines_adjacency_triangle( uint v1, uint v2, uint v3, uint l1, uint l2, uint l3, MeshExtract_LineAdjacency_Data *data) { GPUIndexBufBuilder *elb = &data->elb; - /* Iter around the triangle's edges. */ + /* Iterate around the triangle's edges. */ for (int e = 0; e < 3; e++) { SHIFT3(uint, v3, v2, v1); SHIFT3(uint, l3, l2, l1); @@ -1118,7 +1418,7 @@ BLI_INLINE void lines_adjacency_triangle( int v_data = POINTER_AS_INT(*pval); if (!value_is_init || v_data == NO_EDGE) { /* Save the winding order inside the sign bit. Because the - * edgehash sort the keys and we need to compare winding later. */ + * Edge-hash sort the keys and we need to compare winding later. */ int value = (int)l1 + 1; /* 0 cannot be signed so add one. */ *pval = POINTER_FROM_INT((inv_indices) ? -value : value); /* Store loop indices for remaining non-manifold edges. */ @@ -1130,7 +1430,7 @@ BLI_INLINE void lines_adjacency_triangle( *pval = POINTER_FROM_INT(NO_EDGE); bool inv_opposite = (v_data < 0); uint l_opposite = (uint)abs(v_data) - 1; - /* TODO Make this part threadsafe. */ + /* TODO Make this part thread-safe. */ if (inv_opposite == inv_indices) { /* Don't share edge if triangles have non matching winding. */ GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l1); @@ -1144,42 +1444,48 @@ BLI_INLINE void lines_adjacency_triangle( } } -static void extract_lines_adjacency_looptri_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(t), - BMLoop **elt, - void *data) +static void extract_lines_adjacency_iter_looptri_bm(const MeshRenderData *UNUSED(mr), + const struct ExtractTriBMesh_Params *params, + void *data) { - if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { - lines_adjacency_triangle(BM_elem_index_get(elt[0]->v), - BM_elem_index_get(elt[1]->v), - BM_elem_index_get(elt[2]->v), - BM_elem_index_get(elt[0]), - BM_elem_index_get(elt[1]), - BM_elem_index_get(elt[2]), - data); + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params) + { + if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { + lines_adjacency_triangle(BM_elem_index_get(elt[0]->v), + BM_elem_index_get(elt[1]->v), + BM_elem_index_get(elt[2]->v), + BM_elem_index_get(elt[0]), + BM_elem_index_get(elt[1]), + BM_elem_index_get(elt[2]), + data); + } } + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; } -static void extract_lines_adjacency_looptri_mesh(const MeshRenderData *mr, - int UNUSED(t), - const MLoopTri *mlt, - void *data) +static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData *mr, + const struct ExtractTriMesh_Params *params, + void *data) { - const MPoly *mpoly = &mr->mpoly[mlt->poly]; - if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) { - lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v, - mr->mloop[mlt->tri[1]].v, - mr->mloop[mlt->tri[2]].v, - mlt->tri[0], - mlt->tri[1], - mlt->tri[2], - data); + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params) + { + const MPoly *mp = &mr->mpoly[mlt->poly]; + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v, + mr->mloop[mlt->tri[1]].v, + mr->mloop[mlt->tri[2]].v, + mlt->tri[0], + mlt->tri[1], + mlt->tri[2], + data); + } } + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; } static void extract_lines_adjacency_finish(const MeshRenderData *mr, void *ibo, void *_data) { - MeshExtract_LineAdjacency_Data *data = (MeshExtract_LineAdjacency_Data *)_data; + MeshExtract_LineAdjacency_Data *data = _data; /* Create edges for remaining non manifold edges. */ EdgeHashIterator *ehi = BLI_edgehashIterator_new(data->eh); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { @@ -1209,18 +1515,12 @@ static void extract_lines_adjacency_finish(const MeshRenderData *mr, void *ibo, #undef NO_EDGE static const MeshExtract extract_lines_adjacency = { - extract_lines_adjacency_init, - extract_lines_adjacency_looptri_bmesh, - extract_lines_adjacency_looptri_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_lines_adjacency_finish, - 0, - false, + .init = extract_lines_adjacency_init, + .iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm, + .iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh, + .finish = extract_lines_adjacency_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1250,53 +1550,53 @@ BLI_INLINE void edituv_tri_add( } } -static void extract_edituv_tris_looptri_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(t), - BMLoop **elt, - void *data) +static void extract_edituv_tris_iter_looptri_bm(const MeshRenderData *UNUSED(mr), + const struct ExtractTriBMesh_Params *params, + void *data) { - edituv_tri_add(data, - BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT), - BM_elem_index_get(elt[0]), - BM_elem_index_get(elt[1]), - BM_elem_index_get(elt[2])); + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params) + { + edituv_tri_add(data, + BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN), + BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT), + BM_elem_index_get(elt[0]), + BM_elem_index_get(elt[1]), + BM_elem_index_get(elt[2])); + } + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; } -static void extract_edituv_tris_looptri_mesh(const MeshRenderData *mr, - int UNUSED(t), - const MLoopTri *mlt, - void *data) +static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData *mr, + const struct ExtractTriMesh_Params *params, + void *data) { - const MPoly *mpoly = &mr->mpoly[mlt->poly]; - edituv_tri_add(data, - (mpoly->flag & ME_HIDE) != 0, - (mpoly->flag & ME_FACE_SEL) != 0, - mlt->tri[0], - mlt->tri[1], - mlt->tri[2]); + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params) + { + const MPoly *mp = &mr->mpoly[mlt->poly]; + edituv_tri_add(data, + (mp->flag & ME_HIDE) != 0, + (mp->flag & ME_FACE_SEL) != 0, + mlt->tri[0], + mlt->tri[1], + mlt->tri[2]); + } + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; } static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data) { - MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data; + MeshExtract_EditUvElem_Data *extract_data = data; GPU_indexbuf_build_in_place(&extract_data->elb, ibo); MEM_freeN(extract_data); } static const MeshExtract extract_edituv_tris = { - extract_edituv_tris_init, - extract_edituv_tris_looptri_bmesh, - extract_edituv_tris_looptri_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_edituv_tris_finish, - 0, - false, + .init = extract_edituv_tris_init, + .iter_looptri_bm = extract_edituv_tris_iter_looptri_bm, + .iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh, + .finish = extract_edituv_tris_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1322,55 +1622,53 @@ BLI_INLINE void edituv_edge_add( } } -static void extract_edituv_lines_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - edituv_edge_add(data, - BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(loop->f, BM_ELEM_SELECT), - l, - BM_elem_index_get(loop->next)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(loop, l_index, params, mr) + { + edituv_edge_add(data, + BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), + BM_elem_flag_test(loop->f, BM_ELEM_SELECT), + l_index, + BM_elem_index_get(loop->next)); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(loop); } -static void extract_edituv_lines_loop_mesh(const MeshRenderData *mr, - int loop_idx, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *data) +static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - int loopend = mpoly->totloop + mpoly->loopstart - 1; - int loop_next_idx = (loop_idx == loopend) ? mpoly->loopstart : (loop_idx + 1); - const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[mloop->e] != ORIGINDEX_NONE); - edituv_edge_add(data, - (mpoly->flag & ME_HIDE) != 0 || !real_edge, - (mpoly->flag & ME_FACE_SEL) != 0, - loop_idx, - loop_next_idx); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const int ml_index_last = mp->totloop + mp->loopstart - 1; + const int ml_index_next = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1); + const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[ml->e] != ORIGINDEX_NONE); + edituv_edge_add(data, + (mp->flag & ME_HIDE) != 0 || !real_edge, + (mp->flag & ME_FACE_SEL) != 0, + ml_index, + ml_index_next); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data) { - MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data; + MeshExtract_EditUvElem_Data *extract_data = data; GPU_indexbuf_build_in_place(&extract_data->elb, ibo); MEM_freeN(extract_data); } static const MeshExtract extract_edituv_lines = { - extract_edituv_lines_init, - NULL, - NULL, - extract_edituv_lines_loop_bmesh, - extract_edituv_lines_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_edituv_lines_finish, - 0, - false, + .init = extract_edituv_lines_init, + .iter_poly_bm = extract_edituv_lines_iter_poly_bm, + .iter_poly_mesh = extract_edituv_lines_iter_poly_mesh, + .finish = extract_edituv_lines_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1398,50 +1696,48 @@ BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data, } } -static void extract_edituv_points_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_edituv_points_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - edituv_point_add(data, - BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(loop->f, BM_ELEM_SELECT), - l); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + edituv_point_add(data, + BM_elem_flag_test(l->f, BM_ELEM_HIDDEN), + BM_elem_flag_test(l->f, BM_ELEM_SELECT), + l_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edituv_points_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *data) +static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && - mr->v_origindex[mloop->v] != ORIGINDEX_NONE); - edituv_point_add( - data, ((mpoly->flag & ME_HIDE) != 0) || !real_vert, (mpoly->flag & ME_FACE_SEL) != 0, l); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && + mr->v_origindex[ml->v] != ORIGINDEX_NONE); + edituv_point_add( + data, ((mp->flag & ME_HIDE) != 0) || !real_vert, (mp->flag & ME_FACE_SEL) != 0, ml_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data) { - MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data; + MeshExtract_EditUvElem_Data *extract_data = data; GPU_indexbuf_build_in_place(&extract_data->elb, ibo); MEM_freeN(extract_data); } static const MeshExtract extract_edituv_points = { - extract_edituv_points_init, - NULL, - NULL, - extract_edituv_points_loop_bmesh, - extract_edituv_points_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_edituv_points_finish, - 0, - false, + .init = extract_edituv_points_init, + .iter_poly_bm = extract_edituv_points_iter_poly_bm, + .iter_poly_mesh = extract_edituv_points_iter_poly_mesh, + .finish = extract_edituv_points_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1462,64 +1758,75 @@ static void *extract_edituv_fdots_init(const MeshRenderData *mr, void *UNUSED(ib BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, - int face_idx) + int face_index) { if (!hidden && (data->sync_selection || selected)) { - GPU_indexbuf_set_point_vert(&data->elb, face_idx, face_idx); + GPU_indexbuf_set_point_vert(&data->elb, face_index, face_index); } else { - GPU_indexbuf_set_point_restart(&data->elb, face_idx); + GPU_indexbuf_set_point_restart(&data->elb, face_index); } } -static void extract_edituv_fdots_loop_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(l), - BMLoop *loop, - void *data) +static void extract_edituv_fdots_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - edituv_facedot_add(data, - BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(loop->f, BM_ELEM_SELECT), - BM_elem_index_get(loop->f)); + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + edituv_facedot_add( + data, BM_elem_flag_test(f, BM_ELEM_HIDDEN), BM_elem_flag_test(f, BM_ELEM_SELECT), f_index); + } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_edituv_fdots_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *mloop, - int p, - const MPoly *mpoly, - void *data) +static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && - mr->p_origindex[p] != ORIGINDEX_NONE); - const bool subd_fdot = (!mr->use_subsurf_fdots || - (mr->mvert[mloop->v].flag & ME_VERT_FACEDOT) != 0); - edituv_facedot_add(data, - ((mpoly->flag & ME_HIDE) != 0) || !real_fdot || !subd_fdot, - (mpoly->flag & ME_FACE_SEL) != 0, - p); + if (mr->use_subsurf_fdots) { + /* Check #ME_VERT_FACEDOT. */ + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && + mr->p_origindex[mp_index] != ORIGINDEX_NONE); + const bool subd_fdot = (!mr->use_subsurf_fdots || + (mr->mvert[ml->v].flag & ME_VERT_FACEDOT) != 0); + edituv_facedot_add(data, + ((mp->flag & ME_HIDE) != 0) || !real_fdot || !subd_fdot, + (mp->flag & ME_FACE_SEL) != 0, + mp_index); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; + } + else { + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && + mr->p_origindex[mp_index] != ORIGINDEX_NONE); + edituv_facedot_add(data, + ((mp->flag & ME_HIDE) != 0) || !real_fdot, + (mp->flag & ME_FACE_SEL) != 0, + mp_index); + } + EXTRACT_POLY_FOREACH_MESH_END; + } } static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *_data) { - MeshExtract_EditUvElem_Data *data = (MeshExtract_EditUvElem_Data *)_data; + MeshExtract_EditUvElem_Data *data = _data; GPU_indexbuf_build_in_place(&data->elb, ibo); MEM_freeN(data); } static const MeshExtract extract_edituv_fdots = { - extract_edituv_fdots_init, - NULL, - NULL, - extract_edituv_fdots_loop_bmesh, - extract_edituv_fdots_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_edituv_fdots_finish, - 0, - false, + .init = extract_edituv_fdots_init, + .iter_poly_bm = extract_edituv_fdots_iter_poly_bm, + .iter_poly_mesh = extract_edituv_fdots_iter_poly_mesh, + .finish = extract_edituv_fdots_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1542,7 +1849,7 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - /* WARNING Adjust PosNorLoop struct accordingly. */ + /* WARNING Adjust #PosNorLoop struct accordingly. */ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); GPU_vertformat_alias_add(&format, "vnor"); @@ -1566,95 +1873,122 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf) } } else { - const MVert *mvert = mr->mvert; - for (int v = 0; v < mr->vert_len; v++, mvert++) { - data->packed_nor[v] = GPU_normal_convert_i10_s3(mvert->no); + const MVert *mv = mr->mvert; + for (int v = 0; v < mr->vert_len; v++, mv++) { + data->packed_nor[v] = GPU_normal_convert_i10_s3(mv->no); } } return data; } -static void extract_pos_nor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data) +static void extract_pos_nor_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, loop->v)); - vert->nor = data->packed_nor[BM_elem_index_get(loop->v)]; - BMFace *efa = loop->f; - vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + PosNorLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert->pos, bm_vert_co_get(mr, l->v)); + vert->nor = data->packed_nor[BM_elem_index_get(l->v)]; + BMFace *efa = l->f; + vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_pos_nor_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *mpoly, - void *_data) +static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - const MVert *mvert = &mr->mvert[mloop->v]; - copy_v3_v3(vert->pos, mvert->co); - vert->nor = data->packed_nor[mloop->v]; - /* Flag for paint mode overlay. */ - if (mpoly->flag & ME_HIDE || mvert->flag & ME_HIDE || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && - (mr->v_origindex[mloop->v] == ORIGINDEX_NONE))) { - vert->nor.w = -1; - } - else if (mvert->flag & SELECT) { - vert->nor.w = 1; - } - else { - vert->nor.w = 0; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + PosNorLoop *vert = &data->vbo_data[ml_index]; + const MVert *mv = &mr->mvert[ml->v]; + copy_v3_v3(vert->pos, mv->co); + vert->nor = data->packed_nor[ml->v]; + /* Flag for paint mode overlay. */ + if (mp->flag & ME_HIDE || mv->flag & ME_HIDE || + ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && + (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) { + vert->nor.w = -1; + } + else if (mv->flag & SELECT) { + vert->nor.w = 1; + } + else { + vert->nor.w = 0; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_pos_nor_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *_data) +static void extract_pos_nor_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *_data) { - int l = mr->loop_len + e * 2; MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); - copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); - vert[0].nor = data->packed_nor[BM_elem_index_get(eed->v1)]; - vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)]; + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + int l_index = mr->loop_len + ledge_index * 2; + PosNorLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); + copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); + vert[0].nor = data->packed_nor[BM_elem_index_get(eed->v1)]; + vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)]; + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_pos_nor_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *medge, - void *_data) +static void extract_pos_nor_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *_data) { - int l = mr->loop_len + e * 2; MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert[0].pos, mr->mvert[medge->v1].co); - copy_v3_v3(vert[1].pos, mr->mvert[medge->v2].co); - vert[0].nor = data->packed_nor[medge->v1]; - vert[1].nor = data->packed_nor[medge->v2]; + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + const int ml_index = mr->loop_len + ledge_index * 2; + PosNorLoop *vert = &data->vbo_data[ml_index]; + copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co); + copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co); + vert[0].nor = data->packed_nor[med->v1]; + vert[1].nor = data->packed_nor[med->v2]; + } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_pos_nor_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *_data) +static void extract_pos_nor_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *_data) { - int l = mr->loop_len + mr->edge_loose_len * 2 + v; MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); - vert->nor = data->packed_nor[BM_elem_index_get(eve)]; + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + const int l_index = offset + lvert_index; + PosNorLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); + vert->nor = data->packed_nor[BM_elem_index_get(eve)]; + } + EXTRACT_LVERT_FOREACH_BM_END; } -static void extract_pos_nor_lvert_mesh(const MeshRenderData *mr, - int v, - const MVert *mvert, - void *_data) +static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *_data) { - int l = mr->loop_len + mr->edge_loose_len * 2 + v; - int v_idx = mr->lverts[v]; MeshExtract_PosNor_Data *data = _data; - PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, mvert->co); - vert->nor = data->packed_nor[v_idx]; + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) + { + const int ml_index = offset + lvert_index; + const int v_index = mr->lverts[lvert_index]; + PosNorLoop *vert = &data->vbo_data[ml_index]; + copy_v3_v3(vert->pos, mv->co); + vert->nor = data->packed_nor[v_index]; + } + EXTRACT_LVERT_FOREACH_MESH_END; } static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(vbo), void *data) @@ -1663,18 +1997,16 @@ static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), void *UNUSE } static const MeshExtract extract_pos_nor = { - extract_pos_nor_init, - NULL, - NULL, - extract_pos_nor_loop_bmesh, - extract_pos_nor_loop_mesh, - extract_pos_nor_ledge_bmesh, - extract_pos_nor_ledge_mesh, - extract_pos_nor_lvert_bmesh, - extract_pos_nor_lvert_mesh, - extract_pos_nor_finish, - 0, - true, + .init = extract_pos_nor_init, + .iter_poly_bm = extract_pos_nor_iter_poly_bm, + .iter_poly_mesh = extract_pos_nor_iter_poly_mesh, + .iter_ledge_bm = extract_pos_nor_iter_ledge_bm, + .iter_ledge_mesh = extract_pos_nor_iter_ledge_mesh, + .iter_lvert_bm = extract_pos_nor_iter_lvert_bm, + .iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh, + .finish = extract_pos_nor_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -1700,62 +2032,71 @@ static void *extract_lnor_hq_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_lnor_hq_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *data) +static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { if (mr->loop_normals) { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, mr->loop_normals[l]); - } - else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_vert_no_get(mr, loop->v)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(_l, l_index, params, mr) + { + normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, mr->loop_normals[l_index]); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(_l); } else { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_face_no_get(mr, loop->f)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH)) { + normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_vert_no_get(mr, l->v)); + } + else { + normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_face_no_get(mr, l->f)); + } + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } } -static void extract_lnor_hq_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data) +static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - gpuHQNor *lnor_data = &((gpuHQNor *)data)[l]; - if (mr->loop_normals) { - normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[l]); - } - else if (mpoly->flag & ME_SMOOTH) { - copy_v3_v3_short(&lnor_data->x, mr->mvert[mloop->v].no); - } - else { - normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[p]); - } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + gpuHQNor *lnor_data = &((gpuHQNor *)data)[ml_index]; + if (mr->loop_normals) { + normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]); + } + else if (mp->flag & ME_SMOOTH) { + copy_v3_v3_short(&lnor_data->x, mr->mvert[ml->v].no); + } + else { + normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]); + } - /* Flag for paint mode overlay. - * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In - * paint mode it will use the unmapped data to draw the wireframe. */ - if (mpoly->flag & ME_HIDE || - (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && - mr->v_origindex[mloop->v] == ORIGINDEX_NONE)) { - lnor_data->w = -1; - } - else if (mpoly->flag & ME_FACE_SEL) { - lnor_data->w = 1; - } - else { - lnor_data->w = 0; + /* Flag for paint mode overlay. + * Only use #MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. + * In paint mode it will use the un-mapped data to draw the wire-frame. */ + if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && + (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) { + lnor_data->w = -1; + } + else if (mp->flag & ME_FACE_SEL) { + lnor_data->w = 1; + } + else { + lnor_data->w = 0; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static const MeshExtract extract_lnor_hq = { - extract_lnor_hq_init, - NULL, - NULL, - extract_lnor_hq_loop_bmesh, - extract_lnor_hq_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - MR_DATA_LOOP_NOR, - true, + .init = extract_lnor_hq_init, + .iter_poly_bm = extract_lnor_hq_iter_poly_bm, + .iter_poly_mesh = extract_lnor_hq_iter_poly_mesh, + .data_flag = MR_DATA_LOOP_NOR, + .use_threading = true, }; /** \} */ @@ -1777,64 +2118,75 @@ static void *extract_lnor_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_lnor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *data) +static void extract_lnor_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { if (mr->loop_normals) { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->loop_normals[l]); - } - else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, loop->v)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]); + BMFace *efa = l->f; + ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } else { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, loop->f)); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH)) { + ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, l->v)); + } + else { + ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, l->f)); + } + BMFace *efa = l->f; + ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } - BMFace *efa = loop->f; - ((GPUPackedNormal *)data)[l].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; } -static void extract_lnor_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data) +static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - GPUPackedNormal *lnor_data = &((GPUPackedNormal *)data)[l]; - if (mr->loop_normals) { - *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[l]); - } - else if (mpoly->flag & ME_SMOOTH) { - *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[mloop->v].no); - } - else { - *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[p]); - } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + GPUPackedNormal *lnor_data = &((GPUPackedNormal *)data)[ml_index]; + if (mr->loop_normals) { + *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]); + } + else if (mp->flag & ME_SMOOTH) { + *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[ml->v].no); + } + else { + *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]); + } - /* Flag for paint mode overlay. - * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In - * paint mode it will use the unmapped data to draw the wireframe. */ - if (mpoly->flag & ME_HIDE || - (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && - mr->v_origindex[mloop->v] == ORIGINDEX_NONE)) { - lnor_data->w = -1; - } - else if (mpoly->flag & ME_FACE_SEL) { - lnor_data->w = 1; - } - else { - lnor_data->w = 0; + /* Flag for paint mode overlay. + * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. + * In paint mode it will use the un-mapped data to draw the wire-frame. */ + if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && + (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) { + lnor_data->w = -1; + } + else if (mp->flag & ME_FACE_SEL) { + lnor_data->w = 1; + } + else { + lnor_data->w = 0; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static const MeshExtract extract_lnor = { - extract_lnor_init, - NULL, - NULL, - extract_lnor_loop_bmesh, - extract_lnor_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - MR_DATA_LOOP_NOR, - true, + .init = extract_lnor_init, + .iter_poly_bm = extract_lnor_iter_poly_bm, + .iter_poly_mesh = extract_lnor_iter_poly_mesh, + .data_flag = MR_DATA_LOOP_NOR, + .use_threading = true, }; /** \} */ @@ -1878,7 +2230,7 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf) /* Active display layer name. */ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { GPU_vertformat_alias_add(&format, "au"); - /* Alias to pos for edit uvs. */ + /* Alias to `pos` for edit uvs. */ GPU_vertformat_alias_add(&format, "pos"); } /* Stencil mask uv layer name. */ @@ -1904,20 +2256,21 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf) if (uv_layers & (1 << i)) { if (mr->extract_type == MR_EXTRACT_BMESH) { int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPUV, i); - BMIter f_iter, l_iter; + BMIter f_iter; BMFace *efa; - BMLoop *loop; BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs); memcpy(uv_data, luv->uv, sizeof(*uv_data)); uv_data++; - } + } while ((l_iter = l_iter->next) != l_first); } } else { MLoopUV *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i); - for (int l = 0; l < mr->loop_len; l++, uv_data++, layer_data++) { + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, uv_data++, layer_data++) { memcpy(uv_data, layer_data->uv, sizeof(*uv_data)); } } @@ -1928,18 +2281,9 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf) } static const MeshExtract extract_uv = { - extract_uv_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - false, + .init = extract_uv_init, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -1987,7 +2331,7 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool } } if (use_orco_tan && orco == NULL) { - /* If orco is not available compute it ourselves */ + /* If `orco` is not available compute it ourselves */ orco_allocated = true; orco = MEM_mallocN(sizeof(*orco) * mr->vert_len, __func__); @@ -2001,17 +2345,18 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool } } else { - const MVert *mvert = mr->mvert; - for (int v = 0; v < mr->vert_len; v++, mvert++) { - copy_v3_v3(orco[v], mvert->co); + const MVert *mv = mr->mvert; + for (int v = 0; v < mr->vert_len; v++, mv++) { + copy_v3_v3(orco[v], mv->co); } } BKE_mesh_orco_verts_transform(mr->me, orco, mr->vert_len, 0); } /* Start Fresh */ - CustomData_free_layers(cd_ldata, CD_TANGENT, mr->loop_len); - + CustomData loop_data; + CustomData_reset(&loop_data); + CustomData *ldata = cd_ldata; if (tan_len != 0 || use_orco_tan) { short tangent_mask = 0; bool calc_active_tangent = false; @@ -2041,9 +2386,10 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool mr->poly_normals, mr->loop_normals, orco, - cd_ldata, + &loop_data, mr->loop_len, &tangent_mask); + ldata = &loop_data; } } @@ -2075,18 +2421,18 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool short(*tan_data)[4] = (short(*)[4])vbo->data; for (int i = 0; i < tan_len; i++) { const char *name = tangent_names[i]; - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(cd_ldata, CD_TANGENT, name); - for (int l = 0; l < mr->loop_len; l++) { - normal_float_to_short_v3(*tan_data, layer_data[l]); - (*tan_data)[3] = (layer_data[l][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(ldata, CD_TANGENT, name); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { + normal_float_to_short_v3(*tan_data, layer_data[ml_index]); + (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; tan_data++; } } if (use_orco_tan) { - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(cd_ldata, CD_TANGENT, 0); - for (int l = 0; l < mr->loop_len; l++) { - normal_float_to_short_v3(*tan_data, layer_data[l]); - (*tan_data)[3] = (layer_data[l][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(ldata, CD_TANGENT, 0); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { + normal_float_to_short_v3(*tan_data, layer_data[ml_index]); + (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; tan_data++; } } @@ -2095,24 +2441,25 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool GPUPackedNormal *tan_data = (GPUPackedNormal *)vbo->data; for (int i = 0; i < tan_len; i++) { const char *name = tangent_names[i]; - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(cd_ldata, CD_TANGENT, name); - for (int l = 0; l < mr->loop_len; l++) { - *tan_data = GPU_normal_convert_i10_v3(layer_data[l]); - tan_data->w = (layer_data[l][3] > 0.0f) ? 1 : -2; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(ldata, CD_TANGENT, name); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { + *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]); + tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2; tan_data++; } } if (use_orco_tan) { - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(cd_ldata, CD_TANGENT, 0); - for (int l = 0; l < mr->loop_len; l++) { - *tan_data = GPU_normal_convert_i10_v3(layer_data[l]); - tan_data->w = (layer_data[l][3] > 0.0f) ? 1 : -2; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(ldata, CD_TANGENT, 0); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { + *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]); + tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2; tan_data++; } } } - CustomData_free_layers(cd_ldata, CD_TANGENT, mr->loop_len); + CustomData_free_layers(ldata, CD_TANGENT, mr->loop_len); + CustomData_free(&loop_data, mr->loop_len); } static void *extract_tan_init(const MeshRenderData *mr, void *buf) @@ -2122,18 +2469,9 @@ static void *extract_tan_init(const MeshRenderData *mr, void *buf) } static const MeshExtract extract_tan = { - extract_tan_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, - false, + .init = extract_tan_init, + .data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, + .use_threading = false, }; /** \} */ @@ -2149,18 +2487,9 @@ static void *extract_tan_hq_init(const MeshRenderData *mr, void *buf) } static const MeshExtract extract_tan_hq = { - extract_tan_hq_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, - false, + .init = extract_tan_hq_init, + .data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, + .use_threading = false, }; /** \} */ @@ -2175,7 +2504,9 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) GPU_vertformat_deinterleave(&format); CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; uint32_t vcol_layers = mr->cache->cd_used.vcol; + uint32_t svcol_layers = mr->cache->cd_used.sculpt_vcol; for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { @@ -2192,14 +2523,42 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) { GPU_vertformat_alias_add(&format, "ac"); } + /* Gather number of auto layers. */ - /* We only do vcols that are not overridden by uvs */ + /* We only do `vcols` that are not overridden by `uvs` and sculpt vertex colors. */ + if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1 && + CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, layer_name) == -1) { + BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); + GPU_vertformat_alias_add(&format, attr_name); + } + } + } + + /* Sculpt Vertex Colors */ + for (int i = 0; i < 8; i++) { + if (svcol_layers & (1 << i)) { + char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; + const char *layer_name = CustomData_get_layer_name(cd_vdata, CD_PROP_COLOR, i); + GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); + + BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name); + GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + + if (i == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) { + GPU_vertformat_alias_add(&format, "c"); + } + if (i == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) { + GPU_vertformat_alias_add(&format, "ac"); + } + /* Gather number of auto layers. */ + /* We only do `vcols` that are not overridden by `uvs`. */ if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) { BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); GPU_vertformat_alias_add(&format, attr_name); } } } + GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -2209,27 +2568,30 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) } gpuMeshVcol; gpuMeshVcol *vcol_data = (gpuMeshVcol *)vbo->data; + MLoop *loops = CustomData_get_layer(cd_ldata, CD_MLOOP); + for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { if (mr->extract_type == MR_EXTRACT_BMESH) { int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPCOL, i); - BMIter f_iter, l_iter; + BMIter f_iter; BMFace *efa; - BMLoop *loop; BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { - const MLoopCol *mloopcol = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const MLoopCol *mloopcol = BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs); vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); vcol_data++; - } + } while ((l_iter = l_iter->next) != l_first); } } else { const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); - for (int l = 0; l < mr->loop_len; l++, mloopcol++, vcol_data++) { + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, mloopcol++, vcol_data++) { vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); @@ -2237,22 +2599,45 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) } } } + + if (svcol_layers & (1 << i)) { + if (mr->extract_type == MR_EXTRACT_BMESH) { + int cd_ofs = CustomData_get_n_offset(cd_vdata, CD_PROP_COLOR, i); + BMIter f_iter; + BMFace *efa; + BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const MPropCol *prop_col = BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs); + vcol_data->r = unit_float_to_ushort_clamp(prop_col->color[0]); + vcol_data->g = unit_float_to_ushort_clamp(prop_col->color[1]); + vcol_data->b = unit_float_to_ushort_clamp(prop_col->color[2]); + vcol_data->a = unit_float_to_ushort_clamp(prop_col->color[3]); + vcol_data++; + } while ((l_iter = l_iter->next) != l_first); + } + } + else { + MPropCol *vcol = CustomData_get_layer_n(cd_vdata, CD_PROP_COLOR, i); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vcol_data++) { + vcol_data->r = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[0]); + vcol_data->g = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[1]); + vcol_data->b = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[2]); + vcol_data->a = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[3]); + } + } + + vcol_data += mr->loop_len; + } } return NULL; } static const MeshExtract extract_vcol = { - extract_vcol_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - false, + .init = extract_vcol_init, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -2271,7 +2656,7 @@ static void *extract_orco_init(const MeshRenderData *mr, void *buf) static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex - * attributes. This is a substantial waste of Vram and should be done another way. + * attributes. This is a substantial waste of video-ram and should be done another way. * Unfortunately, at the time of writing, I did not found any other "non disruptive" * alternative. */ GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); @@ -2286,33 +2671,37 @@ static void *extract_orco_init(const MeshRenderData *mr, void *buf) MeshExtract_Orco_Data *data = MEM_mallocN(sizeof(*data), __func__); data->vbo_data = (float(*)[4])vbo->data; data->orco = CustomData_get_layer(cd_vdata, CD_ORCO); - /* Make sure orco layer was requested only if needed! */ + /* Make sure `orco` layer was requested only if needed! */ BLI_assert(data->orco); return data; } -static void extract_orco_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_orco_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; - float *loop_orco = orco_data->vbo_data[l]; - copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]); - loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(loop, l_index, params, mr) + { + float *loop_orco = orco_data->vbo_data[l_index]; + copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]); + loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(loop); } -static void extract_orco_loop_mesh(const MeshRenderData *UNUSED(mr), - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *data) +static void extract_orco_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; - float *loop_orco = orco_data->vbo_data[l]; - copy_v3_v3(loop_orco, orco_data->orco[mloop->v]); - loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; + float *loop_orco = orco_data->vbo_data[ml_index]; + copy_v3_v3(loop_orco, orco_data->orco[ml->v]); + loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_orco_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data) @@ -2321,18 +2710,12 @@ static void extract_orco_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(b } static const MeshExtract extract_orco = { - extract_orco_init, - NULL, - NULL, - extract_orco_loop_bmesh, - extract_orco_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_orco_finish, - 0, - true, + .init = extract_orco_init, + .iter_poly_bm = extract_orco_iter_poly_bm, + .iter_poly_mesh = extract_orco_iter_poly_mesh, + .finish = extract_orco_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -2359,7 +2742,7 @@ static float loop_edge_factor_get(const float f_no[3], cross_v3_v3v3(enor, v_no, evec); normalize_v3(enor); float d = fabsf(dot_v3v3(enor, f_no)); - /* Rescale to the slider range. */ + /* Re-scale to the slider range. */ d *= (1.0f / 0.065f); CLAMP(d, 0.0f, 1.0f); return d; @@ -2383,9 +2766,9 @@ static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf) /* HACK(fclem) Detecting the need for edge render. * We could have a flag in the mesh instead or check the modifier stack. */ - const MEdge *medge = mr->medge; - for (int e = 0; e < mr->edge_len; e++, medge++) { - if ((medge->flag & ME_EDGERENDER) == 0) { + const MEdge *med = mr->medge; + for (int e_index = 0; e_index < mr->edge_len; e_index++, med++) { + if ((med->flag & ME_EDGERENDER) == 0) { data->use_edge_render = true; break; } @@ -2401,81 +2784,103 @@ static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_edge_fac_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data) +static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; - if (BM_edge_is_manifold(loop->e)) { - float ratio = loop_edge_factor_get(bm_face_no_get(mr, loop->f), - bm_vert_co_get(mr, loop->v), - bm_vert_no_get(mr, loop->v), - bm_vert_co_get(mr, loop->next->v)); - data->vbo_data[l] = ratio * 253 + 1; - } - else { - data->vbo_data[l] = 255; + MeshExtract_EdgeFac_Data *data = _data; + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + if (BM_edge_is_manifold(l->e)) { + float ratio = loop_edge_factor_get(bm_face_no_get(mr, l->f), + bm_vert_co_get(mr, l->v), + bm_vert_no_get(mr, l->v), + bm_vert_co_get(mr, l->next->v)); + data->vbo_data[l_index] = ratio * 253 + 1; + } + else { + data->vbo_data[l_index] = 255; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edge_fac_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data) +static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; + if (data->use_edge_render) { - const MEdge *medge = &mr->medge[mloop->e]; - data->vbo_data[l] = (medge->flag & ME_EDGERENDER) ? 255 : 0; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MEdge *med = &mr->medge[ml->e]; + data->vbo_data[ml_index] = (med->flag & ME_EDGERENDER) ? 255 : 0; + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } else { - /* Count loop per edge to detect non-manifold. */ - if (data->edge_loop_count[mloop->e] < 3) { - data->edge_loop_count[mloop->e]++; - } - if (data->edge_loop_count[mloop->e] == 2) { - /* Manifold */ - int loopend = mpoly->totloop + mpoly->loopstart - 1; - int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1); - const MLoop *mloop_next = &mr->mloop[other_loop]; - const MVert *v1 = &mr->mvert[mloop->v]; - const MVert *v2 = &mr->mvert[mloop_next->v]; - float vnor_f[3]; - normal_short_to_float_v3(vnor_f, v1->no); - float ratio = loop_edge_factor_get(mr->poly_normals[p], v1->co, vnor_f, v2->co); - data->vbo_data[l] = ratio * 253 + 1; - } - else { - /* Non-manifold */ - data->vbo_data[l] = 255; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + /* Count loop per edge to detect non-manifold. */ + if (data->edge_loop_count[ml->e] < 3) { + data->edge_loop_count[ml->e]++; + } + if (data->edge_loop_count[ml->e] == 2) { + /* Manifold */ + const int ml_index_last = mp->totloop + mp->loopstart - 1; + const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1); + const MLoop *ml_next = &mr->mloop[ml_index_other]; + const MVert *v1 = &mr->mvert[ml->v]; + const MVert *v2 = &mr->mvert[ml_next->v]; + float vnor_f[3]; + normal_short_to_float_v3(vnor_f, v1->no); + float ratio = loop_edge_factor_get(mr->poly_normals[mp_index], v1->co, vnor_f, v2->co); + data->vbo_data[ml_index] = ratio * 253 + 1; + } + else { + /* Non-manifold */ + data->vbo_data[ml_index] = 255; + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } } -static void extract_edge_fac_ledge_bmesh(const MeshRenderData *mr, - int e, - BMEdge *UNUSED(eed), - void *_data) +static void extract_edge_fac_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *_data) { - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; - data->vbo_data[mr->loop_len + e * 2 + 0] = 255; - data->vbo_data[mr->loop_len + e * 2 + 1] = 255; + MeshExtract_EdgeFac_Data *data = _data; + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255; + data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255; + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_edge_fac_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *UNUSED(edge), - void *_data) +static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *_data) { - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; - data->vbo_data[mr->loop_len + e * 2 + 0] = 255; - data->vbo_data[mr->loop_len + e * 2 + 1] = 255; + MeshExtract_EdgeFac_Data *data = _data; + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255; + data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255; + } + EXTRACT_LEDGE_FOREACH_MESH_END; } static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_data) { - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; + MeshExtract_EdgeFac_Data *data = _data; if (GPU_crappy_amd_driver()) { GPUVertBuf *vbo = (GPUVertBuf *)buf; - /* Some AMD drivers strangely crash with VBOs with a one byte format. - * To workaround we reinit the vbo with another format and convert + /* Some AMD drivers strangely crash with VBO's with a one byte format. + * To workaround we reinitialize the VBO with another format and convert * all bytes to floats. */ static GPUVertFormat format = {0}; if (format.attr_len == 0) { @@ -2490,8 +2895,8 @@ static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_ GPU_vertbuf_data_alloc(vbo, buf_len); float *fdata = (float *)vbo->data; - for (int l = 0; l < buf_len; l++, fdata++) { - *fdata = data->vbo_data[l] / 255.0f; + for (int ml_index = 0; ml_index < buf_len; ml_index++, fdata++) { + *fdata = data->vbo_data[ml_index] / 255.0f; } /* Free old byte data. */ MEM_freeN(data->vbo_data); @@ -2500,18 +2905,14 @@ static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_ } static const MeshExtract extract_edge_fac = { - extract_edge_fac_init, - NULL, - NULL, - extract_edge_fac_loop_bmesh, - extract_edge_fac_loop_mesh, - extract_edge_fac_ledge_bmesh, - extract_edge_fac_ledge_mesh, - NULL, - NULL, - extract_edge_fac_finish, - MR_DATA_POLY_NOR, - false, + .init = extract_edge_fac_init, + .iter_poly_bm = extract_edge_fac_iter_poly_bm, + .iter_poly_mesh = extract_edge_fac_iter_poly_mesh, + .iter_ledge_bm = extract_edge_fac_iter_ledge_bm, + .iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh, + .finish = extract_edge_fac_finish, + .data_flag = MR_DATA_POLY_NOR, + .use_threading = false, }; /** \} */ @@ -2522,8 +2923,8 @@ static const MeshExtract extract_edge_fac = { typedef struct MeshExtract_Weight_Data { float *vbo_data; const DRW_MeshWeightState *wstate; - const MDeformVert *dvert; /* For Mesh. */ - int cd_ofs; /* For BMesh. */ + const MDeformVert *dvert; /* For #Mesh. */ + int cd_ofs; /* For #BMesh. */ } MeshExtract_Weight_Data; static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate) @@ -2609,27 +3010,49 @@ static void *extract_weights_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_weights_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *_data) +static void extract_weights_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_Weight_Data *data = (MeshExtract_Weight_Data *)_data; - const MDeformVert *dvert = (data->cd_ofs != -1) ? BM_ELEM_CD_GET_VOID_P(loop->v, data->cd_ofs) : - NULL; - data->vbo_data[l] = evaluate_vertex_weight(dvert, data->wstate); + MeshExtract_Weight_Data *data = _data; + if (data->cd_ofs != -1) { + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(l->v, data->cd_ofs); + data->vbo_data[l_index] = evaluate_vertex_weight(dvert, data->wstate); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + } + else { + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + data->vbo_data[l_index] = evaluate_vertex_weight(NULL, data->wstate); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + } } -static void extract_weights_loop_mesh(const MeshRenderData *UNUSED(mr), - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *_data) +static void extract_weights_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - MeshExtract_Weight_Data *data = (MeshExtract_Weight_Data *)_data; - const MDeformVert *dvert = data->dvert ? &data->dvert[mloop->v] : NULL; - data->vbo_data[l] = evaluate_vertex_weight(dvert, data->wstate); + MeshExtract_Weight_Data *data = _data; + if (data->dvert != NULL) { + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MDeformVert *dvert = &data->dvert[ml->v]; + data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; + } + else { + const MDeformVert *dvert = NULL; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; + } } static void extract_weights_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data) @@ -2638,18 +3061,12 @@ static void extract_weights_finish(const MeshRenderData *UNUSED(mr), void *UNUSE } static const MeshExtract extract_weights = { - extract_weights_init, - NULL, - NULL, - extract_weights_loop_bmesh, - extract_weights_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_weights_finish, - 0, - true, + .init = extract_weights_init, + .iter_poly_bm = extract_weights_iter_poly_bm, + .iter_poly_mesh = extract_weights_iter_poly_mesh, + .finish = extract_weights_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -2756,31 +3173,31 @@ static void mesh_render_data_edge_flag(const MeshRenderData *mr, BMEdge *eed, Ed } static void mesh_render_data_loop_flag(const MeshRenderData *mr, - BMLoop *loop, + BMLoop *l, const int cd_ofs, EditLoopData *eattr) { if (cd_ofs == -1) { return; } - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs); + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_ofs); if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) { eattr->v_flag |= VFLAG_VERT_UV_PINNED; } - if (uvedit_uv_select_test_ex(mr->toolsettings, loop, cd_ofs)) { + if (uvedit_uv_select_test_ex(mr->toolsettings, l, cd_ofs)) { eattr->v_flag |= VFLAG_VERT_UV_SELECT; } } static void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, - BMLoop *loop, + BMLoop *l, const int cd_ofs, EditLoopData *eattr) { if (cd_ofs == -1) { return; } - if (uvedit_edge_select_test_ex(mr->toolsettings, loop, cd_ofs)) { + if (uvedit_edge_select_test_ex(mr->toolsettings, l, cd_ofs)) { eattr->v_flag |= VFLAG_EDGE_UV_SELECT; eattr->v_flag |= VFLAG_VERT_UV_SELECT; } @@ -2800,7 +3217,7 @@ static void *extract_edit_data_init(const MeshRenderData *mr, void *buf) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - /* WARNING Adjust EditLoopData struct accordingly. */ + /* WARNING: Adjust #EditLoopData struct accordingly. */ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); GPU_vertformat_alias_add(&format, "flag"); } @@ -2810,114 +3227,130 @@ static void *extract_edit_data_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_edit_data_loop_bmesh(const MeshRenderData *mr, - int l, - BMLoop *loop, - void *_data) +static void extract_edit_data_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + l; - memset(data, 0x0, sizeof(*data)); - mesh_render_data_face_flag(mr, loop->f, -1, data); - mesh_render_data_edge_flag(mr, loop->e, data); - mesh_render_data_vert_flag(mr, loop->v, data); -} -static void extract_edit_data_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int p, - const MPoly *UNUSED(mpoly), - void *_data) -{ - EditLoopData *data = (EditLoopData *)_data + l; - memset(data, 0x0, sizeof(*data)); - BMFace *efa = bm_original_face_get(mr, p); - BMEdge *eed = bm_original_edge_get(mr, mloop->e); - BMVert *eve = bm_original_vert_get(mr, mloop->v); - if (efa) { - mesh_render_data_face_flag(mr, efa, -1, data); - } - if (eed) { - mesh_render_data_edge_flag(mr, eed, data); - } - if (eve) { - mesh_render_data_vert_flag(mr, eve, data); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + EditLoopData *data = (EditLoopData *)_data + l_index; + memset(data, 0x0, sizeof(*data)); + mesh_render_data_face_flag(mr, l->f, -1, data); + mesh_render_data_edge_flag(mr, l->e, data); + mesh_render_data_vert_flag(mr, l->v, data); } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edit_data_ledge_bmesh(const MeshRenderData *mr, - int e, - BMEdge *eed, - void *_data) +static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + e * 2; - memset(data, 0x0, sizeof(*data) * 2); - mesh_render_data_edge_flag(mr, eed, &data[0]); - data[1] = data[0]; - mesh_render_data_vert_flag(mr, eed->v1, &data[0]); - mesh_render_data_vert_flag(mr, eed->v2, &data[1]); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + EditLoopData *data = (EditLoopData *)_data + ml_index; + memset(data, 0x0, sizeof(*data)); + BMFace *efa = bm_original_face_get(mr, mp_index); + BMEdge *eed = bm_original_edge_get(mr, ml->e); + BMVert *eve = bm_original_vert_get(mr, ml->v); + if (efa) { + mesh_render_data_face_flag(mr, efa, -1, data); + } + if (eed) { + mesh_render_data_edge_flag(mr, eed, data); + } + if (eve) { + mesh_render_data_vert_flag(mr, eve, data); + } + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_edit_data_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *edge, - void *_data) +static void extract_edit_data_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + e * 2; - memset(data, 0x0, sizeof(*data) * 2); - int e_idx = mr->ledges[e]; - BMEdge *eed = bm_original_edge_get(mr, e_idx); - BMVert *eve1 = bm_original_vert_get(mr, edge->v1); - BMVert *eve2 = bm_original_vert_get(mr, edge->v2); - if (eed) { + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + EditLoopData *data = (EditLoopData *)_data + mr->loop_len + (ledge_index * 2); + memset(data, 0x0, sizeof(*data) * 2); mesh_render_data_edge_flag(mr, eed, &data[0]); data[1] = data[0]; + mesh_render_data_vert_flag(mr, eed->v1, &data[0]); + mesh_render_data_vert_flag(mr, eed->v2, &data[1]); + } + EXTRACT_LEDGE_FOREACH_BM_END; +} + +static void extract_edit_data_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *_data) +{ + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + EditLoopData *data = (EditLoopData *)_data + mr->loop_len + ledge_index * 2; + memset(data, 0x0, sizeof(*data) * 2); + const int e_index = mr->ledges[ledge_index]; + BMEdge *eed = bm_original_edge_get(mr, e_index); + BMVert *eve1 = bm_original_vert_get(mr, med->v1); + BMVert *eve2 = bm_original_vert_get(mr, med->v2); + if (eed) { + mesh_render_data_edge_flag(mr, eed, &data[0]); + data[1] = data[0]; + } + if (eve1) { + mesh_render_data_vert_flag(mr, eve1, &data[0]); + } + if (eve2) { + mesh_render_data_vert_flag(mr, eve2, &data[1]); + } } - if (eve1) { - mesh_render_data_vert_flag(mr, eve1, &data[0]); - } - if (eve2) { - mesh_render_data_vert_flag(mr, eve2, &data[1]); - } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_edit_data_lvert_bmesh(const MeshRenderData *mr, - int v, - BMVert *eve, - void *_data) +static void extract_edit_data_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + mr->edge_loose_len * 2 + v; - memset(data, 0x0, sizeof(*data)); - mesh_render_data_vert_flag(mr, eve, data); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + EditLoopData *data = (EditLoopData *)_data + offset + lvert_index; + memset(data, 0x0, sizeof(*data)); + mesh_render_data_vert_flag(mr, eve, data); + } + EXTRACT_LVERT_FOREACH_BM_END; } -static void extract_edit_data_lvert_mesh(const MeshRenderData *mr, - int v, - const MVert *UNUSED(mvert), - void *_data) +static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *_data) { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + mr->edge_loose_len * 2 + v; - memset(data, 0x0, sizeof(*data)); - int v_idx = mr->lverts[v]; - BMVert *eve = bm_original_vert_get(mr, v_idx); - if (eve) { - mesh_render_data_vert_flag(mr, eve, data); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) + { + EditLoopData *data = (EditLoopData *)_data + offset + lvert_index; + memset(data, 0x0, sizeof(*data)); + const int v_index = mr->lverts[lvert_index]; + BMVert *eve = bm_original_vert_get(mr, v_index); + if (eve) { + mesh_render_data_vert_flag(mr, eve, data); + } } + EXTRACT_LVERT_FOREACH_MESH_END; } static const MeshExtract extract_edit_data = { - extract_edit_data_init, - NULL, - NULL, - extract_edit_data_loop_bmesh, - extract_edit_data_loop_mesh, - extract_edit_data_ledge_bmesh, - extract_edit_data_ledge_mesh, - extract_edit_data_lvert_bmesh, - extract_edit_data_lvert_mesh, - NULL, - 0, - true, + .init = extract_edit_data_init, + .iter_poly_bm = extract_edit_data_iter_poly_bm, + .iter_poly_mesh = extract_edit_data_iter_poly_mesh, + .iter_ledge_bm = extract_edit_data_iter_ledge_bm, + .iter_ledge_mesh = extract_edit_data_iter_ledge_mesh, + .iter_lvert_bm = extract_edit_data_iter_lvert_bm, + .iter_lvert_mesh = extract_edit_data_iter_lvert_mesh, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -2935,7 +3368,7 @@ static void *extract_edituv_data_init(const MeshRenderData *mr, void *buf) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - /* WARNING Adjust EditLoopData struct accordingly. */ + /* WARNING: Adjust #EditLoopData struct accordingly. */ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); GPU_vertformat_alias_add(&format, "flag"); } @@ -2952,51 +3385,59 @@ static void *extract_edituv_data_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_edituv_data_loop_bmesh(const MeshRenderData *mr, - int l, - BMLoop *loop, - void *_data) +static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_EditUVData_Data *data = (MeshExtract_EditUVData_Data *)_data; - EditLoopData *eldata = data->vbo_data + l; - memset(eldata, 0x0, sizeof(*eldata)); - mesh_render_data_loop_flag(mr, loop, data->cd_ofs, eldata); - mesh_render_data_face_flag(mr, loop->f, data->cd_ofs, eldata); - mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata); -} - -static void extract_edituv_data_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data) -{ - MeshExtract_EditUVData_Data *data = (MeshExtract_EditUVData_Data *)_data; - EditLoopData *eldata = data->vbo_data + l; - memset(eldata, 0x0, sizeof(*eldata)); - BMFace *efa = bm_original_face_get(mr, p); - if (efa) { - BMEdge *eed = bm_original_edge_get(mr, mloop->e); - BMVert *eve = bm_original_vert_get(mr, mloop->v); - if (eed && eve) { - /* Loop on an edge endpoint. */ - BMLoop *loop = BM_face_edge_share_loop(efa, eed); - mesh_render_data_loop_flag(mr, loop, data->cd_ofs, eldata); - mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata); - } - else { - if (eed == NULL) { - /* Find if the loop's vert is not part of an edit edge. - * For this, we check if the previous loop was on an edge. */ - int loopend = mpoly->loopstart + mpoly->totloop - 1; - int l_prev = (l == mpoly->loopstart) ? loopend : (l - 1); - const MLoop *mloop_prev = &mr->mloop[l_prev]; - eed = bm_original_edge_get(mr, mloop_prev->e); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + MeshExtract_EditUVData_Data *data = _data; + EditLoopData *eldata = &data->vbo_data[l_index]; + memset(eldata, 0x0, sizeof(*eldata)); + mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata); + mesh_render_data_face_flag(mr, l->f, data->cd_ofs, eldata); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); +} + +static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) +{ + MeshExtract_EditUVData_Data *data = _data; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + EditLoopData *eldata = &data->vbo_data[ml_index]; + memset(eldata, 0x0, sizeof(*eldata)); + BMFace *efa = bm_original_face_get(mr, mp_index); + if (efa) { + BMEdge *eed = bm_original_edge_get(mr, ml->e); + BMVert *eve = bm_original_vert_get(mr, ml->v); + if (eed && eve) { + /* Loop on an edge endpoint. */ + BMLoop *l = BM_face_edge_share_loop(efa, eed); + mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata); } - if (eed) { - /* Mapped points on an edge between two edit verts. */ - BMLoop *loop = BM_face_edge_share_loop(efa, eed); - mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata); + else { + if (eed == NULL) { + /* Find if the loop's vert is not part of an edit edge. + * For this, we check if the previous loop was on an edge. */ + const int ml_index_last = mp->loopstart + mp->totloop - 1; + const int l_prev = (ml_index == mp->loopstart) ? ml_index_last : (ml_index - 1); + const MLoop *ml_prev = &mr->mloop[l_prev]; + eed = bm_original_edge_get(mr, ml_prev->e); + } + if (eed) { + /* Mapped points on an edge between two edit verts. */ + BMLoop *l = BM_face_edge_share_loop(efa, eed); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata); + } } } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr), @@ -3007,18 +3448,12 @@ static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr), } static const MeshExtract extract_edituv_data = { - extract_edituv_data_init, - NULL, - NULL, - extract_edituv_data_loop_bmesh, - extract_edituv_data_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_edituv_data_finish, - 0, - true, + .init = extract_edituv_data_init, + .iter_poly_bm = extract_edituv_data_iter_poly_bm, + .iter_poly_mesh = extract_edituv_data_iter_poly_mesh, + .finish = extract_edituv_data_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -3078,13 +3513,13 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void * } else if (mr->extract_type == MR_EXTRACT_MAPPED) { const MLoopUV *uv_data = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV); - const MPoly *mpoly = mr->mpoly; - for (int p = 0; p < mr->poly_len; p++, mpoly++) { - float area = BKE_mesh_calc_poly_area(mpoly, &mr->mloop[mpoly->loopstart], mr->mvert); - float uvarea = BKE_mesh_calc_poly_uv_area(mpoly, uv_data); + const MPoly *mp = mr->mpoly; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + float area = BKE_mesh_calc_poly_area(mp, &mr->mloop[mp->loopstart], mr->mvert); + float uvarea = BKE_mesh_calc_poly_uv_area(mp, uv_data); tot_area += area; tot_uv_area += uvarea; - area_ratio[p] = area_ratio_get(area, uvarea); + area_ratio[mp_index] = area_ratio_get(area, uvarea); } } else { @@ -3097,8 +3532,8 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void * /* Convert in place to avoid an extra allocation */ uint16_t *poly_stretch = (uint16_t *)area_ratio; - for (int p = 0; p < mr->poly_len; p++) { - poly_stretch[p] = area_ratio[p] * SHRT_MAX; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) { + poly_stretch[mp_index] = area_ratio[mp_index] * SHRT_MAX; } /* Copy face data for each loop. */ @@ -3108,18 +3543,18 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void * if (mr->extract_type == MR_EXTRACT_BMESH) { BMFace *efa; BMIter f_iter; - int f, l = 0; + int f, l_index = 0; BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) { - for (int i = 0; i < efa->len; i++, l++) { - loop_stretch[l] = poly_stretch[f]; + for (int i = 0; i < efa->len; i++, l_index++) { + loop_stretch[l_index] = poly_stretch[f]; } } } else if (mr->extract_type == MR_EXTRACT_MAPPED) { - const MPoly *mpoly = mr->mpoly; - for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) { - for (int i = 0; i < mpoly->totloop; i++, l++) { - loop_stretch[l] = poly_stretch[p]; + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + for (int i = 0; i < mp->totloop; i++, l_index++) { + loop_stretch[l_index] = poly_stretch[mp_index]; } } } @@ -3132,18 +3567,10 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void * } static const MeshExtract extract_stretch_area = { - extract_stretch_area_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - mesh_stretch_area_finish, - 0, - false, + .init = extract_stretch_area_init, + .finish = mesh_stretch_area_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -3190,7 +3617,7 @@ static short v2_to_short_angle(float v[2]) static void edituv_get_stretch_angle(float auv[2][2], float av[2][3], UVStretchAngle *r_stretch) { - /* Send uvs to the shader and let it compute the aspect corrected angle. */ + /* Send UV's to the shader and let it compute the aspect corrected angle. */ r_stretch->uv_angles[0] = v2_to_short_angle(auv[0]); r_stretch->uv_angles[1] = v2_to_short_angle(auv[1]); /* Compute 3D angle here. */ @@ -3208,7 +3635,7 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - /* WARNING Adjust UVStretchAngle struct accordingly. */ + /* Waning: adjust #UVStretchAngle struct accordingly. */ GPU_vertformat_attr_add(&format, "angle", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT); } @@ -3220,7 +3647,7 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf) MeshExtract_StretchAngle_Data *data = MEM_callocN(sizeof(*data), __func__); data->vbo_data = (UVStretchAngle *)vbo->data; - /* Special iter nneded to save about half of the computing cost. */ + /* Special iterator needed to save about half of the computing cost. */ if (mr->extract_type == MR_EXTRACT_BMESH) { data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV); } @@ -3233,94 +3660,95 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_stretch_angle_loop_bmesh(const MeshRenderData *mr, - int l, - BMLoop *loop, - void *_data) +static void extract_stretch_angle_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_StretchAngle_Data *data = (MeshExtract_StretchAngle_Data *)_data; + MeshExtract_StretchAngle_Data *data = _data; float(*auv)[2] = data->auv, *last_auv = data->last_auv; float(*av)[3] = data->av, *last_av = data->last_av; - const MLoopUV *luv, *luv_next; - BMLoop *l_next = loop->next; - BMFace *efa = loop->f; - if (loop == efa->l_first) { - /* First loop in face. */ - BMLoop *l_tmp = loop->prev; - BMLoop *l_next_tmp = loop; - luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs); - luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs); - compute_normalize_edge_vectors(auv, - av, - luv->uv, - luv_next->uv, - bm_vert_co_get(mr, l_tmp->v), - bm_vert_co_get(mr, l_next_tmp->v)); - /* Save last edge. */ - copy_v2_v2(last_auv, auv[1]); - copy_v3_v3(last_av, av[1]); - } - if (l_next == efa->l_first) { - /* Move previous edge. */ - copy_v2_v2(auv[0], auv[1]); - copy_v3_v3(av[0], av[1]); - /* Copy already calculated last edge. */ - copy_v2_v2(auv[1], last_auv); - copy_v3_v3(av[1], last_av); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + const MLoopUV *luv, *luv_next; + BMLoop *l_next = l->next; + BMFace *efa = l->f; + if (l == BM_FACE_FIRST_LOOP(efa)) { + /* First loop in face. */ + BMLoop *l_tmp = l->prev; + BMLoop *l_next_tmp = l; + luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs); + luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs); + compute_normalize_edge_vectors(auv, + av, + luv->uv, + luv_next->uv, + bm_vert_co_get(mr, l_tmp->v), + bm_vert_co_get(mr, l_next_tmp->v)); + /* Save last edge. */ + copy_v2_v2(last_auv, auv[1]); + copy_v3_v3(last_av, av[1]); + } + if (l_next == BM_FACE_FIRST_LOOP(efa)) { + /* Move previous edge. */ + copy_v2_v2(auv[0], auv[1]); + copy_v3_v3(av[0], av[1]); + /* Copy already calculated last edge. */ + copy_v2_v2(auv[1], last_auv); + copy_v3_v3(av[1], last_av); + } + else { + luv = BM_ELEM_CD_GET_VOID_P(l, data->cd_ofs); + luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs); + compute_normalize_edge_vectors( + auv, av, luv->uv, luv_next->uv, bm_vert_co_get(mr, l->v), bm_vert_co_get(mr, l_next->v)); + } + edituv_get_stretch_angle(auv, av, &data->vbo_data[l_index]); } - else { - luv = BM_ELEM_CD_GET_VOID_P(loop, data->cd_ofs); - luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs); - compute_normalize_edge_vectors(auv, - av, - luv->uv, - luv_next->uv, - bm_vert_co_get(mr, loop->v), - bm_vert_co_get(mr, l_next->v)); - } - edituv_get_stretch_angle(auv, av, data->vbo_data + l); -} - -static void extract_stretch_angle_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *UNUSED(mloop), - int UNUSED(p), - const MPoly *mpoly, - void *_data) + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); +} + +static void extract_stretch_angle_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - MeshExtract_StretchAngle_Data *data = (MeshExtract_StretchAngle_Data *)_data; - float(*auv)[2] = data->auv, *last_auv = data->last_auv; - float(*av)[3] = data->av, *last_av = data->last_av; - int l_next = l + 1, loopend = mpoly->loopstart + mpoly->totloop; - const MVert *v, *v_next; - if (l == mpoly->loopstart) { - /* First loop in face. */ - int l_tmp = loopend - 1; - int l_next_tmp = mpoly->loopstart; - v = &mr->mvert[mr->mloop[l_tmp].v]; - v_next = &mr->mvert[mr->mloop[l_next_tmp].v]; - compute_normalize_edge_vectors( - auv, av, data->luv[l_tmp].uv, data->luv[l_next_tmp].uv, v->co, v_next->co); - /* Save last edge. */ - copy_v2_v2(last_auv, auv[1]); - copy_v3_v3(last_av, av[1]); - } - if (l_next == loopend) { - l_next = mpoly->loopstart; - /* Move previous edge. */ - copy_v2_v2(auv[0], auv[1]); - copy_v3_v3(av[0], av[1]); - /* Copy already calculated last edge. */ - copy_v2_v2(auv[1], last_auv); - copy_v3_v3(av[1], last_av); - } - else { - v = &mr->mvert[mr->mloop[l].v]; - v_next = &mr->mvert[mr->mloop[l_next].v]; - compute_normalize_edge_vectors( - auv, av, data->luv[l].uv, data->luv[l_next].uv, v->co, v_next->co); + MeshExtract_StretchAngle_Data *data = _data; + + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + float(*auv)[2] = data->auv, *last_auv = data->last_auv; + float(*av)[3] = data->av, *last_av = data->last_av; + int l_next = ml_index + 1, ml_index_end = mp->loopstart + mp->totloop; + const MVert *v, *v_next; + if (ml_index == mp->loopstart) { + /* First loop in face. */ + const int ml_index_last = ml_index_end - 1; + const int l_next_tmp = mp->loopstart; + v = &mr->mvert[mr->mloop[ml_index_last].v]; + v_next = &mr->mvert[mr->mloop[l_next_tmp].v]; + compute_normalize_edge_vectors( + auv, av, data->luv[ml_index_last].uv, data->luv[l_next_tmp].uv, v->co, v_next->co); + /* Save last edge. */ + copy_v2_v2(last_auv, auv[1]); + copy_v3_v3(last_av, av[1]); + } + if (l_next == ml_index_end) { + l_next = mp->loopstart; + /* Move previous edge. */ + copy_v2_v2(auv[0], auv[1]); + copy_v3_v3(av[0], av[1]); + /* Copy already calculated last edge. */ + copy_v2_v2(auv[1], last_auv); + copy_v3_v3(av[1], last_av); + } + else { + v = &mr->mvert[mr->mloop[ml_index].v]; + v_next = &mr->mvert[mr->mloop[l_next].v]; + compute_normalize_edge_vectors( + auv, av, data->luv[ml_index].uv, data->luv[l_next].uv, v->co, v_next->co); + } + edituv_get_stretch_angle(auv, av, &data->vbo_data[ml_index]); } - edituv_get_stretch_angle(auv, av, data->vbo_data + l); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_stretch_angle_finish(const MeshRenderData *UNUSED(mr), @@ -3331,18 +3759,12 @@ static void extract_stretch_angle_finish(const MeshRenderData *UNUSED(mr), } static const MeshExtract extract_stretch_angle = { - extract_stretch_angle_init, - NULL, - NULL, - extract_stretch_angle_loop_bmesh, - extract_stretch_angle_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_stretch_angle_finish, - 0, - false, + .init = extract_stretch_angle_init, + .iter_poly_bm = extract_stretch_angle_iter_poly_bm, + .iter_poly_mesh = extract_stretch_angle_iter_poly_mesh, + .finish = extract_stretch_angle_finish, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -3414,28 +3836,30 @@ static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang) normalize_v3(dir); if (mr->extract_type == MR_EXTRACT_BMESH) { - int l = 0; + int l_index = 0; BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { float fac = angle_normalized_v3v3(bm_face_no_get(mr, f), dir) / (float)M_PI; fac = overhang_remap(fac, min, max, minmax_irange); - for (int i = 0; i < f->len; i++, l++) { - r_overhang[l] = fac; + for (int i = 0; i < f->len; i++, l_index++) { + r_overhang[l_index] = fac; } } } else { - const MPoly *mpoly = mr->mpoly; - for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) { - float fac = angle_normalized_v3v3(mr->poly_normals[p], dir) / (float)M_PI; + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + float fac = angle_normalized_v3v3(mr->poly_normals[mp_index], dir) / (float)M_PI; fac = overhang_remap(fac, min, max, minmax_irange); - for (int i = 0; i < mpoly->totloop; i++, l++) { - r_overhang[l] = fac; + for (int i = 0; i < mp->totloop; i++, l_index++) { + r_overhang[l_index] = fac; } } } } -/* so we can use jitter values for face interpolation */ +/** + * Needed so we can use jitter values for face interpolation. + */ static void uv_from_jitter_v2(float uv[2]) { uv[0] += 0.5f; @@ -3527,12 +3951,12 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness) BMIter iter; BMFace *f; - int l = 0; + int l_index = 0; BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { float fac = face_dists[BM_elem_index_get(f)]; fac = thickness_remap(fac, min, max, minmax_irange); - for (int i = 0; i < f->len; i++, l++) { - r_thickness[l] = fac; + for (int i = 0; i < f->len; i++, l_index++) { + r_thickness[l_index] = fac; } } } @@ -3573,12 +3997,12 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness) } } - const MPoly *mpoly = mr->mpoly; - for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) { - float fac = face_dists[p]; + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + float fac = face_dists[mp_index]; fac = thickness_remap(fac, min, max, minmax_irange); - for (int i = 0; i < mpoly->totloop; i++, l++) { - r_thickness[l] = fac; + for (int i = 0; i < mp->totloop; i++, l_index++) { + r_thickness[l_index] = fac; } } } @@ -3629,8 +4053,8 @@ static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect) { BMEditMesh *em = mr->edit_bmesh; - for (int l = 0; l < mr->loop_len; l++) { - r_intersect[l] = -1.0f; + for (int l_index = 0; l_index < mr->loop_len; l_index++) { + r_intersect[l_index] = -1.0f; } if (mr->extract_type == MR_EXTRACT_BMESH) { @@ -3651,9 +4075,9 @@ static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect) for (int j = 0; j < 2; j++) { BMFace *f_hit = f_hit_pair[j]; BMLoop *l_first = BM_FACE_FIRST_LOOP(f_hit); - int l = BM_elem_index_get(l_first); - for (int k = 0; k < f_hit->len; k++, l++) { - r_intersect[l] = 1.0f; + int l_index = BM_elem_index_get(l_first); + for (int k = 0; k < f_hit->len; k++, l_index++) { + r_intersect[l_index] = 1.0f; } } } @@ -3680,9 +4104,9 @@ static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect) }; for (int j = 0; j < 2; j++) { const MPoly *f_hit = f_hit_pair[j]; - int l = f_hit->loopstart; - for (int k = 0; k < f_hit->totloop; k++, l++) { - r_intersect[l] = 1.0f; + int l_index = f_hit->loopstart; + for (int k = 0; k < f_hit->totloop; k++, l_index++) { + r_intersect[l_index] = 1.0f; } } } @@ -3725,9 +4149,9 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) BM_mesh_elem_index_ensure(em->bm, BM_VERT); } - int l = 0; - int p = 0; - BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, p) { + int l_index = 0; + int f_index = 0; + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, f_index) { float fac = -1.0f; if (f->len > 3) { @@ -3739,7 +4163,7 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) const float *no_face; float no_corner[3]; if (mr->bm_vert_coords != NULL) { - no_face = mr->bm_poly_normals[p]; + no_face = mr->bm_poly_normals[f_index]; BM_loop_calc_face_normal_safe_vcos(l_iter, no_face, mr->bm_vert_coords, no_corner); } else { @@ -3758,24 +4182,24 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) } fac = distort_remap(fac, min, max, minmax_irange); - for (int i = 0; i < f->len; i++, l++) { - r_distort[l] = fac; + for (int i = 0; i < f->len; i++, l_index++) { + r_distort[l_index] = fac; } } } else { - const MPoly *mpoly = mr->mpoly; - for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) { + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { float fac = -1.0f; - if (mpoly->totloop > 3) { - float *f_no = mr->poly_normals[p]; + if (mp->totloop > 3) { + float *f_no = mr->poly_normals[mp_index]; fac = 0.0f; - for (int i = 1; i <= mpoly->totloop; i++) { - const MLoop *l_prev = &mr->mloop[mpoly->loopstart + (i - 1) % mpoly->totloop]; - const MLoop *l_curr = &mr->mloop[mpoly->loopstart + (i + 0) % mpoly->totloop]; - const MLoop *l_next = &mr->mloop[mpoly->loopstart + (i + 1) % mpoly->totloop]; + for (int i = 1; i <= mp->totloop; i++) { + const MLoop *l_prev = &mr->mloop[mp->loopstart + (i - 1) % mp->totloop]; + const MLoop *l_curr = &mr->mloop[mp->loopstart + (i + 0) % mp->totloop]; + const MLoop *l_next = &mr->mloop[mp->loopstart + (i + 1) % mp->totloop]; float no_corner[3]; normal_tri_v3(no_corner, mr->mvert[l_prev->v].co, @@ -3791,8 +4215,8 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) } fac = distort_remap(fac, min, max, minmax_irange); - for (int i = 0; i < mpoly->totloop; i++, l++) { - r_distort[l] = fac; + for (int i = 0; i < mp->totloop; i++, l_index++) { + r_distort[l_index] = fac; } } } @@ -3825,11 +4249,10 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) copy_vn_fl(vert_angles, mr->vert_len, -M_PI); if (mr->extract_type == MR_EXTRACT_BMESH) { - BMIter iter, l_iter; + BMIter iter; BMesh *bm = em->bm; BMFace *efa; BMEdge *e; - BMLoop *loop; /* first assign float values to verts */ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { float angle = BM_edge_calc_face_angle_signed(e); @@ -3840,35 +4263,37 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) } /* Copy vert value to loops. */ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { - int l = BM_elem_index_get(loop); - int v = BM_elem_index_get(loop->v); - r_sharp[l] = sharp_remap(vert_angles[v], min, max, minmax_irange); - } + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + int l_index = BM_elem_index_get(l_iter); + int v_index = BM_elem_index_get(l_iter->v); + r_sharp[l_index] = sharp_remap(vert_angles[v_index], min, max, minmax_irange); + } while ((l_iter = l_iter->next) != l_first); } } else { /* first assign float values to verts */ - const MPoly *mpoly = mr->mpoly; + const MPoly *mp = mr->mpoly; EdgeHash *eh = BLI_edgehash_new_ex(__func__, mr->edge_len); - for (int p = 0; p < mr->poly_len; p++, mpoly++) { - for (int i = 0; i < mpoly->totloop; i++) { - const MLoop *l_curr = &mr->mloop[mpoly->loopstart + (i + 0) % mpoly->totloop]; - const MLoop *l_next = &mr->mloop[mpoly->loopstart + (i + 1) % mpoly->totloop]; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + for (int i = 0; i < mp->totloop; i++) { + const MLoop *l_curr = &mr->mloop[mp->loopstart + (i + 0) % mp->totloop]; + const MLoop *l_next = &mr->mloop[mp->loopstart + (i + 1) % mp->totloop]; const MVert *v_curr = &mr->mvert[l_curr->v]; const MVert *v_next = &mr->mvert[l_next->v]; float angle; void **pval; bool value_is_init = BLI_edgehash_ensure_p(eh, l_curr->v, l_next->v, &pval); if (!value_is_init) { - *pval = mr->poly_normals[p]; + *pval = mr->poly_normals[mp_index]; /* non-manifold edge, yet... */ continue; } else if (*pval != NULL) { - const float *f1_no = mr->poly_normals[p]; + const float *f1_no = mr->poly_normals[mp_index]; const float *f2_no = *pval; angle = angle_normalized_v3v3(f1_no, f2_no); angle = is_edge_convex_v3(v_curr->co, v_next->co, f1_no, f2_no) ? angle : -angle; @@ -3901,9 +4326,9 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) BLI_edgehashIterator_free(ehi); BLI_edgehash_free(eh, NULL); - const MLoop *mloop = mr->mloop; - for (int l = 0; l < mr->loop_len; l++, mloop++) { - r_sharp[l] = sharp_remap(vert_angles[mloop->v], min, max, minmax_irange); + const MLoop *ml = mr->mloop; + for (int l_index = 0; l_index < mr->loop_len; l_index++, ml++) { + r_sharp[l_index] = sharp_remap(vert_angles[ml->v], min, max, minmax_irange); } } @@ -3937,20 +4362,12 @@ static void extract_mesh_analysis_finish(const MeshRenderData *mr, void *buf, vo } static const MeshExtract extract_mesh_analysis = { - extract_mesh_analysis_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_mesh_analysis_finish, - /* This is not needed for all vis type. - * Maybe split into different extract. */ - MR_DATA_POLY_NOR | MR_DATA_LOOPTRI, - false, + .init = extract_mesh_analysis_init, + .finish = extract_mesh_analysis_finish, + /* This is not needed for all visualization types. + * * Maybe split into different extract. */ + .data_flag = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI, + .use_threading = false, }; /** \} */ @@ -3975,49 +4392,46 @@ static void *extract_fdots_pos_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_fdots_pos_loop_bmesh(const MeshRenderData *mr, - int UNUSED(l), - BMLoop *loop, - void *data) +static void extract_fdots_pos_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - float(*center)[3] = (float(*)[3])data; - float w = 1.0f / (float)loop->f->len; - madd_v3_v3fl(center[BM_elem_index_get(loop->f)], bm_vert_co_get(mr, loop->v), w); + float(*center)[3] = data; + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + float w = 1.0f / (float)l->f->len; + madd_v3_v3fl(center[BM_elem_index_get(l->f)], bm_vert_co_get(mr, l->v), w); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_fdots_pos_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *mloop, - int p, - const MPoly *mpoly, - void *data) +static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { float(*center)[3] = (float(*)[3])data; - const MVert *mvert = &mr->mvert[mloop->v]; - if (mr->use_subsurf_fdots) { - if (mvert->flag & ME_VERT_FACEDOT) { - copy_v3_v3(center[p], mvert->co); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MVert *mv = &mr->mvert[ml->v]; + if (mr->use_subsurf_fdots) { + if (mv->flag & ME_VERT_FACEDOT) { + copy_v3_v3(center[mp_index], mv->co); + } + } + else { + float w = 1.0f / (float)mp->totloop; + madd_v3_v3fl(center[mp_index], mv->co, w); } } - else { - float w = 1.0f / (float)mpoly->totloop; - madd_v3_v3fl(center[p], mvert->co, w); - } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static const MeshExtract extract_fdots_pos = { - extract_fdots_pos_init, - NULL, - NULL, - extract_fdots_pos_loop_bmesh, - extract_fdots_pos_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - true, + .init = extract_fdots_pos_init, + .iter_poly_bm = extract_fdots_pos_iter_poly_bm, + .iter_poly_mesh = extract_fdots_pos_iter_poly_mesh, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -4090,18 +4504,10 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void * } static const MeshExtract extract_fdots_nor = { - extract_fdots_nor_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - extract_fdots_nor_finish, - MR_DATA_POLY_NOR, - false, + .init = extract_fdots_nor_init, + .finish = extract_fdots_nor_finish, + .data_flag = MR_DATA_POLY_NOR, + .use_threading = false, }; /** \} */ @@ -4145,30 +4551,42 @@ static void *extract_fdots_uv_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_fdots_uv_loop_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(l), - BMLoop *loop, - void *_data) +static void extract_fdots_uv_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_FdotUV_Data *data = (MeshExtract_FdotUV_Data *)_data; - float w = 1.0f / (float)loop->f->len; - const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, data->cd_ofs); - madd_v2_v2fl(data->vbo_data[BM_elem_index_get(loop->f)], luv->uv, w); + MeshExtract_FdotUV_Data *data = _data; + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + float w = 1.0f / (float)l->f->len; + const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, data->cd_ofs); + madd_v2_v2fl(data->vbo_data[BM_elem_index_get(l->f)], luv->uv, w); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_fdots_uv_loop_mesh( - const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data) +static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - MeshExtract_FdotUV_Data *data = (MeshExtract_FdotUV_Data *)_data; + MeshExtract_FdotUV_Data *data = _data; if (mr->use_subsurf_fdots) { - const MVert *mvert = &mr->mvert[mloop->v]; - if (mvert->flag & ME_VERT_FACEDOT) { - copy_v2_v2(data->vbo_data[p], data->uv_data[l].uv); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + const MVert *mv = &mr->mvert[ml->v]; + if (mv->flag & ME_VERT_FACEDOT) { + copy_v2_v2(data->vbo_data[mp_index], data->uv_data[ml_index].uv); + } } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } else { - float w = 1.0f / (float)mpoly->totloop; - madd_v2_v2fl(data->vbo_data[p], data->uv_data[l].uv, w); + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + float w = 1.0f / (float)mp->totloop; + madd_v2_v2fl(data->vbo_data[mp_index], data->uv_data[ml_index].uv, w); + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } } @@ -4180,18 +4598,12 @@ static void extract_fdots_uv_finish(const MeshRenderData *UNUSED(mr), } static const MeshExtract extract_fdots_uv = { - extract_fdots_uv_init, - NULL, - NULL, - extract_fdots_uv_loop_bmesh, - extract_fdots_uv_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_fdots_uv_finish, - 0, - true, + .init = extract_fdots_uv_init, + .iter_poly_bm = extract_fdots_uv_iter_poly_bm, + .iter_poly_mesh = extract_fdots_uv_iter_poly_mesh, + .finish = extract_fdots_uv_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -4220,31 +4632,35 @@ static void *extract_fdots_edituv_data_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_fdots_edituv_data_loop_bmesh(const MeshRenderData *mr, - int UNUSED(l), - BMLoop *loop, - void *_data) +static void extract_fdots_edituv_data_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *_data) { - MeshExtract_EditUVFdotData_Data *data = (MeshExtract_EditUVFdotData_Data *)_data; - EditLoopData *eldata = data->vbo_data + BM_elem_index_get(loop->f); - memset(eldata, 0x0, sizeof(*eldata)); - mesh_render_data_face_flag(mr, loop->f, data->cd_ofs, eldata); + MeshExtract_EditUVFdotData_Data *data = _data; + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + EditLoopData *eldata = &data->vbo_data[BM_elem_index_get(f)]; + memset(eldata, 0x0, sizeof(*eldata)); + mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata); + } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_fdots_edituv_data_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *UNUSED(mloop), - int p, - const MPoly *UNUSED(mpoly), - void *_data) +static void extract_fdots_edituv_data_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *_data) { - MeshExtract_EditUVFdotData_Data *data = (MeshExtract_EditUVFdotData_Data *)_data; - EditLoopData *eldata = data->vbo_data + p; - memset(eldata, 0x0, sizeof(*eldata)); - BMFace *efa = bm_original_face_get(mr, p); - if (efa) { - mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata); + MeshExtract_EditUVFdotData_Data *data = _data; + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + EditLoopData *eldata = &data->vbo_data[mp_index]; + memset(eldata, 0x0, sizeof(*eldata)); + BMFace *efa = bm_original_face_get(mr, mp_index); + if (efa) { + mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata); + } } + EXTRACT_POLY_FOREACH_MESH_END; } static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr), @@ -4255,18 +4671,12 @@ static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr), } static const MeshExtract extract_fdots_edituv_data = { - extract_fdots_edituv_data_init, - NULL, - NULL, - extract_fdots_edituv_data_loop_bmesh, - extract_fdots_edituv_data_loop_mesh, - NULL, - NULL, - NULL, - NULL, - extract_fdots_edituv_data_finish, - 0, - true, + .init = extract_fdots_edituv_data_init, + .iter_poly_bm = extract_fdots_edituv_data_iter_poly_bm, + .iter_poly_mesh = extract_fdots_edituv_data_iter_poly_mesh, + .finish = extract_fdots_edituv_data_finish, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -4317,18 +4727,9 @@ static void *extract_skin_roots_init(const MeshRenderData *mr, void *buf) } static const MeshExtract extract_skin_roots = { - extract_skin_roots_init, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - false, + .init = extract_skin_roots_init, + .data_flag = 0, + .use_threading = false, }; /** \} */ @@ -4350,157 +4751,183 @@ static void *extract_select_idx_init(const MeshRenderData *mr, void *buf) return vbo->data; } -/* TODO Use glVertexID to get loop index and use the data structure on the CPU to retrieve the +/* TODO Use #glVertexID to get loop index and use the data structure on the CPU to retrieve the * select element associated with this loop ID. This would remove the need for this separate - * index VBOs. We could upload the p/e/v_origindex as a buffer texture and sample it inside the + * index VBO's. We could upload the p/e/v_origindex as a buffer texture and sample it inside the * shader to output original index. */ -static void extract_poly_idx_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_poly_idx_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = BM_elem_index_get(loop->f); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + ((uint32_t *)data)[l_index] = BM_elem_index_get(l->f); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edge_idx_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_edge_idx_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = BM_elem_index_get(loop->e); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + ((uint32_t *)data)[l_index] = BM_elem_index_get(l->e); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_vert_idx_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *data) +static void extract_vert_idx_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = BM_elem_index_get(loop->v); + EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) + { + ((uint32_t *)data)[l_index] = BM_elem_index_get(l->v); + } + EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); } -static void extract_edge_idx_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *data) +static void extract_edge_idx_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *data) { - ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = BM_elem_index_get(eed); - ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = BM_elem_index_get(eed); + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed); + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed); + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_vert_idx_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *data) +static void extract_vert_idx_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + void *data) { - ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = BM_elem_index_get(eed->v1); - ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = BM_elem_index_get(eed->v2); + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed->v1); + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed->v2); + } + EXTRACT_LEDGE_FOREACH_BM_END; } -static void extract_vert_idx_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *data) +static void extract_vert_idx_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + void *data) { - ((uint32_t *)data)[mr->loop_len + mr->edge_loose_len * 2 + v] = BM_elem_index_get(eve); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + ((uint32_t *)data)[offset + lvert_index] = BM_elem_index_get(eve); + } + EXTRACT_LVERT_FOREACH_BM_END; } -static void extract_poly_idx_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *UNUSED(mloop), - int p, - const MPoly *UNUSED(mpoly), - void *data) +static void extract_poly_idx_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = (mr->p_origindex) ? mr->p_origindex[p] : p; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + ((uint32_t *)data)[ml_index] = (mr->p_origindex) ? mr->p_origindex[mp_index] : mp_index; + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_edge_idx_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *data) +static void extract_edge_idx_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = (mr->e_origindex) ? mr->e_origindex[mloop->e] : mloop->e; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + ((uint32_t *)data)[ml_index] = (mr->e_origindex) ? mr->e_origindex[ml->e] : ml->e; + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_vert_idx_loop_mesh(const MeshRenderData *mr, - int l, - const MLoop *mloop, - int UNUSED(p), - const MPoly *UNUSED(mpoly), - void *data) +static void extract_vert_idx_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - ((uint32_t *)data)[l] = (mr->v_origindex) ? mr->v_origindex[mloop->v] : mloop->v; + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) + { + ((uint32_t *)data)[ml_index] = (mr->v_origindex) ? mr->v_origindex[ml->v] : ml->v; + } + EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static void extract_edge_idx_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *UNUSED(medge), - void *data) +static void extract_edge_idx_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *data) { - int e_idx = mr->ledges[e]; - int e_orig = (mr->e_origindex) ? mr->e_origindex[e_idx] : e_idx; - ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = e_orig; - ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = e_orig; + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + const int e_index = mr->ledges[ledge_index]; + const int e_orig = (mr->e_origindex) ? mr->e_origindex[e_index] : e_index; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = e_orig; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = e_orig; + } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_vert_idx_ledge_mesh(const MeshRenderData *mr, - int e, - const MEdge *medge, - void *data) +static void extract_vert_idx_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + void *data) { - int v1_orig = (mr->v_origindex) ? mr->v_origindex[medge->v1] : medge->v1; - int v2_orig = (mr->v_origindex) ? mr->v_origindex[medge->v2] : medge->v2; - ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = v1_orig; - ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = v2_orig; + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + int v1_orig = (mr->v_origindex) ? mr->v_origindex[med->v1] : med->v1; + int v2_orig = (mr->v_origindex) ? mr->v_origindex[med->v2] : med->v2; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = v1_orig; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = v2_orig; + } + EXTRACT_LEDGE_FOREACH_MESH_END; } -static void extract_vert_idx_lvert_mesh(const MeshRenderData *mr, - int v, - const MVert *UNUSED(mvert), - void *data) +static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + void *data) { - int v_idx = mr->lverts[v]; - int v_orig = (mr->v_origindex) ? mr->v_origindex[v_idx] : v_idx; - ((uint32_t *)data)[mr->loop_len + mr->edge_loose_len * 2 + v] = v_orig; + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EXTRACT_LVERT_FOREACH_MESH_BEGIN(med, lvert_index, params, mr) + { + const int v_index = mr->lverts[lvert_index]; + const int v_orig = (mr->v_origindex) ? mr->v_origindex[v_index] : v_index; + ((uint32_t *)data)[offset + lvert_index] = v_orig; + } + EXTRACT_LVERT_FOREACH_MESH_END; } static const MeshExtract extract_poly_idx = { - extract_select_idx_init, - NULL, - NULL, - extract_poly_idx_loop_bmesh, - extract_poly_idx_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - true, + .init = extract_select_idx_init, + .iter_poly_bm = extract_poly_idx_iter_poly_bm, + .iter_poly_mesh = extract_poly_idx_iter_poly_mesh, + .data_flag = 0, + .use_threading = true, }; static const MeshExtract extract_edge_idx = { - extract_select_idx_init, - NULL, - NULL, - extract_edge_idx_loop_bmesh, - extract_edge_idx_loop_mesh, - extract_edge_idx_ledge_bmesh, - extract_edge_idx_ledge_mesh, - NULL, - NULL, - NULL, - 0, - true, + .init = extract_select_idx_init, + .iter_poly_bm = extract_edge_idx_iter_poly_bm, + .iter_poly_mesh = extract_edge_idx_iter_poly_mesh, + .iter_ledge_bm = extract_edge_idx_iter_ledge_bm, + .iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh, + .data_flag = 0, + .use_threading = true, }; static const MeshExtract extract_vert_idx = { - extract_select_idx_init, - NULL, - NULL, - extract_vert_idx_loop_bmesh, - extract_vert_idx_loop_mesh, - extract_vert_idx_ledge_bmesh, - extract_vert_idx_ledge_mesh, - extract_vert_idx_lvert_bmesh, - extract_vert_idx_lvert_mesh, - NULL, - 0, - true, + .init = extract_select_idx_init, + .iter_poly_bm = extract_vert_idx_iter_poly_bm, + .iter_poly_mesh = extract_vert_idx_iter_poly_mesh, + .iter_ledge_bm = extract_vert_idx_iter_ledge_bm, + .iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh, + .iter_lvert_bm = extract_vert_idx_iter_lvert_bm, + .iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh, + .data_flag = 0, + .use_threading = true, }; static void *extract_select_fdot_idx_init(const MeshRenderData *mr, void *buf) @@ -4516,37 +4943,43 @@ static void *extract_select_fdot_idx_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_fdot_idx_loop_bmesh(const MeshRenderData *UNUSED(mr), - int UNUSED(l), - BMLoop *loop, - void *data) +static void extract_fdot_idx_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + void *data) { - ((uint32_t *)data)[BM_elem_index_get(loop->f)] = BM_elem_index_get(loop->f); + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + ((uint32_t *)data)[f_index] = f_index; + } + EXTRACT_POLY_FOREACH_BM_END; } -static void extract_fdot_idx_loop_mesh(const MeshRenderData *mr, - int UNUSED(l), - const MLoop *UNUSED(mloop), - int p, - const MPoly *UNUSED(mpoly), - void *data) +static void extract_fdot_idx_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + void *data) { - ((uint32_t *)data)[p] = (mr->p_origindex) ? mr->p_origindex[p] : p; + if (mr->p_origindex != NULL) { + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + ((uint32_t *)data)[mp_index] = mr->p_origindex[mp_index]; + } + EXTRACT_POLY_FOREACH_MESH_END; + } + else { + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + ((uint32_t *)data)[mp_index] = mp_index; + } + EXTRACT_POLY_FOREACH_MESH_END; + } } static const MeshExtract extract_fdot_idx = { - extract_select_fdot_idx_init, - NULL, - NULL, - extract_fdot_idx_loop_bmesh, - extract_fdot_idx_loop_mesh, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - true, + .init = extract_select_fdot_idx_init, + .iter_poly_bm = extract_fdot_idx_iter_poly_bm, + .iter_poly_mesh = extract_fdot_idx_iter_poly_mesh, + .data_flag = 0, + .use_threading = true, }; /** \} */ @@ -4589,9 +5022,9 @@ static ExtractTaskData *extract_task_data_create_mesh_extract(const MeshRenderDa taskdata->extract = extract; taskdata->buf = buf; - /* ExtractUserData is shared between the iterations as it holds counters to detect if the - * extraction is finished. To make sure the duplication of the userdata does not create a new - * instance of the counters we allocate the userdata in its own container. + /* #ExtractUserData is shared between the iterations as it holds counters to detect if the + * extraction is finished. To make sure the duplication of the user_data does not create a new + * instance of the counters we allocate the user_data in its own container. * * This structure makes sure that when extract_init is called, that the user data of all * iterations are updated. */ @@ -4628,67 +5061,69 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, switch (mr->extract_type) { case MR_EXTRACT_BMESH: if (iter_type & MR_ITER_LOOPTRI) { - int t_end = min_ii(mr->tri_len, end); - for (int t = start; t < t_end; t++) { - BMLoop **elt = &mr->edit_bmesh->looptris[t][0]; - extract->iter_looptri_bm(mr, t, elt, user_data); - } + extract->iter_looptri_bm(mr, + &(const ExtractTriBMesh_Params){ + .looptris = mr->edit_bmesh->looptris, + .tri_range = {start, min_ii(mr->tri_len, end)}, + }, + user_data); } - if (iter_type & MR_ITER_LOOP) { - int l_end = min_ii(mr->poly_len, end); - for (int f = start; f < l_end; f++) { - BMFace *efa = BM_face_at_index(mr->bm, f); - BMLoop *loop; - BMIter l_iter; - BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) { - extract->iter_loop_bm(mr, BM_elem_index_get(loop), loop, user_data); - } - } + if (iter_type & MR_ITER_POLY) { + extract->iter_poly_bm(mr, + &(const ExtractPolyBMesh_Params){ + .poly_range = {start, min_ii(mr->poly_len, end)}, + }, + user_data); } if (iter_type & MR_ITER_LEDGE) { - int le_end = min_ii(mr->edge_loose_len, end); - for (int e = start; e < le_end; e++) { - BMEdge *eed = BM_edge_at_index(mr->bm, mr->ledges[e]); - extract->iter_ledge_bm(mr, e, eed, user_data); - } + extract->iter_ledge_bm(mr, + &(const ExtractLEdgeBMesh_Params){ + .ledge = mr->ledges, + .ledge_range = {start, min_ii(mr->edge_loose_len, end)}, + }, + user_data); } if (iter_type & MR_ITER_LVERT) { - int lv_end = min_ii(mr->vert_loose_len, end); - for (int v = start; v < lv_end; v++) { - BMVert *eve = BM_vert_at_index(mr->bm, mr->lverts[v]); - extract->iter_lvert_bm(mr, v, eve, user_data); - } + extract->iter_lvert_bm(mr, + &(const ExtractLVertBMesh_Params){ + .lvert = mr->lverts, + .lvert_range = {start, min_ii(mr->vert_loose_len, end)}, + }, + user_data); } break; case MR_EXTRACT_MAPPED: case MR_EXTRACT_MESH: if (iter_type & MR_ITER_LOOPTRI) { - int t_end = min_ii(mr->tri_len, end); - for (int t = start; t < t_end; t++) { - extract->iter_looptri(mr, t, &mr->mlooptri[t], user_data); - } + extract->iter_looptri_mesh(mr, + &(const ExtractTriMesh_Params){ + .mlooptri = mr->mlooptri, + .tri_range = {start, min_ii(mr->tri_len, end)}, + }, + user_data); } - if (iter_type & MR_ITER_LOOP) { - int l_end = min_ii(mr->poly_len, end); - for (int p = start; p < l_end; p++) { - const MPoly *mpoly = &mr->mpoly[p]; - int l = mpoly->loopstart; - for (int i = 0; i < mpoly->totloop; i++, l++) { - extract->iter_loop(mr, l, &mr->mloop[l], p, mpoly, user_data); - } - } + if (iter_type & MR_ITER_POLY) { + extract->iter_poly_mesh(mr, + &(const ExtractPolyMesh_Params){ + .poly_range = {start, min_ii(mr->poly_len, end)}, + }, + user_data); } if (iter_type & MR_ITER_LEDGE) { - int le_end = min_ii(mr->edge_loose_len, end); - for (int e = start; e < le_end; e++) { - extract->iter_ledge(mr, e, &mr->medge[mr->ledges[e]], user_data); - } + extract->iter_ledge_mesh(mr, + &(const ExtractLEdgeMesh_Params){ + .ledge = mr->ledges, + .ledge_range = {start, min_ii(mr->edge_loose_len, end)}, + }, + user_data); } if (iter_type & MR_ITER_LVERT) { - int lv_end = min_ii(mr->vert_loose_len, end); - for (int v = start; v < lv_end; v++) { - extract->iter_lvert(mr, v, &mr->mvert[mr->lverts[v]], user_data); - } + extract->iter_lvert_mesh(mr, + &(const ExtractLVertMesh_Params){ + .lvert = mr->lverts, + .lvert_range = {start, min_ii(mr->vert_loose_len, end)}, + }, + user_data); } break; } @@ -4915,10 +5350,10 @@ static void extract_task_create(struct TaskGraph *task_graph, task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOPTRI, i, chunk_size); } } - if (taskdata->iter_type & MR_ITER_LOOP) { + if (taskdata->iter_type & MR_ITER_POLY) { for (int i = 0; i < mr->poly_len; i += chunk_size) { extract_range_task_create( - task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOP, i, chunk_size); + task_graph, task_node_user_data_init, taskdata, MR_ITER_POLY, i, chunk_size); } } if (taskdata->iter_type & MR_ITER_LEDGE) { @@ -4973,9 +5408,9 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, * `extract_single_threaded_task_node`. * * Other extractions will create a node for each loop exceeding 8192 items. these nodes are - * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the userdata - * needed for the extraction based on the data extracted from the mesh. counters are used to - * check if the finalize of a task has to be called. + * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the + * user_data needed for the extraction based on the data extracted from the mesh. + * counters are used to check if the finalize of a task has to be called. * * Mesh extraction sub graph * diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 191d75342d0..5cf1c24af0b 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -170,6 +170,7 @@ struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(struct Mesh *me, struct GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_weights(struct Mesh *me); /* edit-mesh drawing */ struct GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(struct Mesh *me); @@ -199,6 +200,11 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_uv_edges(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(struct Mesh *me); +/* For direct data access. */ +struct GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(struct Mesh *me); +struct GPUVertBuf *DRW_curve_batch_cache_pos_vertbuf_get(struct Curve *cu); +struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(struct Object *ob); + int DRW_mesh_material_count_get(struct Mesh *me); /* See 'common_globals_lib.glsl' for duplicate defines. */ diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c index 8798549a416..73e0ff7ef83 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.c +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -903,6 +903,16 @@ GPUBatch **DRW_curve_batch_cache_get_surface_shaded(struct Curve *cu, return cache->surf_per_mat; } +GPUVertBuf *DRW_curve_batch_cache_pos_vertbuf_get(struct Curve *cu) +{ + CurveBatchCache *cache = curve_batch_cache_get(cu); + /* Request surface to trigger the vbo filling. Otherwise it may do nothing. */ + DRW_batch_request(&cache->batch.surfaces); + + DRW_vbo_request(NULL, &cache->ordered.loop_pos_nor); + return cache->ordered.loop_pos_nor; +} + GPUBatch *DRW_curve_batch_cache_get_wireframes_face(Curve *cu) { CurveBatchCache *cache = curve_batch_cache_get(cu); diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c index b4974330043..53e04fb61ee 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c @@ -349,10 +349,10 @@ static void gpencil_stroke_iter_cb(bGPDlayer *UNUSED(gpl), } } -static void gp_object_verts_count_cb(bGPDlayer *UNUSED(gpl), - bGPDframe *UNUSED(gpf), - bGPDstroke *gps, - void *thunk) +static void gpencil_object_verts_count_cb(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) { gpIterData *iter = (gpIterData *)thunk; @@ -387,7 +387,7 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr .tri_len = 0, }; BKE_gpencil_visible_stroke_iter( - NULL, ob, NULL, gp_object_verts_count_cb, &iter, do_onion, cfra); + NULL, ob, NULL, gpencil_object_verts_count_cb, &iter, do_onion, cfra); /* Create VBOs. */ GPUVertFormat *format = gpencil_stroke_format(); @@ -441,10 +441,10 @@ GPUBatch *DRW_cache_gpencil_fills_get(Object *ob, int cfra) return cache->fill_batch; } -static void gp_lines_indices_cb(bGPDlayer *UNUSED(gpl), - bGPDframe *UNUSED(gpf), - bGPDstroke *gps, - void *thunk) +static void gpencil_lines_indices_cb(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) { gpIterData *iter = (gpIterData *)thunk; int pts_len = gps->totpoints + gpencil_stroke_is_cyclic(gps); @@ -477,7 +477,8 @@ GPUBatch *DRW_cache_gpencil_face_wireframe_get(Object *ob) /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */ bool do_onion = true; - BKE_gpencil_visible_stroke_iter(NULL, ob, NULL, gp_lines_indices_cb, &iter, do_onion, cfra); + BKE_gpencil_visible_stroke_iter( + NULL, ob, NULL, gpencil_lines_indices_cb, &iter, do_onion, cfra); GPUIndexBuf *ibo = GPU_indexbuf_build(&iter.ibo); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 99e285a18f1..ea1717f0684 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -112,6 +112,21 @@ BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me) return &me->ldata; } +BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me) +{ + switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_MDATA: + return &me->vdata; + break; + case ME_WRAPPER_TYPE_BMESH: + return &me->edit_mesh->bm->vdata; + break; + } + + BLI_assert(0); + return &me->vdata; +} + static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; @@ -135,7 +150,19 @@ static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; - const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); + const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); + + int layer = CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR); + if (layer != -1) { + cd_used->sculpt_vcol |= (1 << layer); + } +} + +static void mesh_cd_calc_active_mloopcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used) +{ + const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const CustomData *cd_ldata = &me_final->ldata; + int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL); if (layer != -1) { cd_used->vcol |= (1 << layer); @@ -148,6 +175,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); + const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); /* See: DM_vertex_attributes_from_gpu for similar logic */ DRW_MeshCDMask cd_used; @@ -175,6 +203,11 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name); type = CD_MCOL; } + + if (layer == -1) { + layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name); + type = CD_PROP_COLOR; + } #if 0 /* Tangents are always from UV's - this will never happen. */ if (layer == -1) { layer = CustomData_get_named_layer(cd_ldata, CD_TANGENT, name); @@ -222,7 +255,20 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, } break; } + case CD_PROP_COLOR: { + /* Sculpt Vertex Colors */ + if (layer == -1) { + layer = (name[0] != '\0') ? + CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name) : + CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR); + } + if (layer != -1) { + cd_used.sculpt_vcol |= (1 << layer); + } + break; + } case CD_MCOL: { + /* Vertex Color Data */ if (layer == -1) { layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name) : CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL); @@ -230,6 +276,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, if (layer != -1) { cd_used.vcol |= (1 << layer); } + break; } case CD_ORCO: { @@ -679,10 +726,22 @@ static void texpaint_request_active_vcol(MeshBatchCache *cache, Mesh *me) { DRW_MeshCDMask cd_needed; mesh_cd_layers_type_clear(&cd_needed); - mesh_cd_calc_active_vcol_layer(me, &cd_needed); + mesh_cd_calc_active_mloopcol_layer(me, &cd_needed); BLI_assert(cd_needed.vcol != 0 && - "No vcol layer available in vertpaint, but batches requested anyway!"); + "No MLOOPCOL layer available in vertpaint, but batches requested anyway!"); + + mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); +} + +static void sculpt_request_active_vcol(MeshBatchCache *cache, Mesh *me) +{ + DRW_MeshCDMask cd_needed; + mesh_cd_layers_type_clear(&cd_needed); + mesh_cd_calc_active_vcol_layer(me, &cd_needed); + + BLI_assert(cd_needed.sculpt_vcol != 0 && + "No MPropCol layer available in Sculpt, but batches requested anyway!"); mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); } @@ -799,6 +858,14 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Mesh *me) return DRW_batch_request(&cache->batch.surface); } +GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + sculpt_request_active_vcol(cache, me); + mesh_batch_cache_add_request(cache, MBC_SURFACE); + return DRW_batch_request(&cache->batch.surface); +} + int DRW_mesh_material_count_get(Mesh *me) { return mesh_render_mat_len_get(me); @@ -810,6 +877,23 @@ int DRW_mesh_material_count_get(Mesh *me) /** \name Edit Mode API * \{ */ +GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + /* Request surface to trigger the vbo filling. Otherwise it may do nothing. */ + mesh_batch_cache_add_request(cache, MBC_SURFACE); + DRW_batch_request(&cache->batch.surface); + + DRW_vbo_request(NULL, &cache->final.vbo.pos_nor); + return cache->final.vbo.pos_nor; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Edit Mode API + * \{ */ + GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); @@ -1120,7 +1204,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, if (cache->cd_used.orco != cache->cd_needed.orco) { GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.orco); } - if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) { + if (((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) || + ((cache->cd_used.sculpt_vcol & cache->cd_needed.sculpt_vcol) != + cache->cd_needed.sculpt_vcol)) { GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.vcol); } } @@ -1201,7 +1287,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, if (cache->cd_used.uv != 0) { DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.uv); } - if (cache->cd_used.vcol != 0) { + if (cache->cd_used.vcol != 0 || cache->cd_used.sculpt_vcol != 0) { DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.vcol); } } @@ -1269,7 +1355,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, if ((cache->cd_used.tan != 0) || (cache->cd_used.tan_orco != 0)) { DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.tan); } - if (cache->cd_used.vcol != 0) { + if (cache->cd_used.vcol != 0 || cache->cd_used.sculpt_vcol != 0) { DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.vcol); } if (cache->cd_used.orco != 0) { diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c index c14e66c2b47..076d32ffe1f 100644 --- a/source/blender/draw/intern/draw_cache_impl_metaball.c +++ b/source/blender/draw/intern/draw_cache_impl_metaball.c @@ -274,6 +274,18 @@ struct GPUBatch *DRW_metaball_batch_cache_get_edge_detection(struct Object *ob, return cache->edge_detection; } +struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(Object *ob) +{ + if (!BKE_mball_is_basis(ob)) { + return NULL; + } + + MetaBall *mb = ob->data; + MetaBallBatchCache *cache = metaball_batch_cache_get(mb); + + return mball_batch_cache_get_pos_and_normals(ob, cache); +} + int DRW_metaball_material_count_get(MetaBall *mb) { return max_ii(1, mb->totcol); diff --git a/source/blender/draw/intern/draw_cache_inline.h b/source/blender/draw/intern/draw_cache_inline.h index a067434f3bb..67f44b5fb0c 100644 --- a/source/blender/draw/intern/draw_cache_inline.h +++ b/source/blender/draw/intern/draw_cache_inline.h @@ -90,17 +90,19 @@ BLI_INLINE void DRW_vbo_request(GPUBatch *batch, GPUVertBuf **vbo) if (*vbo == NULL) { *vbo = MEM_callocN(sizeof(GPUVertBuf), "GPUVertBuf"); } - /* HACK set first vbo if not init. */ - if (batch->verts[0] == NULL) { - GPU_batch_vao_cache_clear(batch); - batch->verts[0] = *vbo; - } - else { - /* HACK: bypass assert */ - int vbo_vert_len = (*vbo)->vertex_len; - (*vbo)->vertex_len = batch->verts[0]->vertex_len; - GPU_batch_vertbuf_add(batch, *vbo); - (*vbo)->vertex_len = vbo_vert_len; + if (batch != NULL) { + /* HACK set first vbo if not init. */ + if (batch->verts[0] == NULL) { + GPU_batch_vao_cache_clear(batch); + batch->verts[0] = *vbo; + } + else { + /* HACK: bypass assert */ + int vbo_vert_len = (*vbo)->vertex_len; + (*vbo)->vertex_len = batch->verts[0]->vertex_len; + GPU_batch_vertbuf_add(batch, *vbo); + (*vbo)->vertex_len = vbo_vert_len; + } } } diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 656d72b2808..81c0e97a1a8 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -176,6 +176,13 @@ struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object, struct ParticleSystem *psys, struct ModifierData *md, struct DRWShadingGroup *shgrp); +struct GPUVertBuf *DRW_hair_pos_buffer_get(struct Object *object, + struct ParticleSystem *psys, + struct ModifierData *md); +void DRW_hair_duplimat_get(struct Object *object, + struct ParticleSystem *psys, + struct ModifierData *md, + float (*dupli_mat)[4]); void DRW_hair_init(void); void DRW_hair_update(void); diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 2fdaf0d5345..6cfba0e2a78 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -124,32 +124,109 @@ void DRW_hair_init(void) } } -DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, - ParticleSystem *psys, - ModifierData *md, - DRWShadingGroup *shgrp_parent) +static ParticleHairCache *drw_hair_particle_cache_get( + Object *object, ParticleSystem *psys, ModifierData *md, int subdiv, int thickness_res) +{ + bool update; + ParticleHairCache *cache; + if (psys) { + /* Old particle hair. */ + update = particles_ensure_procedural_data(object, psys, md, &cache, subdiv, thickness_res); + } + else { + /* New hair object. */ + update = hair_ensure_procedural_data(object, &cache, subdiv, thickness_res); + } + + if (update) { + int final_points_len = cache->final[subdiv].strands_res * cache->strands_len; + if (final_points_len > 0) { + GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM); + +#ifdef USE_TRANSFORM_FEEDBACK + DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create( + tf_shader, g_tf_pass, cache->final[subdiv].proc_buf); +#else + DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); + + ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__); + pr_call->next = g_tf_calls; + pr_call->vbo = cache->final[subdiv].proc_buf; + pr_call->shgrp = tf_shgrp; + pr_call->vert_len = final_points_len; + g_tf_calls = pr_call; + DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1); + DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1); + DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1); +#endif + + DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", cache->point_tex); + DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", cache->strand_tex); + DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", cache->strand_seg_tex); + DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1); + DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len); + } + } + return cache; +} + +/* Note: Only valid after DRW_hair_update(). */ +GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, ModifierData *md) { - /* TODO(fclem): Pass the scene as parameter */ const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - float dupli_mat[4][4]; - Object *dupli_parent = DRW_object_get_dupli_parent(object); - DupliObject *dupli_object = DRW_object_get_dupli(object); int subdiv = scene->r.hair_subdiv; int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; - ParticleHairCache *hair_cache; - bool need_ft_update; + ParticleHairCache *cache = drw_hair_particle_cache_get(object, psys, md, subdiv, thickness_res); + + return cache->final[subdiv].proc_buf; +} + +void DRW_hair_duplimat_get(Object *object, + ParticleSystem *psys, + ModifierData *UNUSED(md), + float (*dupli_mat)[4]) +{ + Object *dupli_parent = DRW_object_get_dupli_parent(object); + DupliObject *dupli_object = DRW_object_get_dupli(object); + if (psys) { - /* Old particle hair. */ - need_ft_update = particles_ensure_procedural_data( - object, psys, md, &hair_cache, subdiv, thickness_res); + if ((dupli_parent != NULL) && (dupli_object != NULL)) { + if (dupli_object->type & OB_DUPLICOLLECTION) { + copy_m4_m4(dupli_mat, dupli_parent->obmat); + } + else { + copy_m4_m4(dupli_mat, dupli_object->ob->obmat); + invert_m4(dupli_mat); + mul_m4_m4m4(dupli_mat, object->obmat, dupli_mat); + } + } + else { + unit_m4(dupli_mat); + } } else { /* New hair object. */ - need_ft_update = hair_ensure_procedural_data(object, &hair_cache, subdiv, thickness_res); + copy_m4_m4(dupli_mat, object->obmat); } +} + +DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, + ParticleSystem *psys, + ModifierData *md, + DRWShadingGroup *shgrp_parent) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + float dupli_mat[4][4]; + + int subdiv = scene->r.hair_subdiv; + int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; + + ParticleHairCache *hair_cache = drw_hair_particle_cache_get( + object, psys, md, subdiv, thickness_res); DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent); @@ -177,25 +254,7 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture); } - if (psys) { - if ((dupli_parent != NULL) && (dupli_object != NULL)) { - if (dupli_object->type & OB_DUPLICOLLECTION) { - copy_m4_m4(dupli_mat, dupli_parent->obmat); - } - else { - copy_m4_m4(dupli_mat, dupli_object->ob->obmat); - invert_m4(dupli_mat); - mul_m4_m4m4(dupli_mat, object->obmat, dupli_mat); - } - } - else { - unit_m4(dupli_mat); - } - } - else { - /* New hair object. */ - copy_m4_m4(dupli_mat, object->obmat); - } + DRW_hair_duplimat_get(object, psys, md, dupli_mat); /* Get hair shape parameters. */ float hair_rad_shape, hair_rad_root, hair_rad_tip; @@ -229,38 +288,6 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, GPUBatch *geom = hair_cache->final[subdiv].proc_hairs[thickness_res - 1]; DRW_shgroup_call_no_cull(shgrp, geom, object); - /* Transform Feedback subdiv. */ - if (need_ft_update) { - int final_points_len = hair_cache->final[subdiv].strands_res * hair_cache->strands_len; - if (final_points_len) { - GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM); - -#ifdef USE_TRANSFORM_FEEDBACK - DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create( - tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf); -#else - DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); - - ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__); - pr_call->next = g_tf_calls; - pr_call->vbo = hair_cache->final[subdiv].proc_buf; - pr_call->shgrp = tf_shgrp; - pr_call->vert_len = final_points_len; - g_tf_calls = pr_call; - DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1); - DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1); - DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1); -#endif - - DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex); - DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex); - DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex); - DRW_shgroup_uniform_int( - tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1); - DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len); - } - } - return shgrp; } diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 10ef8d9c4c8..3e42c4cdb23 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -373,6 +373,8 @@ void DRW_render_viewport_size_set(int size[2]) { DST.size[0] = size[0]; DST.size[1] = size[1]; + DST.inv_size[0] = 1.0f / size[0]; + DST.inv_size[1] = 1.0f / size[1]; } const float *DRW_viewport_size_get(void) @@ -1635,13 +1637,6 @@ bool DRW_render_check_grease_pencil(Depsgraph *depsgraph) return false; } -static void drw_view_reset(void) -{ - DST.view_default = NULL; - DST.view_active = NULL; - DST.view_previous = NULL; -} - static void DRW_render_gpencil_to_image(RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect) @@ -1719,7 +1714,7 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph for (RenderView *render_view = render_result->views.first; render_view != NULL; render_view = render_view->next) { RE_SetActiveRenderView(render, render_view->name); - drw_view_reset(); + DRW_view_reset(); DST.buffer_finish_called = false; DRW_render_gpencil_to_image(engine, render_layer, &render_rect); } @@ -1827,7 +1822,7 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) for (RenderView *render_view = render_result->views.first; render_view != NULL; render_view = render_view->next) { RE_SetActiveRenderView(render, render_view->name); - drw_view_reset(); + DRW_view_reset(); engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect); DST.buffer_finish_called = false; } @@ -1949,6 +1944,28 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, #endif } +/* Used when the render engine want to redo another cache populate inside the same render frame. */ +void DRW_cache_restart(void) +{ + /* Save viewport size. */ + float size[2], inv_size[2]; + copy_v2_v2(size, DST.size); + copy_v2_v2(inv_size, DST.inv_size); + + /* Force cache to reset. */ + drw_viewport_cache_resize(); + + drw_viewport_var_init(); + + DST.buffer_finish_called = false; + + DRW_hair_init(); + + /* Restore. */ + copy_v2_v2(DST.size, size); + copy_v2_v2(DST.inv_size, inv_size); +} + static struct DRWSelectBuffer { struct GPUFrameBuffer *framebuffer_depth_only; struct GPUTexture *texture_depth; @@ -2374,6 +2391,17 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph, void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, const rcti *rect) { + SELECTID_Context *sel_ctx = DRW_select_engine_context_get(); + GPUViewport *viewport = WM_draw_region_get_viewport(region); + if (!viewport) { + /* Selection engine requires a viewport. + * TODO (germano): This should be done internally in the engine. */ + sel_ctx->is_dirty = true; + sel_ctx->objects_drawn_len = 0; + sel_ctx->index_drawn_len = 1; + return; + } + Scene *scene = DEG_get_evaluated_scene(depsgraph); ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); @@ -2394,14 +2422,13 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons drw_context_state_init(); /* Setup viewport */ - DST.viewport = WM_draw_region_get_viewport(region); + DST.viewport = viewport; drw_viewport_var_init(); /* Update ubos */ DRW_globals_update(); /* Init Select Engine */ - struct SELECTID_Context *sel_ctx = DRW_select_engine_context_get(); sel_ctx->last_rect = *rect; use_drw_engine(&draw_engine_select_type); diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 07fb97236fb..3d83b918757 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -76,7 +76,7 @@ static void draw_call_sort(DRWCommand *array, DRWCommand *array_tmp, int array_l for (int i = 1; i < ARRAY_SIZE(idx); i++) { idx[i] += idx[i - 1]; } - /* Traverse in reverse to not change the order of the resource ids. */ + /* Traverse in reverse to not change the order of the resource ID's. */ for (int src = array_len - 1; src >= 0; src--) { array_tmp[--idx[KEY(array[src])]] = array[src]; } @@ -116,7 +116,7 @@ void drw_resource_buffer_finish(ViewportMemoryPool *vmempool) vmempool->ubo_len = ubo_len; } - /* Remove unecessary buffers */ + /* Remove unnecessary buffers */ for (int i = ubo_len; i < vmempool->ubo_len; i++) { GPU_uniformbuffer_free(vmempool->matrices_ubo[i]); GPU_uniformbuffer_free(vmempool->obinfos_ubo[i]); @@ -151,7 +151,7 @@ void drw_resource_buffer_finish(ViewportMemoryPool *vmempool) BLI_memblock_iternew(vmempool->commands, &iter); while ((chunk = BLI_memblock_iterstep(&iter))) { bool sortable = true; - /* We can only sort chunks that contain DRWCommandDraw only. */ + /* We can only sort chunks that contain #DRWCommandDraw only. */ for (int i = 0; i < ARRAY_SIZE(chunk->command_type) && sortable; i++) { if (chunk->command_type[i] != 0) { sortable = false; @@ -179,7 +179,7 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, int arraysize) { if (loc == -1) { - /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ + /* Nice to enable eventually, for now EEVEE uses uniforms that might not exist. */ // BLI_assert(0); return; } @@ -262,11 +262,19 @@ void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, con DRW_shgroup_uniform_texture_ex(shgroup, name, tex, GPU_SAMPLER_MAX); } -void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) +void DRW_shgroup_uniform_texture_ref_ex(DRWShadingGroup *shgroup, + const char *name, + GPUTexture **tex, + eGPUSamplerState sampler_state) { BLI_assert(tex != NULL); int loc = GPU_shader_get_texture_binding(shgroup->shader, name); - drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE_REF, tex, GPU_SAMPLER_MAX, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE_REF, tex, sampler_state, 0, 1); +} + +void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) +{ + DRW_shgroup_uniform_texture_ref_ex(shgroup, name, tex, GPU_SAMPLER_MAX); } void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, @@ -424,7 +432,7 @@ void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, int location = GPU_shader_get_uniform(shgroup->shader, name); if (location == -1) { - /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ + /* Nice to enable eventually, for now EEVEE uses uniforms that might not exist. */ // BLI_assert(0); return; } @@ -530,6 +538,11 @@ static void drw_call_culling_init(DRWCullingState *cull, Object *ob) mul_v3_m4v3(corner, ob->obmat, bbox->vec[0]); mul_m4_v3(ob->obmat, cull->bsphere.center); cull->bsphere.radius = len_v3v3(cull->bsphere.center, corner); + + /* Bypass test for very large objects (see T67319). */ + if (UNLIKELY(cull->bsphere.radius > 1e12)) { + cull->bsphere.radius = -1.0f; + } } else { /* Bypass test. */ @@ -569,7 +582,7 @@ uint32_t DRW_object_resource_id_get(Object *UNUSED(ob)) /* Handle not yet allocated. Return next handle. */ handle = DST.resource_handle; } - return handle; + return handle & ~(1 << 31); } static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup, @@ -1786,6 +1799,14 @@ const DRWView *DRW_view_default_get(void) return DST.view_default; } +/* WARNING: Only use in render AND only if you are going to set view_default again. */ +void DRW_view_reset(void) +{ + DST.view_default = NULL; + DST.view_active = NULL; + DST.view_previous = NULL; +} + /* MUST only be called once per render and only in render mode. Sets default view. */ void DRW_view_default_set(DRWView *view) { diff --git a/source/blender/draw/intern/draw_select_buffer.c b/source/blender/draw/intern/draw_select_buffer.c index 81c9f400f6e..558d5441136 100644 --- a/source/blender/draw/intern/draw_select_buffer.c +++ b/source/blender/draw/intern/draw_select_buffer.c @@ -122,7 +122,6 @@ uint *DRW_select_buffer_read(struct Depsgraph *depsgraph, /** * \param rect: The rectangle to sample indices from (min/max inclusive). - * \param mask: Specifies the rect pixels (optional). * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure. */ uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph, @@ -165,10 +164,10 @@ uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph, } /** - * \param bitmap_len: Number of indices in the selection id buffer. * \param center: Circle center. * \param radius: Circle radius. - * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure. + * \param r_bitmap_len: Number of indices in the selection id buffer. + * \returns a #BLI_bitmap the length of \a r_bitmap_len or NULL on failure. */ uint *DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph, struct ARegion *region, @@ -338,7 +337,7 @@ uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph, /** * Find the selection id closest to \a center. - * \param dist[in,out]: Use to initialize the distance, + * \param dist: Use to initialize the distance, * when found, this value is set to the distance of the selection that's returned. */ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, |