Blender V4.3
select_engine.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include "DNA_screen_types.h"
12
13#include "ED_view3d.hh"
14
15#include "UI_resources.hh"
16
17#include "DRW_engine.hh"
18#include "DRW_select_buffer.hh"
19
20#include "draw_cache_impl.hh"
21#include "draw_manager_c.hh"
22
23#include "select_engine.hh"
24#include "select_private.hh"
25
26#define SELECT_ENGINE "SELECT_ENGINE"
27
28/* *********** STATIC *********** */
29
37
39{
40 static SelectEngineData data = {};
41 return data;
42}
43
44/* -------------------------------------------------------------------- */
49{
52 int size[2];
53 size[0] = GPU_texture_width(dtxl->depth);
54 size[1] = GPU_texture_height(dtxl->depth);
55
56 if (e_data.framebuffer_select_id == nullptr) {
57 e_data.framebuffer_select_id = GPU_framebuffer_create("framebuffer_select_id");
58 }
59
60 if ((e_data.texture_u32 != nullptr) && ((GPU_texture_width(e_data.texture_u32) != size[0]) ||
61 (GPU_texture_height(e_data.texture_u32) != size[1])))
62 {
63 GPU_texture_free(e_data.texture_u32);
64 e_data.texture_u32 = nullptr;
65 }
66
67 /* Make sure the depth texture is attached.
68 * It may disappear when loading another Blender session. */
69 GPU_framebuffer_texture_attach(e_data.framebuffer_select_id, dtxl->depth, 0, 0);
70
71 if (e_data.texture_u32 == nullptr) {
73 e_data.texture_u32 = GPU_texture_create_2d(
74 "select_buf_ids", size[0], size[1], 1, GPU_R32UI, usage, nullptr);
75 GPU_framebuffer_texture_attach(e_data.framebuffer_select_id, e_data.texture_u32, 0, 0);
76
77 GPU_framebuffer_check_valid(e_data.framebuffer_select_id, nullptr);
78 }
79}
80
83/* -------------------------------------------------------------------- */
87static void select_engine_init(void *vedata)
88{
90 const DRWContextState *draw_ctx = DRW_context_state_get();
91 eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg;
92
93 SELECTID_StorageList *stl = ((SELECTID_Data *)vedata)->stl;
94 SELECTID_Shaders *sh_data = &e_data.sh_data[sh_cfg];
95
96 /* Prepass */
97 if (!sh_data->select_id_flat) {
99 sh_cfg == GPU_SHADER_CFG_CLIPPED ? "select_id_flat_clipped" : "select_id_flat");
100 }
101 if (!sh_data->select_id_uniform) {
102 sh_data->select_id_uniform = GPU_shader_create_from_info_name(
103 sh_cfg == GPU_SHADER_CFG_CLIPPED ? "select_id_uniform_clipped" : "select_id_uniform");
104 }
105
106 if (!stl->g_data) {
107 /* Alloc transient pointers */
108 stl->g_data = static_cast<SELECTID_PrivateData *>(MEM_mallocN(sizeof(*stl->g_data), __func__));
109 }
110
111 {
112 /* Create view with depth offset */
113 const DRWView *view_default = DRW_view_default_get();
114 stl->g_data->view_faces = (DRWView *)view_default;
115 stl->g_data->view_edges = DRW_view_create_with_zoffset(view_default, draw_ctx->rv3d, 1.0f);
116 stl->g_data->view_verts = DRW_view_create_with_zoffset(view_default, draw_ctx->rv3d, 1.1f);
117 }
118}
119
120static void select_cache_init(void *vedata)
121{
123 SELECTID_PassList *psl = ((SELECTID_Data *)vedata)->psl;
124 SELECTID_StorageList *stl = ((SELECTID_Data *)vedata)->stl;
125 SELECTID_PrivateData *pd = stl->g_data;
126
127 const DRWContextState *draw_ctx = DRW_context_state_get();
128 SELECTID_Shaders *sh = &e_data.sh_data[draw_ctx->sh_cfg];
129
130 if (e_data.context.select_mode == -1) {
131 e_data.context.select_mode = select_id_get_object_select_mode(draw_ctx->scene,
132 draw_ctx->obact);
133 BLI_assert(e_data.context.select_mode != 0);
134 }
135
137 if (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) {
139 }
140
141 bool retopology_occlusion = RETOPOLOGY_ENABLED(draw_ctx->v3d) && !XRAY_ENABLED(draw_ctx->v3d);
142 float retopology_offset = RETOPOLOGY_OFFSET(draw_ctx->v3d);
143
144 {
147 /* Not setting ID because this pass only draws to the depth buffer. */
148 DRW_shgroup_uniform_float_copy(pd->shgrp_depth_only, "retopologyOffset", retopology_offset);
149
150 if (retopology_occlusion) {
152 /* Not setting ID because this pass only draws to the depth buffer. */
153 DRW_shgroup_uniform_float_copy(pd->shgrp_occlude, "retopologyOffset", 0.0f);
154 }
155
157 if (e_data.context.select_mode & SCE_SELECT_FACE) {
159 DRW_shgroup_uniform_float_copy(pd->shgrp_face_flat, "retopologyOffset", retopology_offset);
160 }
161 else {
164 DRW_shgroup_uniform_float_copy(pd->shgrp_face_unif, "retopologyOffset", retopology_offset);
165 }
166
167 if (e_data.context.select_mode & SCE_SELECT_EDGE) {
169
171 DRW_shgroup_uniform_float_copy(pd->shgrp_edge, "retopologyOffset", retopology_offset);
172 }
173
174 if (e_data.context.select_mode & SCE_SELECT_VERTEX) {
178 DRW_shgroup_uniform_float_copy(pd->shgrp_vert, "retopologyOffset", retopology_offset);
179 }
180 }
181
182 /* Create selection data. */
183 for (uint sel_id : e_data.context.objects.index_range()) {
184 Object *obj_eval = e_data.context.objects[sel_id];
186 &obj_eval->id, &draw_engine_select_type, sizeof(SELECTID_ObjectData), nullptr, nullptr);
187 SELECTID_ObjectData *sel_data = reinterpret_cast<SELECTID_ObjectData *>(data);
188
189 data->recalc = 0;
190 sel_data->drawn_index = sel_id;
191 sel_data->in_pass = false;
192 sel_data->is_drawn = false;
193 }
194
195 copy_m4_m4(e_data.context.persmat, draw_ctx->rv3d->persmat);
196 e_data.context.index_drawn_len = 1;
198 GPU_framebuffer_bind(e_data.framebuffer_select_id);
199 GPU_framebuffer_clear_color_depth(e_data.framebuffer_select_id, blender::float4{0.0f}, 1.0f);
200}
201
202static void select_cache_populate(void *vedata, Object *ob)
203{
204 using namespace blender::draw;
206 SELECTID_StorageList *stl = ((SELECTID_Data *)vedata)->stl;
209
210 if (!sel_data || sel_data->is_drawn) {
211 if (sel_data) {
212 /* Remove data, object is not in array. */
213 DrawDataList *drawdata = DRW_drawdatalist_from_id(&ob->id);
214 BLI_freelinkN((ListBase *)drawdata, sel_data);
215 }
216
217 /* This object is not in the array. It is here to participate in the depth buffer. */
218 if (ob->dt >= OB_SOLID) {
219 blender::gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(
220 *static_cast<Mesh *>(ob->data));
221 DRW_shgroup_call_obmat(stl->g_data->shgrp_occlude, geom_faces, ob->object_to_world().ptr());
222 }
223 }
224 else if (!sel_data->in_pass) {
225 const DRWContextState *draw_ctx = DRW_context_state_get();
226 ObjectOffsets *ob_offsets = &e_data.context.index_offsets[sel_data->drawn_index];
227 uint offset = e_data.context.index_drawn_len;
229 draw_ctx->v3d,
230 ob,
231 e_data.context.select_mode,
232 offset,
233 &ob_offsets->vert,
234 &ob_offsets->edge,
235 &ob_offsets->face);
236
237 ob_offsets->offset = offset;
238 sel_data->in_pass = true;
239 e_data.context.index_drawn_len = ob_offsets->vert;
240 }
241}
242
243static void select_draw_scene(void *vedata)
244{
246 SELECTID_StorageList *stl = ((SELECTID_Data *)vedata)->stl;
247 SELECTID_PassList *psl = ((SELECTID_Data *)vedata)->psl;
248
250
256 }
257
258 /* Setup framebuffer */
259 GPU_framebuffer_bind(e_data.framebuffer_select_id);
260
262
263 if (e_data.context.select_mode & SCE_SELECT_EDGE) {
266 }
267
268 if (e_data.context.select_mode & SCE_SELECT_VERTEX) {
271 }
272
273 /* Mark objects from the array to later identify which ones are not in the array. */
274 for (Object *obj_eval : e_data.context.objects) {
276 &obj_eval->id, &draw_engine_select_type, sizeof(SELECTID_ObjectData), nullptr, nullptr);
277 SELECTID_ObjectData *sel_data = reinterpret_cast<SELECTID_ObjectData *>(data);
278 sel_data->is_drawn = true;
279 }
280}
281
283{
285 for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
286 SELECTID_Shaders *sh_data = &e_data.sh_data[sh_data_index];
287 DRW_SHADER_FREE_SAFE(sh_data->select_id_flat);
288 DRW_SHADER_FREE_SAFE(sh_data->select_id_uniform);
289 }
290
291 DRW_TEXTURE_FREE_SAFE(e_data.texture_u32);
292 GPU_FRAMEBUFFER_FREE_SAFE(e_data.framebuffer_select_id);
293}
294
297/* -------------------------------------------------------------------- */
302
304 /*next*/ nullptr,
305 /*prev*/ nullptr,
306 /*idname*/ N_("Select ID"),
307 /*vedata_size*/ &select_data_size,
308 /*engine_init*/ &select_engine_init,
309 /*engine_free*/ &select_engine_free,
310 /*instance_free*/ nullptr,
311 /*cache_init*/ &select_cache_init,
312 /*cache_populate*/ &select_cache_populate,
313 /*cache_finish*/ nullptr,
314 /*draw_scene*/ &select_draw_scene,
315 /*view_update*/ nullptr,
316 /*id_update*/ nullptr,
317 /*render_to_image*/ nullptr,
318 /*store_metadata*/ nullptr,
319};
320
321/* NOTE: currently unused, we may want to register so we can see this when debugging the view. */
322
324 /*next*/ nullptr,
325 /*prev*/ nullptr,
326 /*idname*/ SELECT_ENGINE,
327 /*name*/ N_("Select ID"),
329 /*update*/ nullptr,
330 /*render*/ nullptr,
331 /*render_frame_finish*/ nullptr,
332 /*draw*/ nullptr,
333 /*bake*/ nullptr,
334 /*view_update*/ nullptr,
335 /*view_draw*/ nullptr,
336 /*update_script_node*/ nullptr,
337 /*update_render_passes*/ nullptr,
338 /*draw_engine*/ &draw_engine_select_type,
339 /*rna_ext*/
340 {
341 /*data*/ nullptr,
342 /*srna*/ nullptr,
343 /*call*/ nullptr,
344 },
345};
346
349/* -------------------------------------------------------------------- */
358
360{
362 return e_data.framebuffer_select_id;
363}
364
366{
368 return e_data.texture_u32;
369}
370
373#undef SELECT_ENGINE
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
void copy_m4_m4(float m1[4][4], const float m2[4][4])
unsigned int uint
#define ARRAY_SIZE(arr)
@ OB_SOLID
@ SCE_SELECT_FACE
@ SCE_SELECT_VERTEX
@ SCE_SELECT_EDGE
#define RV3D_CLIPPING_ENABLED(v3d, rv3d)
DrawDataList * DRW_drawdatalist_from_id(ID *id)
#define DRW_SHADER_FREE_SAFE(shader)
#define DRW_PASS_CREATE(pass, state)
#define DRW_shgroup_call_obmat(shgroup, geom, obmat)
#define DRW_VIEWPORT_DATA_SIZE(ty)
#define DRW_TEXTURE_FREE_SAFE(tex)
#define XRAY_ENABLED(v3d)
#define RETOPOLOGY_ENABLED(v3d)
#define RETOPOLOGY_OFFSET(v3d)
bool GPU_framebuffer_check_valid(GPUFrameBuffer *framebuffer, char err_out[256])
GPUFrameBuffer * GPU_framebuffer_create(const char *name)
#define GPU_FRAMEBUFFER_FREE_SAFE(fb)
void GPU_framebuffer_clear_color_depth(GPUFrameBuffer *fb, const float clear_col[4], float clear_depth)
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
void GPU_framebuffer_clear_depth(GPUFrameBuffer *fb, float clear_depth)
void GPU_framebuffer_texture_attach(GPUFrameBuffer *framebuffer, GPUTexture *texture, int slot, int mip)
GPUShader * GPU_shader_create_from_info_name(const char *info_name)
@ GPU_SHADER_CFG_CLIPPED
#define GPU_SHADER_CFG_LEN
int GPU_texture_height(const GPUTexture *texture)
GPUTexture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(GPUTexture *texture)
int GPU_texture_width(const GPUTexture *texture)
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_ATTACHMENT
@ RE_INTERNAL
Definition RE_engine.h:47
@ RE_USE_STEREO_VIEWPORT
Definition RE_engine.h:53
@ RE_USE_GPU_CONTEXT
Definition RE_engine.h:54
static struct @193 e_data
BASIC_Shaders sh_data[GPU_SHADER_CFG_LEN]
DRWView * DRW_view_create_with_zoffset(const DRWView *parent_view, const RegionView3D *rv3d, float offset)
DRW_Global G_draw
DrawData * DRW_drawdata_get(ID *id, DrawEngineType *engine_type)
DefaultFramebufferList * DRW_viewport_framebuffer_list_get()
DrawData * DRW_drawdata_ensure(ID *id, DrawEngineType *engine_type, size_t size, DrawDataInitCb init_cb, DrawDataFreeCb free_cb)
DefaultTextureList * DRW_viewport_texture_list_get()
const DRWContextState * DRW_context_state_get()
const DRWView * DRW_view_default_get()
DRWShadingGroup * DRW_shgroup_create(GPUShader *shader, DRWPass *pass)
void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value)
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value)
bool DRW_pass_is_empty(DRWPass *pass)
void DRW_draw_pass(DRWPass *pass)
void DRW_view_set_active(const DRWView *view)
DRWState
Definition draw_state.hh:25
@ DRW_STATE_CLIP_PLANES
Definition draw_state.hh:69
@ DRW_STATE_FIRST_VERTEX_CONVENTION
Definition draw_state.hh:70
#define DRW_STATE_DEFAULT
Definition draw_state.hh:77
SHADOW_TILEMAP_RES tiles_buf[] statistics_buf render_view_buf[SHADOW_VIEW_MAX] GPU_R32UI
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
static ulong state[N]
short select_id_get_object_select_mode(Scene *scene, Object *ob)
void select_id_draw_object(void *vedata, View3D *v3d, Object *ob, short select_mode, uint initial_offset, uint *r_vert_offset, uint *r_edge_offset, uint *r_face_offset)
DrawEngineType draw_engine_select_type
static void select_engine_free()
static void select_cache_populate(void *vedata, Object *ob)
SELECTID_Context * DRW_select_engine_context_get()
static void select_cache_init(void *vedata)
GPUFrameBuffer * DRW_engine_select_framebuffer_get()
RenderEngineType DRW_engine_viewport_select_type
static const DrawEngineDataSize select_data_size
static void select_draw_scene(void *vedata)
static void select_engine_init(void *vedata)
static SelectEngineData & get_engine_data()
#define SELECT_ENGINE
static void select_engine_framebuffer_setup()
GPUTexture * DRW_engine_select_texture_get()
eGPUShaderConfig sh_cfg
RegionView3D * rv3d
GlobalsUboStorage block
GPUFrameBuffer * depth_only_fb
float persmat[4][4]
DRWPass * select_id_vert_pass
DRWPass * depth_only_pass
DRWPass * select_id_edge_pass
DRWPass * select_id_face_pass
DRWShadingGroup * shgrp_face_unif
DRWShadingGroup * shgrp_edge
DRWShadingGroup * shgrp_depth_only
DRWShadingGroup * shgrp_face_flat
DRWShadingGroup * shgrp_occlude
DRWShadingGroup * shgrp_vert
GPUShader * select_id_uniform
GPUShader * select_id_flat
struct SELECTID_PrivateData * g_data
GPUFrameBuffer * framebuffer_select_id
SELECTID_Context context
SELECTID_Shaders sh_data[GPU_SHADER_CFG_LEN]
GPUTexture * texture_u32
#define N_(msgid)