Blender V5.0
overlay_mesh.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#pragma once
10
11#include <string>
12
13#include "BKE_customdata.hh"
14#include "BKE_editmesh.hh"
15#include "BKE_mask.h"
16#include "BKE_mesh_types.hh"
17#include "BKE_paint.hh"
19
21
22#include "DNA_brush_types.h"
23#include "DNA_mask_types.h"
24#include "DNA_mesh_types.h"
25#include "DNA_userdef_types.h"
26
27#include "ED_view3d.hh"
28
29#include "GPU_capabilities.hh"
30
31#include "draw_cache.hh"
32#include "draw_cache_impl.hh"
33#include "draw_manager_text.hh"
34#include "overlay_base.hh"
35
36namespace blender::draw::overlay {
37
41
45class Meshes : Overlay {
46 private:
47 PassSimple edit_mesh_normals_ps_ = {"Normals"};
48 PassSimple::Sub *face_normals_ = nullptr;
49 PassSimple::Sub *face_normals_subdiv_ = nullptr;
50 PassSimple::Sub *loop_normals_ = nullptr;
51 PassSimple::Sub *loop_normals_subdiv_ = nullptr;
52 PassSimple::Sub *vert_normals_ = nullptr;
53 PassSimple::Sub *vert_normals_subdiv_ = nullptr;
54
55 PassSimple edit_mesh_analysis_ps_ = {"Mesh Analysis"};
56 PassSimple edit_mesh_weight_ps_ = {"Edit Weight"};
57
58 PassSimple edit_mesh_edges_ps_ = {"Edges"};
59 PassSimple edit_mesh_faces_ps_ = {"Faces"};
60 PassSimple edit_mesh_cages_ps_ = {"Cages"}; /* Same as faces but with a different offset. */
61 PassSimple edit_mesh_verts_ps_ = {"Verts"};
62 PassSimple edit_mesh_facedots_ps_ = {"FaceDots"};
63 PassSimple edit_mesh_skin_roots_ps_ = {"SkinRoots"};
64
65 /* Depth pre-pass to cull edit cage in case the object is not opaque. */
66 PassSimple edit_mesh_prepass_ps_ = {"Prepass"};
67
68 bool xray_enabled_ = false;
69 bool xray_flag_enabled_ = false;
70
71 bool show_retopology_ = false;
72 bool show_mesh_analysis_ = false;
73 bool show_face_overlay_ = false;
74 bool show_weight_ = false;
75
76 bool select_vert_ = false;
77 bool select_edge_ = false;
78 bool select_face_ = false;
79 bool select_face_dots_ = false;
80
85 static constexpr float cage_ndc_offset_ = 0.5f;
86 static constexpr float edge_ndc_offset_ = 1.0f;
87 static constexpr float vert_ndc_offset_ = 1.5f;
88
89 /* TODO(fclem): This is quite wasteful and expensive, prefer in shader Z modification like the
90 * retopology offset. */
91 View view_edit_cage_ = {"view_edit_cage"};
92 View::OffsetData offset_data_;
93
94 public:
95 void begin_sync(Resources &res, const State &state) final
96 {
97 enabled_ = state.is_space_v3d();
98
99 if (!enabled_) {
100 return;
101 }
102
103 offset_data_ = state.offset_data_get();
104 xray_enabled_ = state.xray_enabled;
105 xray_flag_enabled_ = state.xray_flag_enabled;
106
107 const int edit_flag = state.v3d->overlay.edit_flag;
108
109 const ToolSettings *tsettings = state.scene->toolsettings;
110 select_vert_ = (tsettings->selectmode & SCE_SELECT_VERTEX);
111 select_edge_ = (tsettings->selectmode & SCE_SELECT_EDGE);
112 select_face_ = (tsettings->selectmode & SCE_SELECT_FACE);
113 select_face_dots_ = ((edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) || state.xray_flag_enabled) &
114 select_face_;
115
116 show_retopology_ = (edit_flag & V3D_OVERLAY_EDIT_RETOPOLOGY) && !state.xray_enabled;
117 show_mesh_analysis_ = (edit_flag & V3D_OVERLAY_EDIT_STATVIS);
118 show_face_overlay_ = (edit_flag & V3D_OVERLAY_EDIT_FACES);
119 show_weight_ = (edit_flag & V3D_OVERLAY_EDIT_WEIGHT);
120
121 const bool show_face_nor = (edit_flag & V3D_OVERLAY_EDIT_FACE_NORMALS);
122 const bool show_loop_nor = (edit_flag & V3D_OVERLAY_EDIT_LOOP_NORMALS);
123 const bool show_vert_nor = (edit_flag & V3D_OVERLAY_EDIT_VERT_NORMALS);
124
125 const bool do_smooth_wire = (U.gpu_flag & USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE) == 0;
126 const bool is_wire_shading_mode = (state.v3d->shading.type == OB_WIRE);
127
128 uint4 data_mask = data_mask_get(edit_flag);
129
130 float backwire_opacity = (state.xray_flag_enabled) ? 0.5f : 1.0f;
131 float face_alpha = (show_face_overlay_) ? 1.0f : 0.0f;
132 float retopology_offset = state.is_depth_only_drawing ? 0.0f : RETOPOLOGY_OFFSET(state.v3d);
133 /* Cull back-faces for retopology face pass. This makes it so back-faces are not drawn.
134 * Doing so lets us distinguish back-faces from front-faces. */
135 DRWState face_culling = (show_retopology_) ? DRW_STATE_CULL_BACK : DRWState(0);
136
137 gpu::Texture **depth_tex = (state.xray_flag_enabled) ? &res.depth_tx : &res.dummy_depth_tx;
138
139 {
140 auto &pass = edit_mesh_prepass_ps_;
141 pass.init();
142 pass.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | face_culling,
143 state.clipping_plane_count);
144 pass.shader_set(res.shaders->mesh_edit_depth.get());
145 pass.push_constant("retopology_offset", retopology_offset);
146 pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
147 pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
148 }
149 {
150 /* Normals */
151 const bool use_screen_size = (edit_flag & V3D_OVERLAY_EDIT_CONSTANT_SCREEN_SIZE_NORMALS);
152 const bool use_hq_normals = (state.scene->r.perf_flag & SCE_PERF_HQ_NORMALS) ||
154
157 if (state.xray_flag_enabled) {
158 pass_state |= DRW_STATE_BLEND_ALPHA;
159 }
160
161 auto &pass = edit_mesh_normals_ps_;
162 pass.init();
163 pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
164 pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
165 pass.state_set(pass_state, state.clipping_plane_count);
166
167 auto shader_pass = [&](gpu::Shader *shader, const char *name) {
168 auto &sub = pass.sub(name);
169 sub.shader_set(shader);
170 sub.bind_texture("depth_tx", depth_tex);
171 sub.push_constant("alpha", backwire_opacity);
172 sub.push_constant("is_constant_screen_size_normals", use_screen_size);
173 sub.push_constant("normal_size", state.overlay.normals_length);
174 sub.push_constant("normal_screen_size", state.overlay.normals_constant_screen_size);
175 sub.push_constant("retopology_offset", retopology_offset);
176 sub.push_constant("hq_normals", use_hq_normals);
177 return &sub;
178 };
179
180 face_normals_ = loop_normals_ = vert_normals_ = nullptr;
181
182 if (show_face_nor) {
183 face_normals_subdiv_ = shader_pass(res.shaders->mesh_face_normal_subdiv.get(), "SubdFNor");
184 face_normals_ = shader_pass(res.shaders->mesh_face_normal.get(), "FaceNor");
185 }
186 if (show_loop_nor) {
187 loop_normals_subdiv_ = shader_pass(res.shaders->mesh_loop_normal_subdiv.get(), "SubdLNor");
188 loop_normals_ = shader_pass(res.shaders->mesh_loop_normal.get(), "LoopNor");
189 }
190 if (show_vert_nor) {
191 vert_normals_subdiv_ = shader_pass(res.shaders->mesh_vert_normal_subdiv.get(), "SubdVNor");
192 vert_normals_ = shader_pass(res.shaders->mesh_vert_normal.get(), "VertexNor");
193 }
194 }
195 {
196 /* Support masked transparency in Workbench.
197 * EEVEE can't be supported since depth won't match. */
198 const bool shadeless = eDrawType(state.v3d->shading.type) == OB_WIRE;
199
200 auto &pass = edit_mesh_weight_ps_;
201 pass.init();
203 state.clipping_plane_count);
204 pass.shader_set(shadeless ? res.shaders->paint_weight.get() :
205 res.shaders->paint_weight_fake_shading.get());
206 pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
207 pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
208 pass.bind_texture("colorramp", &res.weight_ramp_tx);
209 pass.push_constant("draw_contours", false);
210 pass.push_constant("opacity", state.overlay.weight_paint_mode_opacity);
211 if (!shadeless) {
212 /* Arbitrary light to give a hint of the geometry behind the weights. */
213 pass.push_constant("light_dir", math::normalize(float3(0.0f, 0.5f, 0.86602f)));
214 }
215 }
216 {
217 auto &pass = edit_mesh_analysis_ps_;
218 pass.init();
220 state.clipping_plane_count);
221 pass.shader_set(res.shaders->mesh_analysis.get());
222 pass.bind_texture("weight_tx", res.weight_ramp_tx);
223 }
224
225 auto mesh_edit_common_resource_bind = [&](PassSimple &pass, float alpha, float ndc_offset) {
226 pass.bind_texture("depth_tx", depth_tex);
227 /* TODO(fclem): UBO. */
228 pass.push_constant("wire_shading", is_wire_shading_mode);
229 pass.push_constant("select_face", select_face_);
230 pass.push_constant("select_edge", select_edge_);
231 pass.push_constant("alpha", alpha);
232 pass.push_constant("retopology_offset", retopology_offset);
233 pass.push_constant("ndc_offset_factor", &state.ndc_offset_factor);
234 pass.push_constant("ndc_offset", ndc_offset);
235 pass.push_constant("data_mask", int4(data_mask));
236 pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
237 pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
238 };
239
240 {
241 auto &pass = edit_mesh_edges_ps_;
242 pass.init();
243 /* Change first vertex convention to match blender loop structure. */
246 state.clipping_plane_count);
247 pass.shader_set(res.shaders->mesh_edit_edge.get());
248 pass.push_constant("do_smooth_wire", do_smooth_wire);
249 pass.push_constant("use_vertex_selection", select_vert_);
250 mesh_edit_common_resource_bind(pass, backwire_opacity, edge_ndc_offset_);
251 }
252 {
253 auto &pass = edit_mesh_faces_ps_;
254 pass.init();
256 face_culling,
257 state.clipping_plane_count);
258 pass.shader_set(res.shaders->mesh_edit_face.get());
259 mesh_edit_common_resource_bind(pass, face_alpha, 0.0f);
260 }
261 {
262 auto &pass = edit_mesh_cages_ps_;
263 pass.init();
265 state.clipping_plane_count);
266 pass.shader_set(res.shaders->mesh_edit_face.get());
267 mesh_edit_common_resource_bind(pass, face_alpha, cage_ndc_offset_);
268 }
269 {
270 auto &pass = edit_mesh_verts_ps_;
271 pass.init();
274 state.clipping_plane_count);
275 pass.shader_set(res.shaders->mesh_edit_vert.get());
276 mesh_edit_common_resource_bind(pass, backwire_opacity, vert_ndc_offset_);
277 }
278 {
279 auto &pass = edit_mesh_facedots_ps_;
280 pass.init();
283 state.clipping_plane_count);
284 pass.shader_set(res.shaders->mesh_edit_facedot.get());
285 mesh_edit_common_resource_bind(pass, backwire_opacity, vert_ndc_offset_);
286 }
287 {
288 auto &pass = edit_mesh_skin_roots_ps_;
289 pass.init();
292 state.clipping_plane_count);
293 pass.shader_set(res.shaders->mesh_edit_skin_root.get());
294 pass.push_constant("retopology_offset", retopology_offset);
295 pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
296 pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
297 }
298 }
299
301 const ObjectRef &ob_ref,
302 Resources & /*res*/,
303 const State &state) final
304 {
305 if (!enabled_) {
306 return;
307 }
308
309 ResourceHandleRange res_handle = manager.unique_handle(ob_ref);
310
311 Object *ob = ob_ref.object;
313 /* WORKAROUND: GPU subdiv uses a different normal format. Remove this once GPU subdiv is
314 * refactored. */
315 const bool use_gpu_subdiv = BKE_subsurf_modifier_has_gpu_subdiv(&mesh);
316 const bool draw_as_solid = (ob->dt > OB_WIRE) && !state.xray_enabled;
317 const bool has_edit_cage = mesh_has_edit_cage(ob);
318
319 if (show_retopology_) {
320 gpu::Batch *geom = DRW_mesh_batch_cache_get_edit_triangles(mesh);
321 edit_mesh_prepass_ps_.draw(geom, res_handle);
322 }
323 if (draw_as_solid && !state.is_render_depth_available) {
324 gpu::Batch *geom = DRW_cache_mesh_surface_get(ob);
325 edit_mesh_prepass_ps_.draw(geom, res_handle);
326 }
327
328 if (show_mesh_analysis_) {
329 gpu::Batch *geom = DRW_cache_mesh_surface_mesh_analysis_get(ob);
330 edit_mesh_analysis_ps_.draw(geom, res_handle);
331 }
332
333 if (show_weight_) {
334 gpu::Batch *geom = DRW_cache_mesh_surface_weights_get(ob);
335 edit_mesh_weight_ps_.draw(geom, res_handle);
336 }
337
338 if (face_normals_) {
339 gpu::Batch *geom = DRW_mesh_batch_cache_get_edit_facedots(mesh);
340 (use_gpu_subdiv && !has_edit_cage ? face_normals_subdiv_ : face_normals_)
341 ->draw_expand(geom, GPU_PRIM_LINES, 1, 1, res_handle);
342 }
343 if (loop_normals_) {
344 gpu::Batch *geom = DRW_mesh_batch_cache_get_edit_loop_normals(mesh);
345 (use_gpu_subdiv && !has_edit_cage ? loop_normals_subdiv_ : loop_normals_)
346 ->draw_expand(geom, GPU_PRIM_LINES, 1, 1, res_handle);
347 }
348 if (vert_normals_) {
349 gpu::Batch *geom = DRW_mesh_batch_cache_get_edit_vert_normals(mesh);
350 ((use_gpu_subdiv && !has_edit_cage) ? vert_normals_subdiv_ : vert_normals_)
351 ->draw_expand(geom, GPU_PRIM_LINES, 1, 1, res_handle);
352 }
353
354 {
355 gpu::Batch *geom = DRW_mesh_batch_cache_get_edit_edges(mesh);
356 edit_mesh_edges_ps_.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, res_handle);
357 }
358 {
359 gpu::Batch *geom = DRW_mesh_batch_cache_get_edit_triangles(mesh);
360 (has_edit_cage ? &edit_mesh_cages_ps_ : &edit_mesh_faces_ps_)->draw(geom, res_handle);
361 }
362 if (select_vert_) {
363 gpu::Batch *geom = DRW_mesh_batch_cache_get_edit_vertices(mesh);
364 edit_mesh_verts_ps_.draw(geom, res_handle);
365 }
366 if (select_face_dots_) {
367 gpu::Batch *geom = DRW_mesh_batch_cache_get_edit_facedots(mesh);
368 edit_mesh_facedots_ps_.draw(geom, res_handle);
369 }
370
371 if (mesh_has_skin_roots(ob)) {
372 gpu::Batch *geom = DRW_mesh_batch_cache_get_edit_skin_roots(mesh);
373 edit_mesh_skin_roots_ps_.draw_expand(geom, GPU_PRIM_LINES, 32, 1, res_handle);
374 }
375 if (state.show_text && (state.overlay.edit_flag & overlay_edit_text)) {
376 DRW_text_edit_mesh_measure_stats(state.region, state.v3d, ob, state.scene->unit, state.dt);
377 }
378 }
379
380 void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
381 {
382 if (!enabled_) {
383 return;
384 }
385
386 GPU_debug_group_begin("Mesh Edit");
387
388 GPU_framebuffer_bind(framebuffer);
389 manager.submit(edit_mesh_prepass_ps_, view);
390 manager.submit(edit_mesh_analysis_ps_, view);
391 manager.submit(edit_mesh_weight_ps_, view);
392
393 if (!xray_enabled_) {
394 /* Still use depth-testing for selected faces when X-Ray flag is enabled but transparency is
395 * off (X-Ray Opacity == 1.0 or in Preview/Render mode) (See #135325). */
396 manager.submit(edit_mesh_faces_ps_, view);
397 manager.submit(edit_mesh_cages_ps_, view);
398 }
399
400 if (xray_flag_enabled_) {
402 return;
403 }
404
405 manager.submit(edit_mesh_normals_ps_, view);
406 manager.submit(edit_mesh_edges_ps_, view);
407 manager.submit(edit_mesh_verts_ps_, view);
408 manager.submit(edit_mesh_skin_roots_ps_, view);
409 manager.submit(edit_mesh_facedots_ps_, view);
410
412 }
413
414 void draw_color_only(Framebuffer &framebuffer, Manager &manager, View &view) final
415 {
416 if (!enabled_) {
417 return;
418 }
419
420 if (xray_enabled_) {
421 /* Still use depth-testing for selected faces when X-Ray flag is enabled but transparency is
422 * off (X-Ray Opacity == 1.0 or in Preview/Render mode) (See #135325). */
423 GPU_framebuffer_bind(framebuffer);
424 manager.submit(edit_mesh_faces_ps_, view);
425 manager.submit(edit_mesh_cages_ps_, view);
426 }
427
428 if (!xray_flag_enabled_) {
429 return;
430 }
431
432 GPU_debug_group_begin("Mesh Edit Color Only");
433
434 GPU_framebuffer_bind(framebuffer);
435 manager.submit(edit_mesh_normals_ps_, view);
436 manager.submit(edit_mesh_edges_ps_, view);
437 manager.submit(edit_mesh_verts_ps_, view);
438 manager.submit(edit_mesh_skin_roots_ps_, view);
439 manager.submit(edit_mesh_facedots_ps_, view);
440
442 }
443
444 static bool mesh_has_edit_cage(const Object *ob)
445 {
446 BLI_assert(ob->type == OB_MESH);
448 if (mesh.runtime->edit_mesh != nullptr) {
449 const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
450 const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
451
452 return (editmesh_eval_cage != nullptr) && (editmesh_eval_cage != editmesh_eval_final);
453 }
454 return false;
455 }
456
457 private:
458 uint4 data_mask_get(const int flag)
459 {
460 uint4 mask = {0xFF, 0xFF, 0x00, 0x00};
468 return mask;
469 }
470
471 static bool mesh_has_skin_roots(const Object *ob)
472 {
474 if (BMEditMesh *em = mesh.runtime->edit_mesh.get()) {
475 return CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN) != -1;
476 }
477 return false;
478 }
479};
480
485 private:
486 PassSimple analysis_ps_ = {"Mesh Analysis"};
487
488 /* TODO(fclem): Should be its own Overlay?. */
489 PassSimple wireframe_ps_ = {"Wireframe"};
490
491 PassSimple edges_ps_ = {"Edges"};
492 PassSimple faces_ps_ = {"Faces"};
493 PassSimple verts_ps_ = {"Verts"};
494 PassSimple facedots_ps_ = {"FaceDots"};
495
496 /* TODO(fclem): Should be its own Overlay?. */
497 PassSimple image_border_ps_ = {"ImageBorder"};
498
499 /* TODO(fclem): Should be its own Overlay?. */
500 PassSimple brush_stencil_ps_ = {"BrushStencil"};
501
502 /* TODO(fclem): Should be its own Overlay?. */
503 PassSimple paint_mask_ps_ = {"PaintMask"};
504
505 bool select_vert_ = false;
506 bool select_edge_ = false;
507 bool select_face_ = false;
508 bool select_face_dots_ = false;
509
510 bool show_face_overlay_ = false;
511
512 bool show_uv_edit_ = false;
513
515 /* Draw final evaluated UVs (modifier stack applied) as grayed out wire-frame. */
516 /* TODO(fclem): Maybe should be its own Overlay?. */
517 bool show_wireframe_ = false;
518
520 /* TODO(fclem): Maybe should be its own Overlay?. */
521 bool show_stencil_ = false;
522
524 /* TODO(fclem): Maybe should be its own Overlay?. */
525 bool show_mask_ = false;
527 Mask *mask_id_ = nullptr;
528 Texture mask_texture_ = {"mask_texture_"};
529
531 bool show_mesh_analysis_ = false;
532 eSpaceImage_UVDT_Stretch mesh_analysis_type_;
538 Vector<float *> per_mesh_area_3d_;
539 Vector<float *> per_mesh_area_2d_;
540 float total_area_ratio_;
541
543 bool show_tiled_image_active_ = false;
544 bool show_tiled_image_border_ = false;
545 bool show_tiled_image_label_ = false;
546
547 public:
548 void begin_sync(Resources &res, const State &state) final
549 {
550 enabled_ = state.is_space_image();
551
552 if (!enabled_) {
553 return;
554 }
555
556 const ToolSettings *tool_setting = state.scene->toolsettings;
557 const SpaceImage *space_image = reinterpret_cast<const SpaceImage *>(state.space_data);
558 ::Image *image = space_image->image;
559 const bool space_mode_is_paint = space_image->mode == SI_MODE_PAINT;
560 const bool space_mode_is_mask = space_image->mode == SI_MODE_MASK;
561 const bool space_mode_is_uv = space_image->mode == SI_MODE_UV;
562
563 const bool object_mode_is_edit = state.object_mode & OB_MODE_EDIT;
564
565 const bool is_viewer = image && ELEM(image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE);
566 const bool is_tiled_image = image && (image->source == IMA_SRC_TILED);
567
568 /* The mask overlay is always drawn when enabled, even on top of viewers. */
569 {
570 /* Mask Overlay. */
571 show_mask_ = space_mode_is_mask && space_image->mask_info.mask &&
573 if (show_mask_) {
574 mask_mode_ = eMaskOverlayMode(space_image->mask_info.overlay_mode);
575 mask_id_ = DEG_get_evaluated(state.depsgraph, space_image->mask_info.mask);
576 }
577 else {
578 mask_id_ = nullptr;
579 }
580 }
581
582 /* Only disable UV drawing on top of render results.
583 * Otherwise, show UVs even in the absence of active image. */
584 enabled_ = !is_viewer || show_mask_;
585
586 if (!enabled_) {
587 return;
588 }
589
590 {
591 /* Edit UV Overlay. */
592 show_uv_edit_ = space_mode_is_uv && object_mode_is_edit;
593 show_mesh_analysis_ = show_uv_edit_ && (space_image->flag & SI_DRAW_STRETCH);
594
595 if (!show_uv_edit_) {
596 select_vert_ = false;
597 select_edge_ = false;
598 select_face_ = false;
599 select_face_dots_ = false;
600
601 show_face_overlay_ = false;
602 }
603 else {
604 const bool hide_faces = space_image->flag & SI_NO_DRAWFACES;
605 select_face_ = !show_mesh_analysis_ && !hide_faces;
606
607 /* FIXME: Always showing verts in edge mode when `uv_select_sync_valid`.
608 * needs investigation. */
609 if (tool_setting->uv_flag & UV_FLAG_SELECT_SYNC) {
610 const char sel_mode_3d = tool_setting->selectmode;
611 if (tool_setting->uv_sticky == UV_STICKY_VERT) {
612 /* NOTE: Ignore #SCE_SELECT_VERTEX because a single selected edge
613 * on the mesh may cause single UV vertices to be selected. */
614 select_vert_ = true;
615 }
616 else {
617 select_vert_ = (sel_mode_3d & SCE_SELECT_VERTEX);
618 }
619 /* When */
620 select_edge_ = (sel_mode_3d & SCE_SELECT_VERTEX) == 0;
621 select_face_dots_ = (sel_mode_3d & SCE_SELECT_FACE) && !hide_faces;
622 }
623 else {
624 const char sel_mode_2d = tool_setting->uv_selectmode;
625 select_vert_ = (sel_mode_2d != UV_SELECT_EDGE);
626 select_edge_ = (sel_mode_2d == UV_SELECT_EDGE);
627 select_face_dots_ = (sel_mode_2d & UV_SELECT_FACE) && !hide_faces;
628 }
629 }
630
631 if (show_mesh_analysis_) {
632 mesh_analysis_type_ = eSpaceImage_UVDT_Stretch(space_image->dt_uvstretch);
633 }
634 }
635 {
636 /* Wireframe UV Overlay. */
637 const bool show_wireframe_uv_edit = space_image->flag & SI_DRAWSHADOW;
638 const bool show_wireframe_uv_guide = !(space_image->flag & SI_NO_DRAW_UV_GUIDE) &&
639 (space_mode_is_paint || space_mode_is_uv);
640
641 if (space_mode_is_uv && object_mode_is_edit) {
642 show_wireframe_ = show_wireframe_uv_edit;
643 show_face_overlay_ = !(space_image->flag & SI_NO_DRAWFACES);
644 }
645 else {
646 show_wireframe_ = show_wireframe_uv_guide;
647 /* The face overlay is always enabled when showing wire-frame. */
648 show_face_overlay_ = show_wireframe_;
649 }
650 }
651
652 {
653 /* Brush Stencil Overlay. */
654 const ImagePaintSettings &image_paint_settings = tool_setting->imapaint;
655 const Brush *brush = BKE_paint_brush_for_read(&image_paint_settings.paint);
656 show_stencil_ = space_mode_is_paint && brush &&
658 image_paint_settings.clone;
659 }
660 {
661 /* UDIM Overlay. */
662 /* TODO: Always enable this overlay even if overlays are disabled. */
663 show_tiled_image_border_ = is_tiled_image;
664 show_tiled_image_active_ = is_tiled_image; /* TODO: Only disable this if overlays are off. */
665 show_tiled_image_label_ = is_tiled_image; /* TODO: Only disable this if overlays are off. */
666 }
667
668 const bool do_smooth_wire = (U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) != 0;
669 const float dash_length = 4.0f * UI_SCALE_FAC;
670
671 if (show_wireframe_) {
672 auto &pass = wireframe_ps_;
673 pass.init();
676 pass.shader_set(res.shaders->uv_wireframe.get());
677 pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
678 pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
679 pass.push_constant("alpha", space_image->uv_opacity);
680 pass.push_constant("do_smooth_wire", do_smooth_wire);
681 }
682
683 if (show_uv_edit_) {
684 auto &pass = edges_ps_;
685 pass.init();
688
689 gpu::Shader *sh = res.shaders->uv_edit_edge.get();
690 pass.specialize_constant(sh, "use_edge_select", select_edge_);
691 pass.shader_set(sh);
692 pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
693 pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
694 pass.push_constant("line_style", int(edit_uv_line_style_from_space_image(space_image)));
695
696 /* The `uv_opacity` setting does not apply to vertices & face-dots.
697 * This means it may be useful show vertices/faces while hiding the wire-frame.
698 * An exception to this is when only UV edges are displayed (UV edge mode).
699 * In this case, hiding the wire-frame has the effect of hiding UV's entirely.
700 * Set the alpha to 1.0 in this case.
701 * To hide all UV's, overlays can be disabled entirely. */
702 const float alpha = (select_vert_ || select_face_dots_) ? space_image->uv_opacity : 1.0f;
703 pass.push_constant("alpha", alpha);
704 pass.push_constant("dash_length", dash_length);
705 pass.push_constant("do_smooth_wire", do_smooth_wire);
706 }
707
708 if (select_vert_) {
709 const float dot_size = UI_GetThemeValuef(TH_VERTEX_SIZE) * UI_SCALE_FAC;
710 float4 theme_color;
711 UI_GetThemeColor4fv(TH_VERTEX, theme_color);
712 srgb_to_linearrgb_v4(theme_color, theme_color);
713
714 auto &pass = verts_ps_;
715 pass.init();
718 pass.shader_set(res.shaders->uv_edit_vert.get());
719 pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
720 pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
721 pass.push_constant("dot_size", (dot_size + 1.5f) * float(M_SQRT2));
722 pass.push_constant("outline_width", 0.75f);
723 pass.push_constant("color", theme_color);
724 }
725
726 if (select_face_dots_) {
727 const float dot_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) * UI_SCALE_FAC;
728
729 auto &pass = facedots_ps_;
730 pass.init();
733 pass.shader_set(res.shaders->uv_edit_facedot.get());
734 pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
735 pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
736 pass.push_constant("dot_size", dot_size);
737 }
738
739 if (show_face_overlay_ || select_face_) {
740 const float opacity = (object_mode_is_edit && space_mode_is_uv) ?
741 space_image->uv_opacity :
742 space_image->uv_face_opacity;
743
744 auto &pass = faces_ps_;
745 pass.init();
747 pass.shader_set(res.shaders->uv_edit_face.get());
748 pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
749 pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
750 pass.push_constant("uv_opacity", opacity);
751 }
752
753 if (show_mesh_analysis_) {
754 auto &pass = analysis_ps_;
755 pass.init();
757 pass.shader_set(mesh_analysis_type_ == SI_UVDT_STRETCH_ANGLE ?
758 res.shaders->uv_analysis_stretch_angle.get() :
759 res.shaders->uv_analysis_stretch_area.get());
760 pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
761 pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
762 pass.push_constant("aspect", state.image_uv_aspect);
763 pass.push_constant("stretch_opacity", space_image->stretch_opacity);
764 pass.push_constant("total_area_ratio", &total_area_ratio_);
765 }
766
767 per_mesh_area_3d_.clear();
768 per_mesh_area_2d_.clear();
769 }
770
771 void object_sync(Manager &manager,
772 const ObjectRef &ob_ref,
773 Resources & /*res*/,
774 const State &state) final
775 {
776 if (!enabled_ || ob_ref.object->type != OB_MESH ||
777 !((ob_ref.object->base_flag & BASE_SELECTED) || (ob_ref.object == state.object_active)))
778 {
779 return;
780 }
781
782 Object *ob = ob_ref.object;
784
785 const SpaceImage *space_image = reinterpret_cast<const SpaceImage *>(state.space_data);
786 const bool has_active_object_uvmap = CustomData_get_active_layer(&mesh.corner_data,
787 CD_PROP_FLOAT2) != -1;
788
789 ResourceHandleRange res_handle = manager.unique_handle(ob_ref);
790
791 if (show_wireframe_ && has_active_object_uvmap) {
792 gpu::Batch *geom = DRW_mesh_batch_cache_get_all_uv_wireframe(*ob, mesh);
793 wireframe_ps_.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, res_handle);
794 }
795 if (show_face_overlay_ && has_active_object_uvmap && space_image->uv_face_opacity > 0.0f) {
796 gpu::Batch *geom = DRW_mesh_batch_cache_get_uv_faces(*ob, mesh);
797 faces_ps_.draw(geom, res_handle);
798 }
799 }
800
802 const ObjectRef &ob_ref,
803 Resources & /*res*/,
804 const State &state) final
805 {
806 if (!enabled_ || ob_ref.object->type != OB_MESH) {
807 return;
808 }
809
810 Object &ob = *ob_ref.object;
812
813 const Object *ob_orig = DEG_get_original(ob_ref.object);
814 const Mesh &mesh_orig = ob_orig->type == OB_MESH ? *static_cast<Mesh *>(ob_orig->data) : mesh;
815
816 const SpaceImage *space_image = reinterpret_cast<const SpaceImage *>(state.space_data);
817 const bool is_edit_object = DRW_object_is_in_edit_mode(&ob);
818 const bool is_uv_editable = is_edit_object && space_image->mode == SI_MODE_UV;
819 /* Sculpt is left out here because selection does not exist in it. */
820 const bool is_paint_mode = ELEM(
822 const bool use_face_selection = (mesh_orig.editflag & ME_EDIT_PAINT_FACE_SEL);
823 const bool is_face_selectable = (is_edit_object || (is_paint_mode && use_face_selection));
824 const bool has_active_object_uvmap = CustomData_get_active_layer(&mesh.corner_data,
825 CD_PROP_FLOAT2) != -1;
826 const bool has_active_edit_uvmap = is_edit_object && (CustomData_get_active_layer(
827 &mesh.runtime->edit_mesh->bm->ldata,
828 CD_PROP_FLOAT2) != -1);
829
830 ResourceHandleRange res_handle = manager.unique_handle(ob_ref);
831
832 /* Fully editable UVs in the UV Editor. */
833 if (has_active_edit_uvmap && is_uv_editable) {
834 if (show_uv_edit_) {
835 gpu::Batch *geom = DRW_mesh_batch_cache_get_edituv_edges(ob, mesh);
836 edges_ps_.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, res_handle);
837 }
838 if (select_vert_) {
839 gpu::Batch *geom = DRW_mesh_batch_cache_get_edituv_verts(ob, mesh);
840 verts_ps_.draw(geom, res_handle);
841 }
842 if (select_face_dots_) {
843 gpu::Batch *geom = DRW_mesh_batch_cache_get_edituv_facedots(ob, mesh);
844 facedots_ps_.draw(geom, res_handle);
845 }
846 if (show_face_overlay_ || select_face_) {
847 gpu::Batch *geom = DRW_mesh_batch_cache_get_edituv_faces(ob, mesh);
848 faces_ps_.draw(geom, res_handle);
849 }
850 if (show_wireframe_) {
851 gpu::Batch *geom = DRW_mesh_batch_cache_get_edituv_wireframe(ob, mesh);
852 wireframe_ps_.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, res_handle);
853 }
854
855 if (show_mesh_analysis_) {
856 int index_3d, index_2d;
857 if (mesh_analysis_type_ == SI_UVDT_STRETCH_AREA) {
858 index_3d = per_mesh_area_3d_.append_and_get_index(nullptr);
859 index_2d = per_mesh_area_2d_.append_and_get_index(nullptr);
860 }
861
862 gpu::Batch *geom =
863 mesh_analysis_type_ == SI_UVDT_STRETCH_ANGLE ?
866 ob, mesh, &per_mesh_area_3d_[index_3d], &per_mesh_area_2d_[index_2d]);
867
868 analysis_ps_.draw(geom, res_handle);
869 }
870 return;
871 }
872
873 /* Selectable faces in 3D viewport that sync with image editor paint mode. */
874 if ((has_active_object_uvmap || has_active_edit_uvmap) && is_face_selectable) {
875 if (show_wireframe_) {
876 gpu::Batch *geom = DRW_mesh_batch_cache_get_uv_wireframe(ob, mesh);
877 wireframe_ps_.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, res_handle);
878 }
879 if ((show_face_overlay_ && space_image->uv_face_opacity > 0.0f) || select_face_) {
880 gpu::Batch *geom = DRW_mesh_batch_cache_get_uv_faces(ob, mesh);
881 faces_ps_.draw(geom, res_handle);
882 }
883 return;
884 }
885
886 /* Non-selectable & non-editable faces in image editor paint mode. */
887 if ((has_active_object_uvmap || has_active_edit_uvmap) && !is_uv_editable &&
888 !is_face_selectable)
889 {
890 if (show_wireframe_) {
891 gpu::Batch *geom = DRW_mesh_batch_cache_get_all_uv_wireframe(ob, mesh);
892 wireframe_ps_.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, res_handle);
893 }
894 if (show_face_overlay_ && space_image->uv_face_opacity > 0.0f) {
895 gpu::Batch *geom = DRW_mesh_batch_cache_get_uv_faces(ob, mesh);
896 faces_ps_.draw(geom, res_handle);
897 }
898 }
899 }
900
901 void end_sync(Resources &res, const State &state) final
902 {
903 if (!enabled_) {
904 return;
905 }
906
907 {
908 float total_3d = 0.0f;
909 float total_2d = 0.0f;
910 for (const float *mesh_area_2d : per_mesh_area_2d_) {
911 total_2d += *mesh_area_2d;
912 }
913 for (const float *mesh_area_3d : per_mesh_area_3d_) {
914 total_3d += *mesh_area_3d;
915 }
916 total_area_ratio_ = total_3d * math::safe_rcp(total_2d);
917 }
918
919 const ToolSettings *tool_setting = state.scene->toolsettings;
920 const SpaceImage *space_image = reinterpret_cast<const SpaceImage *>(state.space_data);
921 ::Image *image = space_image->image;
922
923 if (show_tiled_image_border_) {
924 float4 theme_color;
925 float4 selected_color;
926 uchar4 text_color;
927 /* Color Management: Exception here as texts are drawn in sRGB space directly. No conversion
928 * required. */
929 UI_GetThemeColorShade4ubv(TH_BACK, 60, text_color);
930 UI_GetThemeColorShade4fv(TH_BACK, 60, theme_color);
931 UI_GetThemeColor4fv(TH_FACE_SELECT, selected_color);
932 srgb_to_linearrgb_v4(theme_color, theme_color);
933 srgb_to_linearrgb_v4(selected_color, selected_color);
934
935 auto &pass = image_border_ps_;
936 pass.init();
938 pass.shader_set(res.shaders->uv_image_borders.get());
939
940 auto draw_tile = [&](const ImageTile *tile, const bool is_active) {
941 const int tile_x = ((tile->tile_number - 1001) % 10);
942 const int tile_y = ((tile->tile_number - 1001) / 10);
943 const float3 tile_location(tile_x, tile_y, 0.0f);
944 pass.push_constant("tile_pos", tile_location);
945 pass.push_constant("ucolor", is_active ? selected_color : theme_color);
946 pass.draw(res.shapes.quad_wire.get());
947
948 /* Note: don't draw label twice for active tile. */
949 if (show_tiled_image_label_ && !is_active) {
950 std::string text = std::to_string(tile->tile_number);
952 tile_location,
953 text.c_str(),
954 text.size(),
955 10,
956 10,
958 text_color);
959 }
960 };
961
963 /* image->active_tile_index could point to a non existing ImageTile. To work around this we
964 * get the active tile when looping over all tiles. */
965 const ImageTile *active_tile = nullptr;
966 int tile_index = 0;
967 for (const ImageTile *tile : tiles) {
968 draw_tile(tile, false);
969 if (tile_index == image->active_tile_index) {
970 active_tile = tile;
971 }
972 tile_index++;
973 }
974 /* Draw active tile on top. */
975 if (show_tiled_image_active_ && active_tile != nullptr) {
976 draw_tile(active_tile, true);
977 }
978 }
979
980 if (show_stencil_) {
981 auto &pass = brush_stencil_ps_;
982 pass.init();
985
986 const ImagePaintSettings &image_paint_settings = tool_setting->imapaint;
987 ::Image *stencil_image = image_paint_settings.clone;
988 TextureRef stencil_texture;
989 stencil_texture.wrap(BKE_image_get_gpu_texture(stencil_image, nullptr));
990
991 if (stencil_texture.is_valid()) {
992 float2 size_image;
993 BKE_image_get_size_fl(image, nullptr, &size_image[0]);
994
995 pass.shader_set(res.shaders->uv_brush_stencil.get());
996 pass.bind_texture("img_tx", stencil_texture);
997 pass.push_constant("img_premultiplied", true);
998 pass.push_constant("img_alpha_blend", true);
999 pass.push_constant("ucolor", float4(1.0f, 1.0f, 1.0f, image_paint_settings.clone_alpha));
1000 pass.push_constant("brush_offset", float2(image_paint_settings.clone_offset));
1001 pass.push_constant("brush_scale", float2(stencil_texture.size().xy()) / size_image);
1002 pass.draw(res.shapes.quad_solid.get());
1003 }
1004 }
1005
1006 if (show_mask_) {
1007 paint_mask_texture_ensure(mask_id_, state.image_size, state.image_aspect);
1008
1009 const bool is_combined = mask_mode_ == MASK_OVERLAY_COMBINED;
1010 const float opacity = is_combined ? space_image->mask_info.blend_factor : 1.0f;
1011
1012 auto &pass = paint_mask_ps_;
1013 pass.init();
1015 (is_combined ? DRW_STATE_BLEND_MUL : DRW_STATE_BLEND_ALPHA));
1016 pass.shader_set(res.shaders->uv_paint_mask.get());
1017 pass.bind_texture("img_tx", mask_texture_);
1018 pass.push_constant("color", float4(1.0f, 1.0f, 1.0f, 1.0f));
1019 pass.push_constant("opacity", opacity);
1020 pass.push_constant("brush_offset", float2(0.0f));
1021 pass.push_constant("brush_scale", float2(1.0f));
1022 pass.draw(res.shapes.quad_solid.get());
1023 }
1024 }
1025
1026 void draw(Framebuffer &framebuffer, Manager &manager, View &view) final
1027 {
1028 if (!enabled_) {
1029 return;
1030 }
1031
1032 GPU_debug_group_begin("Mesh Edit UVs");
1033
1034 GPU_framebuffer_bind(framebuffer);
1035 if (show_mask_ && (mask_mode_ != MASK_OVERLAY_COMBINED)) {
1036 manager.submit(paint_mask_ps_, view);
1037 }
1038 if (show_tiled_image_border_) {
1039 manager.submit(image_border_ps_, view);
1040 }
1041 if (show_wireframe_) {
1042 manager.submit(wireframe_ps_, view);
1043 }
1044 if (show_mesh_analysis_) {
1045 manager.submit(analysis_ps_, view);
1046 }
1047 if (show_face_overlay_ || select_face_) {
1048 manager.submit(faces_ps_, view);
1049 }
1050 if (show_uv_edit_) {
1051 manager.submit(edges_ps_, view);
1052 }
1053 if (select_face_dots_) {
1054 manager.submit(facedots_ps_, view);
1055 }
1056 if (select_vert_) {
1057 manager.submit(verts_ps_, view);
1058 }
1059 if (show_stencil_) {
1060 manager.submit(brush_stencil_ps_, view);
1061 }
1062
1064 }
1065
1066 void draw_on_render(gpu::FrameBuffer *framebuffer, Manager &manager, View &view) final
1067 {
1068 if (!enabled_) {
1069 return;
1070 }
1071
1072 GPU_framebuffer_bind(framebuffer);
1073 /* Mask in #MASK_OVERLAY_COMBINED mode renders onto the render framebuffer and modifies the
1074 * image in scene referred color space. The #MASK_OVERLAY_ALPHACHANNEL renders onto the overlay
1075 * framebuffer. */
1076 if (show_mask_ && (mask_mode_ == MASK_OVERLAY_COMBINED)) {
1077 manager.submit(paint_mask_ps_, view);
1078 }
1079 }
1080
1081 private:
1082 static OVERLAY_UVLineStyle edit_uv_line_style_from_space_image(const SpaceImage *sima)
1083 {
1084 const bool is_uv_editor = sima->mode == SI_MODE_UV;
1085 if (is_uv_editor) {
1086 switch (sima->dt_uv) {
1087 case SI_UVDT_OUTLINE:
1089 case SI_UVDT_BLACK:
1091 case SI_UVDT_WHITE:
1093 case SI_UVDT_DASH:
1095 default:
1097 }
1098 }
1099 else {
1101 }
1102 }
1103
1104 /* TODO(jbakker): the GPU texture should be cached with the mask. */
1105 void paint_mask_texture_ensure(Mask *mask, const int2 &resolution, const float2 &aspect)
1106 {
1107 const int width = resolution.x;
1108 const int height = floor(float(resolution.y) * (aspect.y / aspect.x));
1109 float *buffer = MEM_malloc_arrayN<float>(height * width, __func__);
1110
1112 BKE_maskrasterize_handle_init(handle, mask, width, height, true, true, true);
1113 BKE_maskrasterize_buffer(handle, width, height, buffer);
1115
1116 mask_texture_.free();
1117 mask_texture_.ensure_2d(
1118 gpu::TextureFormat::SFLOAT_16, int2(width, height), GPU_TEXTURE_USAGE_SHADER_READ, buffer);
1119
1120 MEM_freeN(buffer);
1121 }
1122};
1123
1124} // namespace blender::draw::overlay
@ CTX_MODE_PAINT_TEXTURE
@ CTX_MODE_PAINT_VERTEX
@ CTX_MODE_PAINT_WEIGHT
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
int CustomData_get_active_layer(const CustomData *data, eCustomDataType type)
void BKE_image_get_size_fl(Image *image, ImageUser *iuser, float r_size[2])
blender::gpu::Texture * BKE_image_get_gpu_texture(Image *image, ImageUser *iuser)
Definition image_gpu.cc:496
void BKE_maskrasterize_handle_free(MaskRasterHandle *mr_handle)
MaskRasterHandle * BKE_maskrasterize_handle_new(void)
void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mask, int width, int height, bool do_aspect_correct, bool do_mask_aa, bool do_feather)
struct MaskRasterHandle MaskRasterHandle
Definition BKE_mask.h:388
void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle, unsigned int width, unsigned int height, float *buffer)
Rasterize a buffer from a single mask (threaded execution).
const Mesh * BKE_object_get_editmesh_eval_cage(const Object *object)
const Mesh * BKE_object_get_editmesh_eval_final(const Object *object)
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:650
bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh)
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
#define M_SQRT2
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
T * DEG_get_original(T *id)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ IMAGE_PAINT_BRUSH_TYPE_CLONE
@ CD_MVERT_SKIN
@ CD_PROP_FLOAT2
@ IMA_SRC_TILED
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
struct Mask Mask
eMaskOverlayMode
@ MASK_OVERLAY_COMBINED
@ MASK_OVERLAY_ALPHACHANNEL
@ MASK_DRAWFLAG_OVERLAY
@ ME_EDIT_PAINT_FACE_SEL
eDrawType
@ OB_WIRE
@ OB_MODE_EDIT
@ OB_MESH
@ UV_SELECT_FACE
@ UV_SELECT_EDGE
#define BASE_SELECTED(v3d, base)
@ SCE_PERF_HQ_NORMALS
@ UV_STICKY_VERT
@ UV_FLAG_SELECT_SYNC
@ SCE_SELECT_FACE
@ SCE_SELECT_VERTEX
@ SCE_SELECT_EDGE
@ SI_NO_DRAW_UV_GUIDE
@ SI_DRAW_STRETCH
@ SI_NO_DRAWFACES
@ SI_DRAWSHADOW
@ SI_UVDT_BLACK
@ SI_UVDT_DASH
@ SI_UVDT_WHITE
@ SI_UVDT_OUTLINE
eSpaceImage_UVDT_Stretch
@ SI_UVDT_STRETCH_AREA
@ SI_UVDT_STRETCH_ANGLE
@ SI_MODE_PAINT
@ SI_MODE_MASK
@ SI_MODE_UV
#define UI_SCALE_FAC
@ USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE
@ USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE
@ V3D_OVERLAY_EDIT_VERT_NORMALS
@ V3D_OVERLAY_EDIT_INDICES
@ V3D_OVERLAY_EDIT_FREESTYLE_FACE
@ V3D_OVERLAY_EDIT_RETOPOLOGY
@ V3D_OVERLAY_EDIT_LOOP_NORMALS
@ V3D_OVERLAY_EDIT_FACE_NORMALS
@ V3D_OVERLAY_EDIT_CREASES
@ V3D_OVERLAY_EDIT_FREESTYLE_EDGE
@ V3D_OVERLAY_EDIT_CONSTANT_SCREEN_SIZE_NORMALS
@ V3D_OVERLAY_EDIT_FACES
@ V3D_OVERLAY_EDIT_FACE_AREA
@ V3D_OVERLAY_EDIT_EDGE_ANG
@ V3D_OVERLAY_EDIT_FACE_DOT
@ V3D_OVERLAY_EDIT_FACE_ANG
@ V3D_OVERLAY_EDIT_SEAMS
@ V3D_OVERLAY_EDIT_STATVIS
@ V3D_OVERLAY_EDIT_BWEIGHTS
@ V3D_OVERLAY_EDIT_WEIGHT
@ V3D_OVERLAY_EDIT_SHARP
@ V3D_OVERLAY_EDIT_EDGE_LEN
T & DRW_object_get_data_for_drawing(const Object &object)
#define RETOPOLOGY_OFFSET(v3d)
static AppView * view
bool GPU_use_hq_normals_workaround()
void GPU_debug_group_end()
Definition gpu_debug.cc:33
void GPU_debug_group_begin(const char *name)
Definition gpu_debug.cc:22
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
@ GPU_PRIM_LINES
@ GPU_PRIM_TRIS
@ GPU_TEXTURE_USAGE_SHADER_READ
@ TH_BACK
@ TH_FACEDOT_SIZE
@ TH_VERTEX
@ TH_VERTEX_SIZE
@ TH_FACE_SELECT
void UI_GetThemeColor4fv(int colorid, float col[4])
void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4])
void UI_GetThemeColorShade4ubv(int colorid, int offset, unsigned char col[4])
float UI_GetThemeValuef(int colorid)
static void draw_tile(const float2 &zoom, const int texcoord_attribute, const int position_attribute, const DrawTile &draw_tile)
#define U
void wrap(gpu::Texture *tex)
int3 size(int miplvl=0) const
void shader_set(gpu::Shader *shader)
void bind_texture(const char *name, gpu::Texture *texture, GPUSamplerState state=sampler_auto)
void state_set(DRWState state, int clip_plane_count=0)
void bind_ubo(const char *name, gpu::UniformBuf *buffer)
void push_constant(const char *name, const float &data)
detail::PassBase< command::DrawCommandBuf > Sub
Definition draw_pass.hh:499
void end_sync(Resources &res, const State &state) final
void object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &, const State &state) final
void draw_on_render(gpu::FrameBuffer *framebuffer, Manager &manager, View &view) final
void draw(Framebuffer &framebuffer, Manager &manager, View &view) final
void edit_object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &, const State &state) final
void begin_sync(Resources &res, const State &state) final
void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
void edit_object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &, const State &state) final
static bool mesh_has_edit_cage(const Object *ob)
void draw_color_only(Framebuffer &framebuffer, Manager &manager, View &view) final
void begin_sync(Resources &res, const State &state) final
bool DRW_object_is_in_edit_mode(const Object *ob)
#define DRW_CLIPPING_UBO_SLOT
#define OVERLAY_GLOBALS_SLOT
void DRW_text_cache_add(DRWTextStore *dt, const float co[3], const char *str, const int str_len, short xoffs, short yoffs, short flag, const uchar col[4], const bool shadow, const bool align_center)
void DRW_text_edit_mesh_measure_stats(const ARegion *region, const View3D *v3d, const Object *ob, const UnitSettings &unit, DRWTextStore *dt)
@ DRW_TEXT_CACHE_GLOBALSPACE
DRWState
Definition draw_state.hh:25
@ DRW_STATE_BLEND_ALPHA
Definition draw_state.hh:55
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
@ DRW_STATE_CULL_BACK
Definition draw_state.hh:43
@ DRW_STATE_FIRST_VERTEX_CONVENTION
Definition draw_state.hh:72
@ DRW_STATE_DEPTH_ALWAYS
Definition draw_state.hh:36
@ DRW_STATE_BLEND_ALPHA_PREMUL
Definition draw_state.hh:57
@ DRW_STATE_BLEND_MUL
Definition draw_state.hh:60
#define floor
ccl_gpu_kernel_postfix ccl_global KernelWorkTile * tiles
const ccl_global KernelWorkTile * tile
const int tile_index
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong state[N]
constexpr int overlay_edit_text
blender::gpu::Batch * DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Object &object, Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edituv_edges(Object &object, Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edit_edges(Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edituv_facedots(Object &object, Mesh &mesh)
detail::Pass< command::DrawCommandBuf > PassSimple
blender::gpu::Batch * DRW_mesh_batch_cache_get_edituv_wireframe(Object &object, Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edit_facedots(Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edituv_verts(Object &object, Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edituv_faces(Object &object, Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edit_loop_normals(Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edit_triangles(Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edit_vertices(Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_all_uv_wireframe(Object &object, Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edit_vert_normals(Mesh &mesh)
gpu::Batch * DRW_cache_mesh_surface_weights_get(Object *ob)
blender::gpu::Batch * DRW_mesh_batch_cache_get_uv_faces(Object &object, Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Object &object, Mesh &mesh, float **tot_area, float **tot_uv_area)
gpu::Batch * DRW_cache_mesh_surface_get(Object *ob)
blender::gpu::Batch * DRW_mesh_batch_cache_get_uv_wireframe(Object &object, Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edit_skin_roots(Mesh &mesh)
gpu::Batch * DRW_cache_mesh_surface_mesh_analysis_get(Object *ob)
T safe_rcp(const T &a)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
VecBase< int32_t, 4 > int4
VecBase< uint32_t, 4 > uint4
blender::VecBase< uint8_t, 4 > uchar4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
ListBaseWrapperTemplate< ListBase, T > ListBaseWrapper
VecBase< float, 3 > float3
@ OVERLAY_UV_LINE_STYLE_DASH
@ OVERLAY_UV_LINE_STYLE_SHADOW
@ OVERLAY_UV_LINE_STYLE_WHITE
@ OVERLAY_UV_LINE_STYLE_OUTLINE
@ OVERLAY_UV_LINE_STYLE_BLACK
const char * name
char image_brush_type
ListBase tiles
short source
int active_tile_index
struct Mask * mask
MeshRuntimeHandle * runtime
CustomData corner_data
char editflag
float uv_face_opacity
MaskSpaceInfo mask_info
struct Image * image
float stretch_opacity
struct ImagePaintSettings imapaint
VecBase< T, 2 > xy() const
virtual void draw(Framebuffer &, Manager &, View &)
float x
float y
uint8_t flag
Definition wm_window.cc:145