Blender V5.0
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
8
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
19#include "DRW_render.hh"
20
22#include "BLI_math_color.h"
23#include "BLI_math_matrix.h"
25#include "BLI_math_rotation.h"
26#include "BLI_math_vector.h"
27#include "BLI_utildefines.h"
28
29#include "BKE_action.hh"
30#include "BKE_armature.hh"
31#include "BKE_deform.hh"
32#include "BKE_object.hh"
33
35
36#include "ED_armature.hh"
37#include "ED_view3d.hh"
38
39#include "ANIM_armature.hh"
40#include "ANIM_bonecolor.hh"
41
42#include "UI_resources.hh"
43
44#include "draw_cache.hh"
46#include "draw_manager_text.hh"
47
48#include "overlay_armature.hh"
49
50#include "draw_cache_impl.hh"
51
52#define PT_DEFAULT_RAD 0.05f /* radius of the point batch. */
53
54using namespace blender::draw::overlay;
55
60 private:
61 union {
64 };
65 bool is_editbone_; /* Discriminator for the above union. */
66
67 public:
70
71 UnifiedBonePtr(EditBone *eBone) : eBone_(eBone), is_editbone_(true) {}
72 UnifiedBonePtr(bPoseChannel *pchan) : pchan_(pchan), is_editbone_(false) {}
73
74 const char *name() const
75 {
76 return is_editbone_ ? eBone_->name : pchan_->name;
77 }
78
79 const EditBone *as_editbone() const
80 {
81 BLI_assert_msg(is_editbone_,
82 "conversion to EditBone* only possible when "
83 "UnifiedBonePtr contains an edit bone");
84 return eBone_;
85 }
87 {
88 BLI_assert_msg(is_editbone_,
89 "conversion to EditBone* only possible when "
90 "UnifiedBonePtr contains an edit bone");
91 return eBone_;
92 }
93
95 {
96 BLI_assert_msg(!is_editbone_,
97 "conversion to bPoseChannel* only possible when "
98 "UnifiedBonePtr contains a pose channel");
99 return pchan_;
100 }
102 {
103 BLI_assert_msg(!is_editbone_,
104 "conversion to bPoseChannel* only possible when "
105 "UnifiedBonePtr contains a pose channel");
106 return pchan_;
107 }
108
109 bool is_editbone() const
110 {
111 return is_editbone_;
112 };
113 bool is_posebone() const
114 {
115 return !is_editbone();
116 };
117
118 void get(const EditBone **eBone, const bPoseChannel **pchan) const
119 {
120 *eBone = eBone_;
121 *pchan = pchan_;
122 }
123 void get(EditBone **eBone, bPoseChannel **pchan)
124 {
125 *eBone = eBone_;
126 *pchan = pchan_;
127 }
128
130 {
131 if (is_editbone_) {
132 return static_cast<eBone_Flag>(eBone_->flag);
133 }
134 /* Making sure the select flag is set correctly since it moved to the pose channel. */
135 eBone_Flag flag = static_cast<eBone_Flag>(pchan_->bone->flag);
136 if (pchan_->flag & POSE_SELECTED) {
138 }
139 else {
141 }
142 return flag;
143 }
144
147 {
148 return ePchan_ConstFlag(is_editbone_ ? 0 : pchan_->constflag);
149 }
150
151 bool has_parent() const
152 {
153 return is_editbone_ ? eBone_->parent != nullptr : pchan_->bone->parent != nullptr;
154 }
155
156 using f44 = float[4][4];
157 const f44 &disp_mat() const
158 {
159 return is_editbone_ ? eBone_->disp_mat : pchan_->disp_mat;
160 }
162 {
163 return is_editbone_ ? eBone_->disp_mat : pchan_->disp_mat;
164 }
165
166 const f44 &disp_tail_mat() const
167 {
168 return is_editbone_ ? eBone_->disp_tail_mat : pchan_->disp_tail_mat;
169 }
170
172 {
173 return is_editbone_ ? eBone_->disp_tail_mat : pchan_->disp_tail_mat;
174 }
175
176 /* For some, to me unknown, reason, the drawing code passes these around as pointers. This is the
177 * reason that these are returned as references. I'll leave refactoring that for another time. */
178 const float &rad_head() const
179 {
180 return is_editbone_ ? eBone_->rad_head : pchan_->bone->rad_head;
181 }
182
183 const float &rad_tail() const
184 {
185 return is_editbone_ ? eBone_->rad_tail : pchan_->bone->rad_tail;
186 }
187
189 {
190 if (is_editbone_) {
191 return eBone_->color.wrap();
192 }
193
194 if (pchan_->color.palette_index == 0) {
195 /* If the pchan has the 'default' color, treat it as a signal to use the underlying bone
196 * color. */
197 return pchan_->bone->color.wrap();
198 }
199 return pchan_->color.wrap();
200 }
201};
202
203/* -------------------------------------------------------------------- */
206
207/* Stick */
209 const float (*bone_mat)[4],
210 const float col_wire[4],
211 const float col_bone[4],
212 const float col_head[4],
213 const float col_tail[4],
214 const int select_id)
215{
216 float4x4 bmat = float4x4(bone_mat);
217 float3 head = math::transform_point(ctx->ob->object_to_world(), bmat.location());
218 float3 tail = math::transform_point(ctx->ob->object_to_world(), bmat.location() + bmat.y_axis());
219
220 auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id);
221
222 ctx->bone_buf->stick_buf.append({head,
223 tail,
224 *(float4 *)col_wire,
225 *(float4 *)col_bone,
226 *(float4 *)col_head,
227 *(float4 *)col_tail},
228 sel_id);
229}
230
231/* Envelope */
233 const float (*bone_mat)[4],
234 const float *radius_head,
235 const float *radius_tail,
236 const float *distance)
237{
238 if (ctx->draw_envelope_distance) {
239 float head_sph[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sph[4] = {0.0f, 1.0f, 0.0f, 1.0f};
240 float xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
241 /* Still less operation than m4 multiplication. */
242 mul_m4_v4(bone_mat, head_sph);
243 mul_m4_v4(bone_mat, tail_sph);
244 mul_m4_v4(bone_mat, xaxis);
245 mul_m4_v4(ctx->ob->object_to_world().ptr(), head_sph);
246 mul_m4_v4(ctx->ob->object_to_world().ptr(), tail_sph);
247 mul_m4_v4(ctx->ob->object_to_world().ptr(), xaxis);
248 sub_v3_v3(xaxis, head_sph);
249 float obscale = mat4_to_scale(ctx->ob->object_to_world().ptr());
250 head_sph[3] = *radius_head * obscale;
251 head_sph[3] += *distance * obscale;
252 tail_sph[3] = *radius_tail * obscale;
253 tail_sph[3] += *distance * obscale;
254 /* TODO(fclem): Cleanup these casts when Overlay Next is shipped. */
255 ctx->bone_buf->envelope_distance_buf.append(
256 {*(float4 *)head_sph, *(float4 *)tail_sph, *(float3 *)xaxis},
258 }
259}
260
262 const float (*bone_mat)[4],
263 const float bone_col[4],
264 const float hint_col[4],
265 const float outline_col[4],
266 const float *radius_head,
267 const float *radius_tail,
268 const int select_id)
269{
270 float head_sph[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sph[4] = {0.0f, 1.0f, 0.0f, 1.0f};
271 float xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
272 /* Still less operation than m4 multiplication. */
273 mul_m4_v4(bone_mat, head_sph);
274 mul_m4_v4(bone_mat, tail_sph);
275 mul_m4_v4(bone_mat, xaxis);
276 mul_m4_v4(ctx->ob->object_to_world().ptr(), head_sph);
277 mul_m4_v4(ctx->ob->object_to_world().ptr(), tail_sph);
278 mul_m4_v4(ctx->ob->object_to_world().ptr(), xaxis);
279 float obscale = mat4_to_scale(ctx->ob->object_to_world().ptr());
280 head_sph[3] = *radius_head * obscale;
281 tail_sph[3] = *radius_tail * obscale;
282
283 auto sel_id = (ctx->bone_buf) ? ctx->res->select_id(*ctx->ob_ref, select_id) :
285
286 if (head_sph[3] < 0.0f || tail_sph[3] < 0.0f) {
288 if (head_sph[3] < 0.0f) {
289 /* Draw Tail only */
290 scale_m4_fl(inst_data.mat, tail_sph[3] / PT_DEFAULT_RAD);
291 copy_v3_v3(inst_data.mat[3], tail_sph);
292 }
293 else {
294 /* Draw Head only */
295 scale_m4_fl(inst_data.mat, head_sph[3] / PT_DEFAULT_RAD);
296 copy_v3_v3(inst_data.mat[3], head_sph);
297 }
298
299 if (ctx->is_filled) {
300 ctx->bone_buf->sphere_fill_buf.append({inst_data.mat44, bone_col, hint_col}, sel_id);
301 }
302 if (outline_col[3] > 0.0f) {
303 ctx->bone_buf->sphere_outline_buf.append({inst_data.mat44, outline_col}, sel_id);
304 }
305 }
306 else {
307 /* Draw Body */
308 float tmp_sph[4];
309 float len = len_v3v3(tail_sph, head_sph);
310 float fac_head = (len - head_sph[3]) / len;
311 float fac_tail = (len - tail_sph[3]) / len;
312 /* Small epsilon to avoid problem with float precision in shader. */
313 if (len > (tail_sph[3] + head_sph[3]) + 1e-8f) {
314 copy_v4_v4(tmp_sph, head_sph);
315 interp_v4_v4v4(head_sph, tail_sph, head_sph, fac_head);
316 interp_v4_v4v4(tail_sph, tmp_sph, tail_sph, fac_tail);
317
318 if (ctx->is_filled) {
319 /* TODO(fclem): Cleanup these casts when Overlay Next is shipped. */
320 ctx->bone_buf->envelope_fill_buf.append({*(float4 *)head_sph,
321 *(float4 *)tail_sph,
322 *(float3 *)bone_col,
323 *(float3 *)hint_col,
324 *(float3 *)xaxis},
325 sel_id);
326 }
327 if (outline_col[3] > 0.0f) {
328 ctx->bone_buf->envelope_outline_buf.append(
329 {*(float4 *)head_sph, *(float4 *)tail_sph, *(float4 *)outline_col, *(float3 *)xaxis},
330 sel_id);
331 }
332 }
333 else {
334 /* Distance between endpoints is too small for a capsule. Draw a Sphere instead. */
335 float fac = max_ff(fac_head, 1.0f - fac_tail);
336 interp_v4_v4v4(tmp_sph, tail_sph, head_sph, clamp_f(fac, 0.0f, 1.0f));
337
339 scale_m4_fl(inst_data.mat, tmp_sph[3] / PT_DEFAULT_RAD);
340 copy_v3_v3(inst_data.mat[3], tmp_sph);
341
342 if (ctx->is_filled) {
343 ctx->bone_buf->sphere_fill_buf.append({inst_data.mat44, bone_col, hint_col}, sel_id);
344 }
345 if (outline_col[3] > 0.0f) {
346 ctx->bone_buf->sphere_outline_buf.append({inst_data.mat44, outline_col}, sel_id);
347 }
348 }
349 }
350}
351
352/* Custom (geometry) */
353
355 Mesh &mesh,
356 const float (*bone_mat)[4],
357 const float bone_color[4],
358 const float hint_color[4],
359 const float outline_color[4],
360 const float wire_width,
361 const draw::select::ID select_id,
362 Object &custom)
363{
364 using namespace blender::draw;
365 /* TODO(fclem): arg... less than ideal but we never iter on this object
366 * to assure batch cache is valid. */
368
369 blender::gpu::Batch *surf = DRW_mesh_batch_cache_get_surface(mesh);
370 blender::gpu::Batch *edges = DRW_mesh_batch_cache_get_edge_detection(mesh, nullptr);
371 blender::gpu::Batch *loose_edges = DRW_mesh_batch_cache_get_loose_edges(mesh);
373
374 if (surf || edges || loose_edges) {
375 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(bone_mat);
376 }
377
378 if (surf) {
379 inst_data.set_hint_color(hint_color);
380 inst_data.set_color(bone_color);
381 if (ctx->is_filled) {
382 ctx->bone_buf->custom_shape_fill_get_buffer(surf).append(inst_data, select_id);
383 }
384 }
385
386 if (edges) {
387 inst_data.set_color(outline_color);
388 ctx->bone_buf->custom_shape_outline_get_buffer(edges).append(inst_data, select_id);
389 }
390
391 if (loose_edges) {
392 inst_data.set_hint_color(outline_color);
393 inst_data.set_color(float4(UNPACK3(outline_color), wire_width / WIRE_WIDTH_COMPRESSION));
394 ctx->bone_buf->custom_shape_wire_get_buffer(loose_edges).append(inst_data, select_id);
395 }
396
397 /* TODO(fclem): needs to be moved elsewhere. */
399}
400
402 Mesh &mesh,
403 const float (*bone_mat)[4],
404 const float color[4],
405 const float wire_width,
406 const draw::select::ID select_id,
407 Object &custom)
408{
409 using namespace blender::draw;
410 /* TODO(fclem): arg... less than ideal but we never iter on this object
411 * to assure batch cache is valid. */
413
414 blender::gpu::Batch *geom = DRW_mesh_batch_cache_get_all_edges(mesh);
415 if (geom) {
417 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(bone_mat);
418 inst_data.set_hint_color(color);
419 inst_data.set_color(float4(UNPACK3(color), wire_width / WIRE_WIDTH_COMPRESSION));
420
421 ctx->bone_buf->custom_shape_wire_get_buffer(geom).append(inst_data, select_id);
422 }
423
424 /* TODO(fclem): needs to be moved elsewhere. */
426}
427
429 Curve *curve,
430 const float (*bone_mat)[4],
431 const float outline_color[4],
432 const float wire_width,
433 const draw::select::ID select_id,
434 Object *custom)
435{
436 using namespace blender::draw;
437 /* TODO(fclem): arg... less than ideal but we never iter on this object
438 * to assure batch cache is valid. */
440
441 /* This only handles curves without any surface. The other curve types should have been converted
442 * to meshes and rendered in the mesh drawing function. */
443 blender::gpu::Batch *loose_edges = nullptr;
444 if (custom->type == OB_FONT) {
445 loose_edges = DRW_cache_text_edge_wire_get(custom);
446 }
447 else {
448 loose_edges = DRW_cache_curve_edge_wire_get(custom);
449 }
450
451 if (loose_edges) {
453 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(bone_mat);
454 inst_data.set_hint_color(outline_color);
455 inst_data.set_color(float4(UNPACK3(outline_color), wire_width / WIRE_WIDTH_COMPRESSION));
456
457 ctx->bone_buf->custom_shape_wire_get_buffer(loose_edges).append(inst_data, select_id);
458 }
459
460 /* TODO(fclem): needs to be moved elsewhere. */
462}
463
465 const float (*bone_mat)[4],
466 const float bone_color[4],
467 const float hint_color[4],
468 const float outline_color[4],
469 const float wire_width,
470 const draw::select::ID select_id,
471 Object *custom)
472{
473 /* The custom object is not an evaluated object, so its object->data field hasn't been replaced
474 * by #data_eval. This is bad since it gives preference to an object's evaluated mesh over any
475 * other data type, but supporting all evaluated geometry components would require a much
476 * larger refactor of this area. */
478 if (mesh != nullptr) {
481 bone_mat,
482 bone_color,
483 hint_color,
484 outline_color,
485 wire_width,
486 select_id,
487 *custom);
488 return;
489 }
490
491 if (ELEM(custom->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) {
494 bone_mat,
495 outline_color,
496 wire_width,
497 select_id,
498 custom);
499 }
500}
501
503 const float (*bone_mat)[4],
504 const float color[4],
505 const float wire_width,
506 const draw::select::ID select_id,
507 Object *custom)
508{
509 /* See comments in #drw_shgroup_bone_custom_solid. */
511 if (mesh != nullptr) {
513 ctx, DRW_mesh_get_for_drawing(*mesh), bone_mat, color, wire_width, select_id, *custom);
514 return;
515 }
516
517 if (ELEM(custom->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) {
520 bone_mat,
521 color,
522 wire_width,
523 select_id,
524 custom);
525 }
526}
527
529 const float (*bone_mat)[4],
530 const float color[4],
531 const float wire_width,
532 const draw::select::ID select_id,
533 Object *custom)
534{
535 using namespace blender::draw;
536
537 gpu::Batch *geom = nullptr;
538 switch (custom->empty_drawtype) {
539 case OB_PLAINAXES:
540 geom = ctx->res->shapes.plain_axes.get();
541 break;
542 case OB_SINGLE_ARROW:
543 geom = ctx->res->shapes.single_arrow.get();
544 break;
545 case OB_CUBE:
546 geom = ctx->res->shapes.cube.get();
547 break;
548 case OB_CIRCLE:
549 geom = ctx->res->shapes.circle.get();
550 break;
551 case OB_EMPTY_SPHERE:
552 geom = ctx->res->shapes.empty_sphere.get();
553 break;
554 case OB_EMPTY_CONE:
555 geom = ctx->res->shapes.empty_cone.get();
556 break;
557 case OB_ARROWS:
558 geom = ctx->res->shapes.arrows.get();
559 break;
560 case OB_EMPTY_IMAGE:
561 /* Not supported. */
562 return;
563 }
564 BLI_assert(geom);
565
566 const float4 final_color(UNPACK3(color), 1.0f);
567
569 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(bone_mat) *
571 inst_data.set_hint_color(final_color);
572 inst_data.set_color(float4(UNPACK3(final_color), wire_width / WIRE_WIDTH_COMPRESSION));
573
574 ctx->bone_buf->custom_shape_wire_get_buffer(geom).append(inst_data, select_id);
575}
576
577/* Head and tail sphere */
579 const float (*bone_mat)[4],
580 const float bone_color[4],
581 const float hint_color[4],
582 const float outline_color[4],
583 const int select_id)
584{
585 auto sel_id = (ctx->bone_buf) ? ctx->res->select_id(*ctx->ob_ref, select_id) :
587 float4x4 mat = ctx->ob->object_to_world() * float4x4(bone_mat);
588
589 if (ctx->is_filled) {
590 ctx->bone_buf->sphere_fill_buf.append({mat, bone_color, hint_color}, sel_id);
591 }
592 if (outline_color[3] > 0.0f) {
593 ctx->bone_buf->sphere_outline_buf.append({mat, outline_color}, sel_id);
594 }
595}
596
597/* Axes */
599 const float (*bone_mat)[4],
600 const float color[4])
601{
602 float4x4 mat = ctx->ob->object_to_world() * float4x4(bone_mat);
603 /* Move to bone tail. */
604 mat[3] += mat[1];
605 ExtraInstanceData data(mat, color, 0.25f);
606 /* NOTE: Axes are not drawn in bone selection (pose or edit mode).
607 * They are only drawn and selectable in object mode. So only load the object select ID. */
608 ctx->bone_buf->arrows_buf.append(data, ctx->res->select_id(*ctx->ob_ref));
609}
610
611/* Relationship lines */
613 const float start[3],
614 const float end[3],
615 const float color[4])
616{
617 float3 start_pt = math::transform_point(ctx->ob->object_to_world(), float3(start));
618 float3 end_pt = math::transform_point(ctx->ob->object_to_world(), float3(end));
619
620 /* Reverse order to have less stipple overlap. */
621 ctx->bone_buf->relations_buf.append(end_pt, start_pt, float4(color));
622}
623
625 const float start[3],
626 const float end[3])
627{
628 const UniformData &theme = ctx->res->theme;
629 drw_shgroup_bone_relationship_lines_ex(ctx, start, end, theme.colors.wire);
630}
631
633 const float start[3],
634 const float end[3])
635{
636 const UniformData &theme = ctx->res->theme;
638}
639
641 const float start[3],
642 const float end[3])
643{
644 const UniformData &theme = ctx->res->theme;
646}
647
649 const float start[3],
650 const float end[3])
651{
652 const UniformData &theme = ctx->res->theme;
654}
655
657
658/* -------------------------------------------------------------------- */
664
665/* This function sets the color-set for coloring a certain bone */
667{
669
670 if ((arm.flag & ARM_COL_CUSTOM) == 0) {
671 /* Only set a custom color if that's enabled on this armature. */
672 ctx->bcolor = nullptr;
673 return;
674 }
675
676 const blender::animrig::BoneColor &bone_color = bone.effective_bonecolor();
677 ctx->bcolor = bone_color.effective_color();
678}
679
680/* This function is for brightening/darkening a given color (like UI_GetThemeColorShade3ubv()) */
681static void cp_shade_color3ub(uchar cp[3], const int offset)
682{
683 int r, g, b;
684
685 r = offset + int(cp[0]);
686 CLAMP(r, 0, 255);
687 g = offset + int(cp[1]);
688 CLAMP(g, 0, 255);
689 b = offset + int(cp[2]);
690 CLAMP(b, 0, 255);
691
692 cp[0] = r;
693 cp[1] = g;
694 cp[2] = b;
695}
696
702static void use_bone_color(float *r_color, const uint8_t *color_from_theme, const int shade_offset)
703{
704 uint8_t srgb_color[4] = {255, 255, 255, 255};
705 /* Only copy RGB, not alpha. The "alpha" channel in the bone theme colors is
706 * essentially just padding, and should be ignored. */
707 copy_v3_v3_uchar(srgb_color, color_from_theme);
708 if (shade_offset != 0) {
709 cp_shade_color3ub(srgb_color, shade_offset);
710 }
711 rgba_uchar_to_float(r_color, srgb_color);
712 /* Meh, hardcoded srgb transform here. */
713 srgb_to_linearrgb_v4(r_color, r_color);
714};
715
716static void get_pchan_color_wire(const UniformData &theme,
717 const ThemeWireColor *bcolor,
718 const eArmatureDrawMode draw_mode,
719 const eBone_Flag boneflag,
720 float r_color[4])
721{
722 const bool draw_active = boneflag & BONE_DRAW_ACTIVE;
723 const bool draw_selected = boneflag & BONE_SELECTED;
724 const bool is_edit = draw_mode == ARM_DRAW_MODE_EDIT;
725 float4 wire_color;
726
727 if (bcolor) {
728 if (draw_active && draw_selected) {
729 use_bone_color(r_color, bcolor->active, 0);
730 }
731 else if (draw_active) {
732 use_bone_color(r_color, bcolor->active, -80);
733 }
734 else if (draw_selected) {
735 use_bone_color(r_color, bcolor->select, 0);
736 }
737 else {
738 use_bone_color(r_color, bcolor->solid, -50);
739 }
740 }
741 else {
742 if (draw_active && draw_selected) {
743 wire_color = is_edit ? theme.colors.bone_active : theme.colors.bone_pose_active;
744 }
745 else if (draw_active) {
746 wire_color = is_edit ? theme.colors.bone_active_unsel : theme.colors.bone_pose_active_unsel;
747 }
748 else if (draw_selected) {
749 wire_color = is_edit ? theme.colors.bone_select : theme.colors.bone_pose;
750 }
751 else {
752 wire_color = is_edit ? theme.colors.wire_edit : theme.colors.wire;
753 }
754 copy_v4_v4(r_color, wire_color);
755 }
756}
757
758static void get_pchan_color_solid(const UniformData &theme,
759 const ThemeWireColor *bcolor,
760 float r_color[4])
761{
762
763 if (bcolor) {
764 use_bone_color(r_color, bcolor->solid, 0);
765 }
766 else {
767 copy_v4_v4(r_color, theme.colors.bone_solid);
768 }
769}
770
772 const ThemeWireColor *bcolor,
773 const UnifiedBonePtr bone,
774 float r_color[4])
775{
776 const ePchan_ConstFlag constflag = bone.constflag();
777 /* Not all flags should result in a different bone color. */
780 if ((constflag & flags_to_color) == 0 ||
781 (bcolor && (bcolor->flag & TH_WIRECOLOR_CONSTCOLS) == 0))
782 {
783 get_pchan_color_solid(theme, bcolor, r_color);
784 return;
785 }
786
787 /* The constraint color needs to be blended with the solid color. */
788 float solid_color[4];
789 get_pchan_color_solid(theme, bcolor, solid_color);
790
791 float4 constraint_color;
792 if (constflag & PCHAN_HAS_NO_TARGET) {
793 constraint_color = theme.colors.bone_pose_no_target;
794 }
795 else if (constflag & PCHAN_HAS_IK) {
796 constraint_color = theme.colors.bone_pose_ik;
797 }
798 else if (constflag & PCHAN_HAS_SPLINEIK) {
799 constraint_color = theme.colors.bone_pose_spline_ik;
800 }
801 else if (constflag & PCHAN_HAS_CONST) {
802 constraint_color = theme.colors.bone_pose_constraint;
803 }
804 interp_v4_v4v4(r_color, solid_color, constraint_color, 0.5f);
805}
806
808
809/* -------------------------------------------------------------------- */
812
813static void bone_locked_color_shade(const UniformData &theme, float color[4])
814{
815 const float *locked_color = theme.colors.bone_locked;
816
817 interp_v3_v3v3(color, color, locked_color, locked_color[3]);
818}
819
820static const float *get_bone_solid_color(const Armatures::DrawContext *ctx,
821 const eBone_Flag boneflag)
822{
823 const UniformData &theme = ctx->res->theme;
824 if (ctx->const_color) {
825 return theme.colors.bone_solid;
826 }
827
828 static float disp_color[4];
829 get_pchan_color_solid(theme, ctx->bcolor, disp_color);
830
831 if (ctx->draw_mode == ARM_DRAW_MODE_POSE && (boneflag & BONE_DRAW_LOCKED_WEIGHT)) {
832 bone_locked_color_shade(theme, disp_color);
833 }
834
835 return disp_color;
836}
837
839 const UnifiedBonePtr bone,
840 const eBone_Flag boneflag)
841{
842 const UniformData &theme = ctx->res->theme;
843 if (ctx->const_color) {
844 return theme.colors.bone_solid;
845 }
846
847 const float *col = get_bone_solid_color(ctx, boneflag);
848
849 if (ctx->draw_mode != ARM_DRAW_MODE_POSE || (boneflag & BONE_DRAW_LOCKED_WEIGHT)) {
850 return col;
851 }
852
853 static float consts_color[4];
854 get_pchan_color_constraint(theme, ctx->bcolor, bone, consts_color);
855 return consts_color;
856}
857
858static float get_bone_wire_thickness(const Armatures::DrawContext *ctx, int boneflag)
859{
860 if (ctx->const_color) {
861 return ctx->const_wire;
862 }
863 if (boneflag & (BONE_DRAW_ACTIVE | BONE_SELECTED)) {
864 return 2.0f;
865 }
866
867 return 1.0f;
868}
869
870static const float *get_bone_wire_color(const Armatures::DrawContext *ctx,
871 const eBone_Flag boneflag)
872{
873 static float disp_color[4];
874
875 if (ctx->const_color) {
876 copy_v3_v3(disp_color, ctx->const_color);
877 }
878 else {
879 const UniformData &theme = ctx->res->theme;
880 switch (ctx->draw_mode) {
882 get_pchan_color_wire(theme, ctx->bcolor, ctx->draw_mode, boneflag, disp_color);
883 break;
885 get_pchan_color_wire(theme, ctx->bcolor, ctx->draw_mode, boneflag, disp_color);
886
887 if (boneflag & BONE_DRAW_LOCKED_WEIGHT) {
888 bone_locked_color_shade(theme, disp_color);
889 }
890 break;
892 copy_v3_v3(disp_color, theme.colors.vert);
893 break;
894 }
895 }
896
897 disp_color[3] = get_bone_wire_thickness(ctx, boneflag);
898
899 return disp_color;
900}
901
902static void bone_hint_color_shade(float hint_color[4], const float color[4])
903{
904 /* Increase contrast. */
905 mul_v3_v3v3(hint_color, color, color);
906 /* Decrease value to add mode shading to the shape. */
907 mul_v3_fl(hint_color, 0.1f);
908 hint_color[3] = 1.0f;
909}
910
911static const float *get_bone_hint_color(const Armatures::DrawContext *ctx,
912 const eBone_Flag boneflag)
913{
914 static float hint_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
915
916 if (ctx->const_color) {
917 bone_hint_color_shade(hint_color, ctx->res->theme.colors.bone_solid);
918 }
919 else {
920 const float *wire_color = get_bone_wire_color(ctx, boneflag);
921 bone_hint_color_shade(hint_color, wire_color);
922 }
923
924 return hint_color;
925}
926
928
929/* -------------------------------------------------------------------- */
932
934{
935 if (pchan->draw_data != nullptr) {
936 if (pchan->draw_data->bbone_matrix_len != pchan->bone->segments) {
937 MEM_SAFE_FREE(pchan->draw_data);
938 }
939 }
940
941 if (pchan->draw_data == nullptr) {
942 pchan->draw_data = static_cast<bPoseChannelDrawData *>(
943 MEM_mallocN(sizeof(*pchan->draw_data) + sizeof(Mat4) * pchan->bone->segments, __func__));
944 pchan->draw_data->bbone_matrix_len = pchan->bone->segments;
945 }
946}
947
949{
950 float ebmat[4][4];
951 float bone_scale[3];
952 float (*bone_mat)[4];
953 float (*disp_mat)[4] = bone.disp_mat();
954 float (*disp_tail_mat)[4] = bone.disp_tail_mat();
955
956 /* TODO: This should be moved to depsgraph or armature refresh
957 * and not be tied to the draw pass creation.
958 * This would refresh armature without invalidating the draw cache */
959 if (bone.is_posebone()) {
960 bPoseChannel *pchan = bone.as_posebone();
961 bone_mat = pchan->pose_mat;
962 copy_v3_fl(bone_scale, pchan->bone->length);
963 }
964 else {
965 EditBone *eBone = bone.as_editbone();
966 eBone->length = len_v3v3(eBone->tail, eBone->head);
967 ED_armature_ebone_to_mat4(eBone, ebmat);
968
969 copy_v3_fl(bone_scale, eBone->length);
970 bone_mat = ebmat;
971 }
972
973 copy_m4_m4(disp_mat, bone_mat);
974 rescale_m4(disp_mat, bone_scale);
975 copy_m4_m4(disp_tail_mat, disp_mat);
976 translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
977}
978
980{
981 float bone_scale[3];
982 float (*bone_mat)[4];
983 float (*disp_mat)[4];
984 float (*disp_tail_mat)[4];
985 float rot_mat[3][3];
986
987 /* Custom bone shapes are only supported in pose mode for now. */
988 bPoseChannel *pchan = bone.as_posebone();
989
990 /* TODO: This should be moved to depsgraph or armature refresh
991 * and not be tied to the draw pass creation.
992 * This would refresh armature without invalidating the draw cache. */
993 mul_v3_v3fl(bone_scale, pchan->custom_scale_xyz, PCHAN_CUSTOM_BONE_LENGTH(pchan));
994 bone_mat = pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat;
995 disp_mat = bone.disp_mat();
996 disp_tail_mat = pchan->disp_tail_mat;
997
999
1000 copy_m4_m4(disp_mat, bone_mat);
1001 translate_m4(disp_mat,
1002 pchan->custom_translation[0],
1003 pchan->custom_translation[1],
1004 pchan->custom_translation[2]);
1005 mul_m4_m4m3(disp_mat, disp_mat, rot_mat);
1006 rescale_m4(disp_mat, bone_scale);
1007 copy_m4_m4(disp_tail_mat, disp_mat);
1008 translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
1009}
1010
1011/* compute connected child pointer for B-Bone drawing */
1013{
1014 LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
1015 eBone->bbone_child = nullptr;
1016 }
1017
1018 LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
1019 if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
1020 eBone->parent->bbone_child = eBone;
1021 }
1022 }
1023}
1024
1025/* A version of BKE_pchan_bbone_spline_setup() for previewing editmode curve settings. */
1026static void ebone_spline_preview(EditBone *ebone, const float result_array[MAX_BBONE_SUBDIV][4][4])
1027{
1029 EditBone *prev, *next;
1030 float imat[4][4], bonemat[4][4];
1031 float tmp[3];
1032
1033 memset(&param, 0, sizeof(param));
1034
1035 param.segments = ebone->segments;
1036 param.length = ebone->length;
1037
1038 /* Get "next" and "prev" bones - these are used for handle calculations. */
1039 if (ebone->bbone_prev_type == BBONE_HANDLE_AUTO) {
1040 /* Use connected parent. */
1041 if (ebone->flag & BONE_CONNECTED) {
1042 prev = ebone->parent;
1043 }
1044 else {
1045 prev = nullptr;
1046 }
1047 }
1048 else {
1049 prev = ebone->bbone_prev;
1050 }
1051
1052 if (ebone->bbone_next_type == BBONE_HANDLE_AUTO) {
1053 /* Use connected child. */
1054 next = ebone->bbone_child;
1055 }
1056 else {
1057 next = ebone->bbone_next;
1058 }
1059
1060 /* compute handles from connected bones */
1061 if (prev || next) {
1062 ED_armature_ebone_to_mat4(ebone, imat);
1063 invert_m4(imat);
1064
1065 if (prev) {
1066 param.use_prev = true;
1067
1068 if (ebone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
1069 zero_v3(param.prev_h);
1070 }
1071 else if (ebone->bbone_prev_type == BBONE_HANDLE_TANGENT) {
1072 sub_v3_v3v3(tmp, prev->tail, prev->head);
1073 sub_v3_v3v3(tmp, ebone->head, tmp);
1074 mul_v3_m4v3(param.prev_h, imat, tmp);
1075 }
1076 else {
1077 param.prev_bbone = (prev->segments > 1);
1078
1079 mul_v3_m4v3(param.prev_h, imat, prev->head);
1080 }
1081
1082 if (!param.prev_bbone) {
1083 ED_armature_ebone_to_mat4(prev, bonemat);
1084 mul_m4_m4m4(param.prev_mat, imat, bonemat);
1085 }
1086 }
1087
1088 if (next) {
1089 param.use_next = true;
1090
1091 if (ebone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
1092 copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0);
1093 }
1094 else if (ebone->bbone_next_type == BBONE_HANDLE_TANGENT) {
1095 sub_v3_v3v3(tmp, next->tail, next->head);
1096 add_v3_v3v3(tmp, ebone->tail, tmp);
1097 mul_v3_m4v3(param.next_h, imat, tmp);
1098 }
1099 else {
1100 param.next_bbone = (next->segments > 1);
1101
1102 mul_v3_m4v3(param.next_h, imat, next->tail);
1103 }
1104
1106 mul_m4_m4m4(param.next_mat, imat, bonemat);
1107 }
1108 }
1109
1110 param.ease1 = ebone->ease1;
1111 param.ease2 = ebone->ease2;
1112 param.roll1 = ebone->roll1;
1113 param.roll2 = ebone->roll2;
1114
1115 if (prev && (ebone->bbone_flag & BBONE_ADD_PARENT_END_ROLL)) {
1116 param.roll1 += prev->roll2;
1117 }
1118
1119 copy_v3_v3(param.scale_in, ebone->scale_in);
1120 copy_v3_v3(param.scale_out, ebone->scale_out);
1121
1122 param.curve_in_x = ebone->curve_in_x;
1123 param.curve_in_z = ebone->curve_in_z;
1124
1125 param.curve_out_x = ebone->curve_out_x;
1126 param.curve_out_z = ebone->curve_out_z;
1127
1128 if (ebone->bbone_flag & BBONE_SCALE_EASING) {
1129 param.ease1 *= param.scale_in[1];
1130 param.curve_in_x *= param.scale_in[1];
1131 param.curve_in_z *= param.scale_in[1];
1132
1133 param.ease2 *= param.scale_out[1];
1134 param.curve_out_x *= param.scale_out[1];
1135 param.curve_out_z *= param.scale_out[1];
1136 }
1137
1138 ebone->segments = BKE_pchan_bbone_spline_compute(&param, false, (Mat4 *)result_array);
1139}
1140
1141/* This function is used for both B-Bone and Wire matrix updates. */
1143{
1144 float s[4][4], ebmat[4][4];
1145 float length, xwidth, zwidth;
1146 float (*bone_mat)[4];
1147 short bbone_segments;
1148
1149 /* TODO: This should be moved to depsgraph or armature refresh
1150 * and not be tied to the draw pass creation.
1151 * This would refresh armature without invalidating the draw cache. */
1152 if (bone.is_posebone()) {
1153 bPoseChannel *pchan = bone.as_posebone();
1154 length = pchan->bone->length;
1155 xwidth = pchan->bone->xwidth;
1156 zwidth = pchan->bone->zwidth;
1157 bone_mat = pchan->pose_mat;
1158 bbone_segments = pchan->bone->segments;
1159 }
1160 else {
1161 EditBone *eBone = bone.as_editbone();
1162 eBone->length = len_v3v3(eBone->tail, eBone->head);
1163 ED_armature_ebone_to_mat4(eBone, ebmat);
1164
1165 length = eBone->length;
1166 xwidth = eBone->xwidth;
1167 zwidth = eBone->zwidth;
1168 bone_mat = ebmat;
1169 bbone_segments = eBone->segments;
1170 }
1171
1172 const float3 size_vec = {xwidth, length / bbone_segments, zwidth};
1173 size_to_mat4(s, size_vec);
1174
1175 /* Compute BBones segment matrices... */
1176 /* Note that we need this even for one-segment bones, because box drawing need specific weirdo
1177 * matrix for the box, that we cannot use to draw end points & co. */
1178 if (bone.is_posebone()) {
1179 bPoseChannel *pchan = bone.as_posebone();
1180 Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
1181 if (bbone_segments > 1) {
1182 BKE_pchan_bbone_spline_setup(pchan, false, false, bbones_mat);
1183
1184 for (int i = bbone_segments; i--; bbones_mat++) {
1185 mul_m4_m4m4(bbones_mat->mat, bbones_mat->mat, s);
1186 mul_m4_m4m4(bbones_mat->mat, bone_mat, bbones_mat->mat);
1187 }
1188 }
1189 else {
1190 mul_m4_m4m4(bbones_mat->mat, bone_mat, s);
1191 }
1192 }
1193 else {
1194 EditBone *eBone = bone.as_editbone();
1195 float (*bbones_mat)[4][4] = eBone->disp_bbone_mat;
1196
1197 if (bbone_segments > 1) {
1198 ebone_spline_preview(eBone, bbones_mat);
1199
1200 for (int i = bbone_segments; i--; bbones_mat++) {
1201 mul_m4_m4m4(*bbones_mat, *bbones_mat, s);
1202 mul_m4_m4m4(*bbones_mat, bone_mat, *bbones_mat);
1203 }
1204 }
1205 else {
1206 mul_m4_m4m4(*bbones_mat, bone_mat, s);
1207 }
1208 }
1209
1210 /* Grrr... We need default display matrix to draw end points, axes, etc. :( */
1212}
1213
1214static void draw_axes(const Armatures::DrawContext *ctx,
1215 const UnifiedBonePtr bone,
1216 const bArmature &arm)
1217{
1218 float final_col[4];
1219 const float *col = (ctx->const_color) ? ctx->const_color :
1220 (bone.flag() & BONE_SELECTED) ? &ctx->res->theme.colors.text_hi.x :
1221 &ctx->res->theme.colors.text.x;
1222 copy_v4_v4(final_col, col);
1223 /* Mix with axes color. */
1224 final_col[3] = (ctx->const_color) ? 1.0 : (bone.flag() & BONE_SELECTED) ? 0.1 : 0.65;
1225
1226 if (bone.is_posebone() && bone.as_posebone()->custom && !(arm.flag & ARM_NO_CUSTOM)) {
1227 const bPoseChannel *pchan = bone.as_posebone();
1228 /* Special case: Custom bones can have different scale than the bone.
1229 * Recompute display matrix without the custom scaling applied. (#65640). */
1230 float axis_mat[4][4];
1231 float length = pchan->bone->length;
1232 copy_m4_m4(axis_mat, pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat);
1233 const float3 length_vec = {length, length, length};
1234 rescale_m4(axis_mat, length_vec);
1235 translate_m4(axis_mat, 0.0, arm.axes_position - 1.0, 0.0);
1236
1237 drw_shgroup_bone_axes(ctx, axis_mat, final_col);
1238 }
1239 else {
1240 float disp_mat[4][4];
1241 copy_m4_m4(disp_mat, bone.disp_mat());
1242 translate_m4(disp_mat, 0.0, arm.axes_position - 1.0, 0.0);
1243 drw_shgroup_bone_axes(ctx, disp_mat, final_col);
1244 }
1245}
1246
1248 const UnifiedBonePtr bone,
1249 const eBone_Flag boneflag,
1250 const float col_solid[4],
1251 const int select_id)
1252{
1253 float col_wire_root[4], col_wire_tail[4];
1254 float col_hint_root[4], col_hint_tail[4];
1255
1256 const UniformData &theme = ctx->res->theme;
1257
1258 copy_v4_v4(col_wire_root, (ctx->const_color) ? ctx->const_color : &theme.colors.vert.x);
1259 copy_v4_v4(col_wire_tail, (ctx->const_color) ? ctx->const_color : &theme.colors.vert.x);
1260
1261 const bool is_envelope_draw = (ctx->drawtype == ARM_DRAW_TYPE_ENVELOPE);
1262 const float envelope_ignore = -1.0f;
1263
1264 col_wire_tail[3] = col_wire_root[3] = get_bone_wire_thickness(ctx, boneflag);
1265
1266 /* Edit bone points can be selected */
1267 if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
1268 const EditBone *eBone = bone.as_editbone();
1269 if (eBone->flag & BONE_ROOTSEL) {
1270 copy_v3_v3(col_wire_root, theme.colors.vert_select);
1271 }
1272 if (eBone->flag & BONE_TIPSEL) {
1273 copy_v3_v3(col_wire_tail, theme.colors.vert_select);
1274 }
1275 }
1276 else if (ctx->draw_mode == ARM_DRAW_MODE_POSE) {
1277 const float *wire_color = get_bone_wire_color(ctx, boneflag);
1278 copy_v4_v4(col_wire_tail, wire_color);
1279 copy_v4_v4(col_wire_root, wire_color);
1280 }
1281
1282 const float *hint_color_shade_root = (ctx->const_color) ?
1283 (const float *)theme.colors.bone_solid :
1284 col_wire_root;
1285 const float *hint_color_shade_tail = (ctx->const_color) ?
1286 (const float *)theme.colors.bone_solid :
1287 col_wire_tail;
1288 bone_hint_color_shade(col_hint_root, hint_color_shade_root);
1289 bone_hint_color_shade(col_hint_tail, hint_color_shade_tail);
1290
1291 /* Draw root point if we are not connected to our parent */
1292
1293 if (!(bone.has_parent() && (boneflag & BONE_CONNECTED))) {
1294 if (is_envelope_draw) {
1296 bone.disp_mat(),
1297 col_solid,
1298 col_hint_root,
1299 col_wire_root,
1300 &bone.rad_head(),
1301 &envelope_ignore,
1302 select_id | BONESEL_ROOT);
1303 }
1304 else {
1306 ctx, bone.disp_mat(), col_solid, col_hint_root, col_wire_root, select_id | BONESEL_ROOT);
1307 }
1308 }
1309
1310 /* Draw tip point. */
1311 if (is_envelope_draw) {
1313 bone.disp_mat(),
1314 col_solid,
1315 col_hint_tail,
1316 col_wire_tail,
1317 &envelope_ignore,
1318 &bone.rad_tail(),
1319 select_id | BONESEL_TIP);
1320 }
1321 else {
1323 bone.disp_tail_mat(),
1324 col_solid,
1325 col_hint_tail,
1326 col_wire_tail,
1327 select_id | BONESEL_TIP);
1328 }
1329}
1330
1332 const UnifiedBonePtr bone,
1333 const eBone_Flag boneflag,
1334 const int select_id)
1335{
1336 const float *col_solid = get_bone_solid_color(ctx, boneflag);
1337 const float *col_wire = get_bone_wire_color(ctx, boneflag);
1338 const float *col_hint = get_bone_hint_color(ctx, boneflag);
1339 const float (*disp_mat)[4] = bone.disp_mat();
1340
1341 auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
1342
1343 /* Custom bone shapes are only supported in pose mode for now. */
1344 const bPoseChannel *pchan = bone.as_posebone();
1345 Object *custom_shape_ob = pchan->custom;
1346
1347 if (custom_shape_ob->type == OB_EMPTY) {
1348 if (custom_shape_ob->empty_drawtype != OB_EMPTY_IMAGE) {
1350 ctx, disp_mat, col_wire, pchan->custom_shape_wire_width, sel_id, pchan->custom);
1351 }
1352 }
1353 else if (boneflag & (BONE_DRAWWIRE | BONE_DRAW_LOCKED_WEIGHT)) {
1355 ctx, disp_mat, col_wire, pchan->custom_shape_wire_width, sel_id, pchan->custom);
1356 }
1357 else {
1359 disp_mat,
1360 col_solid,
1361 col_hint,
1362 col_wire,
1364 sel_id,
1365 pchan->custom);
1366 }
1367}
1368
1370 const UnifiedBonePtr bone,
1371 const eBone_Flag boneflag,
1372 const int select_id)
1373{
1374 const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
1375 const float *col_wire = get_bone_wire_color(ctx, boneflag);
1376 const float *col_hint = get_bone_hint_color(ctx, boneflag);
1377
1378 auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
1379 float4x4 bone_mat = ctx->ob->object_to_world() * float4x4(bone.disp_mat());
1380
1381 if (ctx->is_filled) {
1382 ctx->bone_buf->octahedral_fill_buf.append({bone_mat, col_solid, col_hint}, sel_id);
1383 }
1384 if (col_wire[3] > 0.0f) {
1385 ctx->bone_buf->octahedral_outline_buf.append({bone_mat, col_wire}, sel_id);
1386 }
1387
1388 draw_points(ctx, bone, boneflag, col_solid, select_id);
1389}
1390
1392 const UnifiedBonePtr bone,
1393 const eBone_Flag boneflag,
1394 const int select_id)
1395{
1396 const float *col_bone = get_bone_solid_with_consts_color(ctx, bone, boneflag);
1397 const float *col_wire = get_bone_wire_color(ctx, boneflag);
1398 const float no_display[4] = {0.0f, 0.0f, 0.0f, 0.0f};
1399 const float *col_head = no_display;
1400 const float *col_tail = col_bone;
1401
1402 if (ctx->const_color != nullptr) {
1403 col_wire = no_display; /* actually shrink the display. */
1404 col_bone = col_head = col_tail = ctx->const_color;
1405 }
1406 else {
1407 const UniformData &theme = ctx->res->theme;
1408
1409 if (bone.is_editbone() && bone.flag() & BONE_TIPSEL) {
1410 col_tail = &theme.colors.vert_select.x;
1411 }
1412
1413 /* Draw root point if we are not connected to our parent. */
1414 if (!(bone.has_parent() && (boneflag & BONE_CONNECTED))) {
1415
1416 if (bone.is_editbone()) {
1417 col_head = (bone.flag() & BONE_ROOTSEL) ? &theme.colors.vert_select.x : col_bone;
1418 }
1419 else {
1420 col_head = col_bone;
1421 }
1422 }
1423 }
1424
1425 if (select_id == -1) {
1426 /* Not in bone selection mode (can still be object select mode), draw everything at once.
1427 */
1429 ctx, bone.disp_mat(), col_wire, col_bone, col_head, col_tail, select_id);
1430 }
1431 else {
1432 /* In selection mode, draw bone, root and tip separately. */
1434 bone.disp_mat(),
1435 col_wire,
1436 col_bone,
1437 no_display,
1438 no_display,
1439 select_id | BONESEL_BONE);
1440
1441 if (col_head[3] > 0.0f) {
1443 bone.disp_mat(),
1444 col_wire,
1445 no_display,
1446 col_head,
1447 no_display,
1448 select_id | BONESEL_ROOT);
1449 }
1450
1452 ctx, bone.disp_mat(), col_wire, no_display, no_display, col_tail, select_id | BONESEL_TIP);
1453 }
1454}
1455
1457 const UnifiedBonePtr bone,
1458 const eBone_Flag boneflag,
1459 const int select_id)
1460{
1461 const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
1462 const float *col_wire = get_bone_wire_color(ctx, boneflag);
1463 const float *col_hint = get_bone_hint_color(ctx, boneflag);
1464
1465 /* NOTE: Cannot reinterpret as float4x4 because of alignment requirement of float4x4.
1466 * This would require a deeper refactor. */
1467 Span<Mat4> bbone_matrices;
1468 if (bone.is_posebone()) {
1469 bbone_matrices = {(Mat4 *)bone.as_posebone()->draw_data->bbone_matrix,
1470 bone.as_posebone()->bone->segments};
1471 }
1472 else {
1473 bbone_matrices = {(Mat4 *)bone.as_editbone()->disp_bbone_mat, bone.as_editbone()->segments};
1474 }
1475
1476 auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
1477
1478 for (const Mat4 &in_bone_mat : bbone_matrices) {
1479 float4x4 bone_mat = ctx->ob->object_to_world() * float4x4(in_bone_mat.mat);
1480
1481 if (ctx->is_filled) {
1482 ctx->bone_buf->bbones_fill_buf.append({bone_mat, col_solid, col_hint}, sel_id);
1483 }
1484 if (col_wire[3] > 0.0f) {
1485 ctx->bone_buf->bbones_outline_buf.append({bone_mat, col_wire}, sel_id);
1486 }
1487 }
1488
1489 if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
1490 draw_points(ctx, bone, boneflag, col_solid, select_id);
1491 }
1492}
1493
1495 const UnifiedBonePtr bone,
1496 const eBone_Flag boneflag,
1497 const int select_id)
1498{
1499 const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
1500 const float *col_wire = get_bone_wire_color(ctx, boneflag);
1501 const float *col_hint = get_bone_hint_color(ctx, boneflag);
1502
1503 const float *rad_head, *rad_tail, *distance;
1504 if (bone.is_editbone()) {
1505 const EditBone *eBone = bone.as_editbone();
1506 rad_tail = &eBone->rad_tail;
1507 distance = &eBone->dist;
1508 rad_head = (eBone->parent && (boneflag & BONE_CONNECTED)) ? &eBone->parent->rad_tail :
1509 &eBone->rad_head;
1510 }
1511 else {
1512 const bPoseChannel *pchan = bone.as_posebone();
1513 rad_tail = &pchan->bone->rad_tail;
1514 distance = &pchan->bone->dist;
1515 rad_head = (pchan->parent && (boneflag & BONE_CONNECTED)) ? &pchan->parent->bone->rad_tail :
1516 &pchan->bone->rad_head;
1517 }
1518
1519 if ((select_id == -1) && (boneflag & BONE_NO_DEFORM) == 0 &&
1520 ((boneflag & BONE_SELECTED) ||
1521 (bone.is_editbone() && (boneflag & (BONE_ROOTSEL | BONE_TIPSEL)))))
1522 {
1523 drw_shgroup_bone_envelope_distance(ctx, bone.disp_mat(), rad_head, rad_tail, distance);
1524 }
1525
1527 bone.disp_mat(),
1528 col_solid,
1529 col_hint,
1530 col_wire,
1531 rad_head,
1532 rad_tail,
1533 select_id | BONESEL_BONE);
1534
1535 draw_points(ctx, bone, boneflag, col_solid, select_id);
1536}
1537
1539 const UnifiedBonePtr bone,
1540 const eBone_Flag boneflag,
1541 const int select_id)
1542{
1543 using namespace blender::math;
1544
1545 const float *col_wire = get_bone_wire_color(ctx, boneflag);
1546
1547 auto sel_id = (ctx->bone_buf) ? ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE) :
1549
1550 /* NOTE: Cannot reinterpret as float4x4 because of alignment requirement of float4x4.
1551 * This would require a deeper refactor. */
1552 Span<Mat4> bbone_matrices;
1553 if (bone.is_posebone()) {
1554 bbone_matrices = {(Mat4 *)bone.as_posebone()->draw_data->bbone_matrix,
1555 bone.as_posebone()->bone->segments};
1556 }
1557 else {
1558 bbone_matrices = {(Mat4 *)bone.as_editbone()->disp_bbone_mat, bone.as_editbone()->segments};
1559 }
1560
1561 for (const Mat4 &in_bone_mat : bbone_matrices) {
1562 float4x4 bmat = float4x4(in_bone_mat.mat);
1563 float3 head = transform_point(ctx->ob->object_to_world(), bmat.location());
1564 float3 tail = transform_point(ctx->ob->object_to_world(), bmat.location() + bmat.y_axis());
1565
1566 ctx->bone_buf->wire_buf.append(head, tail, float4(col_wire), sel_id);
1567 }
1568
1569 if (bone.is_editbone()) {
1570 const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
1571 draw_points(ctx, bone, boneflag, col_solid, select_id);
1572 }
1573}
1574
1575static void bone_draw(const eArmature_Drawtype drawtype,
1576 const bool use_custom_shape,
1577 const Armatures::DrawContext *ctx,
1578 const UnifiedBonePtr bone,
1579 const eBone_Flag boneflag,
1580 const int select_id)
1581{
1582 if (use_custom_shape) {
1583 bone_draw_custom_shape(ctx, bone, boneflag, select_id);
1584 return;
1585 }
1586
1587 switch (drawtype) {
1588 case ARM_DRAW_TYPE_OCTA:
1589 bone_draw_octa(ctx, bone, boneflag, select_id);
1590 break;
1592 bone_draw_line(ctx, bone, boneflag, select_id);
1593 break;
1595 bone_draw_b_bone(ctx, bone, boneflag, select_id);
1596 break;
1598 bone_draw_envelope(ctx, bone, boneflag, select_id);
1599 break;
1600 case ARM_DRAW_TYPE_WIRE:
1601 bone_draw_wire(ctx, bone, boneflag, select_id);
1602 break;
1603 default:
1605 break;
1606 }
1607}
1608
1610
1611/* -------------------------------------------------------------------- */
1614
1616 const bPoseChannel *pchan)
1617{
1619 float tmp[4][4], posetrans[4][4];
1620 float xminmax[2], zminmax[2];
1621
1622 /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
1623 xminmax[0] = sinf(pchan->limitmin[0] * 0.5f);
1624 xminmax[1] = sinf(pchan->limitmax[0] * 0.5f);
1625 zminmax[0] = sinf(pchan->limitmin[2] * 0.5f);
1626 zminmax[1] = sinf(pchan->limitmax[2] * 0.5f);
1627
1628 unit_m4(posetrans);
1629 translate_m4(posetrans, pchan->pose_mat[3][0], pchan->pose_mat[3][1], pchan->pose_mat[3][2]);
1630 /* In parent-bone pose space... */
1631 if (pchan->parent) {
1632 copy_m4_m4(tmp, pchan->parent->pose_mat);
1633 zero_v3(tmp[3]);
1634 mul_m4_m4m4(posetrans, posetrans, tmp);
1635 }
1636 /* ... but its own rest-space. */
1637 mul_m4_m4m3(posetrans, posetrans, pchan->bone->bone_mat);
1638
1639 float scale = pchan->bone->length * pchan->scale[1];
1640 scale_m4_fl(tmp, scale);
1641 tmp[1][1] = -tmp[1][1];
1642 mul_m4_m4m4(posetrans, posetrans, tmp);
1643
1644 /* into world space. */
1645 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(posetrans);
1646
1647 /* Not selectable. */
1649
1650 if ((pchan->ikflag & BONE_IK_XLIMIT) && (pchan->ikflag & BONE_IK_ZLIMIT)) {
1652 inst_data.mat44, float4(0.25f), xminmax[0], zminmax[0], xminmax[1], zminmax[1]);
1653
1654 ctx->bone_buf->degrees_of_freedom_fill_buf.append(data, sel_id);
1655 ctx->bone_buf->degrees_of_freedom_wire_buf.append(data.with_color({0.0f, 0.0f, 0.0f, 1.0f}),
1656 sel_id);
1657 }
1658 if (pchan->ikflag & BONE_IK_XLIMIT) {
1660 inst_data.mat44, float4(1.0f, 0.0f, 0.0f, 1.0f), xminmax[0], 0.0f, xminmax[1], 0.0f);
1661 ctx->bone_buf->degrees_of_freedom_wire_buf.append(data, sel_id);
1662 }
1663 if (pchan->ikflag & BONE_IK_ZLIMIT) {
1665 inst_data.mat44, float4(0.0f, 0.0f, 1.0f, 1.0f), 0.0f, zminmax[0], 0.0f, zminmax[1]);
1666 ctx->bone_buf->degrees_of_freedom_wire_buf.append(data, sel_id);
1667 }
1668}
1669
1671
1672/* -------------------------------------------------------------------- */
1675
1677static bool should_draw_relation_to_parent(const UnifiedBonePtr bone, const eBone_Flag boneflag)
1678{
1679 const bool has_parent = bone.has_parent();
1680
1681 if (bone.is_editbone() && has_parent) {
1682 /* Always draw for unconnected bones, regardless of selection,
1683 * since riggers will want to know about the links between bones
1684 */
1685 return (boneflag & BONE_CONNECTED) == 0;
1686 }
1687
1688 if (bone.is_posebone() && has_parent) {
1689 /* Only draw between unconnected bones. */
1690 if (boneflag & BONE_CONNECTED) {
1691 return false;
1692 }
1693
1694 /* Only draw if bone or its parent is selected - reduces viewport
1695 * complexity with complex rigs */
1696 const bPoseChannel *pchan = bone.as_posebone();
1697 return (pchan->flag & POSE_SELECTED) ||
1698 (pchan->parent && (pchan->parent->flag & POSE_SELECTED));
1699 }
1700
1701 return false;
1702}
1703
1705 const bPoseChannel *pchan,
1706 const bool only_temp)
1707{
1708 const bPoseChannel *parchan;
1709 const float *line_start = nullptr, *line_end = nullptr;
1710 const ePchan_ConstFlag constflag = ePchan_ConstFlag(pchan->constflag);
1711
1712 LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
1713 if (con->enforce == 0.0f) {
1714 continue;
1715 }
1716
1717 switch (con->type) {
1720 int segcount = 0;
1721
1722 /* if only_temp, only draw if it is a temporary ik-chain */
1723 if (only_temp && !(data->flag & CONSTRAINT_IK_TEMP)) {
1724 continue;
1725 }
1726
1727 /* exclude tip from chain? */
1728 parchan = ((data->flag & CONSTRAINT_IK_TIP) == 0) ? pchan->parent : pchan;
1729 line_start = parchan->pose_tail;
1730
1731 /* Find the chain's root */
1732 while (parchan->parent) {
1733 segcount++;
1734 if (segcount == data->rootbone || segcount > 255) {
1735 break; /* 255 is weak */
1736 }
1737 parchan = parchan->parent;
1738 }
1739
1740 if (parchan) {
1741 line_end = parchan->pose_head;
1742
1743 if (constflag & PCHAN_HAS_NO_TARGET) {
1744 drw_shgroup_bone_ik_no_target_lines(ctx, line_start, line_end);
1745 }
1746 else {
1747 drw_shgroup_bone_ik_lines(ctx, line_start, line_end);
1748 }
1749 }
1750 break;
1751 }
1754 int segcount = 0;
1755
1756 /* don't draw if only_temp, as Spline IK chains cannot be temporary */
1757 if (only_temp) {
1758 continue;
1759 }
1760
1761 parchan = pchan;
1762 line_start = parchan->pose_tail;
1763
1764 /* Find the chain's root */
1765 while (parchan->parent) {
1766 segcount++;
1767 /* FIXME: revise the breaking conditions */
1768 if (segcount == data->chainlen || segcount > 255) {
1769 break; /* 255 is weak */
1770 }
1771 parchan = parchan->parent;
1772 }
1773 /* Only draw line in case our chain is more than one bone long! */
1774 if (parchan != pchan) { /* XXX revise the breaking conditions to only stop at the tail? */
1775 line_end = parchan->pose_head;
1776 drw_shgroup_bone_ik_spline_lines(ctx, line_start, line_end);
1777 }
1778 break;
1779 }
1780 }
1781 }
1782}
1783
1785 const float bone_head[3],
1786 const float parent_head[3],
1787 const float parent_tail[3])
1788{
1789 if (ctx->draw_relation_from_head) {
1790 drw_shgroup_bone_relationship_lines(ctx, bone_head, parent_head);
1791 }
1792 else {
1793 drw_shgroup_bone_relationship_lines(ctx, bone_head, parent_tail);
1794 }
1795}
1796
1798 const UnifiedBonePtr bone,
1799 const eBone_Flag boneflag)
1800{
1801 if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
1802 const EditBone *ebone = bone.as_editbone();
1803 if (ebone->parent) {
1804 if (ctx->do_relations && should_draw_relation_to_parent(bone, boneflag)) {
1806 ctx, ebone->head, ebone->parent->head, ebone->parent->tail);
1807 }
1808 }
1809 }
1810 else {
1811 const bPoseChannel *pchan = bone.as_posebone();
1812 if (pchan->parent) {
1813 if (ctx->do_relations && should_draw_relation_to_parent(bone, boneflag)) {
1815 ctx, pchan->pose_head, pchan->parent->pose_head, pchan->parent->pose_tail);
1816 }
1817
1818 /* Draw a line to IK root bone if bone is selected. */
1819 if (ctx->draw_mode == ARM_DRAW_MODE_POSE) {
1820 if (pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK)) {
1821 if (pchan->flag & POSE_SELECTED) {
1822 pchan_draw_ik_lines(ctx, pchan, !ctx->do_relations);
1823 }
1824 }
1825 }
1826 }
1827 }
1828}
1829
1830static void draw_bone_name(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone)
1831{
1832 uchar color[4];
1833 float vec[3];
1834
1835 const bool is_pose = bone.is_posebone();
1836 const EditBone *eBone = nullptr;
1837 const bPoseChannel *pchan = nullptr;
1838 bone.get(&eBone, &pchan);
1839
1840 /* TODO: make this look at `boneflag` only. */
1841 bool highlight = (is_pose && ctx->draw_mode == ARM_DRAW_MODE_POSE &&
1842 (pchan->flag & POSE_SELECTED)) ||
1843 (!is_pose && (eBone->flag & BONE_SELECTED));
1844
1845 /* Color Management: Exception here as texts are drawn in sRGB space directly. */
1847
1848 const float *head = is_pose ? pchan->pose_head : eBone->head;
1849 const float *tail = is_pose ? pchan->pose_tail : eBone->tail;
1850 mid_v3_v3v3(vec, head, tail);
1851 mul_m4_v3(ctx->ob->object_to_world().ptr(), vec);
1852
1854 vec,
1855 is_pose ? pchan->name : eBone->name,
1856 is_pose ? strlen(pchan->name) : strlen(eBone->name),
1857 10,
1858 0,
1860 color,
1861 true);
1862}
1863
1865
1866/* -------------------------------------------------------------------- */
1869
1871 const bool use_custom_shape,
1872 UnifiedBonePtr bone)
1873{
1874 if (use_custom_shape) {
1876 }
1877 else if (ELEM(drawtype, ARM_DRAW_TYPE_B_BONE, ARM_DRAW_TYPE_WIRE)) {
1879 }
1880 else {
1882 }
1883}
1884
1886{
1887 Object *ob = ctx->ob;
1888 EditBone *eBone;
1889 int index;
1890 const bool is_select = ctx->res->is_selection();
1891 const bool show_text = ctx->show_text;
1892
1893 const Object *ob_orig = DEG_get_original(ob);
1894 /* FIXME(@ideasman42): We should be able to use the evaluated object,
1895 * however the active bone isn't updated. Long term solution is an 'EditArmature' struct.
1896 * for now we can draw from the original armature. See: #66773. */
1897 // bArmature *arm = ob->data;
1899
1901
1902 const eArmature_Drawtype arm_drawtype = eArmature_Drawtype(arm.drawtype);
1903
1904 for (eBone = static_cast<EditBone *>(arm.edbo->first),
1905 /* Note: Selection Next handles the object id merging later. */
1906 index = ctx->bone_buf ? 0x0 : ob_orig->runtime->select_id;
1907 eBone;
1908 eBone = eBone->next, index += 0x10000)
1909 {
1910 if (!blender::animrig::bone_is_visible(&arm, eBone)) {
1911 continue;
1912 }
1913
1914 const int select_id = is_select ? index : uint(-1);
1915
1916 /* catch exception for bone with hidden parent */
1917 eBone_Flag boneflag = eBone_Flag(eBone->flag);
1918 if ((eBone->parent) && !blender::animrig::bone_is_visible(&arm, eBone->parent)) {
1919 boneflag &= ~BONE_CONNECTED;
1920 }
1921
1922 /* set temporary flag for drawing bone as active, but only if selected */
1923 if (eBone == arm.act_edbone) {
1924 boneflag |= BONE_DRAW_ACTIVE;
1925 }
1926
1927 boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
1928
1929 UnifiedBonePtr bone = eBone;
1930 if (!ctx->const_color) {
1931 set_ctx_bcolor(ctx, bone);
1932 }
1933
1934 if (!is_select) {
1935 draw_bone_relations(ctx, bone, boneflag);
1936 }
1937
1939 arm_drawtype :
1941 bone_draw_update_display_matrix(drawtype, false, bone);
1942 bone_draw(drawtype, false, ctx, bone, boneflag, select_id);
1943
1944 if (!is_select) {
1945 if (show_text && (arm.flag & ARM_DRAWNAMES)) {
1946 draw_bone_name(ctx, bone);
1947 }
1948
1949 if (arm.flag & ARM_DRAWAXES) {
1950 draw_axes(ctx, bone, arm);
1951 }
1952 }
1953 }
1954}
1955
1957{
1958 Object *ob = ctx->ob;
1959 const DRWContext *draw_ctx = DRW_context_get();
1960 const Scene *scene = draw_ctx->scene;
1962 int index = -1;
1963 const bool show_text = ctx->show_text;
1964 bool draw_locked_weights = false;
1965
1966 /* We can't safely draw non-updated pose, might contain nullptr bone pointers... */
1967 if (ob->pose->flag & POSE_RECALC) {
1968 return;
1969 }
1970
1971 ctx->draw_mode = ARM_DRAW_MODE_OBJECT; /* Will likely be set to ARM_DRAW_MODE_POSE below. */
1972
1973 bool is_pose_select = false;
1974 /* Object can be edited in the scene. */
1975 if (!is_from_dupli_or_set(ob)) {
1976 if ((draw_ctx->object_mode & OB_MODE_POSE) || (ob == draw_ctx->object_pose)) {
1978 }
1979 is_pose_select =
1980 /* If we're in pose-mode or object-mode with the ability to enter pose mode. */
1981 (
1982 /* Draw as if in pose mode (when selection is possible). */
1983 (ctx->draw_mode == ARM_DRAW_MODE_POSE) ||
1984 /* When we're in object mode, which may select bones. */
1985 ((ob->mode & OB_MODE_POSE) &&
1986 (
1987 /* Switch from object mode when object lock is disabled. */
1988 ((draw_ctx->object_mode == OB_MODE_OBJECT) &&
1989 (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) ||
1990 /* Allow selection when in weight-paint mode
1991 * (selection code ensures this won't become active). */
1992 ((draw_ctx->object_mode & OB_MODE_ALL_WEIGHT_PAINT) &&
1993 (draw_ctx->object_pose != nullptr))))) &&
1994 ctx->res->is_selection();
1995
1996 if (is_pose_select) {
1997 const Object *ob_orig = DEG_get_original(ob);
1998 /* Note: Selection Next handles the object id merging later. */
1999 index = ctx->bone_buf ? 0x0 : ob_orig->runtime->select_id;
2000 }
2001 }
2002
2003 /* In weight paint mode retrieve the vertex group lock status. */
2004 if ((draw_ctx->object_mode & OB_MODE_ALL_WEIGHT_PAINT) && (draw_ctx->object_pose == ob) &&
2005 (draw_ctx->obact != nullptr))
2006 {
2007 draw_locked_weights = true;
2008
2010 pchan->bone->flag &= ~BONE_DRAW_LOCKED_WEIGHT;
2011 }
2012
2013 const Object *obact_orig = DEG_get_original(draw_ctx->obact);
2014
2015 const ListBase *defbase = BKE_object_defgroup_list(obact_orig);
2016 for (const bDeformGroup *dg : ConstListBaseWrapper<bDeformGroup>(defbase)) {
2017 if ((dg->flag & DG_LOCK_WEIGHT) == 0) {
2018 continue;
2019 }
2020
2021 bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, dg->name);
2022 if (!pchan) {
2023 continue;
2024 }
2025
2027 }
2028 }
2029
2030 const eArmature_Drawtype arm_drawtype = eArmature_Drawtype(arm.drawtype);
2031
2032 for (bPoseChannel *pchan = static_cast<bPoseChannel *>(ob->pose->chanbase.first); pchan;
2033 pchan = pchan->next, index += 0x10000)
2034 {
2035 if (!blender::animrig::bone_is_visible(&arm, pchan)) {
2036 continue;
2037 }
2038
2039 Bone *bone = pchan->bone;
2040 const bool draw_dofs = !is_pose_select && ctx->show_relations &&
2041 (ctx->draw_mode == ARM_DRAW_MODE_POSE) &&
2042 (pchan->flag & POSE_SELECTED) &&
2043 ((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
2044 (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ZLIMIT));
2045 const int select_id = is_pose_select ? index : uint(-1);
2046
2047 pchan_draw_data_init(pchan);
2048
2049 UnifiedBonePtr bone_ptr = pchan;
2050 if (!ctx->const_color) {
2051 set_ctx_bcolor(ctx, bone_ptr);
2052 }
2053
2054 eBone_Flag boneflag = bone_ptr.flag();
2055 if (pchan->parent && !blender::animrig::bone_is_visible(&arm, pchan->parent)) {
2056 /* Avoid drawing connection line to hidden parent. */
2057 boneflag &= ~BONE_CONNECTED;
2058 }
2059 if (bone == arm.act_bone) {
2060 /* Draw bone as active, but only if selected. */
2061 boneflag |= BONE_DRAW_ACTIVE;
2062 }
2063 if (!draw_locked_weights) {
2064 boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
2065 }
2066
2067 const bool use_custom_shape = (pchan->custom) && !(arm.flag & ARM_NO_CUSTOM);
2068 if (!is_pose_select) {
2069 draw_bone_relations(ctx, bone_ptr, boneflag);
2070 }
2071
2073 arm_drawtype :
2075 bone_draw_update_display_matrix(drawtype, use_custom_shape, bone_ptr);
2076 bone_draw(drawtype, use_custom_shape, ctx, bone_ptr, boneflag, select_id);
2077
2078 /* Below this point nothing is used for selection queries. */
2079 if (is_pose_select) {
2080 continue;
2081 }
2082
2083 if (draw_dofs) {
2084 draw_bone_degrees_of_freedom(ctx, pchan);
2085 }
2086 if (show_text && (arm.flag & ARM_DRAWNAMES)) {
2087 draw_bone_name(ctx, bone_ptr);
2088 }
2089 if (arm.flag & ARM_DRAWAXES) {
2090 draw_axes(ctx, bone_ptr, arm);
2091 }
2092 }
2093}
2094
Functions to deal with Armatures.
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)
#define MAX_BBONE_SUBDIV
int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param, bool for_deform, Mat4 *result_array)
support for deformation groups and hooks.
const ListBase * BKE_object_defgroup_list(const Object *ob)
Definition deform.cc:585
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:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#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 rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[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 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])
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 unit_m4(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 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)
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)
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)
unsigned char uchar
unsigned int uint
#define CLAMP(a, b, c)
#define UNPACK3(a)
#define ELEM(...)
T * DEG_get_original(T *id)
#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_SELECTED
@ POSE_RECALC
@ BBONE_HANDLE_AUTO
@ BBONE_HANDLE_TANGENT
@ BBONE_HANDLE_RELATIVE
@ BONE_DRAW_LOCKED_WEIGHT
@ BONE_ROOTSEL
@ BONE_DRAWWIRE
@ BONE_SELECTED
@ BONE_DRAW_ACTIVE
@ BONE_TIPSEL
@ BONE_NO_DEFORM
@ BONE_CONNECTED
@ ARM_NO_CUSTOM
@ ARM_COL_CUSTOM
@ ARM_DRAWNAMES
@ ARM_DRAWAXES
eArmature_Drawtype
@ ARM_DRAW_TYPE_ENVELOPE
@ ARM_DRAW_TYPE_STICK
@ ARM_DRAW_TYPE_B_BONE
@ ARM_DRAW_TYPE_WIRE
@ ARM_DRAW_TYPE_ARMATURE_DEFINED
@ ARM_DRAW_TYPE_OCTA
@ BBONE_ADD_PARENT_END_ROLL
@ BBONE_SCALE_EASING
@ CONSTRAINT_IK_TEMP
@ CONSTRAINT_IK_TIP
@ CONSTRAINT_TYPE_SPLINEIK
@ CONSTRAINT_TYPE_KINEMATIC
@ BASE_FROM_DUPLI
#define OB_MODE_ALL_WEIGHT_PAINT
@ OB_MODE_POSE
@ OB_MODE_OBJECT
Object is a sort of wrapper for general info.
@ DG_LOCK_WEIGHT
@ OB_EMPTY_CONE
@ OB_SINGLE_ARROW
@ OB_PLAINAXES
@ OB_ARROWS
@ OB_CIRCLE
@ OB_CUBE
@ OB_EMPTY_IMAGE
@ OB_EMPTY_SPHERE
@ OB_EMPTY
@ OB_SURF
@ OB_FONT
@ OB_CURVES_LEGACY
@ SCE_OBJECT_MODE_LOCK
@ TH_WIRECOLOR_CONSTCOLS
T & DRW_object_get_data_for_drawing(const Object &object)
Mesh & DRW_mesh_get_for_drawing(Mesh &mesh)
#define BONESEL_ROOT
#define BONESEL_TIP
#define BONESEL_BONE
#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])
BMesh const char void * data
return true
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:32
static void draw_armature_pose(Armatures::DrawContext *ctx)
static void draw_armature_edit(Armatures::DrawContext *ctx)
nullptr float
const DRWContext * DRW_context_get()
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
uint col
float length(VecOp< float, D >) RET
float distance(VecOp< float, D >, VecOp< float, D >) RET
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
static ulong * next
bool bone_is_visible(const bArmature *armature, const Bone *bone)
static bool is_from_dupli_or_set(const Object *ob)
void DRW_mesh_batch_cache_validate(Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_loose_edges(Mesh &mesh)
gpu::Batch * DRW_cache_text_edge_wire_get(Object *ob)
void DRW_curve_batch_cache_validate(Curve *cu)
blender::gpu::Batch * DRW_mesh_batch_cache_get_surface(Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_all_edges(Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edge_detection(Mesh &mesh, bool *r_is_manifold)
void drw_batch_cache_generate_requested_delayed(Object *ob)
gpu::Batch * DRW_cache_curve_edge_wire_get(Object *ob)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
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
VecBase< float, 3 > float3
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 draw_bone_update_disp_matrix_custom_shape(UnifiedBonePtr bone)
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 void bone_draw_envelope(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
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 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)
static void draw_bone_relations(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag)
static void bone_locked_color_shade(const UniformData &theme, float color[4])
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 const float * get_bone_hint_color(const Armatures::DrawContext *ctx, const eBone_Flag boneflag)
static void use_bone_color(float *r_color, const uint8_t *color_from_theme, const int shade_offset)
static bool should_draw_relation_to_parent(const UnifiedBonePtr bone, const eBone_Flag boneflag)
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)
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 bone_draw(const eArmature_Drawtype drawtype, const bool use_custom_shape, const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
static void drw_shgroup_bone_axes(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float color[4])
static void get_pchan_color_solid(const UniformData &theme, const ThemeWireColor *bcolor, float r_color[4])
static void draw_bone_name(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone)
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)
static void bone_hint_color_shade(float hint_color[4], const float color[4])
static void draw_bone_update_disp_matrix_default(UnifiedBonePtr bone)
static void bone_draw_wire(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
static void bone_draw_update_display_matrix(const eArmature_Drawtype drawtype, const bool use_custom_shape, UnifiedBonePtr bone)
static void draw_bone_update_disp_matrix_bbone(UnifiedBonePtr bone)
static void get_pchan_color_constraint(const UniformData &theme, const ThemeWireColor *bcolor, const UnifiedBonePtr bone, float r_color[4])
static void bone_draw_custom_shape(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
static float get_bone_wire_thickness(const Armatures::DrawContext *ctx, int boneflag)
static void bone_draw_line(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
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 bone_draw_octa(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
static void pchan_draw_ik_lines(const Armatures::DrawContext *ctx, const bPoseChannel *pchan, const bool only_temp)
static void draw_axes(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const bArmature &arm)
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)
static void drw_shgroup_bone_ik_no_target_lines(const Armatures::DrawContext *ctx, const float start[3], const float end[3])
static void bone_draw_b_bone(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
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_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)
#define PT_DEFAULT_RAD
static void get_pchan_color_wire(const UniformData &theme, const ThemeWireColor *bcolor, const eArmatureDrawMode draw_mode, const eBone_Flag boneflag, float r_color[4])
#define WIRE_WIDTH_COMPRESSION
#define sinf
int8_t drawtype
float bone_mat[3][3]
Object * obact
Scene * scene
Object * object_pose
eObjectMode object_mode
float curve_out_z
float scale_in[3]
char name[64]
float ease2
float roll1
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 zwidth
float curve_in_z
float length
float xwidth
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]
short base_flag
struct bPose * pose
ObjectRuntimeHandle * runtime
char empty_drawtype
float empty_drawsize
struct ToolSettings * toolsettings
unsigned char select[4]
unsigned char solid[4]
unsigned char active[4]
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_tail_mat[4][4]
float pose_mat[4][4]
ListBase chanbase
void set_color(const float4 &bone_color)
void set_hint_color(const float4 &hint_color)
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)
i
Definition text_draw.cc:230
ccl_device_inline float3 transform_point(const ccl_private Transform *t, const float3 a)
Definition transform.h:56
uint len
PointerRNA * ptr
Definition wm_files.cc:4238