Blender V4.3
overlay_armature.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
9#include <cmath>
10#include <cstdlib>
11#include <cstring>
12
13#include "DNA_armature_types.h"
15#include "DNA_mesh_types.h"
16#include "DNA_object_types.h"
17#include "DNA_scene_types.h"
18#include "DNA_view3d_types.h"
19
20#include "DRW_render.hh"
21
23#include "BLI_math_color.h"
25#include "BLI_math_rotation.h"
26#include "BLI_utildefines.h"
27
28#include "BKE_action.hh"
29#include "BKE_armature.hh"
30#include "BKE_deform.hh"
31#include "BKE_modifier.hh"
32#include "BKE_object.hh"
33#include "BKE_object_types.hh"
34
36
37#include "ED_armature.hh"
38#include "ED_view3d.hh"
39
41#include "ANIM_bonecolor.hh"
42
43#include "UI_resources.hh"
44
45#include "draw_common_c.hh"
46#include "draw_manager_text.hh"
47
49#include "overlay_private.hh"
50
51#include "draw_cache_impl.hh"
52
53#define PT_DEFAULT_RAD 0.05f /* radius of the point batch. */
54
55using namespace blender::draw::overlay;
56
61 private:
62 union {
65 };
66 bool is_editbone_; /* Discriminator for the above union. */
67
68 public:
71
72 UnifiedBonePtr(EditBone *eBone) : eBone_(eBone), is_editbone_(true) {}
73 UnifiedBonePtr(bPoseChannel *pchan) : pchan_(pchan), is_editbone_(false) {}
74
75 const char *name() const
76 {
77 return is_editbone_ ? eBone_->name : pchan_->name;
78 }
79
80 const EditBone *as_editbone() const
81 {
82 BLI_assert_msg(is_editbone_,
83 "conversion to EditBone* only possible when "
84 "UnifiedBonePtr contains an edit bone");
85 return eBone_;
86 }
88 {
89 BLI_assert_msg(is_editbone_,
90 "conversion to EditBone* only possible when "
91 "UnifiedBonePtr contains an edit bone");
92 return eBone_;
93 }
94
96 {
97 BLI_assert_msg(!is_editbone_,
98 "conversion to bPoseChannel* only possible when "
99 "UnifiedBonePtr contains a pose channel");
100 return pchan_;
101 }
103 {
104 BLI_assert_msg(!is_editbone_,
105 "conversion to bPoseChannel* only possible when "
106 "UnifiedBonePtr contains a pose channel");
107 return pchan_;
108 }
109
110 bool is_editbone() const
111 {
112 return is_editbone_;
113 };
114 bool is_posebone() const
115 {
116 return !is_editbone();
117 };
118
119 void get(const EditBone **eBone, const bPoseChannel **pchan) const
120 {
121 *eBone = eBone_;
122 *pchan = pchan_;
123 }
124 void get(EditBone **eBone, bPoseChannel **pchan)
125 {
126 *eBone = eBone_;
127 *pchan = pchan_;
128 }
129
131 {
132 return static_cast<eBone_Flag>(is_editbone_ ? eBone_->flag : pchan_->bone->flag);
133 }
134
137 {
138 return ePchan_ConstFlag(is_editbone_ ? 0 : pchan_->constflag);
139 }
140
141 bool has_parent() const
142 {
143 return is_editbone_ ? eBone_->parent != nullptr : pchan_->bone->parent != nullptr;
144 }
145
146 using f44 = float[4][4];
147 const f44 &disp_mat() const
148 {
149 return is_editbone_ ? eBone_->disp_mat : pchan_->disp_mat;
150 }
152 {
153 return is_editbone_ ? eBone_->disp_mat : pchan_->disp_mat;
154 }
155
156 const f44 &disp_tail_mat() const
157 {
158 return is_editbone_ ? eBone_->disp_tail_mat : pchan_->disp_tail_mat;
159 }
160
162 {
163 return is_editbone_ ? eBone_->disp_tail_mat : pchan_->disp_tail_mat;
164 }
165
166 /* For some, to me unknown, reason, the drawing code passes these around as pointers. This is the
167 * reason that these are returned as references. I'll leave refactoring that for another time. */
168 const float &rad_head() const
169 {
170 return is_editbone_ ? eBone_->rad_head : pchan_->bone->rad_head;
171 }
172
173 const float &rad_tail() const
174 {
175 return is_editbone_ ? eBone_->rad_tail : pchan_->bone->rad_tail;
176 }
177
179 {
180 if (is_editbone_) {
181 return eBone_->color.wrap();
182 }
183
184 if (pchan_->color.palette_index == 0) {
185 /* If the pchan has the 'default' color, treat it as a signal to use the underlying bone
186 * color. */
187 return pchan_->bone->color.wrap();
188 }
189 return pchan_->color.wrap();
190 }
191};
192
201 public:
202 virtual void update_display_matrix(UnifiedBonePtr bone) const = 0;
203
208 virtual bool culling_test(const DRWView *view,
209 const Object *ob,
210 const bPoseChannel *pchan) const = 0;
211
214 const bool is_filled,
215 const bool do_envelope_dist) const = 0;
216
217 virtual void draw_bone(const Armatures::DrawContext *ctx,
218 const UnifiedBonePtr bone,
219 const eBone_Flag boneflag,
220 const int select_id) const = 0;
221
224 const eBone_Flag boneflag) const
225 {
226 const bool has_parent = bone.has_parent();
227
228 if (bone.is_editbone() && has_parent) {
229 /* Always draw for unconnected bones, regardless of selection,
230 * since riggers will want to know about the links between bones
231 */
232 return (boneflag & BONE_CONNECTED) == 0;
233 }
234
235 if (bone.is_posebone() && has_parent) {
236 /* Only draw between unconnected bones. */
237 if (boneflag & BONE_CONNECTED) {
238 return false;
239 }
240
241 /* Only draw if bone or its parent is selected - reduces viewport
242 * complexity with complex rigs */
243 const bPoseChannel *pchan = bone.as_posebone();
244 return (boneflag & BONE_SELECTED) ||
245 (pchan->parent->bone && (pchan->parent->bone->flag & BONE_SELECTED));
246 }
247
248 return false;
249 }
250};
251
253{
254 Object *active_ob = draw_ctx->obact;
255
256 /* Pose armature is handled by pose mode engine. */
257 if (((ob == active_ob) || (ob->mode & OB_MODE_POSE)) &&
258 ((draw_ctx->object_mode & OB_MODE_POSE) != 0))
259 {
260 return true;
261 }
262
263 /* Armature parent is also handled by pose mode engine. */
264 if ((active_ob != nullptr) && (draw_ctx->object_mode & OB_MODE_ALL_WEIGHT_PAINT)) {
265 if (ob == draw_ctx->object_pose) {
266 return true;
267 }
268 }
269
270 return false;
271}
272
274{
275 OVERLAY_PassList *psl = vedata->psl;
276 OVERLAY_PrivateData *pd = vedata->stl->pd;
277
278 const DRWContextState *draw_ctx = DRW_context_state_get();
279 const bool is_select_mode = DRW_state_is_select();
280 pd->armature.transparent = (draw_ctx->v3d->shading.type == OB_WIRE) ||
281 XRAY_FLAG_ENABLED(draw_ctx->v3d);
282 pd->armature.show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0) &&
283 !is_select_mode;
286 ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) == 0) &&
287 draw_ctx->object_pose != nullptr;
288
289 const float wire_alpha = pd->overlay.bone_wire_alpha;
290 const bool use_wire_alpha = (wire_alpha < 1.0f);
291
293
294 if (pd->armature.do_pose_fade_geom) {
297
298 float alpha = pd->overlay.xray_alpha_bone;
300 DRWShadingGroup *grp;
301
303 float4 color = {0.0f, 0.0f, 0.0f, alpha};
304 DRW_shgroup_uniform_vec4_copy(grp, "ucolor", color);
305
307 color = {0.0f, 0.0f, 0.0f, powf(alpha, 4)};
308 DRW_shgroup_uniform_vec4_copy(grp, "ucolor", color);
309 }
310
311 for (int i = 0; i < 2; i++) {
312 GPUShader *sh;
314 DRWShadingGroup *grp = nullptr;
315
318
321
322 DRWPass **p_armature_ps = &psl->armature_ps[i];
323 DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT :
324 DRWState(0);
326 DRW_PASS_CREATE(*p_armature_ps, state | pd->clipping_state | infront_state);
327 DRWPass *armature_ps = *p_armature_ps;
328
329 DRWPass **p_armature_trans_ps = &psl->armature_transp_ps[i];
331 DRW_PASS_CREATE(*p_armature_trans_ps, state | pd->clipping_state);
332 DRWPass *armature_transp_ps = *p_armature_trans_ps;
333
334#define BUF_INSTANCE DRW_shgroup_call_buffer_instance
335#define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES)
336#define BUF_POINT(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_POINTS)
337
338 {
339 format = formats->instance_bone;
340
342 grp = DRW_shgroup_create(sh, armature_ps);
343 DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
345
346 grp = DRW_shgroup_create(sh, armature_ps);
349 DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.4f);
351
353 grp = DRW_shgroup_create(sh, armature_ps);
354 DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
355 cb->solid.custom_fill = grp;
358
359 grp = DRW_shgroup_create(sh, armature_ps);
362 DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.6f);
363 cb->transp.custom_fill = grp;
366
368 grp = DRW_shgroup_create(sh, armature_ps);
369 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
370 DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
372
373 if (use_wire_alpha) {
374 grp = DRW_shgroup_create(sh, armature_ps);
376 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
377 DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
380 }
381 else {
383 }
385 GPUTexture **depth_tex = &dtxl->depth;
386 const bool do_smooth_wire = U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE;
387
389 cb->solid.custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
390 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
391 DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
392 DRW_shgroup_uniform_bool_copy(grp, "do_smooth_wire", do_smooth_wire);
393 DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
396
397 if (use_wire_alpha) {
398 cb->transp.custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
400 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
401 DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
404 }
405 else {
409 }
410
412 cb->solid.custom_wire = grp = DRW_shgroup_create(sh, armature_ps);
413 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
414 DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
415 DRW_shgroup_uniform_bool_copy(grp, "do_smooth_wire", do_smooth_wire);
416 DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
418
419 if (use_wire_alpha) {
420 cb->transp.custom_wire = grp = DRW_shgroup_create(sh, armature_ps);
421 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
422 DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
423 }
424 else {
426 }
427 }
428 {
429 format = formats->instance_extra;
430
432 grp = DRW_shgroup_create(sh, armature_ps);
433 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
434 DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
436
437 if (use_wire_alpha) {
438 grp = DRW_shgroup_create(sh, armature_ps);
440 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
441 DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
443 }
444 else {
446 }
447
449 grp = DRW_shgroup_create(sh, armature_transp_ps);
450 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
451 DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
453
454 if (use_wire_alpha) {
455 grp = DRW_shgroup_create(sh, armature_transp_ps);
456 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
457 DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
459 }
460 else {
462 }
463 }
464 {
465 format = formats->instance_bone_stick;
466
468 grp = DRW_shgroup_create(sh, armature_ps);
469 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
470 DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
472
473 if (use_wire_alpha) {
474 grp = DRW_shgroup_create(sh, armature_ps);
476 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
477 DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
479 }
480 else {
481 cb->transp.stick = cb->solid.stick;
482 }
483 }
484 {
486
488 grp = DRW_shgroup_create(sh, armature_ps);
490 DRW_shgroup_uniform_bool_copy(grp, "isDistance", false);
491 DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
493
494 grp = DRW_shgroup_create(sh, armature_ps);
497 DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.6f);
499
501
503 grp = DRW_shgroup_create(sh, armature_ps);
504 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
505 DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
508
509 if (use_wire_alpha) {
510 grp = DRW_shgroup_create(sh, armature_ps);
512 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
513 DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
516 }
517 else {
519 }
520
522
524 grp = DRW_shgroup_create(sh, armature_transp_ps);
525 DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
526 DRW_shgroup_uniform_bool_copy(grp, "isDistance", true);
529
530 if (use_wire_alpha) {
531 grp = DRW_shgroup_create(sh, armature_transp_ps);
532 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
533 DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
534 DRW_shgroup_uniform_bool_copy(grp, "isDistance", true);
538 }
539 else {
541 }
542 }
543 {
544 format = formats->pos_color;
545
547 grp = DRW_shgroup_create(sh, armature_ps);
548 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
549 DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
550 cb->solid.wire = BUF_LINE(grp, format);
551
552 if (use_wire_alpha) {
553 grp = DRW_shgroup_create(sh, armature_ps);
555 DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
556 DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
557 cb->transp.wire = BUF_LINE(grp, format);
558 }
559 else {
560 cb->transp.wire = cb->solid.wire;
561 }
562 }
563 }
564}
565
566// #define NO_LEGACY_OVERLAY
567
568/* Allows to check that all legacy API usage are guarded behind this flag.
569 * Checks that all code have been ported to new API. */
570#ifdef NO_LEGACY_OVERLAY
571# define DRW_buffer_add_entry_struct POISON
572# define DRW_select_load_id POISON
573# define OVERLAY_empty_shape POISON
574# define OVERLAY_extra_line_dashed POISON
575#endif
576
577/* -------------------------------------------------------------------- */
582 const float aminx,
583 const float aminz,
584 const float amaxx,
585 const float amaxz)
586{
587 data->amin_a = aminx;
588 data->amin_b = aminz;
589 data->amax_a = amaxx;
590 data->amax_b = amaxz;
591}
592
593/* Encode 2 units float with byte precision into a float. */
594static float encode_2f_to_float(float a, float b)
595{
596 CLAMP(a, 0.0f, 1.0f);
597 CLAMP(b, 0.0f, 2.0f); /* Can go up to 2. Needed for wire size. */
598 return float(int(a * 255) | (int(b * 255) << 8));
599}
600
602{
603 /* Encoded color into 2 floats to be able to use the obmat to color the custom bones. */
604 data->color_hint_a = encode_2f_to_float(hint_color[0], hint_color[1]);
605 data->color_hint_b = encode_2f_to_float(hint_color[2], hint_color[3]);
606}
607
608void OVERLAY_bone_instance_data_set_color(BoneInstanceData *data, const float bone_color[4])
609{
610 /* Encoded color into 2 floats to be able to use the obmat to color the custom bones. */
611 data->color_a = encode_2f_to_float(bone_color[0], bone_color[1]);
612 data->color_b = encode_2f_to_float(bone_color[2], bone_color[3]);
613}
614
615#ifndef NO_LEGACY_OVERLAY
616
617/* Octahedral */
619 const float (*bone_mat)[4],
620 const float bone_color[4],
621 const float hint_color[4],
622 const float outline_color[4])
623{
624 BoneInstanceData inst_data;
625 mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world().ptr(), bone_mat);
626 if (ctx->solid) {
627 OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
628 OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
629 DRW_buffer_add_entry_struct(ctx->solid, &inst_data);
630 }
631 if (outline_color[3] > 0.0f) {
632 OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
633 DRW_buffer_add_entry_struct(ctx->outline, &inst_data);
634 }
635}
636
637/* Box / B-Bone */
639 const float (*bone_mat)[4],
640 const float bone_color[4],
641 const float hint_color[4],
642 const float outline_color[4])
643{
644 BoneInstanceData inst_data;
645 mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world().ptr(), bone_mat);
646 if (ctx->solid) {
647 OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
648 OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
649 DRW_buffer_add_entry_struct(ctx->solid, &inst_data);
650 }
651 if (outline_color[3] > 0.0f) {
652 OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
653 DRW_buffer_add_entry_struct(ctx->outline, &inst_data);
654 }
655}
656#endif
657
658/* Stick */
660 const float (*bone_mat)[4],
661 const float col_wire[4],
662 const float col_bone[4],
663 const float col_head[4],
664 const float col_tail[4],
665 const int select_id)
666{
667 float4x4 bmat = float4x4(bone_mat);
668 float3 head = math::transform_point(ctx->ob->object_to_world(), bmat.location());
669 float3 tail = math::transform_point(ctx->ob->object_to_world(), bmat.location() + bmat.y_axis());
670
671 if (ctx->is_overlay_next()) {
672 auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id);
673
674 ctx->bone_buf->stick_buf.append({head,
675 tail,
676 *(float4 *)col_wire,
677 *(float4 *)col_bone,
678 *(float4 *)col_head,
679 *(float4 *)col_tail},
680 sel_id);
681 }
682#ifndef NO_LEGACY_OVERLAY
683 else {
684 DRW_buffer_add_entry(ctx->stick, head, tail, col_wire, col_bone, col_head, col_tail);
685 }
686#endif
687}
688
689/* Envelope */
691 const float (*bone_mat)[4],
692 const float *radius_head,
693 const float *radius_tail,
694 const float *distance)
695{
696 if (ctx->draw_envelope_distance) {
697 float head_sph[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sph[4] = {0.0f, 1.0f, 0.0f, 1.0f};
698 float xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
699 /* Still less operation than m4 multiplication. */
700 mul_m4_v4(bone_mat, head_sph);
701 mul_m4_v4(bone_mat, tail_sph);
702 mul_m4_v4(bone_mat, xaxis);
703 mul_m4_v4(ctx->ob->object_to_world().ptr(), head_sph);
704 mul_m4_v4(ctx->ob->object_to_world().ptr(), tail_sph);
705 mul_m4_v4(ctx->ob->object_to_world().ptr(), xaxis);
706 sub_v3_v3(xaxis, head_sph);
707 float obscale = mat4_to_scale(ctx->ob->object_to_world().ptr());
708 head_sph[3] = *radius_head * obscale;
709 head_sph[3] += *distance * obscale;
710 tail_sph[3] = *radius_tail * obscale;
711 tail_sph[3] += *distance * obscale;
712 if (ctx->is_overlay_next()) {
713 /* TODO(fclem): Cleanup these casts when Overlay Next is shipped. */
714 ctx->bone_buf->envelope_distance_buf.append(
715 {*(float4 *)head_sph, *(float4 *)tail_sph, *(float3 *)xaxis},
717 }
718#ifndef NO_LEGACY_OVERLAY
719 else if (ctx->envelope_distance) {
720 DRW_buffer_add_entry(ctx->envelope_distance, head_sph, tail_sph, xaxis);
721 }
722#endif
723 }
724}
725
727 const float (*bone_mat)[4],
728 const float bone_col[4],
729 const float hint_col[4],
730 const float outline_col[4],
731 const float *radius_head,
732 const float *radius_tail,
733 const int select_id)
734{
735 float head_sph[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sph[4] = {0.0f, 1.0f, 0.0f, 1.0f};
736 float xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
737 /* Still less operation than m4 multiplication. */
738 mul_m4_v4(bone_mat, head_sph);
739 mul_m4_v4(bone_mat, tail_sph);
740 mul_m4_v4(bone_mat, xaxis);
741 mul_m4_v4(ctx->ob->object_to_world().ptr(), head_sph);
742 mul_m4_v4(ctx->ob->object_to_world().ptr(), tail_sph);
743 mul_m4_v4(ctx->ob->object_to_world().ptr(), xaxis);
744 float obscale = mat4_to_scale(ctx->ob->object_to_world().ptr());
745 head_sph[3] = *radius_head * obscale;
746 tail_sph[3] = *radius_tail * obscale;
747
748 auto sel_id = (ctx->bone_buf) ? ctx->res->select_id(*ctx->ob_ref, select_id) :
750
751 if (head_sph[3] < 0.0f || tail_sph[3] < 0.0f) {
752 BoneInstanceData inst_data;
753 if (head_sph[3] < 0.0f) {
754 /* Draw Tail only */
755 scale_m4_fl(inst_data.mat, tail_sph[3] / PT_DEFAULT_RAD);
756 copy_v3_v3(inst_data.mat[3], tail_sph);
757 }
758 else {
759 /* Draw Head only */
760 scale_m4_fl(inst_data.mat, head_sph[3] / PT_DEFAULT_RAD);
761 copy_v3_v3(inst_data.mat[3], head_sph);
762 }
763
764 if (ctx->is_overlay_next()) {
765 if (ctx->is_filled) {
766 ctx->bone_buf->sphere_fill_buf.append({inst_data.mat44, bone_col, hint_col}, sel_id);
767 }
768 if (outline_col[3] > 0.0f) {
769 ctx->bone_buf->sphere_outline_buf.append({inst_data.mat44, outline_col}, sel_id);
770 }
771 }
772#ifndef NO_LEGACY_OVERLAY
773 else {
774 if (ctx->point_solid) {
775 OVERLAY_bone_instance_data_set_color(&inst_data, bone_col);
776 OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_col);
778 }
779 if (outline_col[3] > 0.0f) {
780 OVERLAY_bone_instance_data_set_color(&inst_data, outline_col);
782 }
783 }
784#endif
785 }
786 else {
787 /* Draw Body */
788 float tmp_sph[4];
789 float len = len_v3v3(tail_sph, head_sph);
790 float fac_head = (len - head_sph[3]) / len;
791 float fac_tail = (len - tail_sph[3]) / len;
792 /* Small epsilon to avoid problem with float precision in shader. */
793 if (len > (tail_sph[3] + head_sph[3]) + 1e-8f) {
794 copy_v4_v4(tmp_sph, head_sph);
795 interp_v4_v4v4(head_sph, tail_sph, head_sph, fac_head);
796 interp_v4_v4v4(tail_sph, tmp_sph, tail_sph, fac_tail);
797
798 if (ctx->is_overlay_next()) {
799 if (ctx->is_filled) {
800 /* TODO(fclem): Cleanup these casts when Overlay Next is shipped. */
801 ctx->bone_buf->envelope_fill_buf.append({*(float4 *)head_sph,
802 *(float4 *)tail_sph,
803 *(float3 *)bone_col,
804 *(float3 *)hint_col,
805 *(float3 *)xaxis},
806 sel_id);
807 }
808 if (outline_col[3] > 0.0f) {
809 ctx->bone_buf->envelope_outline_buf.append(
810 {*(float4 *)head_sph, *(float4 *)tail_sph, *(float4 *)outline_col, *(float3 *)xaxis},
811 sel_id);
812 }
813 }
814#ifndef NO_LEGACY_OVERLAY
815 else {
816 if (ctx->envelope_solid) {
817 DRW_buffer_add_entry(ctx->envelope_solid, head_sph, tail_sph, bone_col, hint_col, xaxis);
818 }
819 if (outline_col[3] > 0.0f) {
820 DRW_buffer_add_entry(ctx->envelope_outline, head_sph, tail_sph, outline_col, xaxis);
821 }
822 }
823#endif
824 }
825 else {
826 /* Distance between endpoints is too small for a capsule. Draw a Sphere instead. */
827 float fac = max_ff(fac_head, 1.0f - fac_tail);
828 interp_v4_v4v4(tmp_sph, tail_sph, head_sph, clamp_f(fac, 0.0f, 1.0f));
829
830 BoneInstanceData inst_data;
831 scale_m4_fl(inst_data.mat, tmp_sph[3] / PT_DEFAULT_RAD);
832 copy_v3_v3(inst_data.mat[3], tmp_sph);
833
834 if (ctx->is_overlay_next()) {
835 if (ctx->is_filled) {
836 ctx->bone_buf->sphere_fill_buf.append({inst_data.mat44, bone_col, hint_col}, sel_id);
837 }
838 if (outline_col[3] > 0.0f) {
839 ctx->bone_buf->sphere_outline_buf.append({inst_data.mat44, outline_col}, sel_id);
840 }
841 }
842#ifndef NO_LEGACY_OVERLAY
843 else {
844 if (ctx->point_solid) {
845 OVERLAY_bone_instance_data_set_color(&inst_data, bone_col);
846 OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_col);
848 }
849 if (outline_col[3] > 0.0f) {
850 OVERLAY_bone_instance_data_set_color(&inst_data, outline_col);
852 }
853 }
854#endif
855 }
856 }
857}
858
859/* Custom (geometry) */
860
861#ifndef NO_LEGACY_OVERLAY
863 DRWShadingGroup *grp,
864 blender::gpu::Batch *custom_geom)
865{
866 DRWCallBuffer *buf = static_cast<DRWCallBuffer *>(
867 BLI_ghash_lookup(ctx->custom_shapes_ghash, custom_geom));
868 if (buf == nullptr) {
870 buf = DRW_shgroup_call_buffer_instance(grp, formats->instance_bone, custom_geom);
871 BLI_ghash_insert(ctx->custom_shapes_ghash, custom_geom, buf);
872 }
873 return buf;
874}
875#endif
876
878 Mesh &mesh,
879 const float (*bone_mat)[4],
880 const float bone_color[4],
881 const float hint_color[4],
882 const float outline_color[4],
883 const float wire_width,
884 const draw::select::ID select_id,
885 Object &custom)
886{
887 using namespace blender::draw;
888 /* TODO(fclem): arg... less than ideal but we never iter on this object
889 * to assure batch cache is valid. */
890 DRW_mesh_batch_cache_validate(custom, mesh);
891
892 blender::gpu::Batch *surf = DRW_mesh_batch_cache_get_surface(mesh);
893 blender::gpu::Batch *edges = DRW_mesh_batch_cache_get_edge_detection(mesh, nullptr);
894 blender::gpu::Batch *loose_edges = DRW_mesh_batch_cache_get_loose_edges(mesh);
895 BoneInstanceData inst_data;
896 DRWCallBuffer *buf;
897
898 if (surf || edges || loose_edges) {
899 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(bone_mat);
900 }
901
902 if (surf) {
903 inst_data.set_hint_color(hint_color);
904 inst_data.set_color(bone_color);
905 if (ctx->is_overlay_next() && ctx->is_filled) {
906 ctx->bone_buf->custom_shape_fill_get_buffer(surf).append(inst_data, select_id);
907 }
908#ifndef NO_LEGACY_OVERLAY
909 else if (ctx->custom_solid) {
910 buf = custom_bone_instance_shgroup(ctx, ctx->custom_solid, surf);
911 DRW_buffer_add_entry_struct(buf, inst_data.mat);
912 }
913#endif
914 }
915
916 if (edges) {
917 inst_data.set_color(outline_color);
918 if (ctx->is_overlay_next()) {
919 ctx->bone_buf->custom_shape_outline_get_buffer(edges).append(inst_data, select_id);
920 }
921#ifndef NO_LEGACY_OVERLAY
922 else if (ctx->custom_outline) {
923 buf = custom_bone_instance_shgroup(ctx, ctx->custom_outline, edges);
924 DRW_buffer_add_entry_struct(buf, inst_data.mat);
925 }
926#endif
927 }
928
929 if (loose_edges) {
930 inst_data.set_hint_color(outline_color);
931 inst_data.set_color(float4(UNPACK3(outline_color), wire_width / WIRE_WIDTH_COMPRESSION));
932 if (ctx->is_overlay_next()) {
933 ctx->bone_buf->custom_shape_wire_get_buffer(loose_edges).append(inst_data, select_id);
934 }
935#ifndef NO_LEGACY_OVERLAY
936 else {
937 buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, loose_edges);
938 DRW_buffer_add_entry_struct(buf, inst_data.mat);
939 }
940#endif
941 }
942
943 /* TODO(fclem): needs to be moved elsewhere. */
945}
946
948 Mesh &mesh,
949 const float (*bone_mat)[4],
950 const float color[4],
951 const float wire_width,
952 const draw::select::ID select_id,
953 Object &custom)
954{
955 using namespace blender::draw;
956 /* TODO(fclem): arg... less than ideal but we never iter on this object
957 * to assure batch cache is valid. */
958 DRW_mesh_batch_cache_validate(custom, mesh);
959
960 blender::gpu::Batch *geom = DRW_mesh_batch_cache_get_all_edges(mesh);
961 if (geom) {
962 BoneInstanceData inst_data;
963 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(bone_mat);
964 inst_data.set_hint_color(color);
965 inst_data.set_color(float4(UNPACK3(color), wire_width / WIRE_WIDTH_COMPRESSION));
966
967 if (ctx->is_overlay_next()) {
968 ctx->bone_buf->custom_shape_wire_get_buffer(geom).append(inst_data, select_id);
969 }
970#ifndef NO_LEGACY_OVERLAY
971 else {
973 DRW_buffer_add_entry_struct(buf, inst_data.mat);
974 }
975#endif
976 }
977
978 /* TODO(fclem): needs to be moved elsewhere. */
980}
981
983 Curve *curve,
984 const float (*bone_mat)[4],
985 const float outline_color[4],
986 const float wire_width,
987 const draw::select::ID select_id,
988 Object *custom)
989{
990 using namespace blender::draw;
991 /* TODO(fclem): arg... less than ideal but we never iter on this object
992 * to assure batch cache is valid. */
993 DRW_curve_batch_cache_validate(curve);
994
995 /* This only handles curves without any surface. The other curve types should have been converted
996 * to meshes and rendered in the mesh drawing function. */
997 blender::gpu::Batch *loose_edges = nullptr;
998 if (custom->type == OB_FONT) {
999 loose_edges = DRW_cache_text_edge_wire_get(custom);
1000 }
1001 else {
1002 loose_edges = DRW_cache_curve_edge_wire_get(custom);
1003 }
1004
1005 if (loose_edges) {
1006 BoneInstanceData inst_data;
1007 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(bone_mat);
1008 inst_data.set_hint_color(outline_color);
1009 inst_data.set_color(float4(UNPACK3(outline_color), wire_width / WIRE_WIDTH_COMPRESSION));
1010
1011 if (ctx->is_overlay_next()) {
1012 ctx->bone_buf->custom_shape_wire_get_buffer(loose_edges).append(inst_data, select_id);
1013 }
1014#ifndef NO_LEGACY_OVERLAY
1015 else {
1016 DRWCallBuffer *buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, loose_edges);
1017 DRW_buffer_add_entry_struct(buf, inst_data.mat);
1018 }
1019#endif
1020 }
1021
1022 /* TODO(fclem): needs to be moved elsewhere. */
1024}
1025
1027 const float (*bone_mat)[4],
1028 const float bone_color[4],
1029 const float hint_color[4],
1030 const float outline_color[4],
1031 const float wire_width,
1032 const draw::select::ID select_id,
1033 Object *custom)
1034{
1035 /* The custom object is not an evaluated object, so its object->data field hasn't been replaced
1036 * by #data_eval. This is bad since it gives preference to an object's evaluated mesh over any
1037 * other data type, but supporting all evaluated geometry components would require a much
1038 * larger refactor of this area. */
1040 if (mesh != nullptr) {
1042 *mesh,
1043 bone_mat,
1044 bone_color,
1045 hint_color,
1046 outline_color,
1047 wire_width,
1048 select_id,
1049 *custom);
1050 return;
1051 }
1052
1053 if (ELEM(custom->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) {
1055 static_cast<Curve *>(custom->data),
1056 bone_mat,
1057 outline_color,
1058 wire_width,
1059 select_id,
1060 custom);
1061 }
1062}
1063
1065 const float (*bone_mat)[4],
1066 const float color[4],
1067 const float wire_width,
1068 const draw::select::ID select_id,
1069 Object *custom)
1070{
1071 /* See comments in #drw_shgroup_bone_custom_solid. */
1073 if (mesh != nullptr) {
1074 drw_shgroup_bone_custom_mesh_wire(ctx, *mesh, bone_mat, color, wire_width, select_id, *custom);
1075 return;
1076 }
1077
1078 if (ELEM(custom->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) {
1080 ctx, static_cast<Curve *>(custom->data), bone_mat, color, wire_width, select_id, custom);
1081 }
1082}
1083
1085 const float (*bone_mat)[4],
1086 const float color[4],
1087 const float wire_width,
1088 const draw::select::ID select_id,
1089 Object *custom)
1090{
1091 using namespace blender::draw;
1092
1093 if (ctx->is_overlay_next()) {
1094 gpu::Batch *geom = nullptr;
1095 switch (custom->empty_drawtype) {
1096 case OB_PLAINAXES:
1097 geom = ctx->shapes->plain_axes.get();
1098 break;
1099 case OB_SINGLE_ARROW:
1100 geom = ctx->shapes->single_arrow.get();
1101 break;
1102 case OB_CUBE:
1103 geom = ctx->shapes->cube.get();
1104 break;
1105 case OB_CIRCLE:
1106 geom = ctx->shapes->circle.get();
1107 break;
1108 case OB_EMPTY_SPHERE:
1109 geom = ctx->shapes->empty_sphere.get();
1110 break;
1111 case OB_EMPTY_CONE:
1112 geom = ctx->shapes->empty_cone.get();
1113 break;
1114 case OB_ARROWS:
1115 geom = ctx->shapes->arrows.get();
1116 break;
1117 case OB_EMPTY_IMAGE:
1118 /* Not supported. */
1119 return;
1120 }
1121 BLI_assert(geom);
1122
1123 const float4 final_color(UNPACK3(color), 1.0f);
1124
1125 BoneInstanceData inst_data;
1126 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(bone_mat);
1127 inst_data.set_hint_color(final_color);
1128 inst_data.set_color(float4(UNPACK3(final_color), wire_width / WIRE_WIDTH_COMPRESSION));
1129
1130 ctx->bone_buf->custom_shape_wire_get_buffer(geom).append(inst_data, select_id);
1131 return;
1132 }
1133
1134#ifndef NO_LEGACY_OVERLAY
1135 const float4 final_color(UNPACK3(color), 1.0f);
1136 const float4x4 mat = ctx->ob->object_to_world() * float4x4(bone_mat);
1137
1138 switch (custom->empty_drawtype) {
1139 case OB_PLAINAXES:
1140 case OB_SINGLE_ARROW:
1141 case OB_CUBE:
1142 case OB_CIRCLE:
1143 case OB_EMPTY_SPHERE:
1144 case OB_EMPTY_CONE:
1145 case OB_ARROWS:
1147 ctx->extras, mat.ptr(), custom->empty_drawsize, custom->empty_drawtype, final_color);
1148 break;
1149 case OB_EMPTY_IMAGE:
1150 break;
1151 }
1152#endif
1153}
1154
1155/* Head and tail sphere */
1157 const float (*bone_mat)[4],
1158 const float bone_color[4],
1159 const float hint_color[4],
1160 const float outline_color[4],
1161 const int select_id)
1162{
1163 auto sel_id = (ctx->bone_buf) ? ctx->res->select_id(*ctx->ob_ref, select_id) :
1165 float4x4 mat = ctx->ob->object_to_world() * float4x4(bone_mat);
1166
1167 if (ctx->is_overlay_next()) {
1168 if (ctx->is_filled) {
1169 ctx->bone_buf->sphere_fill_buf.append({mat, bone_color, hint_color}, sel_id);
1170 }
1171 if (outline_color[3] > 0.0f) {
1172 ctx->bone_buf->sphere_outline_buf.append({mat, outline_color}, sel_id);
1173 }
1174 return;
1175 }
1176
1177#ifndef NO_LEGACY_OVERLAY
1178 BoneInstanceData inst_data;
1179 inst_data.mat44 = mat;
1180
1181 if (ctx->point_solid) {
1182 OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
1183 OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
1184 DRW_buffer_add_entry_struct(ctx->point_solid, &inst_data);
1185 }
1186 if (outline_color[3] > 0.0f) {
1187 OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
1189 }
1190#endif
1191}
1192
1193/* Axes */
1195 const float (*bone_mat)[4],
1196 const float color[4])
1197{
1198 float4x4 mat = ctx->ob->object_to_world() * float4x4(bone_mat);
1199 /* Move to bone tail. */
1200 mat[3] += mat[1];
1201 if (ctx->is_overlay_next()) {
1202 ExtraInstanceData data(mat, color, 0.25f);
1203 /* NOTE: Axes are not drawn in bone selection (pose or edit mode).
1204 * They are only drawn and selectable in object mode. So only load the object select ID. */
1205 ctx->bone_buf->arrows_buf.append(data, ctx->res->select_id(*ctx->ob_ref));
1206 return;
1207 }
1208#ifndef NO_LEGACY_OVERLAY
1209 OVERLAY_empty_shape(ctx->extras, mat.ptr(), 0.25f, OB_ARROWS, color);
1210#endif
1211}
1212
1213/* Relationship lines */
1215 const float start[3],
1216 const float end[3],
1217 const float color[4])
1218{
1219 float3 start_pt = math::transform_point(ctx->ob->object_to_world(), float3(start));
1220 float3 end_pt = math::transform_point(ctx->ob->object_to_world(), float3(end));
1221
1222 if (ctx->is_overlay_next()) {
1223 /* reverse order to have less stipple overlap */
1224 ctx->bone_buf->relations_buf.append(start_pt, end_pt, float4(color));
1225 }
1226#ifndef NO_LEGACY_OVERLAY
1227 else {
1228 /* reverse order to have less stipple overlap */
1229 OVERLAY_extra_line_dashed(ctx->extras, start_pt, end_pt, color);
1230 }
1231#endif
1232}
1233
1235 const float start[3],
1236 const float end[3])
1237{
1239}
1240
1242 const float start[3],
1243 const float end[3])
1244{
1246}
1247
1249 const float start[3],
1250 const float end[3])
1251{
1253 ctx, start, end, G_draw.block.color_bone_ik_line_no_target);
1254}
1255
1257 const float start[3],
1258 const float end[3])
1259{
1261}
1262
1265/* -------------------------------------------------------------------- */
1272/* This function sets the color-set for coloring a certain bone */
1274{
1275 bArmature *arm = static_cast<bArmature *>(ctx->ob->data);
1276
1277 if ((arm->flag & ARM_COL_CUSTOM) == 0) {
1278 /* Only set a custom color if that's enabled on this armature. */
1279 ctx->bcolor = nullptr;
1280 return;
1281 }
1282
1283 const blender::animrig::BoneColor &bone_color = bone.effective_bonecolor();
1284 ctx->bcolor = bone_color.effective_color();
1285}
1286
1287/* This function is for brightening/darkening a given color (like UI_GetThemeColorShade3ubv()) */
1288static void cp_shade_color3ub(uchar cp[3], const int offset)
1289{
1290 int r, g, b;
1291
1292 r = offset + int(cp[0]);
1293 CLAMP(r, 0, 255);
1294 g = offset + int(cp[1]);
1295 CLAMP(g, 0, 255);
1296 b = offset + int(cp[2]);
1297 CLAMP(b, 0, 255);
1298
1299 cp[0] = r;
1300 cp[1] = g;
1301 cp[2] = b;
1302}
1303
1309static void use_bone_color(float *r_color, const uint8_t *color_from_theme, const int shade_offset)
1310{
1311 uint8_t srgb_color[4] = {255, 255, 255, 255};
1312 /* Only copy RGB, not alpha. The "alpha" channel in the bone theme colors is
1313 * essentially just padding, and should be ignored. */
1314 copy_v3_v3_uchar(srgb_color, color_from_theme);
1315 if (shade_offset != 0) {
1316 cp_shade_color3ub(srgb_color, shade_offset);
1317 }
1318 rgba_uchar_to_float(r_color, srgb_color);
1319 /* Meh, hardcoded srgb transform here. */
1320 srgb_to_linearrgb_v4(r_color, r_color);
1321};
1322
1323static void get_pchan_color_wire(const ThemeWireColor *bcolor,
1324 const eArmatureDrawMode draw_mode,
1325 const eBone_Flag boneflag,
1326 float r_color[4])
1327{
1328 const bool draw_active = boneflag & BONE_DRAW_ACTIVE;
1329 const bool draw_selected = boneflag & BONE_SELECTED;
1330 const bool is_edit = draw_mode == ARM_DRAW_MODE_EDIT;
1331 float4 wire_color;
1332
1333 if (bcolor) {
1334 if (draw_active && draw_selected) {
1335 use_bone_color(r_color, bcolor->active, 0);
1336 }
1337 else if (draw_active) {
1338 use_bone_color(r_color, bcolor->active, -80);
1339 }
1340 else if (draw_selected) {
1341 use_bone_color(r_color, bcolor->select, 0);
1342 }
1343 else {
1344 use_bone_color(r_color, bcolor->solid, -50);
1345 }
1346 }
1347 else {
1348 if (draw_active && draw_selected) {
1350 }
1351 else if (draw_active) {
1352 wire_color = is_edit ? G_draw.block.color_bone_active_unsel :
1354 }
1355 else if (draw_selected) {
1356 wire_color = is_edit ? G_draw.block.color_bone_select : G_draw.block.color_bone_pose;
1357 }
1358 else {
1359 wire_color = is_edit ? G_draw.block.color_wire_edit : G_draw.block.color_wire;
1360 }
1361 copy_v4_v4(r_color, wire_color);
1362 }
1363}
1364
1365static void get_pchan_color_solid(const ThemeWireColor *bcolor, float r_color[4])
1366{
1367
1368 if (bcolor) {
1369 use_bone_color(r_color, bcolor->solid, 0);
1370 }
1371 else {
1373 }
1374}
1375
1377 const UnifiedBonePtr bone,
1378 float r_color[4])
1379{
1380 const ePchan_ConstFlag constflag = bone.constflag();
1381 /* Not all flags should result in a different bone color. */
1384 if ((constflag & flags_to_color) == 0 ||
1385 (bcolor && (bcolor->flag & TH_WIRECOLOR_CONSTCOLS) == 0))
1386 {
1387 get_pchan_color_solid(bcolor, r_color);
1388 return;
1389 }
1390
1391 /* The constraint color needs to be blended with the solid color. */
1392 float solid_color[4];
1393 get_pchan_color_solid(bcolor, solid_color);
1394
1395 float4 constraint_color;
1396 if (constflag & PCHAN_HAS_NO_TARGET) {
1397 constraint_color = G_draw.block.color_bone_pose_no_target;
1398 }
1399 else if (constflag & PCHAN_HAS_IK) {
1400 constraint_color = G_draw.block.color_bone_pose_ik;
1401 }
1402 else if (constflag & PCHAN_HAS_SPLINEIK) {
1403 constraint_color = G_draw.block.color_bone_pose_spline_ik;
1404 }
1405 else if (constflag & PCHAN_HAS_CONST) {
1406 constraint_color = G_draw.block.color_bone_pose_constraint;
1407 }
1408 interp_v4_v4v4(r_color, solid_color, constraint_color, 0.5f);
1409}
1410
1413/* -------------------------------------------------------------------- */
1417static void bone_locked_color_shade(float color[4])
1418{
1419 float *locked_color = G_draw.block.color_bone_locked;
1420
1421 interp_v3_v3v3(color, color, locked_color, locked_color[3]);
1422}
1423
1424static const float *get_bone_solid_color(const Armatures::DrawContext *ctx,
1425 const eBone_Flag boneflag)
1426{
1427 if (ctx->const_color) {
1429 }
1430
1431 static float disp_color[4];
1432 get_pchan_color_solid(ctx->bcolor, disp_color);
1433
1434 if (ctx->draw_mode == ARM_DRAW_MODE_POSE && (boneflag & BONE_DRAW_LOCKED_WEIGHT)) {
1435 bone_locked_color_shade(disp_color);
1436 }
1437
1438 return disp_color;
1439}
1440
1442 const UnifiedBonePtr bone,
1443 const eBone_Flag boneflag)
1444{
1445 if (ctx->const_color) {
1447 }
1448
1449 const float *col = get_bone_solid_color(ctx, boneflag);
1450
1451 if (ctx->draw_mode != ARM_DRAW_MODE_POSE || (boneflag & BONE_DRAW_LOCKED_WEIGHT)) {
1452 return col;
1453 }
1454
1455 static float consts_color[4];
1456 get_pchan_color_constraint(ctx->bcolor, bone, consts_color);
1457 return consts_color;
1458}
1459
1460static float get_bone_wire_thickness(const Armatures::DrawContext *ctx, int boneflag)
1461{
1462 if (ctx->const_color) {
1463 return ctx->const_wire;
1464 }
1465 if (boneflag & (BONE_DRAW_ACTIVE | BONE_SELECTED)) {
1466 return 2.0f;
1467 }
1468
1469 return 1.0f;
1470}
1471
1472static const float *get_bone_wire_color(const Armatures::DrawContext *ctx,
1473 const eBone_Flag boneflag)
1474{
1475 static float disp_color[4];
1476
1477 if (ctx->const_color) {
1478 copy_v3_v3(disp_color, ctx->const_color);
1479 }
1480 else {
1481 switch (ctx->draw_mode) {
1482 case ARM_DRAW_MODE_EDIT:
1483 get_pchan_color_wire(ctx->bcolor, ctx->draw_mode, boneflag, disp_color);
1484 break;
1485 case ARM_DRAW_MODE_POSE:
1486 get_pchan_color_wire(ctx->bcolor, ctx->draw_mode, boneflag, disp_color);
1487
1488 if (boneflag & BONE_DRAW_LOCKED_WEIGHT) {
1489 bone_locked_color_shade(disp_color);
1490 }
1491 break;
1493 copy_v3_v3(disp_color, G_draw.block.color_vertex);
1494 break;
1495 }
1496 }
1497
1498 disp_color[3] = get_bone_wire_thickness(ctx, boneflag);
1499
1500 return disp_color;
1501}
1502
1503static void bone_hint_color_shade(float hint_color[4], const float color[4])
1504{
1505 /* Increase contrast. */
1506 mul_v3_v3v3(hint_color, color, color);
1507 /* Decrease value to add mode shading to the shape. */
1508 mul_v3_fl(hint_color, 0.1f);
1509 hint_color[3] = 1.0f;
1510}
1511
1512static const float *get_bone_hint_color(const Armatures::DrawContext *ctx,
1513 const eBone_Flag boneflag)
1514{
1515 static float hint_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
1516
1517 if (ctx->const_color) {
1519 }
1520 else {
1521 const float *wire_color = get_bone_wire_color(ctx, boneflag);
1522 bone_hint_color_shade(hint_color, wire_color);
1523 }
1524
1525 return hint_color;
1526}
1527
1530/* -------------------------------------------------------------------- */
1535{
1536 if (pchan->draw_data != nullptr) {
1537 if (pchan->draw_data->bbone_matrix_len != pchan->bone->segments) {
1538 MEM_SAFE_FREE(pchan->draw_data);
1539 }
1540 }
1541
1542 if (pchan->draw_data == nullptr) {
1543 pchan->draw_data = static_cast<bPoseChannelDrawData *>(
1544 MEM_mallocN(sizeof(*pchan->draw_data) + sizeof(Mat4) * pchan->bone->segments, __func__));
1545 pchan->draw_data->bbone_matrix_len = pchan->bone->segments;
1546 }
1547}
1548
1550{
1551 float ebmat[4][4];
1552 float bone_scale[3];
1553 float(*bone_mat)[4];
1554 float(*disp_mat)[4] = bone.disp_mat();
1555 float(*disp_tail_mat)[4] = bone.disp_tail_mat();
1556
1557 /* TODO: This should be moved to depsgraph or armature refresh
1558 * and not be tight to the draw pass creation.
1559 * This would refresh armature without invalidating the draw cache */
1560 if (bone.is_posebone()) {
1561 bPoseChannel *pchan = bone.as_posebone();
1562 bone_mat = pchan->pose_mat;
1563 copy_v3_fl(bone_scale, pchan->bone->length);
1564 }
1565 else {
1566 EditBone *eBone = bone.as_editbone();
1567 eBone->length = len_v3v3(eBone->tail, eBone->head);
1568 ED_armature_ebone_to_mat4(eBone, ebmat);
1569
1570 copy_v3_fl(bone_scale, eBone->length);
1571 bone_mat = ebmat;
1572 }
1573
1574 copy_m4_m4(disp_mat, bone_mat);
1575 rescale_m4(disp_mat, bone_scale);
1576 copy_m4_m4(disp_tail_mat, disp_mat);
1577 translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
1578}
1579
1580/* compute connected child pointer for B-Bone drawing */
1582{
1583 LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
1584 eBone->bbone_child = nullptr;
1585 }
1586
1587 LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
1588 if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
1589 eBone->parent->bbone_child = eBone;
1590 }
1591 }
1592}
1593
1594/* A version of BKE_pchan_bbone_spline_setup() for previewing editmode curve settings. */
1595static void ebone_spline_preview(EditBone *ebone, const float result_array[MAX_BBONE_SUBDIV][4][4])
1596{
1598 EditBone *prev, *next;
1599 float imat[4][4], bonemat[4][4];
1600 float tmp[3];
1601
1602 memset(&param, 0, sizeof(param));
1603
1604 param.segments = ebone->segments;
1605 param.length = ebone->length;
1606
1607 /* Get "next" and "prev" bones - these are used for handle calculations. */
1608 if (ebone->bbone_prev_type == BBONE_HANDLE_AUTO) {
1609 /* Use connected parent. */
1610 if (ebone->flag & BONE_CONNECTED) {
1611 prev = ebone->parent;
1612 }
1613 else {
1614 prev = nullptr;
1615 }
1616 }
1617 else {
1618 prev = ebone->bbone_prev;
1619 }
1620
1621 if (ebone->bbone_next_type == BBONE_HANDLE_AUTO) {
1622 /* Use connected child. */
1623 next = ebone->bbone_child;
1624 }
1625 else {
1626 next = ebone->bbone_next;
1627 }
1628
1629 /* compute handles from connected bones */
1630 if (prev || next) {
1631 ED_armature_ebone_to_mat4(ebone, imat);
1632 invert_m4(imat);
1633
1634 if (prev) {
1635 param.use_prev = true;
1636
1637 if (ebone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
1638 zero_v3(param.prev_h);
1639 }
1640 else if (ebone->bbone_prev_type == BBONE_HANDLE_TANGENT) {
1641 sub_v3_v3v3(tmp, prev->tail, prev->head);
1642 sub_v3_v3v3(tmp, ebone->head, tmp);
1643 mul_v3_m4v3(param.prev_h, imat, tmp);
1644 }
1645 else {
1646 param.prev_bbone = (prev->segments > 1);
1647
1648 mul_v3_m4v3(param.prev_h, imat, prev->head);
1649 }
1650
1651 if (!param.prev_bbone) {
1652 ED_armature_ebone_to_mat4(prev, bonemat);
1653 mul_m4_m4m4(param.prev_mat, imat, bonemat);
1654 }
1655 }
1656
1657 if (next) {
1658 param.use_next = true;
1659
1660 if (ebone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
1661 copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0);
1662 }
1663 else if (ebone->bbone_next_type == BBONE_HANDLE_TANGENT) {
1664 sub_v3_v3v3(tmp, next->tail, next->head);
1665 add_v3_v3v3(tmp, ebone->tail, tmp);
1666 mul_v3_m4v3(param.next_h, imat, tmp);
1667 }
1668 else {
1669 param.next_bbone = (next->segments > 1);
1670
1671 mul_v3_m4v3(param.next_h, imat, next->tail);
1672 }
1673
1675 mul_m4_m4m4(param.next_mat, imat, bonemat);
1676 }
1677 }
1678
1679 param.ease1 = ebone->ease1;
1680 param.ease2 = ebone->ease2;
1681 param.roll1 = ebone->roll1;
1682 param.roll2 = ebone->roll2;
1683
1684 if (prev && (ebone->bbone_flag & BBONE_ADD_PARENT_END_ROLL)) {
1685 param.roll1 += prev->roll2;
1686 }
1687
1688 copy_v3_v3(param.scale_in, ebone->scale_in);
1689 copy_v3_v3(param.scale_out, ebone->scale_out);
1690
1691 param.curve_in_x = ebone->curve_in_x;
1692 param.curve_in_z = ebone->curve_in_z;
1693
1694 param.curve_out_x = ebone->curve_out_x;
1695 param.curve_out_z = ebone->curve_out_z;
1696
1697 if (ebone->bbone_flag & BBONE_SCALE_EASING) {
1698 param.ease1 *= param.scale_in[1];
1699 param.curve_in_x *= param.scale_in[1];
1700 param.curve_in_z *= param.scale_in[1];
1701
1702 param.ease2 *= param.scale_out[1];
1703 param.curve_out_x *= param.scale_out[1];
1704 param.curve_out_z *= param.scale_out[1];
1705 }
1706
1707 ebone->segments = BKE_pchan_bbone_spline_compute(&param, false, (Mat4 *)result_array);
1708}
1709
1710/* This function is used for both B-Bone and Wire matrix updates. */
1712{
1713 float s[4][4], ebmat[4][4];
1714 float length, xwidth, zwidth;
1715 float(*bone_mat)[4];
1716 short bbone_segments;
1717
1718 /* TODO: This should be moved to depsgraph or armature refresh
1719 * and not be tight to the draw pass creation.
1720 * This would refresh armature without invalidating the draw cache. */
1721 if (bone.is_posebone()) {
1722 bPoseChannel *pchan = bone.as_posebone();
1723 length = pchan->bone->length;
1724 xwidth = pchan->bone->xwidth;
1725 zwidth = pchan->bone->zwidth;
1726 bone_mat = pchan->pose_mat;
1727 bbone_segments = pchan->bone->segments;
1728 }
1729 else {
1730 EditBone *eBone = bone.as_editbone();
1731 eBone->length = len_v3v3(eBone->tail, eBone->head);
1732 ED_armature_ebone_to_mat4(eBone, ebmat);
1733
1734 length = eBone->length;
1735 xwidth = eBone->xwidth;
1736 zwidth = eBone->zwidth;
1737 bone_mat = ebmat;
1738 bbone_segments = eBone->segments;
1739 }
1740
1741 const float3 size_vec = {xwidth, length / bbone_segments, zwidth};
1742 size_to_mat4(s, size_vec);
1743
1744 /* Compute BBones segment matrices... */
1745 /* Note that we need this even for one-segment bones, because box drawing need specific weirdo
1746 * matrix for the box, that we cannot use to draw end points & co. */
1747 if (bone.is_posebone()) {
1748 bPoseChannel *pchan = bone.as_posebone();
1749 Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
1750 if (bbone_segments > 1) {
1751 BKE_pchan_bbone_spline_setup(pchan, false, false, bbones_mat);
1752
1753 for (int i = bbone_segments; i--; bbones_mat++) {
1754 mul_m4_m4m4(bbones_mat->mat, bbones_mat->mat, s);
1755 mul_m4_m4m4(bbones_mat->mat, bone_mat, bbones_mat->mat);
1756 }
1757 }
1758 else {
1759 mul_m4_m4m4(bbones_mat->mat, bone_mat, s);
1760 }
1761 }
1762 else {
1763 EditBone *eBone = bone.as_editbone();
1764 float(*bbones_mat)[4][4] = eBone->disp_bbone_mat;
1765
1766 if (bbone_segments > 1) {
1767 ebone_spline_preview(eBone, bbones_mat);
1768
1769 for (int i = bbone_segments; i--; bbones_mat++) {
1770 mul_m4_m4m4(*bbones_mat, *bbones_mat, s);
1771 mul_m4_m4m4(*bbones_mat, bone_mat, *bbones_mat);
1772 }
1773 }
1774 else {
1775 mul_m4_m4m4(*bbones_mat, bone_mat, s);
1776 }
1777 }
1778
1779 /* Grrr... We need default display matrix to draw end points, axes, etc. :( */
1781}
1782
1783static void draw_axes(const Armatures::DrawContext *ctx,
1784 const UnifiedBonePtr bone,
1785 const bArmature *arm)
1786{
1787 float final_col[4];
1788 const float *col = (ctx->const_color) ? ctx->const_color :
1789 (bone.flag() & BONE_SELECTED) ? &G_draw.block.color_text_hi.x :
1791 copy_v4_v4(final_col, col);
1792 /* Mix with axes color. */
1793 final_col[3] = (ctx->const_color) ? 1.0 : (bone.flag() & BONE_SELECTED) ? 0.1 : 0.65;
1794
1795 if (bone.is_posebone() && bone.as_posebone()->custom && !(arm->flag & ARM_NO_CUSTOM)) {
1796 const bPoseChannel *pchan = bone.as_posebone();
1797 /* Special case: Custom bones can have different scale than the bone.
1798 * Recompute display matrix without the custom scaling applied. (#65640). */
1799 float axis_mat[4][4];
1800 float length = pchan->bone->length;
1801 copy_m4_m4(axis_mat, pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat);
1802 const float3 length_vec = {length, length, length};
1803 rescale_m4(axis_mat, length_vec);
1804 translate_m4(axis_mat, 0.0, arm->axes_position - 1.0, 0.0);
1805
1806 drw_shgroup_bone_axes(ctx, axis_mat, final_col);
1807 }
1808 else {
1809 float disp_mat[4][4];
1810 copy_m4_m4(disp_mat, bone.disp_mat());
1811 translate_m4(disp_mat, 0.0, arm->axes_position - 1.0, 0.0);
1812 drw_shgroup_bone_axes(ctx, disp_mat, final_col);
1813 }
1814}
1815
1817 const UnifiedBonePtr bone,
1818 const eBone_Flag boneflag,
1819 const float col_solid[4],
1820 const int select_id)
1821{
1822 float col_wire_root[4], col_wire_tail[4];
1823 float col_hint_root[4], col_hint_tail[4];
1824
1825 copy_v4_v4(col_wire_root, (ctx->const_color) ? ctx->const_color : &G_draw.block.color_vertex.x);
1826 copy_v4_v4(col_wire_tail, (ctx->const_color) ? ctx->const_color : &G_draw.block.color_vertex.x);
1827
1828 const bool is_envelope_draw = (ctx->drawtype == ARM_ENVELOPE);
1829 const float envelope_ignore = -1.0f;
1830
1831 col_wire_tail[3] = col_wire_root[3] = get_bone_wire_thickness(ctx, boneflag);
1832
1833 /* Edit bone points can be selected */
1834 if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
1835 const EditBone *eBone = bone.as_editbone();
1836 if (eBone->flag & BONE_ROOTSEL) {
1838 }
1839 if (eBone->flag & BONE_TIPSEL) {
1841 }
1842 }
1843 else if (ctx->draw_mode == ARM_DRAW_MODE_POSE) {
1844 const float *wire_color = get_bone_wire_color(ctx, boneflag);
1845 copy_v4_v4(col_wire_tail, wire_color);
1846 copy_v4_v4(col_wire_root, wire_color);
1847 }
1848
1849 const float *hint_color_shade_root = (ctx->const_color) ?
1850 (const float *)G_draw.block.color_bone_solid :
1851 col_wire_root;
1852 const float *hint_color_shade_tail = (ctx->const_color) ?
1853 (const float *)G_draw.block.color_bone_solid :
1854 col_wire_tail;
1855 bone_hint_color_shade(col_hint_root, hint_color_shade_root);
1856 bone_hint_color_shade(col_hint_tail, hint_color_shade_tail);
1857
1858 /* Draw root point if we are not connected to our parent */
1859
1860 if (!(bone.has_parent() && (boneflag & BONE_CONNECTED))) {
1861#ifndef NO_LEGACY_OVERLAY
1862 if (!ctx->is_overlay_next() && select_id != -1) {
1863 DRW_select_load_id(select_id | BONESEL_ROOT);
1864 }
1865#endif
1866
1867 if (is_envelope_draw) {
1869 bone.disp_mat(),
1870 col_solid,
1871 col_hint_root,
1872 col_wire_root,
1873 &bone.rad_head(),
1874 &envelope_ignore,
1875 select_id | BONESEL_ROOT);
1876 }
1877 else {
1879 ctx, bone.disp_mat(), col_solid, col_hint_root, col_wire_root, select_id | BONESEL_ROOT);
1880 }
1881 }
1882
1883 /* Draw tip point */
1884#ifndef NO_LEGACY_OVERLAY
1885 if (!ctx->is_overlay_next() && select_id != -1) {
1886 DRW_select_load_id(select_id | BONESEL_TIP);
1887 }
1888#endif
1889
1890 if (is_envelope_draw) {
1892 bone.disp_mat(),
1893 col_solid,
1894 col_hint_tail,
1895 col_wire_tail,
1896 &envelope_ignore,
1897 &bone.rad_tail(),
1898 select_id | BONESEL_TIP);
1899 }
1900 else {
1902 bone.disp_tail_mat(),
1903 col_solid,
1904 col_hint_tail,
1905 col_wire_tail,
1906 select_id | BONESEL_TIP);
1907 }
1908
1909#ifndef NO_LEGACY_OVERLAY
1910 if (!ctx->is_overlay_next() && select_id != -1) {
1912 }
1913#endif
1914}
1915
1918/* -------------------------------------------------------------------- */
1923 const bPoseChannel *pchan)
1924{
1925 BoneInstanceData inst_data;
1926 float tmp[4][4], posetrans[4][4];
1927 float xminmax[2], zminmax[2];
1928 float color[4];
1929
1930 /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
1931 xminmax[0] = sinf(pchan->limitmin[0] * 0.5f);
1932 xminmax[1] = sinf(pchan->limitmax[0] * 0.5f);
1933 zminmax[0] = sinf(pchan->limitmin[2] * 0.5f);
1934 zminmax[1] = sinf(pchan->limitmax[2] * 0.5f);
1935
1936 unit_m4(posetrans);
1937 translate_m4(posetrans, pchan->pose_mat[3][0], pchan->pose_mat[3][1], pchan->pose_mat[3][2]);
1938 /* In parent-bone pose space... */
1939 if (pchan->parent) {
1940 copy_m4_m4(tmp, pchan->parent->pose_mat);
1941 zero_v3(tmp[3]);
1942 mul_m4_m4m4(posetrans, posetrans, tmp);
1943 }
1944 /* ... but its own rest-space. */
1945 mul_m4_m4m3(posetrans, posetrans, pchan->bone->bone_mat);
1946
1947 float scale = pchan->bone->length * pchan->size[1];
1948 scale_m4_fl(tmp, scale);
1949 tmp[1][1] = -tmp[1][1];
1950 mul_m4_m4m4(posetrans, posetrans, tmp);
1951
1952 /* into world space. */
1953 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(posetrans);
1954
1955 /* Not selectable. */
1957
1958 if ((pchan->ikflag & BONE_IK_XLIMIT) && (pchan->ikflag & BONE_IK_ZLIMIT)) {
1959 if (ctx->is_overlay_next()) {
1961 inst_data.mat44, float4(0.25f), xminmax[0], zminmax[0], xminmax[1], zminmax[1]);
1962
1963 ctx->bone_buf->degrees_of_freedom_fill_buf.append(data, sel_id);
1964 ctx->bone_buf->degrees_of_freedom_wire_buf.append(data.with_color({0.0f, 0.0f, 0.0f, 1.0f}),
1965 sel_id);
1966 }
1967#ifndef NO_LEGACY_OVERLAY
1968 else if (ctx->dof_sphere) {
1970 &inst_data, xminmax[0], zminmax[0], xminmax[1], zminmax[1]);
1971 copy_v4_fl4(color, 0.25f, 0.25f, 0.25f, 0.25f);
1972 DRW_buffer_add_entry(ctx->dof_sphere, color, &inst_data);
1973
1974 copy_v4_fl4(color, 0.0f, 0.0f, 0.0f, 1.0f);
1975 DRW_buffer_add_entry(ctx->dof_lines, color, &inst_data);
1976 }
1977#endif
1978 }
1979 if (pchan->ikflag & BONE_IK_XLIMIT) {
1980 if (ctx->is_overlay_next()) {
1982 inst_data.mat44, float4(1.0f, 0.0f, 0.0f, 1.0f), xminmax[0], 0.0f, xminmax[1], 0.0f);
1983 ctx->bone_buf->degrees_of_freedom_wire_buf.append(data, sel_id);
1984 }
1985#ifndef NO_LEGACY_OVERLAY
1986 else if (ctx->dof_sphere) {
1987 bone_instance_data_set_angle_minmax(&inst_data, xminmax[0], 0.0f, xminmax[1], 0.0f);
1988 copy_v4_fl4(color, 1.0f, 0.0f, 0.0f, 1.0f);
1989 DRW_buffer_add_entry(ctx->dof_lines, color, &inst_data);
1990 }
1991#endif
1992 }
1993 if (pchan->ikflag & BONE_IK_ZLIMIT) {
1994 if (ctx->is_overlay_next()) {
1996 inst_data.mat44, float4(0.0f, 0.0f, 1.0f, 1.0f), 0.0f, zminmax[0], 0.0f, zminmax[1]);
1997 ctx->bone_buf->degrees_of_freedom_wire_buf.append(data, sel_id);
1998 }
1999#ifndef NO_LEGACY_OVERLAY
2000 else if (ctx->dof_sphere) {
2001 bone_instance_data_set_angle_minmax(&inst_data, 0.0f, zminmax[0], 0.0f, zminmax[1]);
2002 copy_v4_fl4(color, 0.0f, 0.0f, 1.0f, 1.0f);
2003 DRW_buffer_add_entry(ctx->dof_lines, color, &inst_data);
2004 }
2005#endif
2006 }
2007}
2008
2011/* -------------------------------------------------------------------- */
2016 const bPoseChannel *pchan,
2017 const bool only_temp)
2018{
2019 const bPoseChannel *parchan;
2020 const float *line_start = nullptr, *line_end = nullptr;
2021 const ePchan_ConstFlag constflag = ePchan_ConstFlag(pchan->constflag);
2022
2023 LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
2024 if (con->enforce == 0.0f) {
2025 continue;
2026 }
2027
2028 switch (con->type) {
2030 bKinematicConstraint *data = (bKinematicConstraint *)con->data;
2031 int segcount = 0;
2032
2033 /* if only_temp, only draw if it is a temporary ik-chain */
2034 if (only_temp && !(data->flag & CONSTRAINT_IK_TEMP)) {
2035 continue;
2036 }
2037
2038 /* exclude tip from chain? */
2039 parchan = ((data->flag & CONSTRAINT_IK_TIP) == 0) ? pchan->parent : pchan;
2040 line_start = parchan->pose_tail;
2041
2042 /* Find the chain's root */
2043 while (parchan->parent) {
2044 segcount++;
2045 if (segcount == data->rootbone || segcount > 255) {
2046 break; /* 255 is weak */
2047 }
2048 parchan = parchan->parent;
2049 }
2050
2051 if (parchan) {
2052 line_end = parchan->pose_head;
2053
2054 if (constflag & PCHAN_HAS_NO_TARGET) {
2055 drw_shgroup_bone_ik_no_target_lines(ctx, line_start, line_end);
2056 }
2057 else {
2058 drw_shgroup_bone_ik_lines(ctx, line_start, line_end);
2059 }
2060 }
2061 break;
2062 }
2064 bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
2065 int segcount = 0;
2066
2067 /* don't draw if only_temp, as Spline IK chains cannot be temporary */
2068 if (only_temp) {
2069 continue;
2070 }
2071
2072 parchan = pchan;
2073 line_start = parchan->pose_tail;
2074
2075 /* Find the chain's root */
2076 while (parchan->parent) {
2077 segcount++;
2078 /* FIXME: revise the breaking conditions */
2079 if (segcount == data->chainlen || segcount > 255) {
2080 break; /* 255 is weak */
2081 }
2082 parchan = parchan->parent;
2083 }
2084 /* Only draw line in case our chain is more than one bone long! */
2085 if (parchan != pchan) { /* XXX revise the breaking conditions to only stop at the tail? */
2086 line_end = parchan->pose_head;
2087 drw_shgroup_bone_ik_spline_lines(ctx, line_start, line_end);
2088 }
2089 break;
2090 }
2091 }
2092 }
2093}
2094
2096 const float bone_head[3],
2097 const float parent_head[3],
2098 const float parent_tail[3])
2099{
2100 if (ctx->draw_relation_from_head) {
2101 drw_shgroup_bone_relationship_lines(ctx, bone_head, parent_head);
2102 }
2103 else {
2104 drw_shgroup_bone_relationship_lines(ctx, bone_head, parent_tail);
2105 }
2106}
2107
2109 const ArmatureBoneDrawStrategy &draw_strategy,
2110 const UnifiedBonePtr bone,
2111 const eBone_Flag boneflag)
2112{
2113 if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
2114 const EditBone *ebone = bone.as_editbone();
2115 if (ebone->parent) {
2116 if (ctx->do_relations && draw_strategy.should_draw_relation_to_parent(bone, boneflag)) {
2118 ctx, ebone->head, ebone->parent->head, ebone->parent->tail);
2119 }
2120 }
2121 }
2122 else {
2123 const bPoseChannel *pchan = bone.as_posebone();
2124 if (pchan->parent) {
2125 if (ctx->do_relations && draw_strategy.should_draw_relation_to_parent(bone, boneflag)) {
2127 ctx, pchan->pose_head, pchan->parent->pose_head, pchan->parent->pose_tail);
2128 }
2129
2130 /* Draw a line to IK root bone if bone is selected. */
2131 if (ctx->draw_mode == ARM_DRAW_MODE_POSE) {
2132 if (pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK)) {
2133 if (boneflag & BONE_SELECTED) {
2134 pchan_draw_ik_lines(ctx, pchan, !ctx->do_relations);
2135 }
2136 }
2137 }
2138 }
2139 }
2140}
2141
2143 const UnifiedBonePtr bone,
2144 const eBone_Flag boneflag)
2145{
2147 uchar color[4];
2148 float vec[3];
2149
2150 const bool is_pose = bone.is_posebone();
2151 const EditBone *eBone = nullptr;
2152 const bPoseChannel *pchan = nullptr;
2153 bone.get(&eBone, &pchan);
2154
2155 /* TODO: make this look at `boneflag` only. */
2156 bool highlight = (is_pose && ctx->draw_mode == ARM_DRAW_MODE_POSE &&
2157 (boneflag & BONE_SELECTED)) ||
2158 (!is_pose && (eBone->flag & BONE_SELECTED));
2159
2160 /* Color Management: Exception here as texts are drawn in sRGB space directly. */
2161 UI_GetThemeColor4ubv(highlight ? TH_TEXT_HI : TH_TEXT, color);
2162
2163 const float *head = is_pose ? pchan->pose_head : eBone->head;
2164 const float *tail = is_pose ? pchan->pose_tail : eBone->tail;
2165 mid_v3_v3v3(vec, head, tail);
2166 mul_m4_v3(ctx->ob->object_to_world().ptr(), vec);
2167
2169 vec,
2170 is_pose ? pchan->name : eBone->name,
2171 is_pose ? strlen(pchan->name) : strlen(eBone->name),
2172 10,
2173 0,
2175 color,
2176 true);
2177}
2178
2181/* -------------------------------------------------------------------- */
2193 const bPoseChannel *pchan,
2194 BoundSphere *r_bsphere)
2195{
2196 float min[3], max[3];
2197 INIT_MINMAX(min, max);
2198 BKE_pchan_minmax(ob, pchan, true, min, max);
2199 mid_v3_v3v3(r_bsphere->center, min, max);
2200 r_bsphere->radius = len_v3v3(min, r_bsphere->center);
2201}
2202
2207static bool pchan_culling_test_simple(const DRWView *view,
2208 const Object *ob,
2209 const bPoseChannel *pchan)
2210{
2211 BoundSphere bsphere;
2212 pchan_culling_calc_bsphere(ob, pchan, &bsphere);
2213 return DRW_culling_sphere_test(view, &bsphere);
2214}
2215
2217 const Object *ob,
2218 const bPoseChannel *pchan,
2219 const float scale)
2220{
2221 BoundSphere bsphere;
2222 pchan_culling_calc_bsphere(ob, pchan, &bsphere);
2223 bsphere.radius *= scale;
2224 return DRW_culling_sphere_test(view, &bsphere);
2225}
2226
2229/* -------------------------------------------------------------------- */
2240 public:
2241 void update_display_matrix(UnifiedBonePtr bone) const override
2242 {
2244 }
2245
2246 bool culling_test(const DRWView * /*view*/,
2247 const Object * /*ob*/,
2248 const bPoseChannel * /*pchan*/) const override
2249 {
2250 return false;
2251 }
2252
2254 const OVERLAY_ArmatureCallBuffersInner * /*cb*/,
2255 const bool /*is_filled*/,
2256 const bool /*do_envelope_dist*/) const override
2257 {
2258 }
2259
2260 void draw_bone(const Armatures::DrawContext * /*ctx*/,
2261 const UnifiedBonePtr /*bone*/,
2262 const eBone_Flag /*boneflag*/,
2263 const int /*select_id*/) const override
2264 {
2265 }
2266};
2267
2270 public:
2271 void update_display_matrix(UnifiedBonePtr bone) const override
2272 {
2273 float bone_scale[3];
2274 float(*bone_mat)[4];
2275 float(*disp_mat)[4];
2276 float(*disp_tail_mat)[4];
2277 float rot_mat[3][3];
2278
2279 /* Custom bone shapes are only supported in pose mode for now. */
2280 bPoseChannel *pchan = bone.as_posebone();
2281
2282 /* TODO: This should be moved to depsgraph or armature refresh
2283 * and not be tight to the draw pass creation.
2284 * This would refresh armature without invalidating the draw cache. */
2285 mul_v3_v3fl(bone_scale, pchan->custom_scale_xyz, PCHAN_CUSTOM_BONE_LENGTH(pchan));
2286 bone_mat = pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat;
2287 disp_mat = bone.disp_mat();
2288 disp_tail_mat = pchan->disp_tail_mat;
2289
2291
2292 copy_m4_m4(disp_mat, bone_mat);
2293 translate_m4(disp_mat,
2294 pchan->custom_translation[0],
2295 pchan->custom_translation[1],
2296 pchan->custom_translation[2]);
2297 mul_m4_m4m3(disp_mat, disp_mat, rot_mat);
2298 rescale_m4(disp_mat, bone_scale);
2299 copy_m4_m4(disp_tail_mat, disp_mat);
2300 translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
2301 }
2302
2303 bool culling_test(const DRWView *view,
2304 const Object *ob,
2305 const bPoseChannel *pchan) const override
2306 {
2307 /* For more aggressive culling the bounding box of the custom-object could be used. */
2308 return pchan_culling_test_simple(view, ob, pchan);
2309 }
2310
2312 const OVERLAY_ArmatureCallBuffersInner * /*cb*/,
2313 const bool /*is_filled*/,
2314 const bool /*do_envelope_dist*/) const override
2315 {
2316 }
2317
2319 const UnifiedBonePtr bone,
2320 const eBone_Flag boneflag,
2321 const int select_id) const override
2322 {
2323 const float *col_solid = get_bone_solid_color(ctx, boneflag);
2324 const float *col_wire = get_bone_wire_color(ctx, boneflag);
2325 const float *col_hint = get_bone_hint_color(ctx, boneflag);
2326 const float(*disp_mat)[4] = bone.disp_mat();
2327
2328 if (ctx->is_overlay_next()) {
2329 /* TODO(fclem): Code after this scope should be removed when we remove the legacy code. */
2330 auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
2331
2332 /* Custom bone shapes are only supported in pose mode for now. */
2333 const bPoseChannel *pchan = bone.as_posebone();
2334 Object *custom_shape_ob = pchan->custom;
2335
2336 if (custom_shape_ob->type == OB_EMPTY) {
2337 if (custom_shape_ob->empty_drawtype != OB_EMPTY_IMAGE) {
2339 ctx, disp_mat, col_wire, pchan->custom_shape_wire_width, sel_id, pchan->custom);
2340 }
2341 }
2342 else if (boneflag & (BONE_DRAWWIRE | BONE_DRAW_LOCKED_WEIGHT)) {
2344 ctx, disp_mat, col_wire, pchan->custom_shape_wire_width, sel_id, pchan->custom);
2345 }
2346 else {
2348 disp_mat,
2349 col_solid,
2350 col_hint,
2351 col_wire,
2353 sel_id,
2354 pchan->custom);
2355 }
2356
2357 return;
2358 }
2359
2360#ifndef NO_LEGACY_OVERLAY
2361 if (select_id != -1) {
2362 DRW_select_load_id(select_id | BONESEL_BONE);
2363 }
2364
2365 /* Custom bone shapes are only supported in pose mode for now. */
2366 const bPoseChannel *pchan = bone.as_posebone();
2367
2368 if (pchan->custom->type == OB_EMPTY) {
2369 Object *ob = pchan->custom;
2370 if (ob->empty_drawtype != OB_EMPTY_IMAGE) {
2372 disp_mat,
2373 col_wire,
2375 /* Dummy values for legacy pipeline. */
2377 pchan->custom);
2378 }
2379 }
2380 if ((boneflag & BONE_DRAWWIRE) == 0 && (boneflag & BONE_DRAW_LOCKED_WEIGHT) == 0) {
2382 disp_mat,
2383 col_solid,
2384 col_hint,
2385 col_wire,
2387 /* Dummy values for legacy pipeline. */
2389 pchan->custom);
2390 }
2391 else {
2393 disp_mat,
2394 col_wire,
2396 /* Dummy values for legacy pipeline. */
2398 pchan->custom);
2399 }
2400
2401 if (select_id != -1) {
2403 }
2404#endif
2405 }
2406};
2407
2410 public:
2411 void update_display_matrix(UnifiedBonePtr bone) const override
2412 {
2414 }
2415
2416 bool culling_test(const DRWView *view,
2417 const Object *ob,
2418 const bPoseChannel *pchan) const override
2419 {
2420 /* No type assertion as this is a fallback (files from the future will end up here). */
2421 /* Account for spheres on the end-points. */
2422 const float scale = 1.2f;
2423 return pchan_culling_test_with_radius_scale(view, ob, pchan, scale);
2424 }
2425
2428 const bool is_filled,
2429 const bool /*do_envelope_dist*/) const override
2430 {
2431 ctx->outline = cb->octa_outline;
2432 ctx->solid = (is_filled) ? cb->octa_fill : nullptr;
2433 }
2434
2436 const UnifiedBonePtr bone,
2437 const eBone_Flag boneflag,
2438 const int select_id) const override
2439 {
2440 const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
2441 const float *col_wire = get_bone_wire_color(ctx, boneflag);
2442 const float *col_hint = get_bone_hint_color(ctx, boneflag);
2443
2444 if (ctx->is_overlay_next()) {
2445 /* TODO(fclem): Code after this scope should be removed when we remove the legacy code. */
2446 auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
2447 float4x4 bone_mat = ctx->ob->object_to_world() * float4x4(bone.disp_mat());
2448
2449 if (ctx->is_filled) {
2450 ctx->bone_buf->octahedral_fill_buf.append({bone_mat, col_solid, col_hint}, sel_id);
2451 }
2452 if (col_wire[3] > 0.0f) {
2453 ctx->bone_buf->octahedral_outline_buf.append({bone_mat, col_wire}, sel_id);
2454 }
2455
2456 draw_points(ctx, bone, boneflag, col_solid, select_id);
2457 return;
2458 }
2459
2460#ifndef NO_LEGACY_OVERLAY
2461 if (select_id != -1) {
2462 DRW_select_load_id(select_id | BONESEL_BONE);
2463 }
2464
2465 drw_shgroup_bone_octahedral(ctx, bone.disp_mat(), col_solid, col_hint, col_wire);
2466
2467 if (select_id != -1) {
2469 }
2470
2471 draw_points(ctx, bone, boneflag, col_solid, select_id);
2472#endif
2473 }
2474};
2475
2478 public:
2479 void update_display_matrix(UnifiedBonePtr bone) const override
2480 {
2482 }
2483
2484 bool culling_test(const DRWView *view,
2485 const Object *ob,
2486 const bPoseChannel *pchan) const override
2487 {
2488 /* Account for the end-points, as the line end-points size is in pixels, this is a rough
2489 * value. Since the end-points are small the difference between having any margin or not is
2490 * unlikely to be noticeable. */
2491 const float scale = 1.1f;
2492 return pchan_culling_test_with_radius_scale(view, ob, pchan, scale);
2493 }
2494
2497 const bool /*is_filled*/,
2498 const bool /*do_envelope_dist*/) const override
2499 {
2500 ctx->stick = cb->stick;
2501 }
2502
2504 const UnifiedBonePtr bone,
2505 const eBone_Flag boneflag,
2506 const int select_id) const override
2507 {
2508 const float *col_bone = get_bone_solid_with_consts_color(ctx, bone, boneflag);
2509 const float *col_wire = get_bone_wire_color(ctx, boneflag);
2510 const float no_display[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2511 const float *col_head = no_display;
2512 const float *col_tail = col_bone;
2513
2514 if (ctx->const_color != nullptr) {
2515 col_wire = no_display; /* actually shrink the display. */
2516 col_bone = col_head = col_tail = ctx->const_color;
2517 }
2518 else {
2519 if (bone.is_editbone() && bone.flag() & BONE_TIPSEL) {
2520 col_tail = &G_draw.block.color_vertex_select.x;
2521 }
2522
2523 /* Draw root point if we are not connected to our parent. */
2524 if (!(bone.has_parent() && (boneflag & BONE_CONNECTED))) {
2525
2526 if (bone.is_editbone()) {
2527 col_head = (bone.flag() & BONE_ROOTSEL) ? &G_draw.block.color_vertex_select.x : col_bone;
2528 }
2529 else {
2530 col_head = col_bone;
2531 }
2532 }
2533 }
2534
2535 if (select_id == -1) {
2536 /* Not in bone selection mode (can still be object select mode), draw everything at once. */
2538 ctx, bone.disp_mat(), col_wire, col_bone, col_head, col_tail, select_id);
2539 }
2540 else {
2541 /* In selection mode, draw bone, root and tip separately. */
2542#ifndef NO_LEGACY_OVERLAY
2543 if (!ctx->is_overlay_next()) {
2544 DRW_select_load_id(select_id | BONESEL_BONE);
2545 }
2546#endif
2548 bone.disp_mat(),
2549 col_wire,
2550 col_bone,
2551 no_display,
2552 no_display,
2553 select_id | BONESEL_BONE);
2554
2555 if (col_head[3] > 0.0f) {
2556#ifndef NO_LEGACY_OVERLAY
2557 if (!ctx->is_overlay_next()) {
2558 DRW_select_load_id(select_id | BONESEL_ROOT);
2559 }
2560#endif
2562 bone.disp_mat(),
2563 col_wire,
2564 no_display,
2565 col_head,
2566 no_display,
2567 select_id | BONESEL_ROOT);
2568 }
2569
2570#ifndef NO_LEGACY_OVERLAY
2571 if (!ctx->is_overlay_next()) {
2572 DRW_select_load_id(select_id | BONESEL_TIP);
2573 }
2574#endif
2576 bone.disp_mat(),
2577 col_wire,
2578 no_display,
2579 no_display,
2580 col_tail,
2581 select_id | BONESEL_TIP);
2582
2583#ifndef NO_LEGACY_OVERLAY
2584 if (!ctx->is_overlay_next()) {
2586 }
2587#endif
2588 }
2589 }
2590};
2591
2594 public:
2595 void update_display_matrix(UnifiedBonePtr bone) const override
2596 {
2598 }
2599
2600 bool culling_test(const DRWView *view,
2601 const Object *ob,
2602 const bPoseChannel *pchan) const override
2603 {
2604 const bArmature *arm = static_cast<bArmature *>(ob->data);
2606 UNUSED_VARS_NDEBUG(arm);
2607 const float ob_scale = mat4_to_size_max_axis(ob->object_to_world().ptr());
2608 const Mat4 *bbones_mat = (const Mat4 *)pchan->draw_data->bbone_matrix;
2609 for (int i = pchan->bone->segments; i--; bbones_mat++) {
2610 BoundSphere bsphere;
2611 float size[3];
2612 mat4_to_size(size, bbones_mat->mat);
2613 mul_v3_m4v3(bsphere.center, ob->object_to_world().ptr(), bbones_mat->mat[3]);
2614 bsphere.radius = len_v3(size) * ob_scale;
2615 if (DRW_culling_sphere_test(view, &bsphere)) {
2616 return true;
2617 }
2618 }
2619 return false;
2620 }
2621
2624 const bool is_filled,
2625 const bool /*do_envelope_dist*/) const override
2626 {
2627 ctx->outline = cb->box_outline;
2628 ctx->solid = (is_filled) ? cb->box_fill : nullptr;
2629 }
2630
2632 const UnifiedBonePtr bone,
2633 const eBone_Flag boneflag,
2634 const int select_id) const override
2635 {
2636 const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
2637 const float *col_wire = get_bone_wire_color(ctx, boneflag);
2638 const float *col_hint = get_bone_hint_color(ctx, boneflag);
2639
2640 if (ctx->is_overlay_next()) {
2641 /* TODO(fclem): Code after this scope should be removed when we remove the legacy code. */
2642
2643 /* NOTE: Cannot reinterpret as float4x4 because of alignment requirement of float4x4.
2644 * This would require a deeper refactor. */
2645 Span<Mat4> bbone_matrices;
2646 if (bone.is_posebone()) {
2647 bbone_matrices = {(Mat4 *)bone.as_posebone()->draw_data->bbone_matrix,
2648 bone.as_posebone()->bone->segments};
2649 }
2650 else {
2651 bbone_matrices = {(Mat4 *)bone.as_editbone()->disp_bbone_mat,
2652 bone.as_editbone()->segments};
2653 }
2654
2655 auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
2656
2657 for (const Mat4 &in_bone_mat : bbone_matrices) {
2658 float4x4 bone_mat = ctx->ob->object_to_world() * float4x4(in_bone_mat.mat);
2659
2660 if (ctx->is_filled) {
2661 ctx->bone_buf->bbones_fill_buf.append({bone_mat, col_solid, col_hint}, sel_id);
2662 }
2663 if (col_wire[3] > 0.0f) {
2664 ctx->bone_buf->bbones_outline_buf.append({bone_mat, col_wire}, sel_id);
2665 }
2666 }
2667
2668 if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
2669 draw_points(ctx, bone, boneflag, col_solid, select_id);
2670 }
2671 return;
2672 }
2673
2674#ifndef NO_LEGACY_OVERLAY
2675 if (select_id != -1) {
2676 DRW_select_load_id(select_id | BONESEL_BONE);
2677 }
2678
2679 if (bone.is_posebone()) {
2680 const bPoseChannel *pchan = bone.as_posebone();
2681 Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
2682 BLI_assert(bbones_mat != nullptr);
2683
2684 for (int i = pchan->bone->segments; i--; bbones_mat++) {
2685 drw_shgroup_bone_box(ctx, bbones_mat->mat, col_solid, col_hint, col_wire);
2686 }
2687 }
2688 else {
2689 const EditBone *eBone = bone.as_editbone();
2690 for (int i = 0; i < eBone->segments; i++) {
2691 drw_shgroup_bone_box(ctx, eBone->disp_bbone_mat[i], col_solid, col_hint, col_wire);
2692 }
2693 }
2694
2695 if (select_id != -1) {
2697 }
2698
2699 if (bone.is_editbone()) {
2700 draw_points(ctx, bone, boneflag, col_solid, select_id);
2701 }
2702#endif
2703 }
2704};
2705
2708 public:
2709 void update_display_matrix(UnifiedBonePtr bone) const override
2710 {
2712 }
2713
2714 bool culling_test(const DRWView *view,
2715 const Object *ob,
2716 const bPoseChannel *pchan) const override
2717 {
2718 const bArmature *arm = static_cast<bArmature *>(ob->data);
2720 UNUSED_VARS_NDEBUG(arm);
2721 BoundSphere bsphere;
2722 pchan_culling_calc_bsphere(ob, pchan, &bsphere);
2723 bsphere.radius += max_ff(pchan->bone->rad_head, pchan->bone->rad_tail) *
2724 mat4_to_size_max_axis(ob->object_to_world().ptr()) *
2726 return DRW_culling_sphere_test(view, &bsphere);
2727 }
2728
2731 const bool is_filled,
2732 const bool do_envelope_dist) const override
2733 {
2735 ctx->envelope_solid = (is_filled) ? cb->envelope_fill : nullptr;
2736 ctx->envelope_distance = (do_envelope_dist) ? cb->envelope_distance : nullptr;
2737 }
2738
2740 const UnifiedBonePtr bone,
2741 const eBone_Flag boneflag,
2742 const int select_id) const override
2743 {
2744 const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
2745 const float *col_wire = get_bone_wire_color(ctx, boneflag);
2746 const float *col_hint = get_bone_hint_color(ctx, boneflag);
2747
2748 const float *rad_head, *rad_tail, *distance;
2749 if (bone.is_editbone()) {
2750 const EditBone *eBone = bone.as_editbone();
2751 rad_tail = &eBone->rad_tail;
2752 distance = &eBone->dist;
2753 rad_head = (eBone->parent && (boneflag & BONE_CONNECTED)) ? &eBone->parent->rad_tail :
2754 &eBone->rad_head;
2755 }
2756 else {
2757 const bPoseChannel *pchan = bone.as_posebone();
2758 rad_tail = &pchan->bone->rad_tail;
2759 distance = &pchan->bone->dist;
2760 rad_head = (pchan->parent && (boneflag & BONE_CONNECTED)) ? &pchan->parent->bone->rad_tail :
2761 &pchan->bone->rad_head;
2762 }
2763
2764 if ((select_id == -1) && (boneflag & BONE_NO_DEFORM) == 0 &&
2765 ((boneflag & BONE_SELECTED) ||
2766 (bone.is_editbone() && (boneflag & (BONE_ROOTSEL | BONE_TIPSEL)))))
2767 {
2768 drw_shgroup_bone_envelope_distance(ctx, bone.disp_mat(), rad_head, rad_tail, distance);
2769 }
2770
2771#ifndef NO_LEGACY_OVERLAY
2772 if (select_id != -1) {
2773 DRW_select_load_id(select_id | BONESEL_BONE);
2774 }
2775#endif
2776
2778 bone.disp_mat(),
2779 col_solid,
2780 col_hint,
2781 col_wire,
2782 rad_head,
2783 rad_tail,
2784 select_id | BONESEL_BONE);
2785
2786#ifndef NO_LEGACY_OVERLAY
2787 if (select_id != -1) {
2789 }
2790#endif
2791
2792 draw_points(ctx, bone, boneflag, col_solid, select_id);
2793 }
2794};
2795
2798 public:
2799 void update_display_matrix(UnifiedBonePtr bone) const override
2800 {
2802 }
2803
2804 bool culling_test(const DRWView *view,
2805 const Object *ob,
2806 const bPoseChannel *pchan) const override
2807 {
2808 BLI_assert(((const bArmature *)ob->data)->drawtype == ARM_WIRE);
2809 return pchan_culling_test_simple(view, ob, pchan);
2810 }
2811
2814 const bool /*is_filled*/,
2815 const bool /*do_envelope_dist*/) const override
2816 {
2817 ctx->wire = cb->wire;
2818 ctx->const_wire = 1.5f;
2819 }
2820
2822 const UnifiedBonePtr bone,
2823 const eBone_Flag boneflag,
2824 const int select_id) const override
2825 {
2826 using namespace blender::math;
2827
2828 const float *col_wire = get_bone_wire_color(ctx, boneflag);
2829
2830#ifndef NO_LEGACY_OVERLAY
2831 if (!ctx->is_overlay_next() && select_id != -1) {
2832 DRW_select_load_id(select_id | BONESEL_BONE);
2833 }
2834#endif
2835
2836 auto sel_id = (ctx->bone_buf) ? ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE) :
2838
2839 /* NOTE: Cannot reinterpret as float4x4 because of alignment requirement of float4x4.
2840 * This would require a deeper refactor. */
2841 Span<Mat4> bbone_matrices;
2842 if (bone.is_posebone()) {
2843 bbone_matrices = {(Mat4 *)bone.as_posebone()->draw_data->bbone_matrix,
2844 bone.as_posebone()->bone->segments};
2845 }
2846 else {
2847 bbone_matrices = {(Mat4 *)bone.as_editbone()->disp_bbone_mat, bone.as_editbone()->segments};
2848 }
2849
2850 for (const Mat4 &in_bone_mat : bbone_matrices) {
2851 float4x4 bmat = float4x4(in_bone_mat.mat);
2852 float3 head = transform_point(ctx->ob->object_to_world(), bmat.location());
2853 float3 tail = transform_point(ctx->ob->object_to_world(), bmat.location() + bmat.y_axis());
2854
2855 if (ctx->is_overlay_next()) {
2856 ctx->bone_buf->wire_buf.append(head, tail, float4(col_wire), sel_id);
2857 }
2858 else {
2859 DRW_buffer_add_entry(ctx->wire, head, col_wire);
2860 DRW_buffer_add_entry(ctx->wire, tail, col_wire);
2861 }
2862 }
2863
2864#ifndef NO_LEGACY_OVERLAY
2865 if (!ctx->is_overlay_next() && select_id != -1) {
2867 }
2868#endif
2869
2870 if (bone.is_editbone()) {
2871 const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
2872 draw_points(ctx, bone, boneflag, col_solid, select_id);
2873 }
2874 }
2875};
2876
2877namespace {
2887static ArmatureBoneDrawStrategyOcta strat_octa;
2888static ArmatureBoneDrawStrategyLine strat_line;
2889static ArmatureBoneDrawStrategyBBone strat_b_bone;
2890static ArmatureBoneDrawStrategyEnvelope strat_envelope;
2891static ArmatureBoneDrawStrategyWire strat_wire;
2892static ArmatureBoneDrawStrategyEmpty strat_empty;
2893}; // namespace
2894
2902{
2903 switch (drawtype) {
2904 case ARM_OCTA:
2905 return strat_octa;
2906 case ARM_LINE:
2907 return strat_line;
2908 case ARM_B_BONE:
2909 return strat_b_bone;
2910 case ARM_ENVELOPE:
2911 return strat_envelope;
2912 case ARM_WIRE:
2913 return strat_wire;
2914 }
2916 return strat_empty;
2917}
2918
2921/* -------------------------------------------------------------------- */
2926{
2927 Object *ob = ctx->ob;
2928 EditBone *eBone;
2929 int index;
2930 const bool is_select = DRW_state_is_select();
2931 const bool show_text = DRW_state_show_text();
2932
2933 const Object *ob_orig = DEG_get_original_object(ob);
2934 /* FIXME(@ideasman42): We should be able to use the evaluated object,
2935 * however the active bone isn't updated. Long term solution is an 'EditArmature' struct.
2936 * for now we can draw from the original armature. See: #66773. */
2937 // bArmature *arm = ob->data;
2938 bArmature *arm = static_cast<bArmature *>(ob_orig->data);
2939
2941
2942 /* Determine drawing strategy. */
2945
2946 for (eBone = static_cast<EditBone *>(arm->edbo->first),
2947 /* Note: Selection Next handles the object id merging later. */
2948 index = ctx->bone_buf ? 0x0 : ob_orig->runtime->select_id;
2949 eBone;
2950 eBone = eBone->next, index += 0x10000)
2951 {
2952 if (!EBONE_VISIBLE(arm, eBone)) {
2953 continue;
2954 }
2955
2956 const int select_id = is_select ? index : uint(-1);
2957
2958 /* catch exception for bone with hidden parent */
2959 eBone_Flag boneflag = eBone_Flag(eBone->flag);
2960 if ((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent)) {
2961 boneflag &= ~BONE_CONNECTED;
2962 }
2963
2964 /* set temporary flag for drawing bone as active, but only if selected */
2965 if (eBone == arm->act_edbone) {
2966 boneflag |= BONE_DRAW_ACTIVE;
2967 }
2968
2969 boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
2970
2971 UnifiedBonePtr bone = eBone;
2972 if (!ctx->const_color) {
2973 set_ctx_bcolor(ctx, bone);
2974 }
2975
2976 if (!is_select) {
2977 draw_bone_relations(ctx, draw_strat, bone, boneflag);
2978 }
2979
2980 draw_strat.update_display_matrix(bone);
2981 draw_strat.draw_bone(ctx, bone, boneflag, select_id);
2982
2983 if (!is_select) {
2984 if (show_text && (arm->flag & ARM_DRAWNAMES)) {
2985 draw_bone_name(ctx, bone, boneflag);
2986 }
2987
2988 if (arm->flag & ARM_DRAWAXES) {
2989 draw_axes(ctx, bone, arm);
2990 }
2991 }
2992 }
2993}
2994
2996{
2997 Object *ob = ctx->ob;
2998 const DRWContextState *draw_ctx = DRW_context_state_get();
2999 const Scene *scene = draw_ctx->scene;
3000 bArmature *arm = static_cast<bArmature *>(ob->data);
3001 bPoseChannel *pchan;
3002 int index = -1;
3003 const bool show_text = DRW_state_show_text();
3004 bool draw_locked_weights = false;
3005
3006 /* We can't safely draw non-updated pose, might contain nullptr bone pointers... */
3007 if (ob->pose->flag & POSE_RECALC) {
3008 return;
3009 }
3010
3011 ctx->draw_mode = ARM_DRAW_MODE_OBJECT; /* Will likely be set to ARM_DRAW_MODE_POSE below. */
3012
3013 bool is_pose_select = false;
3014 /* Object can be edited in the scene. */
3015 if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
3016 if ((draw_ctx->object_mode & OB_MODE_POSE) || (ob == draw_ctx->object_pose)) {
3018 }
3019 is_pose_select =
3020 /* If we're in pose-mode or object-mode with the ability to enter pose mode. */
3021 (
3022 /* Draw as if in pose mode (when selection is possible). */
3023 (ctx->draw_mode == ARM_DRAW_MODE_POSE) ||
3024 /* When we're in object mode, which may select bones. */
3025 ((ob->mode & OB_MODE_POSE) &&
3026 (
3027 /* Switch from object mode when object lock is disabled. */
3028 ((draw_ctx->object_mode == OB_MODE_OBJECT) &&
3029 (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) ||
3030 /* Allow selection when in weight-paint mode
3031 * (selection code ensures this won't become active). */
3032 ((draw_ctx->object_mode & OB_MODE_ALL_WEIGHT_PAINT) &&
3033 (draw_ctx->object_pose != nullptr))))) &&
3035
3036 if (is_pose_select) {
3037 const Object *ob_orig = DEG_get_original_object(ob);
3038 /* Note: Selection Next handles the object id merging later. */
3039 index = ctx->bone_buf ? 0x0 : ob_orig->runtime->select_id;
3040 }
3041 }
3042
3043 /* In weight paint mode retrieve the vertex group lock status. */
3044 if ((draw_ctx->object_mode & OB_MODE_ALL_WEIGHT_PAINT) && (draw_ctx->object_pose == ob) &&
3045 (draw_ctx->obact != nullptr))
3046 {
3047 draw_locked_weights = true;
3048
3050 pchan->bone->flag &= ~BONE_DRAW_LOCKED_WEIGHT;
3051 }
3052
3053 const Object *obact_orig = DEG_get_original_object(draw_ctx->obact);
3054
3055 const ListBase *defbase = BKE_object_defgroup_list(obact_orig);
3056 for (const bDeformGroup *dg : ConstListBaseWrapper<bDeformGroup>(defbase)) {
3057 if ((dg->flag & DG_LOCK_WEIGHT) == 0) {
3058 continue;
3059 }
3060
3061 pchan = BKE_pose_channel_find_name(ob->pose, dg->name);
3062 if (!pchan) {
3063 continue;
3064 }
3065
3067 }
3068 }
3069
3070 /* TODO(fclem): Remove global access. This is only used for culling in selection mode.
3071 * This is just a workaround for slow selection queries. Selection-next will not have this issue.
3072 */
3073 const DRWView *view = is_pose_select ? DRW_view_default_get() : nullptr;
3074
3077 const ArmatureBoneDrawStrategyCustomShape draw_strat_custom;
3078
3079 for (pchan = static_cast<bPoseChannel *>(ob->pose->chanbase.first); pchan;
3080 pchan = pchan->next, index += 0x10000)
3081 {
3082 Bone *bone = pchan->bone;
3083 if (!ANIM_bone_is_visible(arm, bone)) {
3084 continue;
3085 }
3086
3087 const bool draw_dofs = !is_pose_select && ctx->show_relations &&
3088 (ctx->draw_mode == ARM_DRAW_MODE_POSE) &&
3089 (bone->flag & BONE_SELECTED) &&
3090 ((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
3091 (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ZLIMIT));
3092 const int select_id = is_pose_select ? index : uint(-1);
3093
3094 pchan_draw_data_init(pchan);
3095
3096 UnifiedBonePtr bone_ptr = pchan;
3097 if (!ctx->const_color) {
3098 set_ctx_bcolor(ctx, bone_ptr);
3099 }
3100
3101 eBone_Flag boneflag = eBone_Flag(bone->flag);
3102 if (bone->parent && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
3103 /* Avoid drawing connection line to hidden parent. */
3104 boneflag &= ~BONE_CONNECTED;
3105 }
3106 if (bone == arm->act_bone) {
3107 /* Draw bone as active, but only if selected. */
3108 boneflag |= BONE_DRAW_ACTIVE;
3109 }
3110 if (!draw_locked_weights) {
3111 boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
3112 }
3113
3114 const bool use_custom_shape = (pchan->custom) && !(arm->flag & ARM_NO_CUSTOM);
3115 const ArmatureBoneDrawStrategy &draw_strat = use_custom_shape ? draw_strat_custom :
3116 draw_strat_normal;
3117 if (!is_pose_select) {
3118 draw_bone_relations(ctx, draw_strat, bone_ptr, boneflag);
3119 }
3120
3121 draw_strat.update_display_matrix(bone_ptr);
3122 if (!is_pose_select || draw_strat.culling_test(view, ob, pchan)) {
3123 draw_strat.draw_bone(ctx, bone_ptr, boneflag, select_id);
3124 }
3125
3126 /* Below this point nothing is used for selection queries. */
3127 if (is_pose_select) {
3128 continue;
3129 }
3130
3131 if (draw_dofs) {
3132 draw_bone_degrees_of_freedom(ctx, pchan);
3133 }
3134 if (show_text && (arm->flag & ARM_DRAWNAMES)) {
3135 draw_bone_name(ctx, bone_ptr, boneflag);
3136 }
3137 if (arm->flag & ARM_DRAWAXES) {
3138 draw_axes(ctx, bone_ptr, arm);
3139 }
3140 }
3141}
3142
3145 Object *ob,
3146 const eArmatureDrawMode draw_mode,
3147 const float *const_color)
3148{
3149 /* Not true anymore. */
3150 // BLI_assert(BLI_memory_is_zero(ctx, sizeof(*ctx)));
3151 const bool is_edit_or_pose_mode = draw_mode != ARM_DRAW_MODE_OBJECT;
3152 const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0 ||
3153 (pd->armature.do_pose_xray && draw_mode == ARM_DRAW_MODE_POSE);
3154 const bool draw_as_wire = (ob->dt < OB_SOLID);
3155 const bool is_filled = (!pd->armature.transparent && !draw_as_wire) || is_edit_or_pose_mode;
3156 const bool is_transparent = pd->armature.transparent || (draw_as_wire && is_edit_or_pose_mode);
3157 bArmature *arm = static_cast<bArmature *>(ob->data);
3159 const OVERLAY_ArmatureCallBuffersInner *cb = is_transparent ? &cbo->transp : &cbo->solid;
3160
3161 static const float select_const_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
3162
3163 ctx->ob = ob;
3164 ctx->draw_mode = draw_mode;
3165 ctx->extras = &pd->extra_call_buffers[is_xray];
3166 ctx->dof_lines = cb->dof_lines;
3167 ctx->dof_sphere = cb->dof_sphere;
3168 ctx->point_solid = (is_filled) ? cb->point_fill : nullptr;
3169 ctx->point_outline = cb->point_outline;
3170 ctx->custom_solid = (is_filled) ? cb->custom_fill : nullptr;
3171 ctx->custom_outline = cb->custom_outline;
3172 ctx->custom_wire = cb->custom_wire;
3176 is_edit_or_pose_mode;
3177 ctx->const_color = DRW_state_is_select() ? select_const_color : const_color;
3178 ctx->const_wire = ((ob->base_flag & BASE_SELECTED) && (pd->v3d_flag & V3D_SELECT_OUTLINE) ?
3179 1.5f :
3180 ((!is_filled || is_transparent) ? 1.0f : 0.0f));
3181 ctx->draw_envelope_distance = is_edit_or_pose_mode;
3183
3184 /* Call the draw strategy after setting the generic context properties, so
3185 * that they can be overridden. */
3186 const eArmature_Drawtype drawtype = eArmature_Drawtype(arm->drawtype);
3187 ctx->drawtype = drawtype;
3188 const ArmatureBoneDrawStrategy &draw_strat = strategy_for_armature_drawtype(drawtype);
3189 draw_strat.draw_context_setup(ctx, cb, is_filled, is_edit_or_pose_mode);
3190}
3191
3193{
3194 OVERLAY_PrivateData *pd = vedata->stl->pd;
3195 Armatures::DrawContext arm_ctx = {};
3196 armature_context_setup(&arm_ctx, pd, ob, ARM_DRAW_MODE_EDIT, nullptr);
3198}
3199
3201{
3202 OVERLAY_PrivateData *pd = vedata->stl->pd;
3203 Armatures::DrawContext arm_ctx = {};
3204 armature_context_setup(&arm_ctx, pd, ob, ARM_DRAW_MODE_POSE, nullptr);
3206}
3207
3209{
3210 const DRWContextState *draw_ctx = DRW_context_state_get();
3211 OVERLAY_PrivateData *pd = vedata->stl->pd;
3212 Armatures::DrawContext arm_ctx = {};
3213 float *color;
3214
3215 if (ob->dt == OB_BOUNDBOX) {
3216 return;
3217 }
3218
3219 DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
3220 armature_context_setup(&arm_ctx, pd, ob, ARM_DRAW_MODE_OBJECT, color);
3222}
3223
3225{
3227 if (ob_arm) {
3228 const DRWContextState *draw_ctx = DRW_context_state_get();
3229 bool is_active = OVERLAY_armature_is_pose_mode(ob_arm, draw_ctx);
3230 return is_active;
3231 }
3232
3233 Object *ob_mesh_deform = BKE_modifiers_is_deformed_by_meshdeform(ob);
3234 if (ob_mesh_deform) {
3235 /* Recursive. */
3236 return POSE_is_driven_by_active_armature(ob_mesh_deform);
3237 }
3238
3239 return false;
3240}
3241
3243{
3244 OVERLAY_PrivateData *pd = vedata->stl->pd;
3245
3246 blender::gpu::Batch *geom = DRW_cache_object_surface_get(ob);
3247 if (geom) {
3250 }
3251 else {
3253 }
3254 }
3255}
3256
3258{
3259 OVERLAY_PrivateData *pd = vedata->stl->pd;
3260
3261 for (int i = 0; i < 2; i++) {
3263 /* TODO(fclem): Do not free it for each frame but reuse it. Avoiding alloc cost. */
3266 }
3267 }
3268}
3269
3271{
3272 OVERLAY_PassList *psl = vedata->psl;
3273
3275 DRW_draw_pass(psl->armature_ps[0]);
3276}
3277
3279{
3280 OVERLAY_PassList *psl = vedata->psl;
3281
3282 if (psl->armature_bone_select_ps == nullptr || DRW_state_is_select()) {
3284 DRW_draw_pass(psl->armature_ps[1]);
3285 }
3286}
3287
3289{
3290 OVERLAY_PassList *psl = vedata->psl;
3291 OVERLAY_FramebufferList *fbl = vedata->fbl;
3292
3293 if (psl->armature_bone_select_ps != nullptr) {
3294 if (DRW_state_is_fbo()) {
3296 }
3297
3299
3300 if (DRW_state_is_fbo()) {
3303 }
3304
3306 DRW_draw_pass(psl->armature_ps[1]);
3307 }
3308}
3309
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
bool ANIM_bone_is_visible(const bArmature *armature, const Bone *bone)
C++ part of the BoneColor DNA struct.
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
void BKE_pchan_bbone_spline_setup(bPoseChannel *pchan, bool rest, bool for_deform, Mat4 *result_array)
Definition armature.cc:1334
#define MAX_BBONE_SUBDIV
void BKE_pchan_minmax(const Object *ob, const bPoseChannel *pchan, const bool use_empty_drawtype, float r_min[3], float r_max[3])
Definition armature.cc:3040
int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param, bool for_deform, Mat4 *result_array)
Definition armature.cc:1506
support for deformation groups and hooks.
const ListBase * BKE_object_defgroup_list(const Object *ob)
Definition deform.cc:579
Object * BKE_modifiers_is_deformed_by_meshdeform(Object *ob)
Object * BKE_modifiers_is_deformed_by_armature(Object *ob)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh_no_subsurf_unchecked(const Object *object)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define BLI_INLINE
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
#define LISTBASE_FOREACH(type, var, list)
MINLINE float max_ff(float a, float b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
float mat4_to_scale(const float mat[4][4])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3])
void unit_m4(float m[4][4])
Definition rct.c:1127
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void rescale_m4(float mat[4][4], const float scale[3])
void size_to_mat4(float R[4][4], const float size[3])
void mul_m4_v3(const float M[4][4], float r[3])
void scale_m4_fl(float R[4][4], float scale)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
float mat4_to_size_max_axis(const float M[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
void mul_m4_v4(const float mat[4][4], float r[4])
bool invert_m4(float mat[4][4])
void mat4_to_size(float size[3], const float M[4][4])
void eulO_to_mat3(float M[3][3], const float e[3], short order)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v4_fl4(float v[4], float x, float y, float z, float w)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v4_v4v4(float r[4], const float a[4], const float b[4], float t)
Definition math_vector.c:45
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition math_vector.c:36
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_v3v3(float r[3], const float v1[3], const float v2[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
unsigned char uchar
unsigned int uint
#define CLAMP(a, b, c)
#define INIT_MINMAX(min, max)
#define UNUSED_VARS_NDEBUG(...)
#define UNPACK3(a)
#define ELEM(...)
Object * DEG_get_original_object(Object *object)
#define PCHAN_CUSTOM_BONE_LENGTH(pchan)
@ ROT_MODE_XYZ
@ BONE_IK_ZLIMIT
@ BONE_IK_XLIMIT
ePchan_ConstFlag
@ PCHAN_HAS_CONST
@ PCHAN_HAS_NO_TARGET
@ PCHAN_HAS_IK
@ PCHAN_HAS_SPLINEIK
@ POSE_RECALC
@ BBONE_HANDLE_AUTO
@ BBONE_HANDLE_TANGENT
@ BBONE_HANDLE_RELATIVE
@ BONE_DRAW_LOCKED_WEIGHT
@ BONE_ROOTSEL
@ BONE_DRAWWIRE
@ BONE_SELECTED
@ BONE_HIDDEN_P
@ BONE_DRAW_ACTIVE
@ BONE_TIPSEL
@ BONE_NO_DEFORM
@ BONE_CONNECTED
@ BONE_HIDDEN_PG
@ ARM_DRAW_RELATION_FROM_HEAD
@ ARM_NO_CUSTOM
@ ARM_COL_CUSTOM
@ ARM_DRAWNAMES
@ ARM_DRAWAXES
eArmature_Drawtype
@ ARM_B_BONE
@ ARM_ENVELOPE
@ BBONE_ADD_PARENT_END_ROLL
@ BBONE_SCALE_EASING
@ CONSTRAINT_IK_TEMP
@ CONSTRAINT_IK_TIP
@ CONSTRAINT_TYPE_SPLINEIK
@ CONSTRAINT_TYPE_KINEMATIC
@ BASE_FROM_DUPLI
@ BASE_FROM_SET
@ OB_WIRE
@ OB_BOUNDBOX
@ OB_SOLID
#define OB_MODE_ALL_WEIGHT_PAINT
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_POSE
@ OB_MODE_OBJECT
Object is a sort of wrapper for general info.
@ OB_EMPTY
@ OB_SURF
@ OB_FONT
@ OB_CURVES_LEGACY
@ OB_DRAW_IN_FRONT
@ OB_EMPTY_CONE
@ OB_SINGLE_ARROW
@ OB_PLAINAXES
@ OB_ARROWS
@ OB_CIRCLE
@ OB_CUBE
@ OB_EMPTY_IMAGE
@ OB_EMPTY_SPHERE
@ DG_LOCK_WEIGHT
#define BASE_SELECTED(v3d, base)
@ SCE_OBJECT_MODE_LOCK
@ TH_WIRECOLOR_CONSTCOLS
@ USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE
@ V3D_OVERLAY_BONE_SELECT
@ V3D_SELECT_OUTLINE
@ V3D_HIDE_HELPLINES
#define DRW_buffer_add_entry(buffer,...)
#define DRW_PASS_CREATE(pass, state)
#define DRW_shgroup_uniform_block(shgroup, name, ubo)
#define DRW_shgroup_call(shgroup, geom, ob)
#define EBONE_VISIBLE(arm, ebone)
#define BONESEL_ROOT
#define BONESEL_TIP
#define BONESEL_BONE
#define XRAY_FLAG_ENABLED(v3d)
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
void GPU_framebuffer_clear_depth(GPUFrameBuffer *fb, float clear_depth)
#define MEM_SAFE_FREE(v)
@ TH_TEXT
@ TH_TEXT_HI
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
void ED_armature_ebone_to_mat4(EditBone *ebone, float r_mat[4][4])
struct GPUShader GPUShader
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
void draw_context_setup(Armatures::DrawContext *ctx, const OVERLAY_ArmatureCallBuffersInner *cb, const bool is_filled, const bool) const override
void update_display_matrix(UnifiedBonePtr bone) const override
void draw_bone(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id) const override
bool culling_test(const DRWView *view, const Object *ob, const bPoseChannel *pchan) const override
bool culling_test(const DRWView *view, const Object *ob, const bPoseChannel *pchan) const override
void draw_bone(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id) const override
void update_display_matrix(UnifiedBonePtr bone) const override
void draw_context_setup(Armatures::DrawContext *, const OVERLAY_ArmatureCallBuffersInner *, const bool, const bool) const override
void draw_context_setup(Armatures::DrawContext *, const OVERLAY_ArmatureCallBuffersInner *, const bool, const bool) const override
bool culling_test(const DRWView *, const Object *, const bPoseChannel *) const override
void draw_bone(const Armatures::DrawContext *, const UnifiedBonePtr, const eBone_Flag, const int) const override
void update_display_matrix(UnifiedBonePtr bone) const override
void update_display_matrix(UnifiedBonePtr bone) const override
bool culling_test(const DRWView *view, const Object *ob, const bPoseChannel *pchan) const override
void draw_context_setup(Armatures::DrawContext *ctx, const OVERLAY_ArmatureCallBuffersInner *cb, const bool is_filled, const bool do_envelope_dist) const override
void draw_bone(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id) const override
void draw_context_setup(Armatures::DrawContext *ctx, const OVERLAY_ArmatureCallBuffersInner *cb, const bool, const bool) const override
void draw_bone(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id) const override
bool culling_test(const DRWView *view, const Object *ob, const bPoseChannel *pchan) const override
void update_display_matrix(UnifiedBonePtr bone) const override
void update_display_matrix(UnifiedBonePtr bone) const override
void draw_context_setup(Armatures::DrawContext *ctx, const OVERLAY_ArmatureCallBuffersInner *cb, const bool is_filled, const bool) const override
bool culling_test(const DRWView *view, const Object *ob, const bPoseChannel *pchan) const override
void draw_bone(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id) const override
void draw_bone(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id) const override
void update_display_matrix(UnifiedBonePtr bone) const override
void draw_context_setup(Armatures::DrawContext *ctx, const OVERLAY_ArmatureCallBuffersInner *cb, const bool, const bool) const override
bool culling_test(const DRWView *view, const Object *ob, const bPoseChannel *pchan) const override
virtual void update_display_matrix(UnifiedBonePtr bone) const =0
virtual void draw_bone(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id) const =0
virtual bool culling_test(const DRWView *view, const Object *ob, const bPoseChannel *pchan) const =0
virtual bool should_draw_relation_to_parent(const UnifiedBonePtr bone, const eBone_Flag boneflag) const
virtual void draw_context_setup(Armatures::DrawContext *ctx, const OVERLAY_ArmatureCallBuffersInner *cb, const bool is_filled, const bool do_envelope_dist) const =0
bPoseChannel * pchan_
const f44 & disp_tail_mat() const
ePchan_ConstFlag constflag() const
UnifiedBonePtr(EditBone *eBone)
bPoseChannel * as_posebone()
bool is_posebone() const
bool is_editbone() const
void get(EditBone **eBone, bPoseChannel **pchan)
const f44 & disp_mat() const
void get(const EditBone **eBone, const bPoseChannel **pchan) const
const EditBone * as_editbone() const
UnifiedBonePtr(const UnifiedBonePtr &ptr)=default
UnifiedBonePtr(bPoseChannel *pchan)
const float & rad_head() const
const float & rad_tail() const
EditBone * as_editbone()
const blender::animrig::BoneColor & effective_bonecolor() const
eBone_Flag flag() const
const char * name() const
bool has_parent() const
const bPoseChannel * as_posebone() const
const ThemeWireColor * effective_color() const
Definition bonecolor.cc:30
static void draw_armature_pose(Armatures::DrawContext *ctx)
static void draw_armature_edit(Armatures::DrawContext *ctx)
local_group_size(16, 16) .push_constant(Type b
#define sinf(x)
#define powf(x, y)
blender::gpu::Batch * DRW_cache_bone_point_get()
blender::gpu::Batch * DRW_cache_object_surface_get(Object *ob)
blender::gpu::Batch * DRW_cache_curve_edge_wire_get(Object *ob)
blender::gpu::Batch * DRW_cache_bone_point_wire_outline_get()
blender::gpu::Batch * DRW_cache_text_edge_wire_get(Object *ob)
blender::gpu::Batch * DRW_cache_bone_envelope_solid_get()
blender::gpu::Batch * DRW_cache_bone_octahedral_wire_get()
blender::gpu::Batch * DRW_cache_bone_octahedral_get()
void drw_batch_cache_generate_requested_delayed(Object *ob)
blender::gpu::Batch * DRW_cache_bone_envelope_outline_get()
blender::gpu::Batch * DRW_cache_bone_dof_lines_get()
blender::gpu::Batch * DRW_cache_bone_box_get()
blender::gpu::Batch * DRW_cache_bone_stick_get()
blender::gpu::Batch * DRW_cache_bone_dof_sphere_get()
blender::gpu::Batch * DRW_cache_bone_box_wire_get()
int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color)
DRW_Global G_draw
bool DRW_state_show_text()
DRWTextStore * DRW_text_cache_ensure()
DefaultTextureList * DRW_viewport_texture_list_get()
const DRWContextState * DRW_context_state_get()
bool DRW_state_is_fbo()
bool DRW_state_is_select()
int len
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_state_disable(DRWShadingGroup *shgroup, DRWState state)
void DRW_buffer_add_entry_struct(DRWCallBuffer *callbuf, const void *data)
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
DRWCallBuffer * DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup, GPUVertFormat *format, blender::gpu::Batch *geom)
void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value)
bool DRW_culling_sphere_test(const DRWView *view, const BoundSphere *bsphere)
void DRW_draw_pass(DRWPass *pass)
void DRW_select_load_id(uint id)
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)
@ DRW_TEXT_CACHE_GLOBALSPACE
@ DRW_TEXT_CACHE_STRING_PTR
DRWState
Definition draw_state.hh:25
@ DRW_STATE_BLEND_ALPHA
Definition draw_state.hh:55
@ DRW_STATE_BLEND_ADD
Definition draw_state.hh:51
@ DRW_STATE_CULL_FRONT
Definition draw_state.hh:44
@ DRW_STATE_IN_FRONT_SELECT
Definition draw_state.hh:67
@ DRW_STATE_DEPTH_EQUAL
Definition draw_state.hh:39
@ 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
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uint col
format
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
static ulong * next
static ulong state[N]
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
ListBaseWrapperTemplate< const ListBase, const T > ConstListBaseWrapper
VecBase< float, 4 > float4
ListBaseWrapperTemplate< ListBase, T > ListBaseWrapper
float distance(float a, float b)
static void drw_shgroup_bone_stick(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float col_wire[4], const float col_bone[4], const float col_head[4], const float col_tail[4], const int select_id)
static const float * get_bone_solid_color(const Armatures::DrawContext *ctx, const eBone_Flag boneflag)
static void drw_shgroup_bone_relationship_lines_ex(const Armatures::DrawContext *ctx, const float start[3], const float end[3], const float color[4])
static const float * get_bone_solid_with_consts_color(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag)
static void ebone_spline_preview(EditBone *ebone, const float result_array[MAX_BBONE_SUBDIV][4][4])
static void drw_shgroup_bone_envelope_distance(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float *radius_head, const float *radius_tail, const float *distance)
static void drw_shgroup_bone_ik_spline_lines(const Armatures::DrawContext *ctx, const float start[3], const float end[3])
static bool POSE_is_driven_by_active_armature(Object *ob)
void OVERLAY_armature_in_front_draw(OVERLAY_Data *vedata)
static void drw_shgroup_bone_custom_empty(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float color[4], const float wire_width, const draw::select::ID select_id, Object *custom)
static void drw_shgroup_bone_envelope(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float bone_col[4], const float hint_col[4], const float outline_col[4], const float *radius_head, const float *radius_tail, const int select_id)
bool OVERLAY_armature_is_pose_mode(Object *ob, const DRWContextState *draw_ctx)
static void drw_shgroup_bone_box(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float bone_color[4], const float hint_color[4], const float outline_color[4])
void OVERLAY_edit_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
static void drw_shgroup_bone_custom_solid(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float bone_color[4], const float hint_color[4], const float outline_color[4], const float wire_width, const draw::select::ID select_id, Object *custom)
static bool pchan_culling_test_with_radius_scale(const DRWView *view, const Object *ob, const bPoseChannel *pchan, const float scale)
static const float * get_bone_hint_color(const Armatures::DrawContext *ctx, const eBone_Flag boneflag)
static void pchan_culling_calc_bsphere(const Object *ob, const bPoseChannel *pchan, BoundSphere *r_bsphere)
static void draw_axes(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const bArmature *arm)
void OVERLAY_armature_cache_finish(OVERLAY_Data *vedata)
void OVERLAY_bone_instance_data_set_color_hint(BoneInstanceData *data, const float hint_color[4])
static void use_bone_color(float *r_color, const uint8_t *color_from_theme, const int shade_offset)
void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
static void draw_bone_bone_relationship_line(const Armatures::DrawContext *ctx, const float bone_head[3], const float parent_head[3], const float parent_tail[3])
static void draw_points(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const float col_solid[4], const int select_id)
#define BUF_INSTANCE
static void drw_shgroup_bone_custom_wire(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float color[4], const float wire_width, const draw::select::ID select_id, Object *custom)
static void draw_bone_degrees_of_freedom(const Armatures::DrawContext *ctx, const bPoseChannel *pchan)
static void draw_bone_relations(const Armatures::DrawContext *ctx, const ArmatureBoneDrawStrategy &draw_strategy, const UnifiedBonePtr bone, const eBone_Flag boneflag)
static void drw_shgroup_bone_axes(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float color[4])
static void edbo_compute_bbone_child(bArmature *arm)
static void drw_shgroup_bone_ik_lines(const Armatures::DrawContext *ctx, const float start[3], const float end[3])
static void drw_shgroup_custom_bone_curve(const Armatures::DrawContext *ctx, Curve *curve, const float(*bone_mat)[4], const float outline_color[4], const float wire_width, const draw::select::ID select_id, Object *custom)
void OVERLAY_pose_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
static void draw_bone_name(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag)
static void bone_hint_color_shade(float hint_color[4], const float color[4])
static void draw_bone_update_disp_matrix_default(UnifiedBonePtr bone)
void OVERLAY_pose_cache_populate(OVERLAY_Data *vedata, Object *ob)
static void bone_locked_color_shade(float color[4])
static ArmatureBoneDrawStrategy & strategy_for_armature_drawtype(const eArmature_Drawtype drawtype)
void OVERLAY_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
static void draw_bone_update_disp_matrix_bbone(UnifiedBonePtr bone)
static void get_pchan_color_wire(const ThemeWireColor *bcolor, const eArmatureDrawMode draw_mode, const eBone_Flag boneflag, float r_color[4])
static float encode_2f_to_float(float a, float b)
static void get_pchan_color_solid(const ThemeWireColor *bcolor, float r_color[4])
static void armature_context_setup(Armatures::DrawContext *ctx, OVERLAY_PrivateData *pd, Object *ob, const eArmatureDrawMode draw_mode, const float *const_color)
static float get_bone_wire_thickness(const Armatures::DrawContext *ctx, int boneflag)
#define BUF_LINE(grp, format)
BLI_INLINE DRWCallBuffer * custom_bone_instance_shgroup(const Armatures::DrawContext *ctx, DRWShadingGroup *grp, blender::gpu::Batch *custom_geom)
static void bone_instance_data_set_angle_minmax(BoneInstanceData *data, const float aminx, const float aminz, const float amaxx, const float amaxz)
static void get_pchan_color_constraint(const ThemeWireColor *bcolor, const UnifiedBonePtr bone, float r_color[4])
static void drw_shgroup_bone_custom_mesh_wire(const Armatures::DrawContext *ctx, Mesh &mesh, const float(*bone_mat)[4], const float color[4], const float wire_width, const draw::select::ID select_id, Object &custom)
static void pchan_draw_ik_lines(const Armatures::DrawContext *ctx, const bPoseChannel *pchan, const bool only_temp)
static void drw_shgroup_bone_custom_solid_mesh(const Armatures::DrawContext *ctx, Mesh &mesh, const float(*bone_mat)[4], const float bone_color[4], const float hint_color[4], const float outline_color[4], const float wire_width, const draw::select::ID select_id, Object &custom)
static void pchan_draw_data_init(bPoseChannel *pchan)
void OVERLAY_pose_draw(OVERLAY_Data *vedata)
static bool pchan_culling_test_simple(const DRWView *view, const Object *ob, const bPoseChannel *pchan)
void OVERLAY_armature_draw(OVERLAY_Data *vedata)
static void drw_shgroup_bone_ik_no_target_lines(const Armatures::DrawContext *ctx, const float start[3], const float end[3])
static void set_ctx_bcolor(Armatures::DrawContext *ctx, const UnifiedBonePtr bone)
static void cp_shade_color3ub(uchar cp[3], const int offset)
static const float * get_bone_wire_color(const Armatures::DrawContext *ctx, const eBone_Flag boneflag)
static void drw_shgroup_bone_octahedral(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float bone_color[4], const float hint_color[4], const float outline_color[4])
static void drw_shgroup_bone_relationship_lines(const Armatures::DrawContext *ctx, const float start[3], const float end[3])
static void drw_shgroup_bone_sphere(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float bone_color[4], const float hint_color[4], const float outline_color[4], const int select_id)
void OVERLAY_bone_instance_data_set_color(BoneInstanceData *data, const float bone_color[4])
#define PT_DEFAULT_RAD
void OVERLAY_empty_shape(OVERLAY_ExtraCallBuffers *cb, const float mat[4][4], const float draw_size, const char draw_type, const float color[4])
void OVERLAY_extra_line_dashed(OVERLAY_ExtraCallBuffers *cb, const float start[3], const float end[3], const float color[4])
GPUShader * OVERLAY_shader_armature_wire()
GPUShader * OVERLAY_shader_uniform_color()
GPUShader * OVERLAY_shader_armature_stick()
GPUShader * OVERLAY_shader_armature_shape(bool use_outline)
GPUShader * OVERLAY_shader_armature_sphere(bool use_outline)
GPUShader * OVERLAY_shader_armature_shape_wire()
GPUShader * OVERLAY_shader_armature_degrees_of_freedom_wire()
GPUShader * OVERLAY_shader_armature_degrees_of_freedom_solid()
GPUShader * OVERLAY_shader_armature_envelope(bool use_outline)
OVERLAY_InstanceFormats * OVERLAY_shader_instance_formats_get()
#define WIRE_WIDTH_COMPRESSION
#define min(a, b)
Definition sort.c:32
unsigned char uint8_t
Definition stdint.h:78
void set_hint_color(const float4 &hint_color)
void set_color(const float4 &bone_color)
BoneColor color
struct Bone * parent
float bone_mat[3][3]
float center[3]
Definition DRW_render.hh:93
Object * object_pose
ViewLayer * view_layer
eObjectMode object_mode
GlobalsUboStorage block
GPUUniformBuf * block_ubo
float curve_out_z
float scale_in[3]
char name[64]
float ease2
float roll1
::BoneColor color
short segments
float tail[3]
char bbone_prev_type
EditBone * parent
float roll2
float disp_bbone_mat[32][4][4]
float curve_in_x
float disp_mat[4][4]
float zwidth
float curve_in_z
float length
float xwidth
float disp_tail_mat[4][4]
EditBone * next
EditBone * bbone_prev
char bbone_next_type
float rad_tail
EditBone * bbone_next
EditBone * bbone_child
float ease1
float rad_head
float scale_out[3]
float curve_out_x
float head[3]
void * first
float mat[4][4]
OVERLAY_ArmatureCallBuffersInner transp
OVERLAY_ArmatureCallBuffersInner solid
OVERLAY_PassList * psl
OVERLAY_StorageList * stl
OVERLAY_FramebufferList * fbl
GPUFrameBuffer * overlay_default_fb
GPUFrameBuffer * overlay_line_in_front_fb
GPUVertFormat * instance_bone_envelope_distance
GPUVertFormat * instance_bone_envelope_outline
GPUVertFormat * instance_bone
GPUVertFormat * instance_extra
GPUVertFormat * instance_bone_stick
GPUVertFormat * instance_bone_envelope
DRWPass * armature_ps[2]
DRWPass * armature_bone_select_ps
DRWPass * armature_transp_ps[2]
OVERLAY_ExtraCallBuffers extra_call_buffers[2]
DRWShadingGroup * armature_bone_select_grp
struct OVERLAY_PrivateData::@234 armature
OVERLAY_ArmatureCallBuffers armature_call_buffers[2]
DRWShadingGroup * armature_bone_select_act_grp
OVERLAY_PrivateData * pd
short base_flag
struct bPose * pose
ObjectRuntimeHandle * runtime
char empty_drawtype
unsigned char select[4]
unsigned char solid[4]
unsigned char active[4]
View3DShading shading
struct EditBone * act_edbone
ListBase * edbo
float bbone_matrix[0][4][4]
float custom_scale_xyz[3]
bPoseChannelDrawData * draw_data
float custom_rotation_euler[3]
struct Bone * bone
struct bPoseChannel * parent
struct bPoseChannel * custom_tx
struct Object * custom
struct bPoseChannel * next
float custom_translation[3]
float custom_shape_wire_width
float disp_mat[4][4]
float disp_tail_mat[4][4]
float pose_mat[4][4]
ListBase chanbase
const c_style_mat & ptr() const
void append(const float3 &start, const float3 &end, const float4 &color, select::ID select_id=select::SelectMap::select_invalid_id())
void append(const InstanceDataT &data, select::ID select_id)
const ID select_id(const ObjectRef &ob_ref, uint sub_object_id=0)
CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a)
Definition transform.h:63
PointerRNA * ptr
Definition wm_files.cc:4126