This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/draw/engines/basic/basic_engine.c
Jeroen Bakker 54f5c174a8 Asset: Dropping Material assets on material slot under mouse cursor.
This patch allows dropping material assets from material slot under the mouse
cursor. Before this change the material slot had to be hand-picked from the
properties panel.

For consistency it is chosen to do this in any shading mode as the tooltip shows
what is exactly going to happen during release.

The feature also works for other object types than Meshes as it uses the drawn surface on the
GPU to detect the material slots. Performance of this patch has been tested with AMD GCN3.0
cards and are very responsive.

Reviewed By: fclem, Severin

Differential Revision: https://developer.blender.org/D12190
2021-09-08 08:47:26 +02:00

310 lines
10 KiB
C

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2016, Blender Foundation.
*/
/** \file
* \ingroup draw_engine
*
* Simple engine for drawing color and/or depth.
* When we only need simple flat shaders.
*/
#include "DRW_render.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BLI_alloca.h"
#include "DNA_particle_types.h"
#include "GPU_shader.h"
#include "basic_engine.h"
/* Shaders */
#define BASIC_ENGINE "BLENDER_BASIC"
extern char datatoc_depth_frag_glsl[];
extern char datatoc_depth_vert_glsl[];
extern char datatoc_conservative_depth_geom_glsl[];
extern char datatoc_common_view_lib_glsl[];
/* *********** LISTS *********** */
/* GPUViewport.storage
* Is freed every time the viewport engine changes. */
typedef struct BASIC_StorageList {
struct BASIC_PrivateData *g_data;
} BASIC_StorageList;
typedef struct BASIC_PassList {
struct DRWPass *depth_pass[2];
struct DRWPass *depth_pass_cull[2];
} BASIC_PassList;
typedef struct BASIC_Data {
void *engine_type;
DRWViewportEmptyList *fbl;
DRWViewportEmptyList *txl;
BASIC_PassList *psl;
BASIC_StorageList *stl;
} BASIC_Data;
typedef struct BASIC_Shaders {
/* Depth Pre Pass */
struct GPUShader *depth;
struct GPUShader *depth_conservative;
} BASIC_Shaders;
/* *********** STATIC *********** */
static struct {
BASIC_Shaders sh_data[GPU_SHADER_CFG_LEN];
} e_data = {{{NULL}}}; /* Engine data */
typedef struct BASIC_PrivateData {
DRWShadingGroup *depth_shgrp[2];
DRWShadingGroup *depth_shgrp_cull[2];
DRWShadingGroup *depth_hair_shgrp[2];
bool use_material_slot_selection;
} BASIC_PrivateData; /* Transient data */
/* Functions */
static void basic_engine_init(void *UNUSED(vedata))
{
const DRWContextState *draw_ctx = DRW_context_state_get();
BASIC_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
/* Depth prepass */
if (!sh_data->depth) {
const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
sh_data->depth = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg->lib,
datatoc_common_view_lib_glsl,
datatoc_depth_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_depth_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg->def, NULL},
});
sh_data->depth_conservative = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg->lib,
datatoc_common_view_lib_glsl,
datatoc_depth_vert_glsl,
NULL},
.geom = (const char *[]){sh_cfg->lib,
datatoc_common_view_lib_glsl,
datatoc_conservative_depth_geom_glsl,
NULL},
.frag = (const char *[]){datatoc_depth_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg->def, "#define CONSERVATIVE_RASTER\n", NULL},
});
}
}
static void basic_cache_init(void *vedata)
{
BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
DRWShadingGroup *grp;
const DRWContextState *draw_ctx = DRW_context_state_get();
BASIC_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
if (!stl->g_data) {
/* Alloc transient pointers */
stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
}
stl->g_data->use_material_slot_selection = DRW_state_is_material_select();
/* 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;
DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
GPUShader *sh = DRW_state_is_select() ? sh_data->depth_conservative : sh_data->depth;
DRW_PASS_CREATE(psl->depth_pass[i], state | clip_state | infront_state);
stl->g_data->depth_shgrp[i] = grp = DRW_shgroup_create(sh, psl->depth_pass[i]);
DRW_shgroup_uniform_vec2(grp, "sizeViewport", DRW_viewport_size_get(), 1);
DRW_shgroup_uniform_vec2(grp, "sizeViewportInv", DRW_viewport_invert_size_get(), 1);
stl->g_data->depth_hair_shgrp[i] = grp = DRW_shgroup_create(sh_data->depth,
psl->depth_pass[i]);
state |= DRW_STATE_CULL_BACK;
DRW_PASS_CREATE(psl->depth_pass_cull[i], state | clip_state | infront_state);
stl->g_data->depth_shgrp_cull[i] = grp = DRW_shgroup_create(sh, psl->depth_pass_cull[i]);
DRW_shgroup_uniform_vec2(grp, "sizeViewport", DRW_viewport_size_get(), 1);
DRW_shgroup_uniform_vec2(grp, "sizeViewportInv", DRW_viewport_invert_size_get(), 1);
}
}
/* TODO(fclem): DRW_cache_object_surface_material_get needs a refactor to allow passing NULL
* instead of gpumat_array. Avoiding all this boilerplate code. */
static struct GPUBatch **basic_object_surface_material_get(Object *ob)
{
const int materials_len = DRW_cache_object_material_count_get(ob);
struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
return DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
}
static void basic_cache_populate_particles(void *vedata, Object *ob)
{
const bool do_in_front = (ob->dtx & OB_DRAW_IN_FRONT) != 0;
BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) {
if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
continue;
}
ParticleSettings *part = psys->part;
const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
if (draw_as == PART_DRAW_PATH) {
struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL);
if (stl->g_data->use_material_slot_selection) {
const short material_slot = part->omat;
DRW_select_load_id(ob->runtime.select_id | (material_slot << 16));
}
DRW_shgroup_call(stl->g_data->depth_hair_shgrp[do_in_front], hairs, NULL);
}
}
}
static void basic_cache_populate(void *vedata, Object *ob)
{
BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
/* TODO(fclem): fix selection of smoke domains. */
if (!DRW_object_is_renderable(ob) || (ob->dt < OB_SOLID)) {
return;
}
const DRWContextState *draw_ctx = DRW_context_state_get();
if (ob != draw_ctx->object_edit) {
basic_cache_populate_particles(vedata, ob);
}
/* Make flat object selectable in ortho view if wireframe is enabled. */
const bool do_in_front = (ob->dtx & OB_DRAW_IN_FRONT) != 0;
if ((draw_ctx->v3d->overlay.flag & V3D_OVERLAY_WIREFRAMES) ||
(draw_ctx->v3d->shading.type == OB_WIRE) || (ob->dtx & OB_DRAWWIRE) || (ob->dt == OB_WIRE)) {
int flat_axis = 0;
bool is_flat_object_viewed_from_side = ((draw_ctx->rv3d->persp == RV3D_ORTHO) &&
DRW_object_is_flat(ob, &flat_axis) &&
DRW_object_axis_orthogonal_to_view(ob, flat_axis));
if (is_flat_object_viewed_from_side) {
/* Avoid losing flat objects when in ortho views (see T56549) */
struct GPUBatch *geom = DRW_cache_object_all_edges_get(ob);
if (geom) {
DRW_shgroup_call(stl->g_data->depth_shgrp[do_in_front], geom, ob);
}
return;
}
}
const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
!DRW_state_is_image_render();
const bool do_cull = (draw_ctx->v3d &&
(draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING));
DRWShadingGroup *shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull[do_in_front] :
stl->g_data->depth_shgrp[do_in_front];
if (use_sculpt_pbvh) {
DRW_shgroup_call_sculpt(shgrp, ob, false, false);
}
else {
if (stl->g_data->use_material_slot_selection && BKE_object_supports_material_slots(ob)) {
struct GPUBatch **geoms = basic_object_surface_material_get(ob);
if (geoms) {
const int materials_len = DRW_cache_object_material_count_get(ob);
for (int i = 0; i < materials_len; i++) {
if (geoms[i] == NULL) {
continue;
}
const short material_slot_select_id = i + 1;
DRW_select_load_id(ob->runtime.select_id | (material_slot_select_id << 16));
DRW_shgroup_call(shgrp, geoms[i], ob);
}
}
}
else {
struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
if (geom) {
DRW_shgroup_call(shgrp, geom, ob);
}
}
}
}
static void basic_cache_finish(void *vedata)
{
BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
UNUSED_VARS(stl);
}
static void basic_draw_scene(void *vedata)
{
BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
DRW_draw_pass(psl->depth_pass[0]);
DRW_draw_pass(psl->depth_pass_cull[0]);
DRW_draw_pass(psl->depth_pass[1]);
DRW_draw_pass(psl->depth_pass_cull[1]);
}
static void basic_engine_free(void)
{
for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) {
BASIC_Shaders *sh_data = &e_data.sh_data[i];
DRW_SHADER_FREE_SAFE(sh_data->depth);
DRW_SHADER_FREE_SAFE(sh_data->depth_conservative);
}
}
static const DrawEngineDataSize basic_data_size = DRW_VIEWPORT_DATA_SIZE(BASIC_Data);
DrawEngineType draw_engine_basic_type = {
NULL,
NULL,
N_("Basic"),
&basic_data_size,
&basic_engine_init,
&basic_engine_free,
&basic_cache_init,
&basic_cache_populate,
&basic_cache_finish,
&basic_draw_scene,
NULL,
NULL,
NULL,
NULL,
};
#undef BASIC_ENGINE