diff options
9 files changed, 292 insertions, 267 deletions
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 31549c6f752..8c9dc43afa8 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -215,13 +215,16 @@ static GPUShader *workbench_cavity_shader_get(bool cavity, bool curvature) static GPUShader *ensure_deferred_prepass_shader(WORKBENCH_PrivateData *wpd, bool is_uniform_color, bool is_hair, + bool is_texture_painting, eGPUShaderConfig sh_cfg) { WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - int index = workbench_material_get_prepass_shader_index(wpd, is_uniform_color, is_hair); + int index = workbench_material_get_prepass_shader_index( + wpd, is_uniform_color, is_hair, is_texture_painting); if (sh_data->prepass_sh_cache[index] == NULL) { const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; - char *defines = workbench_material_build_defines(wpd, is_uniform_color, is_hair); + char *defines = workbench_material_build_defines( + wpd, is_uniform_color, is_hair, is_texture_painting); char *prepass_vert = workbench_build_prepass_vert(is_hair); char *prepass_frag = workbench_build_prepass_frag(); sh_data->prepass_sh_cache[index] = GPU_shader_create_from_arrays({ @@ -240,7 +243,7 @@ static GPUShader *ensure_deferred_composite_shader(WORKBENCH_PrivateData *wpd) { int index = workbench_material_get_composite_shader_index(wpd); if (e_data.composite_sh_cache[index] == NULL) { - char *defines = workbench_material_build_defines(wpd, false, false); + char *defines = workbench_material_build_defines(wpd, false, false, false); char *composite_frag = workbench_build_composite_frag(wpd); e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); MEM_freeN(composite_frag); @@ -267,10 +270,11 @@ static GPUShader *ensure_background_shader(WORKBENCH_PrivateData *wpd) static void select_deferred_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg) { - wpd->prepass_sh = ensure_deferred_prepass_shader(wpd, false, false, sh_cfg); - wpd->prepass_hair_sh = ensure_deferred_prepass_shader(wpd, false, true, sh_cfg); - wpd->prepass_uniform_sh = ensure_deferred_prepass_shader(wpd, true, false, sh_cfg); - wpd->prepass_uniform_hair_sh = ensure_deferred_prepass_shader(wpd, true, true, sh_cfg); + wpd->prepass_sh = ensure_deferred_prepass_shader(wpd, false, false, false, sh_cfg); + wpd->prepass_hair_sh = ensure_deferred_prepass_shader(wpd, false, true, false, sh_cfg); + wpd->prepass_uniform_sh = ensure_deferred_prepass_shader(wpd, true, false, false, sh_cfg); + wpd->prepass_uniform_hair_sh = ensure_deferred_prepass_shader(wpd, true, true, false, sh_cfg); + wpd->prepass_textured_sh = ensure_deferred_prepass_shader(wpd, false, false, true, sh_cfg); wpd->composite_sh = ensure_deferred_composite_shader(wpd); wpd->background_sh = ensure_background_shader(wpd); } @@ -483,7 +487,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) e_data.composite_buffer_tx = DRW_texture_pool_query_2d( size[0], size[1], comp_tex_format, &draw_engine_workbench_solid); - if (MATDATA_PASS_ENABLED(wpd) || GPU_unused_fb_slot_workaround()) { + if (workbench_is_matdata_pass_enabled(wpd) || GPU_unused_fb_slot_workaround()) { e_data.color_buffer_tx = DRW_texture_pool_query_2d( size[0], size[1], col_tex_format, &draw_engine_workbench_solid); } @@ -523,7 +527,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), }); - if (!MATDATA_PASS_ENABLED(wpd) && !GPU_unused_fb_slot_workaround()) { + if (!workbench_is_matdata_pass_enabled(wpd) && !GPU_unused_fb_slot_workaround()) { e_data.color_buffer_tx = DRW_texture_pool_query_2d( size[0], size[1], col_tex_format, &draw_engine_workbench_solid); } @@ -675,7 +679,7 @@ void workbench_deferred_engine_free(void) static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp) { DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - if (MATDATA_PASS_ENABLED(wpd)) { + if (workbench_is_matdata_pass_enabled(wpd)) { DRW_shgroup_uniform_texture_ref(grp, "materialBuffer", &e_data.color_buffer_tx); } else { @@ -714,7 +718,6 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata) Scene *scene = draw_ctx->scene; workbench_volume_cache_init(vedata); - select_deferred_shaders(wpd, draw_ctx->sh_cfg); /* Background Pass */ @@ -869,7 +872,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat const bool is_ghost = (ob->dtx & OB_DRAWXRAY); /* Solid */ - workbench_material_update_data(wpd, ob, mat, &material_template); + workbench_material_update_data(wpd, ob, mat, &material_template, color_type); material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1; material_template.color_type = color_type; material_template.ima = ima; @@ -880,9 +883,14 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat material = BLI_ghash_lookup(wpd->material_hash, POINTER_FROM_UINT(hash)); if (material == NULL) { material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__); + /* select the correct prepass shader */ + GPUShader *shader = (wpd->shading.color_type == color_type) ? wpd->prepass_sh : + wpd->prepass_uniform_sh; + if (color_type == V3D_SHADING_TEXTURE_COLOR) { + shader = wpd->prepass_textured_sh; + } material->shgrp = DRW_shgroup_create( - (wpd->shading.color_type == color_type) ? wpd->prepass_sh : wpd->prepass_uniform_sh, - (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass); + shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass); workbench_material_copy(material, &material_template); DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF); DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1); @@ -935,6 +943,49 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o } } +static void workbench_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob) +{ + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_PrivateData *wpd = stl->g_data; + const DRWContextState *draw_ctx = DRW_context_state_get(); + + Scene *scene = draw_ctx->scene; + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + WORKBENCH_MaterialData *material; + + /* Force workbench to render active object textured when in texture paint mode */ + const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + + /* Single Image mode */ + if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { + Image *image = imapaint->canvas; + int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : + SHD_INTERP_CLOSEST; + int color_type = workbench_material_determine_color_type(wpd, image, ob, use_sculpt_pbvh); + struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); + material = get_or_create_material_data(vedata, ob, NULL, image, NULL, color_type, interp); + + DRW_shgroup_call(material->shgrp, geom, ob); + } + else { + /* IMAGEPAINT_MODE_MATERIAL */ + const int materials_len = MAX2(1, ob->totcol); + struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); + for (int i = 0; i < materials_len; i++) { + if (geom_array != NULL && geom_array[i] != NULL) { + Material *mat; + Image *image; + ImageUser *iuser; + int interp; + workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); + int color_type = workbench_material_determine_color_type(wpd, image, ob, use_sculpt_pbvh); + material = get_or_create_material_data(vedata, ob, mat, image, iuser, color_type, interp); + DRW_shgroup_call(material->shgrp, geom_array[i], ob); + } + } + } +} + void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) { WORKBENCH_StorageList *stl = vedata->stl; @@ -975,8 +1026,13 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) const int materials_len = MAX2(1, ob->totcol); const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; bool has_transp_mat = false; + const bool use_texture_paint_drawing = workbench_is_object_in_texture_paint_mode(ob) && me && + me->mloopuv; - if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { + if (use_texture_paint_drawing) { + workbench_cache_populate_texture_paint_mode(vedata, ob); + } + else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { /* Draw textured */ struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); for (int i = 0; i < materials_len; i++) { @@ -990,7 +1046,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) wpd, image, ob, use_sculpt_pbvh); if (color_type == V3D_SHADING_MATERIAL_COLOR && mat && mat->a < 1.0) { material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, 0, use_sculpt_pbvh); + vedata, ob, mat, image, iuser, color_type, 0); has_transp_mat = true; } else { @@ -1010,7 +1066,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) if ((ob->color[3] < 1.0f) && (color_type == V3D_SHADING_OBJECT_COLOR)) { material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, 0, use_sculpt_pbvh); + vedata, ob, NULL, NULL, NULL, color_type, 0); has_transp_mat = true; } else { @@ -1045,7 +1101,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) struct Material *mat = give_current_material(ob, i + 1); if (mat != NULL && mat->a < 1.0f) { material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, use_sculpt_pbvh); + vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); has_transp_mat = true; } else { @@ -1068,7 +1124,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) Material *mat = give_current_material(ob, i + 1); if (mat != NULL && mat->a < 1.0f) { material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, use_sculpt_pbvh); + vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); has_transp_mat = true; } else { diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index 9245d13eab0..5e8cbf71c1e 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -141,8 +141,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ Image *ima, ImageUser *iuser, int color_type, - int interp, - bool use_sculpt_pbvh) + int interp) { const DRWContextState *draw_ctx = DRW_context_state_get(); WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; @@ -160,7 +159,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ DRWShadingGroup *grp; /* Solid */ - workbench_material_update_data(wpd, ob, mat, &material_template); + workbench_material_update_data(wpd, ob, mat, &material_template, color_type); material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1; material_template.color_type = color_type; material_template.ima = ima; @@ -173,10 +172,15 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__); /* transparent accum */ - grp = DRW_shgroup_create(wpd->shading.color_type == color_type ? - wpd->transparent_accum_sh : - wpd->transparent_accum_uniform_sh, - psl->transparent_accum_pass); + /* select the correct transparent accum shader */ + GPUShader *shader = (wpd->shading.color_type == color_type) ? + wpd->transparent_accum_sh : + wpd->transparent_accum_uniform_sh; + if (color_type == V3D_SHADING_TEXTURE_COLOR) { + shader = wpd->transparent_accum_textured_sh; + } + + grp = DRW_shgroup_create(shader, psl->transparent_accum_pass); DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); DRW_shgroup_uniform_float_copy(grp, "alpha", material_template.alpha); DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); @@ -199,8 +203,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ material->shgrp = grp; /* Depth */ - if (workbench_material_determine_color_type(wpd, material->ima, ob, use_sculpt_pbvh) == - V3D_SHADING_TEXTURE_COLOR) { + if (color_type == V3D_SHADING_TEXTURE_COLOR) { material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_texture_sh, psl->object_outline_pass); GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D); @@ -223,13 +226,16 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ static GPUShader *ensure_forward_accum_shaders(WORKBENCH_PrivateData *wpd, bool is_uniform_color, bool is_hair, + bool is_texture_painting, eGPUShaderConfig sh_cfg) { WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - int index = workbench_material_get_accum_shader_index(wpd, is_uniform_color, is_hair); + int index = workbench_material_get_accum_shader_index( + wpd, is_uniform_color, is_hair, is_texture_painting); if (sh_data->transparent_accum_sh_cache[index] == NULL) { const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; - char *defines = workbench_material_build_defines(wpd, is_uniform_color, is_hair); + char *defines = workbench_material_build_defines( + wpd, is_uniform_color, is_hair, is_texture_painting); char *transparent_accum_vert = workbench_build_forward_vert(is_hair); char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag(); sh_data->transparent_accum_sh_cache[index] = GPU_shader_create_from_arrays({ @@ -248,7 +254,7 @@ static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd) { int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0; if (e_data.composite_sh_cache[index] == NULL) { - char *defines = workbench_material_build_defines(wpd, false, false); + char *defines = workbench_material_build_defines(wpd, false, false, false); char *composite_frag = workbench_build_forward_composite_frag(); e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); MEM_freeN(composite_frag); @@ -260,10 +266,14 @@ static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd) void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg) { wpd->composite_sh = ensure_forward_composite_shaders(wpd); - wpd->transparent_accum_sh = ensure_forward_accum_shaders(wpd, false, false, sh_cfg); - wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders(wpd, false, true, sh_cfg); - wpd->transparent_accum_uniform_sh = ensure_forward_accum_shaders(wpd, true, false, sh_cfg); - wpd->transparent_accum_uniform_hair_sh = ensure_forward_accum_shaders(wpd, true, true, sh_cfg); + wpd->transparent_accum_sh = ensure_forward_accum_shaders(wpd, false, false, false, sh_cfg); + wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders(wpd, false, true, false, sh_cfg); + wpd->transparent_accum_uniform_sh = ensure_forward_accum_shaders( + wpd, true, false, false, sh_cfg); + wpd->transparent_accum_uniform_hair_sh = ensure_forward_accum_shaders( + wpd, true, true, false, sh_cfg); + wpd->transparent_accum_textured_sh = ensure_forward_accum_shaders( + wpd, false, false, true, sh_cfg); } void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg) @@ -272,9 +282,9 @@ void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUSh if (sh_data->object_outline_sh == NULL) { const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; - char *defines = workbench_material_build_defines(wpd, false, false); - char *defines_texture = workbench_material_build_defines(wpd, true, false); - char *defines_hair = workbench_material_build_defines(wpd, false, true); + char *defines = workbench_material_build_defines(wpd, false, false, false); + char *defines_texture = workbench_material_build_defines(wpd, true, false, false); + char *defines_hair = workbench_material_build_defines(wpd, false, true, false); char *forward_vert = workbench_build_forward_vert(false); char *forward_hair_vert = workbench_build_forward_vert(true); @@ -503,7 +513,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O workbench_material_get_image_and_mat(ob, part->omat, &image, &iuser, &interp, &mat); int color_type = workbench_material_determine_color_type(wpd, image, ob, false); WORKBENCH_MaterialData *material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp, false); + vedata, ob, mat, image, iuser, color_type, interp); struct GPUShader *shader = (wpd->shading.color_type == color_type) ? wpd->transparent_accum_hair_sh : @@ -533,6 +543,53 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O } } } +static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob) +{ + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_PrivateData *wpd = stl->g_data; + const DRWContextState *draw_ctx = DRW_context_state_get(); + + Scene *scene = draw_ctx->scene; + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + WORKBENCH_MaterialData *material; + + /* Force workbench to render active object textured when in texture paint mode */ + const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + + /* Single Image mode */ + if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { + Image *image = imapaint->canvas; + int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : + SHD_INTERP_CLOSEST; + int color_type = workbench_material_determine_color_type(wpd, image, ob, use_sculpt_pbvh); + struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); + material = workbench_forward_get_or_create_material_data( + vedata, ob, NULL, image, NULL, color_type, interp); + + DRW_shgroup_call(material->shgrp, geom, ob); + DRW_shgroup_call(material->shgrp_object_outline, geom, ob); + } + else { + /* IMAGEPAINT_MODE_MATERIAL */ + const int materials_len = MAX2(1, ob->totcol); + struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); + for (int i = 0; i < materials_len; i++) { + if (geom_array != NULL && geom_array[i] != NULL) { + Material *mat; + Image *image; + ImageUser *iuser; + int interp; + workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); + int color_type = workbench_material_determine_color_type(wpd, image, ob, use_sculpt_pbvh); + material = workbench_forward_get_or_create_material_data( + vedata, ob, mat, image, iuser, color_type, interp); + + DRW_shgroup_call(material->shgrp, geom_array[i], ob); + DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob); + } + } + } +} void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) { @@ -571,8 +628,13 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); const int materials_len = MAX2(1, ob->totcol); const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; + const bool use_texture_paint_drawing = workbench_is_object_in_texture_paint_mode(ob) && me && + me->mloopuv; - if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { + if (use_texture_paint_drawing) { + workbench_forward_cache_populate_texture_paint_mode(vedata, ob); + } + else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); for (int i = 0; i < materials_len; i++) { Material *mat; @@ -582,7 +644,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); int color_type = workbench_material_determine_color_type(wpd, image, ob, use_sculpt_pbvh); material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp, use_sculpt_pbvh); + vedata, ob, mat, image, iuser, color_type, interp); DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob); DRW_shgroup_call(material->shgrp, geom_array[i], ob); } @@ -597,7 +659,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) if (use_sculpt_pbvh) { material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, 0, use_sculpt_pbvh); + vedata, ob, NULL, NULL, NULL, color_type, 0); bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR); /* TODO(fclem) make this call optional */ DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false); @@ -611,7 +673,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) DRW_cache_object_surface_get(ob); if (geom) { material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, 0, use_sculpt_pbvh); + vedata, ob, NULL, NULL, NULL, color_type, 0); /* TODO(fclem) make this call optional */ DRW_shgroup_call(material->shgrp_object_outline, geom, ob); if (!is_wire) { @@ -628,7 +690,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) for (int i = 0; i < materials_len; ++i) { struct Material *mat = give_current_material(ob, i + 1); material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, use_sculpt_pbvh); + vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); shgrps[i] = material->shgrp; } /* TODO(fclem) make this call optional */ @@ -651,7 +713,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) Material *mat = give_current_material(ob, i + 1); material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, use_sculpt_pbvh); + vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); /* TODO(fclem) make this call optional */ DRW_shgroup_call(material->shgrp_object_outline, mat_geom[i], ob); if (!is_wire) { diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 76f035562e5..1473b7df279 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -41,13 +41,9 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, - WORKBENCH_MaterialData *data) + WORKBENCH_MaterialData *data, + int color_type) { - /* When V3D_SHADING_TEXTURE_COLOR is active, use V3D_SHADING_MATERIAL_COLOR as fallback when no - * texture could be determined */ - int color_type = wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR ? - V3D_SHADING_MATERIAL_COLOR : - wpd->shading.color_type; copy_v3_fl3(data->diffuse_color, 0.8f, 0.8f, 0.8f); copy_v3_v3(data->base_color, data->diffuse_color); copy_v3_fl3(data->specular_color, 0.05f, 0.05f, 0.05f); /* Dielectric: 5% reflective. */ @@ -59,6 +55,10 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, copy_v3_v3(data->diffuse_color, wpd->shading.single_color); copy_v3_v3(data->base_color, data->diffuse_color); } + else if (color_type == V3D_SHADING_ERROR_COLOR) { + copy_v3_fl3(data->diffuse_color, 0.8, 0.0, 0.8); + copy_v3_v3(data->base_color, data->diffuse_color); + } else if (color_type == V3D_SHADING_RANDOM_COLOR) { uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); if (ob->id.lib) { @@ -76,7 +76,7 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, data->alpha *= ob->color[3]; } else { - /* V3D_SHADING_MATERIAL_COLOR */ + /* V3D_SHADING_MATERIAL_COLOR or V3D_SHADING_TEXTURE_COLOR */ if (mat) { data->alpha *= mat->a; if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) { @@ -97,13 +97,19 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool is_uniform_color, - bool is_hair) + bool is_hair, + bool is_texture_painting) { char *str = NULL; bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color; bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) && !is_uniform_color; + if (is_texture_painting) { + use_textures = true; + use_vertex_colors = false; + } + DynStr *ds = BLI_dynstr_new(); if (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) { @@ -130,7 +136,7 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, if (OBJECT_ID_PASS_ENABLED(wpd)) { BLI_dynstr_append(ds, "#define OBJECT_ID_PASS_ENABLED\n"); } - if (MATDATA_PASS_ENABLED(wpd)) { + if (workbench_is_matdata_pass_enabled(wpd)) { BLI_dynstr_append(ds, "#define MATDATA_PASS_ENABLED\n"); } if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { @@ -193,22 +199,27 @@ int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd) SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 2); SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 3); SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 4); - SET_FLAG_FROM_TEST(index, MATDATA_PASS_ENABLED(wpd), 1 << 5); + SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 5); BLI_assert(index < MAX_COMPOSITE_SHADERS); return index; } int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd, bool is_uniform_color, - bool is_hair) + bool is_hair, + bool is_texture_painting) { bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color; bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) && !is_uniform_color; + if (is_texture_painting) { + use_textures = true; + use_vertex_colors = false; + } /* NOTE: change MAX_PREPASS_SHADERS accordingly when modifying this function. */ int index = 0; SET_FLAG_FROM_TEST(index, is_hair, 1 << 0); - SET_FLAG_FROM_TEST(index, MATDATA_PASS_ENABLED(wpd), 1 << 1); + SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 1); SET_FLAG_FROM_TEST(index, OBJECT_ID_PASS_ENABLED(wpd), 1 << 2); SET_FLAG_FROM_TEST(index, NORMAL_VIEWPORT_PASS_ENABLED(wpd), 1 << 3); SET_FLAG_FROM_TEST(index, MATCAP_ENABLED(wpd), 1 << 4); @@ -220,11 +231,18 @@ int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd, int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd, bool is_uniform_color, - bool is_hair) + bool is_hair, + bool is_texture_painting) { bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color; bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) && !is_uniform_color; + if (is_texture_painting) { + use_textures = true; + use_vertex_colors = false; + is_hair = false; + } + /* NOTE: change MAX_ACCUM_SHADERS accordingly when modifying this function. */ int index = 0; /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */ @@ -253,6 +271,13 @@ int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, if (color_type == V3D_SHADING_VERTEX_COLOR && (me == NULL || me->mloopcol == NULL)) { color_type = V3D_SHADING_OBJECT_COLOR; } + + /* Force V3D_SHADING_TEXTURE_COLOR for active object when in texture painting + * no matter the shading color that the user has chosen, when there is no + * texture we will render the object with the error color */ + if (workbench_is_object_in_texture_paint_mode(ob)) { + color_type = ima ? V3D_SHADING_TEXTURE_COLOR : V3D_SHADING_ERROR_COLOR; + } return color_type; } @@ -292,7 +317,7 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, const bool deferred, const int interp) { - if (deferred && !MATDATA_PASS_ENABLED(wpd)) { + if (deferred && !workbench_is_matdata_pass_enabled(wpd)) { return; } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 3b62ed33e96..17144c4dc10 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -43,6 +43,7 @@ #define TEXTURE_DRAWING_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) #define VERTEX_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) +#define MATERIAL_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_MATERIAL_COLOR) #define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT) #define STUDIOLIGHT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_STUDIO) #define MATCAP_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_MATCAP) @@ -81,8 +82,6 @@ (!STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd))) #define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) #define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) -#define MATDATA_PASS_ENABLED(wpd) \ - (wpd->shading.color_type != V3D_SHADING_SINGLE_COLOR || MATCAP_ENABLED(wpd)) #define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) \ (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd)) #define NORMAL_VIEWPORT_PASS_ENABLED(wpd) \ @@ -208,12 +207,14 @@ typedef struct WORKBENCH_PrivateData { struct GPUShader *prepass_hair_sh; struct GPUShader *prepass_uniform_sh; struct GPUShader *prepass_uniform_hair_sh; + struct GPUShader *prepass_textured_sh; struct GPUShader *composite_sh; struct GPUShader *background_sh; struct GPUShader *transparent_accum_sh; struct GPUShader *transparent_accum_hair_sh; struct GPUShader *transparent_accum_uniform_sh; struct GPUShader *transparent_accum_uniform_hair_sh; + struct GPUShader *transparent_accum_textured_sh; View3DShading shading; StudioLight *studio_light; const UserDef *preferences; @@ -354,6 +355,32 @@ BLI_INLINE bool workbench_is_fxaa_enabled(WORKBENCH_PrivateData *wpd) } } +/** Is texture paint mode enabled (globally) */ +BLI_INLINE bool workbench_is_in_texture_paint_mode(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + return draw_ctx->object_mode == OB_MODE_TEXTURE_PAINT; +} + +/** Is texture paint mode active for the given object */ +BLI_INLINE bool workbench_is_object_in_texture_paint_mode(Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + if (ob->type == OB_MESH && (draw_ctx->obact == ob)) { + const enum eContextObjectMode mode = CTX_data_mode_enum_ex( + draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode); + return (mode == CTX_MODE_PAINT_TEXTURE); + } + + return false; +} + +BLI_INLINE bool workbench_is_matdata_pass_enabled(WORKBENCH_PrivateData *wpd) +{ + return (wpd->shading.color_type != V3D_SHADING_SINGLE_COLOR || MATCAP_ENABLED(wpd)) || + workbench_is_in_texture_paint_mode(); +} + /* workbench_deferred.c */ void workbench_deferred_engine_init(WORKBENCH_Data *vedata); void workbench_deferred_engine_free(void); @@ -383,8 +410,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ Image *ima, ImageUser *iuser, int color_type, - int interp, - bool use_sculpt_pbvh); + int interp); /* workbench_effect_aa.c */ void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx); @@ -422,19 +448,23 @@ void workbench_material_get_image_and_mat( Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat); char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool is_uniform_color, - bool is_hair); + bool is_hair, + bool is_texture_painting); void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, - WORKBENCH_MaterialData *data); + WORKBENCH_MaterialData *data, + int color_type); uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost); int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd); int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd, bool is_uniform_color, - bool is_hair); + bool is_hair, + bool is_texture_painting); int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd, bool is_uniform_color, - bool is_hair); + bool is_hair, + bool is_texture_painting); void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material, diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c index 6c2f170a220..7c164a74f2f 100644 --- a/source/blender/draw/modes/paint_texture_mode.c +++ b/source/blender/draw/modes/paint_texture_mode.c @@ -63,7 +63,7 @@ typedef struct PAINT_TEXTURE_PassList { /* Declare all passes here and init them in * PAINT_TEXTURE_cache_init(). * Only contains (DRWPass *) */ - struct DRWPass *image_faces; + struct DRWPass *stencil_mask_overlay; struct DRWPass *wire_select_overlay; struct DRWPass *face_select_overlay; @@ -107,9 +107,7 @@ typedef struct PAINT_TEXTURE_Shaders { * Add sources to source/blender/draw/modes/shaders * init in PAINT_TEXTURE_engine_init(); * free in PAINT_TEXTURE_engine_free(); */ - struct GPUShader *fallback; - struct GPUShader *image; - struct GPUShader *image_mask; + struct GPUShader *stencil_mask_overlay; struct GPUShader *wire_select_overlay; struct GPUShader *face_select_overlay; @@ -124,8 +122,7 @@ static struct { typedef struct PAINT_TEXTURE_PrivateData { /* This keeps the references of the shading groups for * easy access in PAINT_TEXTURE_cache_populate() */ - DRWShadingGroup *shgroup_fallback; - DRWShadingGroup **shgroup_image_array; + DRWShadingGroup *shgroup_stencil_mask; /* face-mask */ DRWShadingGroup *lwire_select_shgrp; @@ -144,18 +141,9 @@ static void PAINT_TEXTURE_engine_init(void *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->fallback) { + if (!sh_data->stencil_mask_overlay) { const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; - sh_data->fallback = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, - datatoc_common_view_lib_glsl, - datatoc_paint_face_vert_glsl, - NULL}, - .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg_data->def, NULL}, - }); - - sh_data->image = GPU_shader_create_from_arrays({ + sh_data->stencil_mask_overlay = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, datatoc_common_globals_lib_glsl, datatoc_common_view_lib_glsl, @@ -167,18 +155,6 @@ static void PAINT_TEXTURE_engine_init(void *vedata) .defs = (const char *[]){sh_cfg_data->def, NULL}, }); - sh_data->image_mask = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, - datatoc_common_globals_lib_glsl, - datatoc_common_view_lib_glsl, - datatoc_paint_texture_vert_glsl, - NULL}, - .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl, - datatoc_paint_texture_frag_glsl, - NULL}, - .defs = (const char *[]){sh_cfg_data->def, "#define TEXTURE_PAINT_MASK\n", NULL}, - }); - sh_data->wire_select_overlay = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, datatoc_common_globals_lib_glsl, @@ -204,45 +180,39 @@ static void PAINT_TEXTURE_engine_init(void *vedata) if (!stl->g_data) { /* Alloc transient pointers */ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); - stl->g_data->shgroup_image_array = NULL; + stl->g_data->shgroup_stencil_mask = NULL; } stl->g_data->view_wires = DRW_view_create_with_zoffset(draw_ctx->rv3d, 1.0f); } -static DRWShadingGroup *create_texture_paint_shading_group(PAINT_TEXTURE_PassList *psl, - const Image *image, - const struct GPUTexture *texture, - const DRWContextState *draw_ctx, - const bool nearest_interp) +static DRWShadingGroup *create_texture_paint_stencil_mask_shading_group( + PAINT_TEXTURE_PassList *psl, const DRWContextState *draw_ctx) { PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; Scene *scene = draw_ctx->scene; const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - const bool masking_enabled = imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL && - imapaint->stencil != NULL; - DRWShadingGroup *grp = DRW_shgroup_create(masking_enabled ? sh_data->image_mask : sh_data->image, - psl->image_faces); - DRW_shgroup_uniform_texture(grp, "image", texture); - DRW_shgroup_uniform_bool_copy( - grp, "imagePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL)); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->stencil_mask_overlay, + psl->stencil_mask_overlay); DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_bool_copy(grp, "nearestInterp", nearest_interp); - - if (masking_enabled) { - const bool masking_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) > 0; - GPUTexture *stencil = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D); - DRW_shgroup_uniform_texture(grp, "maskingImage", stencil); - DRW_shgroup_uniform_bool_copy( - grp, "maskingImagePremultiplied", (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL)); - DRW_shgroup_uniform_vec3(grp, "maskingColor", imapaint->stencil_col, 1); - DRW_shgroup_uniform_bool_copy(grp, "maskingInvertStencil", masking_inverted); - } + + const bool masking_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) > 0; + GPUTexture *stencil = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D); + DRW_shgroup_uniform_texture(grp, "maskingImage", stencil); + DRW_shgroup_uniform_bool_copy( + grp, "maskingImagePremultiplied", (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL)); + DRW_shgroup_uniform_vec3(grp, "maskingColor", imapaint->stencil_col, 1); + DRW_shgroup_uniform_bool_copy(grp, "maskingInvertStencil", masking_inverted); return grp; } +static bool PAINT_TEXTURE_stencil_mask_enabled(const ImagePaintSettings *imapaint) +{ + return imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL && imapaint->stencil != NULL; +} + /* Here init all passes and shading groups * Assume that all Passes are NULL */ static void PAINT_TEXTURE_cache_init(void *vedata) @@ -251,69 +221,17 @@ static void PAINT_TEXTURE_cache_init(void *vedata) PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); - PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - - /* Create a pass */ - { - DRWPass *pass = DRW_pass_create( - "Image Color Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA); - DRWShadingGroup *shgrp = DRW_shgroup_create(sh_data->fallback, pass); - - /* Uniforms need a pointer to it's value so be sure it's accessible at - * any given time (i.e. use static vars) */ - static const float color[4] = {1.0f, 0.0f, 1.0f, 1.0}; - DRW_shgroup_uniform_vec4(shgrp, "color", color, 1); - - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES); - } - psl->image_faces = pass; - stl->g_data->shgroup_fallback = shgrp; - } + Scene *scene = draw_ctx->scene; + const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - MEM_SAFE_FREE(stl->g_data->shgroup_image_array); + PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - Object *ob = draw_ctx->obact; - if (ob && ob->type == OB_MESH) { - Scene *scene = draw_ctx->scene; - const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - const bool use_material_slots = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL); - const Mesh *me = ob->data; - const int mat_nr = max_ii(1, me->totcol); - - stl->g_data->shgroup_image_array = MEM_mallocN( - sizeof(*stl->g_data->shgroup_image_array) * (use_material_slots ? mat_nr : 1), __func__); - - if (use_material_slots) { - for (int i = 0; i < mat_nr; i++) { - Material *ma = give_current_material(ob, i + 1); - Image *ima = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].ima : NULL; - int interp = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].interp : 0; - GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D); - - if (tex) { - DRWShadingGroup *grp = create_texture_paint_shading_group( - psl, ima, tex, draw_ctx, interp == SHD_INTERP_CLOSEST); - stl->g_data->shgroup_image_array[i] = grp; - } - else { - stl->g_data->shgroup_image_array[i] = NULL; - } - } - } - else { - Image *ima = imapaint->canvas; - GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D); - - if (tex) { - DRWShadingGroup *grp = create_texture_paint_shading_group( - psl, ima, tex, draw_ctx, imapaint->interp == IMAGEPAINT_INTERP_CLOSEST); - stl->g_data->shgroup_image_array[0] = grp; - } - else { - stl->g_data->shgroup_image_array[0] = NULL; - } - } + /* Stencil Mask */ + if (PAINT_TEXTURE_stencil_mask_enabled(imapaint)) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; + psl->stencil_mask_overlay = DRW_pass_create("Stencil Mask Pass", state); + stl->g_data->shgroup_stencil_mask = create_texture_paint_stencil_mask_shading_group(psl, + draw_ctx); } /* Face Mask */ @@ -358,41 +276,18 @@ static void PAINT_TEXTURE_cache_populate(void *vedata, Object *ob) if ((ob->type == OB_MESH) && (draw_ctx->obact == ob)) { /* Get geometry cache */ - const Mesh *me = ob->data; const Mesh *me_orig = DEG_get_original_object(ob)->data; Scene *scene = draw_ctx->scene; - const bool use_surface = draw_ctx->v3d->overlay.texture_paint_mode_opacity != - 0.0; // DRW_object_is_mode_shade(ob) == true; - const bool use_material_slots = (scene->toolsettings->imapaint.mode == - IMAGEPAINT_MODE_MATERIAL); + const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + const bool masking_enabled = imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL && + imapaint->stencil != NULL; - if (use_surface) { - if (me->mloopuv != NULL) { - if (use_material_slots) { - int mat_nr = max_ii(1, me->totcol); - struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); - - for (int i = 0; i < mat_nr; i++) { - const int index = use_material_slots ? i : 0; - if ((i < me->totcol) && stl->g_data->shgroup_image_array[index]) { - DRW_shgroup_call(stl->g_data->shgroup_image_array[index], geom_array[i], ob); - } - else { - DRW_shgroup_call(stl->g_data->shgroup_fallback, geom_array[i], ob); - } - } - } - else { - if (stl->g_data->shgroup_image_array[0]) { - struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); - DRW_shgroup_call(stl->g_data->shgroup_image_array[0], geom, ob); - } - } - } - else { - struct GPUBatch *geom = DRW_cache_mesh_surface_get(ob); - DRW_shgroup_call(stl->g_data->shgroup_fallback, geom, ob); + if (masking_enabled) { + if (stl->g_data->shgroup_stencil_mask) { + struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); + DRW_shgroup_call(stl->g_data->shgroup_stencil_mask, geom, ob); } } @@ -408,32 +303,15 @@ static void PAINT_TEXTURE_cache_populate(void *vedata, Object *ob) } } -/* Optional: Post-cache_populate callback */ -static void PAINT_TEXTURE_cache_finish(void *vedata) -{ - PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl; - PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl; - - /* Do something here! dependent on the objects gathered */ - UNUSED_VARS(psl); - - MEM_SAFE_FREE(stl->g_data->shgroup_image_array); -} - /* Draw time ! Control rendering pipeline from here */ static void PAINT_TEXTURE_draw_scene(void *vedata) { PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl; - PAINT_TEXTURE_FramebufferList *fbl = ((PAINT_TEXTURE_Data *)vedata)->fbl; PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl; - /* Default framebuffer and texture */ - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - - UNUSED_VARS(fbl, dfbl, dtxl); - - DRW_draw_pass(psl->image_faces); + if (psl->stencil_mask_overlay) { + DRW_draw_pass(psl->stencil_mask_overlay); + } DRW_draw_pass(psl->face_select_overlay); @@ -469,7 +347,7 @@ DrawEngineType draw_engine_paint_texture_type = { &PAINT_TEXTURE_engine_free, &PAINT_TEXTURE_cache_init, &PAINT_TEXTURE_cache_populate, - &PAINT_TEXTURE_cache_finish, + NULL, NULL, /* draw_background but not needed by mode engines */ &PAINT_TEXTURE_draw_scene, NULL, diff --git a/source/blender/draw/modes/shaders/paint_texture_frag.glsl b/source/blender/draw/modes/shaders/paint_texture_frag.glsl index e8722590802..edd7c2af001 100644 --- a/source/blender/draw/modes/shaders/paint_texture_frag.glsl +++ b/source/blender/draw/modes/shaders/paint_texture_frag.glsl @@ -1,35 +1,17 @@ - -in vec2 uv_interp; -#ifdef TEXTURE_PAINT_MASK in vec2 masking_uv_interp; -#endif out vec4 fragColor; -uniform sampler2D image; -uniform bool imagePremultiplied; uniform float alpha = 1.0; -uniform bool nearestInterp; -#ifdef TEXTURE_PAINT_MASK uniform sampler2D maskingImage; uniform bool maskingImagePremultiplied; uniform vec3 maskingColor; uniform bool maskingInvertStencil; -#endif void main() { - vec2 uv = uv_interp; - if (nearestInterp) { - vec2 tex_size = vec2(textureSize(image, 0).xy); - uv = (floor(uv_interp * tex_size) + 0.5) / tex_size; - } - - vec4 color = texture_read_as_srgb(image, imagePremultiplied, uv); - color.a *= alpha; -#ifdef TEXTURE_PAINT_MASK vec4 mask = vec4( texture_read_as_srgb(maskingImage, maskingImagePremultiplied, masking_uv_interp).rgb, 1.0); if (maskingInvertStencil) { @@ -37,8 +19,7 @@ void main() } float mask_step = smoothstep(0, 3.0, mask.r + mask.g + mask.b); mask.rgb *= maskingColor; - color = mix(color, mask, mask_step); -#endif + mask.a = mask_step * alpha; - fragColor = color; + fragColor = mask; } diff --git a/source/blender/draw/modes/shaders/paint_texture_vert.glsl b/source/blender/draw/modes/shaders/paint_texture_vert.glsl index 564f988348e..ddfc2b51437 100644 --- a/source/blender/draw/modes/shaders/paint_texture_vert.glsl +++ b/source/blender/draw/modes/shaders/paint_texture_vert.glsl @@ -1,27 +1,15 @@ -in vec2 u; /* active uv map */ in vec3 pos; - -#ifdef TEXTURE_PAINT_MASK in vec2 mu; /* masking uv map */ -#endif - -out vec2 uv_interp; -#ifdef TEXTURE_PAINT_MASK out vec2 masking_uv_interp; -#endif void main() { vec3 world_pos = point_object_to_world(pos); gl_Position = point_world_to_ndc(world_pos); - uv_interp = u; - -#ifdef TEXTURE_PAINT_MASK masking_uv_interp = mu; -#endif #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 31ffb3efebd..e7a4f9cbd4e 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -433,6 +433,10 @@ enum { V3D_SHADING_TEXTURE_COLOR = 3, V3D_SHADING_OBJECT_COLOR = 4, V3D_SHADING_VERTEX_COLOR = 5, + + /* Is used to display the object using the error color. For example when in + * solid texture paint mode without any textures configured */ + V3D_SHADING_ERROR_COLOR = 999, }; /** #View3DShading.background_type */ diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index d3eb7a9258b..1c76753fb1b 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -3525,7 +3525,8 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) prop = RNA_def_property(srna, "texture_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "overlay.texture_paint_mode_opacity"); RNA_def_property_float_default(prop, 1.0f); - RNA_def_property_ui_text(prop, "Texture Opacity", "Opacity of the texture paint mode overlay"); + RNA_def_property_ui_text( + prop, "Stencil Opacity", "Opacity of the texture paint mode stencil mask overlay"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); |