Blender V4.3
grease_pencil_primitive.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10#include <fmt/format.h>
11
12#include <cstring>
13
14#include "BKE_attribute.hh"
15#include "BKE_brush.hh"
16#include "BKE_colortools.hh"
17#include "BKE_context.hh"
18#include "BKE_curves.hh"
19#include "BKE_grease_pencil.hh"
20#include "BKE_material.h"
21#include "BKE_paint.hh"
22
23#include "WM_api.hh"
24#include "WM_types.hh"
25
26#include "RNA_access.hh"
27#include "RNA_define.hh"
28#include "RNA_enum_types.hh"
29
31
32#include "DNA_material_types.h"
33
34#include "ED_grease_pencil.hh"
35#include "ED_screen.hh"
36#include "ED_space_api.hh"
37#include "ED_view3d.hh"
38
39#include "BLI_array_utils.hh"
40#include "BLI_string.h"
41#include "BLI_vector.hh"
42
43#include "BLT_translation.hh"
44
45#include "GPU_immediate.hh"
46#include "GPU_state.hh"
47
48#include "UI_interface.hh"
49#include "UI_resources.hh"
50
52
53enum class PrimitiveType : int8_t {
54 Line = 0,
55 Polyline = 1,
56 Arc = 2,
57 Curve = 3,
58 Box = 4,
59 Circle = 5,
60};
61
62enum class OperatorMode : int8_t {
63 Idle = 0,
64 Extruding = 1,
65 /* Set the active control point to the mouse. */
66 Grab = 2,
67 /* Move the active control point. */
68 Drag = 3,
69 /* Move all control points. */
70 DragAll = 4,
71 /* Rotate all control points. */
72 RotateAll = 5,
73 /* Scale all control points. */
74 ScaleAll = 6,
75};
76
78 /* The points that are at the end of segments. */
79 JoinPoint = 0,
80 /* The points inside of the segments not including the end points. */
81 HandlePoint = 1,
82};
83
84enum class ModalKeyMode : int8_t {
85 Cancel = 1,
86 Confirm,
87 Extrude,
88 Panning,
89 Grab,
90 Rotate,
91 Scale,
94};
95
96static constexpr float ui_primary_point_draw_size_px = 8.0f;
97static constexpr float ui_secondary_point_draw_size_px = 5.0f;
98static constexpr float ui_tertiary_point_draw_size_px = 3.0f;
99static constexpr float ui_point_hit_size_px = 20.0f;
100static constexpr float ui_point_max_hit_size_px = 600.0f;
101
102/* These three points are only used for `Box` and `Circle` type. */
103static constexpr int control_point_first = 0;
104static constexpr int control_point_center = 1;
105static constexpr int control_point_last = 2;
106
109 /* For drawing preview loop. */
112
114 /* Stored in layer space. */
116 /* Store the control points temporally. */
119
123 /* Helper class to project screen space coordinates to 3D. */
125
129 std::optional<ColorGeometry4f> vertex_color;
130 std::optional<ColorGeometry4f> fill_color;
133 float softness;
137
141
143};
144
146{
147 switch (ptd.type) {
148 case PrimitiveType::Polyline:
149 case PrimitiveType::Line: {
150 return 1;
151 }
152 case PrimitiveType::Box:
153 case PrimitiveType::Circle:
154 case PrimitiveType::Arc: {
155 return 2;
156 }
157 case PrimitiveType::Curve: {
158 return 3;
159 }
160 }
161
163 return 0;
164}
165
167{
168 BLI_assert(point != -1);
169 if (ELEM(ptd.type, PrimitiveType::Circle, PrimitiveType::Box)) {
171 }
172
173 const int num_shared_points = control_points_per_segment(ptd);
174 if (math::mod(point, num_shared_points) == 0) {
176 }
178}
179
182 MutableSpan<float> sizes)
183{
184 ColorGeometry4f color_gizmo_primary;
185 ColorGeometry4f color_gizmo_secondary;
186 ColorGeometry4f color_gizmo_a;
187 ColorGeometry4f color_gizmo_b;
188 UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color_gizmo_primary);
189 UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color_gizmo_secondary);
190 UI_GetThemeColor4fv(TH_GIZMO_A, color_gizmo_a);
191 UI_GetThemeColor4fv(TH_GIZMO_B, color_gizmo_b);
192
193 const float size_primary = ui_primary_point_draw_size_px;
194 const float size_secondary = ui_secondary_point_draw_size_px;
195 const float size_tertiary = ui_tertiary_point_draw_size_px;
196
197 if (ptd.segments == 0) {
198 colors.fill(color_gizmo_primary);
199 sizes.fill(size_primary);
200 return;
201 }
202
203 if (ELEM(ptd.type, PrimitiveType::Box, PrimitiveType::Circle)) {
204 colors.fill(color_gizmo_primary);
205 sizes.fill(size_primary);
206
207 /* Set the center point's color. */
208 colors[control_point_center] = color_gizmo_b;
209 sizes[control_point_center] = size_secondary;
210 }
211 else {
212 colors.fill(color_gizmo_secondary);
213 sizes.fill(size_secondary);
214
215 for (const int i : colors.index_range()) {
216 const ControlPointType control_point_type = get_control_point_type(ptd, i);
217
218 if (control_point_type == ControlPointType::JoinPoint) {
219 colors[i] = color_gizmo_b;
220 sizes[i] = size_tertiary;
221 }
222 }
223
224 colors.last() = color_gizmo_primary;
225 sizes.last() = size_primary;
226
227 if (ELEM(ptd.type, PrimitiveType::Line, PrimitiveType::Polyline)) {
228 colors.last(1) = color_gizmo_secondary;
229 sizes.last(1) = size_primary;
230 }
231 }
232
233 const int active_index = ptd.active_control_point_index;
234 if (active_index != -1) {
235 sizes[active_index] *= 1.5;
236 colors[active_index] = math::interpolate(colors[active_index], color_gizmo_a, 0.5f);
237 }
238}
239
241{
242 GPUVertFormat *format3d = immVertexFormat();
243 const uint pos3d = GPU_vertformat_attr_add(format3d, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
244 const uint col3d = GPU_vertformat_attr_add(format3d, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
245 const uint siz3d = GPU_vertformat_attr_add(format3d, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
247
250
251 Array<ColorGeometry4f> colors(ptd.control_points.size());
252 Array<float> sizes(ptd.control_points.size());
253 control_point_colors_and_sizes(ptd, colors, sizes);
254
255 for (const int point : ptd.control_points.index_range()) {
257 ptd.control_points[point]);
258 const ColorGeometry4f color = colors[point];
259 const float size = sizes[point];
260
261 immAttr4f(col3d, color[0], color[1], color[2], color[3]);
262 immAttr1f(siz3d, size * 2.0f);
263 immVertex3fv(pos3d, world_pos);
264 }
265
266 immEnd();
269}
270
271static void grease_pencil_primitive_draw(const bContext * /*C*/, ARegion * /*region*/, void *arg)
272{
273 PrimitiveToolOperation &ptd = *reinterpret_cast<PrimitiveToolOperation *>(arg);
275}
276
278{
279 ptd.temp_segments = ptd.segments;
280 ptd.temp_control_points.resize(ptd.control_points.size());
281 array_utils::copy(ptd.control_points.as_span(), ptd.temp_control_points.as_mutable_span());
282}
283
285{
286 ptd.segments = ptd.temp_segments;
287 ptd.control_points.resize(ptd.temp_control_points.size());
288 array_utils::copy(ptd.temp_control_points.as_span(), ptd.control_points.as_mutable_span());
289}
290
292 Span<float2> control_points,
293 MutableSpan<float2> new_positions)
294{
295 const int subdivision = ptd.subdivision;
296 const int new_points_num = new_positions.size();
297
298 if (ptd.segments == 0) {
299 new_positions.fill(control_points.last());
300 return;
301 }
302
303 switch (ptd.type) {
304 case PrimitiveType::Line:
305 case PrimitiveType::Polyline: {
306 for (const int i : new_positions.index_range().drop_back(1)) {
307 const float t = math::mod(i / float(subdivision + 1), 1.0f);
308 const int point = int(i / (subdivision + 1));
309 const int point_next = point + 1;
310 new_positions[i] = math::interpolate(control_points[point], control_points[point_next], t);
311 }
312 new_positions.last() = control_points.last();
313 return;
314 }
315 case PrimitiveType::Arc: {
316 const int num_shared_points = control_points_per_segment(ptd);
317 const int num_segments = ptd.segments;
318 for (const int segment_i : IndexRange(num_segments)) {
319 const float2 A = control_points[num_shared_points * segment_i + 0];
320 const float2 B = control_points[num_shared_points * segment_i + 1];
321 const float2 C = control_points[num_shared_points * segment_i + 2];
322 for (const int i : IndexRange(subdivision + 1)) {
323 const float t = i / float(subdivision + 1);
324 const float2 AB = math::interpolate(A, B, t);
325 const float2 BC = math::interpolate(B, C, t);
326 new_positions[i + segment_i * (subdivision + 1)] = math::interpolate(AB, BC, t);
327 }
328 }
329 new_positions.last() = control_points.last();
330 return;
331 }
332 case PrimitiveType::Curve: {
333 const int num_shared_points = control_points_per_segment(ptd);
334 const int num_segments = ptd.segments;
335
336 for (const int segment_i : IndexRange(num_segments)) {
337 const float2 A = control_points[num_shared_points * segment_i + 0];
338 const float2 B = control_points[num_shared_points * segment_i + 1];
339 const float2 C = control_points[num_shared_points * segment_i + 2];
340 const float2 D = control_points[num_shared_points * segment_i + 3];
341 for (const int i : IndexRange(subdivision + 1)) {
342 const float t = i / float(subdivision + 1);
343 const float2 AB = math::interpolate(A, B, t);
344 const float2 BC = math::interpolate(B, C, t);
345 const float2 CD = math::interpolate(C, D, t);
346 const float2 ABBC = math::interpolate(AB, BC, t);
347 const float2 BCCD = math::interpolate(BC, CD, t);
348 new_positions[i + segment_i * (subdivision + 1)] = math::interpolate(ABBC, BCCD, t);
349 }
350 }
351 new_positions.last() = control_points.last();
352 return;
353 }
354 case PrimitiveType::Circle: {
355 const float2 center = control_points[control_point_center];
356 const float2 offset = control_points[control_point_first] - center;
357 for (const int i : new_positions.index_range()) {
358 const float t = i / float(new_points_num);
359 const float a = t * math::numbers::pi * 2.0f;
360 new_positions[i] = offset * float2(sinf(a), cosf(a)) + center;
361 }
362 return;
363 }
364 case PrimitiveType::Box: {
365 const float2 center = control_points[control_point_center];
366 const float2 offset = control_points[control_point_first] - center;
367 /*
368 * Calculate the 4 corners of the box.
369 * Here's a diagram.
370 *
371 * +-----------+
372 * |A B|
373 * | |
374 * | center |
375 * | |
376 * |D C|
377 * +-----------+
378 *
379 */
380 const float2 A = center + offset * float2(1.0f, 1.0f);
381 const float2 B = center + offset * float2(-1.0f, 1.0f);
382 const float2 C = center + offset * float2(-1.0f, -1.0f);
383 const float2 D = center + offset * float2(1.0f, -1.0f);
384 const float2 corners[4] = {A, B, C, D};
385 for (const int i : new_positions.index_range()) {
386 const float t = math::mod(i / float(subdivision + 1), 1.0f);
387 const int point = int(i / (subdivision + 1));
388 const int point_next = math::mod(point + 1, 4);
389 new_positions[i] = math::interpolate(corners[point], corners[point_next], t);
390 }
391 return;
392 }
393 }
394}
395
401
403 MutableSpan<float2> new_positions)
404{
405 Array<float2> control_points_2d(ptd.control_points.size());
406 for (const int i : ptd.control_points.index_range()) {
407 control_points_2d[i] = primitive_local_to_screen(ptd, ptd.control_points[i]);
408 }
409
410 primitive_calulate_curve_positions(ptd, control_points_2d, new_positions);
411}
412
414{
415 const int subdivision = ptd.subdivision;
416
417 switch (ptd.type) {
418 case PrimitiveType::Polyline:
419 case PrimitiveType::Curve:
420 case PrimitiveType::Line:
421 case PrimitiveType::Circle:
422 case PrimitiveType::Arc: {
423 const int join_points = ptd.segments + 1;
424 return join_points + subdivision * ptd.segments;
425 break;
426 }
427 case PrimitiveType::Box: {
428 return 4 + subdivision * 4;
429 break;
430 }
431 }
432
434 return 0;
435}
436
438{
440
441 const int last_points_num = curves.points_by_curve()[curves.curves_range().last()].size();
442 const int new_points_num = grease_pencil_primitive_curve_points_number(ptd);
443
444 curves.resize(curves.points_num() - last_points_num + new_points_num, curves.curves_num());
445 curves.offsets_for_write().last() = curves.points_num();
446 const IndexRange curve_points = curves.points_by_curve()[curves.curves_range().last()];
447
448 MutableSpan<float3> positions_3d = curves.positions_for_write().slice(curve_points);
449 Array<float2> positions_2d(new_points_num);
450
451 primitive_calulate_curve_positions_2d(ptd, positions_2d);
452 ptd.placement.project(positions_2d, positions_3d);
453
454 Set<std::string> point_attributes_to_skip;
455
456 MutableSpan<float> new_radii = ptd.drawing->radii_for_write().slice(curve_points);
457 MutableSpan<float> new_opacities = ptd.drawing->opacities_for_write().slice(curve_points);
458
459 const ToolSettings *ts = ptd.vc.scene->toolsettings;
460 const GP_Sculpt_Settings *gset = &ts->gp_sculpt;
461
462 for (const int point : curve_points.index_range()) {
463 float pressure = 1.0f;
464 /* Apply pressure curve. */
466 const float t = point / float(new_points_num - 1);
467 pressure = BKE_curvemapping_evaluateF(gset->cur_primitive, 0, t);
468 }
469
470 const float radius = ed::greasepencil::radius_from_input_sample(ptd.vc.rv3d,
471 ptd.region,
472 ptd.brush,
473 pressure,
474 positions_3d[point],
476 ptd.settings);
478 pressure, ptd.brush, ptd.settings);
479
480 new_radii[point] = radius;
481 new_opacities[point] = opacity;
482 }
483 point_attributes_to_skip.add_multiple({"position", "radius", "opacity"});
484
485 if (ptd.vertex_color) {
486 ptd.drawing->vertex_colors_for_write().slice(curve_points).fill(*ptd.vertex_color);
487 point_attributes_to_skip.add("vertex_color");
488 }
489
490 /* Initialize the rest of the attributes with default values. */
491 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
494 bke::attribute_filter_from_skip_ref(point_attributes_to_skip),
495 curve_points);
496
499 IndexRange::from_single(curves.curves_range().last()));
500}
501
503{
504 /* Resize the curves geometry so there is one more curve with a single point. */
506 const int num_old_points = curves.points_num();
507 curves.resize(curves.points_num() + 1, curves.curves_num() + 1);
508 curves.offsets_for_write().last(1) = num_old_points;
509
510 Set<std::string> curve_attributes_to_skip;
511
512 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
513 bke::SpanAttributeWriter<int> materials = attributes.lookup_or_add_for_write_span<int>(
514 "material_index", bke::AttrDomain::Curve);
515 bke::SpanAttributeWriter<bool> cyclic = attributes.lookup_or_add_for_write_span<bool>(
516 "cyclic", bke::AttrDomain::Curve);
517 bke::SpanAttributeWriter<float> softness = attributes.lookup_or_add_for_write_span<float>(
518 "softness", bke::AttrDomain::Curve);
519
520 /* Only set the attribute if the type is not the default or if it already exists. */
521 if (ptd.settings->caps_type != GP_STROKE_CAP_TYPE_ROUND || attributes.contains("start_cap")) {
522 bke::SpanAttributeWriter<int8_t> start_caps = attributes.lookup_or_add_for_write_span<int8_t>(
523 "start_cap", bke::AttrDomain::Curve);
524 start_caps.span.last() = ptd.settings->caps_type;
525 start_caps.finish();
526 curve_attributes_to_skip.add("start_cap");
527 }
528
529 if (ptd.settings->caps_type != GP_STROKE_CAP_TYPE_ROUND || attributes.contains("end_cap")) {
530 bke::SpanAttributeWriter<int8_t> end_caps = attributes.lookup_or_add_for_write_span<int8_t>(
531 "end_cap", bke::AttrDomain::Curve);
532 end_caps.span.last() = ptd.settings->caps_type;
533 end_caps.finish();
534 curve_attributes_to_skip.add("end_cap");
535 }
536
537 const bool is_cyclic = ELEM(ptd.type, PrimitiveType::Box, PrimitiveType::Circle);
538 cyclic.span.last() = is_cyclic;
539 materials.span.last() = ptd.material_index;
540 softness.span.last() = ptd.softness;
541
542 if (ptd.use_fill && (ptd.fill_opacity < 1.0f || attributes.contains("fill_opacity"))) {
543 bke::SpanAttributeWriter<float> fill_opacities =
544 attributes.lookup_or_add_for_write_span<float>(
545 "fill_opacity",
547 bke::AttributeInitVArray(VArray<float>::ForSingle(1.0f, curves.curves_num())));
548 fill_opacities.span.last() = ptd.fill_opacity;
549 fill_opacities.finish();
550 curve_attributes_to_skip.add("fill_opacity");
551 }
552
553 if (ptd.fill_color) {
554 ptd.drawing->fill_colors_for_write().last() = *ptd.fill_color;
555 curve_attributes_to_skip.add("fill_color");
556 }
557
558 cyclic.finish();
559 materials.finish();
560 softness.finish();
561 curve_attributes_to_skip.add_multiple({"material_index", "cyclic", "softness"});
562
563 curves.curve_types_for_write().last() = CURVE_TYPE_POLY;
564 curves.update_curve_types();
565 curve_attributes_to_skip.add("curve_type");
566
567 /* Initialize the rest of the attributes with default values. */
570 bke::attribute_filter_from_skip_ref(curve_attributes_to_skip),
571 curves.curves_range().take_back(1));
573}
574
576{
578 curves.remove_curves(IndexMask({curves.curves_range().last(), 1}), {});
580}
581
582/* Helper: Draw status message while the user is running the operator. */
584 wmOperator *op,
586{
587 std::string header;
588
589 switch (ptd.type) {
590 case PrimitiveType::Line: {
591 header += RPT_("Line: ");
592 break;
593 }
594 case (PrimitiveType::Polyline): {
595 header += RPT_("Polyline: ");
596 break;
597 }
598 case (PrimitiveType::Box): {
599 header += RPT_("Rectangle: ");
600 break;
601 }
602 case (PrimitiveType::Circle): {
603 header += RPT_("Circle: ");
604 break;
605 }
606 case (PrimitiveType::Arc): {
607 header += RPT_("Arc: ");
608 break;
609 }
610 case (PrimitiveType::Curve): {
611 header += RPT_("Curve: ");
612 break;
613 }
614 }
615
616 auto get_modal_key_str = [&](ModalKeyMode id) {
617 return WM_modalkeymap_operator_items_to_string(op->type, int(id), true).value_or("");
618 };
619
620 header += fmt::format(IFACE_("{}: confirm, {}: cancel, {}: panning, Shift: align"),
621 get_modal_key_str(ModalKeyMode::Confirm),
622 get_modal_key_str(ModalKeyMode::Cancel),
623 get_modal_key_str(ModalKeyMode::Panning));
624
625 header += fmt::format(IFACE_(", {}/{}: adjust subdivisions: {}"),
626 get_modal_key_str(ModalKeyMode::IncreaseSubdivision),
627 get_modal_key_str(ModalKeyMode::DecreaseSubdivision),
628 int(ptd.subdivision));
629
630 if (ptd.segments == 1) {
631 header += IFACE_(", Alt: center");
632 }
633
634 if (ELEM(ptd.type,
635 PrimitiveType::Line,
636 PrimitiveType::Polyline,
637 PrimitiveType::Arc,
638 PrimitiveType::Curve))
639 {
640 header += fmt::format(IFACE_(", {}: extrude"), get_modal_key_str(ModalKeyMode::Extrude));
641 }
642
643 header += fmt::format(IFACE_(", {}: grab, {}: rotate, {}: scale"),
644 get_modal_key_str(ModalKeyMode::Grab),
645 get_modal_key_str(ModalKeyMode::Rotate),
646 get_modal_key_str(ModalKeyMode::Scale));
647
648 ED_workspace_status_text(C, header.c_str());
649}
650
652{
653 GreasePencil *grease_pencil = static_cast<GreasePencil *>(ptd.vc.obact->data);
654
655 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
656 WM_event_add_notifier(C, NC_GEOM | ND_DATA, grease_pencil);
657
659}
660
661/* Invoke handler: Initialize the operator. */
663{
664 int return_value = ed::greasepencil::grease_pencil_draw_operator_invoke(C, op, false);
665 if (return_value != OPERATOR_RUNNING_MODAL) {
666 return return_value;
667 }
668
669 /* If in tools region, wait till we get to the main (3D-space)
670 * region before allowing drawing to take place. */
672
673 wmWindow *win = CTX_wm_window(C);
674
675 /* Set cursor to indicate modal. */
677
679
680 /* Allocate new data. */
681 PrimitiveToolOperation *ptd_pointer = MEM_new<PrimitiveToolOperation>(__func__);
682 op->customdata = ptd_pointer;
683
684 PrimitiveToolOperation &ptd = *ptd_pointer;
685
686 ptd.vc = vc;
687 ptd.region = vc.region;
688 View3D *view3d = CTX_wm_view3d(C);
689 const float2 start_coords = float2(event->mval);
690
691 GreasePencil *grease_pencil = static_cast<GreasePencil *>(vc.obact->data);
692
693 /* Initialize helper class for projecting screen space coordinates. */
695 *vc.scene, *vc.region, *view3d, *vc.obact, grease_pencil->get_active_layer());
696 if (placement.use_project_to_surface()) {
698 }
699 else if (placement.use_project_to_nearest_stroke()) {
701 placement.set_origin_to_nearest_stroke(start_coords);
702 }
703
704 ptd.placement = placement;
705
706 ptd.vod = ED_view3d_navigation_init(C, nullptr);
707
708 ptd.start_position_2d = start_coords;
709 ptd.subdivision = RNA_int_get(op->ptr, "subdivision");
710 ptd.type = PrimitiveType(RNA_enum_get(op->ptr, "type"));
712 ptd.segments = 0;
714
716
718 ptd.segments++;
719 ptd.control_points.append_n_times(pos, control_points_per_segment(ptd));
722
723 Paint *paint = &vc.scene->toolsettings->gp_paint->paint;
724 ptd.brush = BKE_paint_brush(paint);
725 if (ptd.brush->gpencil_settings == nullptr) {
727 }
729
739
741 GP_Sculpt_Settings *gset = &ts->gp_sculpt;
742 /* Initialize pressure curve. */
745 }
746
748 CTX_data_main(C), vc.obact, ptd.brush);
750 ptd.use_fill = (material->gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0;
751
752 const bool use_vertex_color = (vc.scene->toolsettings->gp_paint->mode ==
754 if (use_vertex_color) {
755 ColorGeometry4f color_base;
756 srgb_to_linearrgb_v3_v3(color_base, ptd.brush->rgb);
757 color_base.a = ptd.settings->vertex_factor;
759 std::make_optional(color_base) :
760 std::nullopt;
762 std::make_optional(color_base) :
763 std::nullopt;
764 }
765 else {
766 ptd.vertex_color = std::nullopt;
767 ptd.fill_color = std::nullopt;
768 }
769
770 ptd.fill_opacity = ptd.brush->alpha;
771 ptd.softness = 1.0 - ptd.settings->hardness;
772
774 vc.scene, ptd.region, ptd.start_position_2d, ptd.placement);
775
776 BLI_assert(grease_pencil->has_active_layer());
777 ptd.local_transform = grease_pencil->get_active_layer()->local_transform();
778 ptd.drawing = grease_pencil->get_editable_drawing_at(*grease_pencil->get_active_layer(),
779 vc.scene->r.cfra);
780
783
786
787 /* Updates indicator in header. */
789
790 /* Add a modal handler for this operator. */
792
794}
795
796/* Exit and free memory. */
798{
800
801 /* Clear status message area. */
802 ED_workspace_status_text(C, nullptr);
803
805
806 /* Deactivate the extra drawing stuff in 3D-View. */
808
810
812
813 MEM_delete<PrimitiveToolOperation>(ptd);
814 /* Clear pointer. */
815 op->customdata = nullptr;
816}
817
819{
820 using namespace math;
821 return sign(p) * float2(1.0f / numbers::sqrt2) * length(p);
822}
823
824/* Using Chebyshev distance instead of Euclidean. */
826{
827 using namespace math;
828 return sign(p) * float2(std::max(abs(p[0]), abs(p[1])));
829}
830
831/* Snaps to the closest diagonal, horizontal or vertical. */
833{
834 using namespace math;
835 /* sin(pi/8) or sin of 22.5 degrees.*/
836 const float sin225 = 0.3826834323650897717284599840304f;
837 return sign(p) * length(p) * normalize(sign(normalize(abs(p)) - sin225) + 1.0f);
838}
839
841 const wmEvent *event)
842{
843 using namespace math;
844 const float2 start = ptd.start_position_2d;
845 const float2 end = float2(event->mval);
846
847 const float2 dif = end - start;
848 float2 offset = dif;
849
850 if (event->modifier & KM_SHIFT) {
851 if (ptd.type == PrimitiveType::Box) {
852 offset = snap_diagonals_box(dif);
853 }
854 else if (ptd.type == PrimitiveType::Circle) {
855 offset = snap_diagonals(dif);
856 }
857 else { /* Line, Polyline, Arc and Curve. */
858 offset = snap_8_angles(dif);
859 }
860 }
861 offset *= 0.5f;
862
863 float2 center = start + offset;
864
865 if (event->modifier & KM_ALT && ptd.segments == 1) {
866 center = start;
867 offset *= 2.0f;
868 }
869
870 const float3 start_pos = ptd.placement.project(center - offset);
871 const float3 end_pos = ptd.placement.project(center + offset);
872
873 const int number_control_points = control_points_per_segment(ptd);
874 for (const int i : IndexRange(number_control_points + 1)) {
875 ptd.control_points.last(i) = interpolate(
876 end_pos, start_pos, (i / float(number_control_points)));
877 }
878}
879
881 const wmEvent *event)
882{
883 const float2 start = ptd.start_position_2d;
884 const float2 end = float2(event->mval);
885 const float2 dif = end - start;
886
887 for (const int point_index : ptd.control_points.index_range()) {
888 const float2 start_pos2 = primitive_local_to_screen(ptd, ptd.temp_control_points[point_index]);
889
890 float3 pos = ptd.placement.project(start_pos2 + dif);
891 ptd.control_points[point_index] = pos;
892 }
893}
894
896{
898 const float3 pos = ptd.placement.project(float2(event->mval));
900
901 if (!ELEM(ptd.type, PrimitiveType::Circle, PrimitiveType::Box)) {
902 return;
903 }
904
905 /* If the center point is been grabbed, move all points. */
908 return;
909 }
910
911 const int other_point = ptd.active_control_point_index == control_point_first ?
914
915 /* Get the location of the other control point.*/
916 const float2 other_point_2d = primitive_local_to_screen(ptd,
917 ptd.temp_control_points[other_point]);
918
919 /* Set the center point to between the first and last point. */
921 (other_point_2d + float2(event->mval)) / 2.0f);
922}
923
925{
927 const float2 start = ptd.start_position_2d;
928 const float2 end = float2(event->mval);
929 const float2 dif = end - start;
930
931 const float2 start_pos2 = primitive_local_to_screen(
933
934 const float3 pos = ptd.placement.project(start_pos2 + dif);
936}
937
939{
940 if (ELEM(ptd.type, PrimitiveType::Box, PrimitiveType::Circle)) {
942 }
943 float2 center_of_mass = float2(0.0f, 0.0f);
944
945 for (const int point_index : ptd.control_points.index_range()) {
946 center_of_mass += primitive_local_to_screen(ptd, ptd.temp_control_points[point_index]);
947 }
948 center_of_mass /= ptd.control_points.size();
949 return center_of_mass;
950}
951
953 const wmEvent *event)
954{
955 const float2 start = ptd.start_position_2d;
956 const float2 end = float2(event->mval);
957
958 const float2 center_of_mass = primitive_center_of_mass(ptd);
959
960 const float2 end_ = end - center_of_mass;
961 const float2 start_ = start - center_of_mass;
962 const float rotation = math::atan2(start_[0], start_[1]) - math::atan2(end_[0], end_[1]);
963
964 for (const int point_index : ptd.control_points.index_range()) {
965 const float2 start_pos2 = primitive_local_to_screen(ptd, ptd.temp_control_points[point_index]);
966
967 const float2 dif = start_pos2 - center_of_mass;
968 const float c = math::cos(rotation);
969 const float s = math::sin(rotation);
970 const float2x2 rot = float2x2(float2(c, s), float2(-s, c));
971 const float2 pos2 = rot * dif + center_of_mass;
972 const float3 pos = ptd.placement.project(pos2);
973 ptd.control_points[point_index] = pos;
974 }
975}
976
978 const wmEvent *event)
979{
980 const float2 start = ptd.start_position_2d;
981 const float2 end = float2(event->mval);
982
983 const float2 center_of_mass = primitive_center_of_mass(ptd);
984
985 const float scale = math::length(end - center_of_mass) / math::length(start - center_of_mass);
986
987 for (const int point_index : ptd.control_points.index_range()) {
988 const float2 start_pos2 = primitive_local_to_screen(ptd, ptd.temp_control_points[point_index]);
989
990 const float2 pos2 = (start_pos2 - center_of_mass) * scale + center_of_mass;
991 const float3 pos = ptd.placement.project(pos2);
992 ptd.control_points[point_index] = pos;
993 }
994}
995
996static int primitive_check_ui_hover(const PrimitiveToolOperation &ptd, const wmEvent *event)
997{
998 float closest_distance_squared = std::numeric_limits<float>::max();
999 int closest_point = -1;
1000
1001 for (const int i : ptd.control_points.index_range()) {
1002 const int point = (ptd.control_points.size() - 1) - i;
1003 const float2 pos_proj = primitive_local_to_screen(ptd, ptd.control_points[point]);
1004 const float radius_sq = ui_point_hit_size_px * ui_point_hit_size_px;
1005 const float distance_squared = math::distance_squared(pos_proj, float2(event->mval));
1006 /* If the mouse is over a control point. */
1007 if (distance_squared <= radius_sq) {
1008 return point;
1009 }
1010
1011 const ControlPointType control_point_type = get_control_point_type(ptd, point);
1012
1013 /* Save the closest handle point. */
1014 if (distance_squared < closest_distance_squared &&
1015 control_point_type == ControlPointType::HandlePoint &&
1017 {
1018 closest_point = point;
1019 closest_distance_squared = distance_squared;
1020 }
1021 }
1022
1023 if (closest_point != -1) {
1024 return closest_point;
1025 }
1026
1027 return -1;
1028}
1029
1032 const wmEvent *event)
1033{
1034 wmWindow *win = CTX_wm_window(C);
1035
1036 if (ptd.mode != OperatorMode::Idle) {
1038 return;
1039 }
1040
1041 const int ui_id = primitive_check_ui_hover(ptd, event);
1042 ptd.active_control_point_index = ui_id;
1043 if (ui_id == -1) {
1044 if (ptd.type == PrimitiveType::Polyline) {
1046 return;
1047 }
1048
1050 return;
1051 }
1052
1054 return;
1055}
1056
1058 wmOperator *op,
1060 const wmEvent *event)
1061{
1062 switch (event->val) {
1063 case int(ModalKeyMode::Cancel): {
1066
1067 return OPERATOR_CANCELLED;
1068 }
1069 case int(ModalKeyMode::Confirm): {
1071
1072 return OPERATOR_FINISHED;
1073 }
1074 case int(ModalKeyMode::Extrude): {
1075 if (ptd.mode == OperatorMode::Idle &&
1076 ELEM(ptd.type, PrimitiveType::Line, PrimitiveType::Arc, PrimitiveType::Curve))
1077 {
1080
1082 const float3 pos = ptd.placement.project(ptd.start_position_2d);
1083
1084 const int number_control_points = control_points_per_segment(ptd);
1085 ptd.control_points.append_n_times(pos, number_control_points);
1087 ptd.segments++;
1088
1090 }
1091
1092 if (ptd.type == PrimitiveType::Polyline &&
1094 {
1097
1100 const float3 pos = ptd.placement.project(float2(event->mval));
1101
1102 /* If we have only two points and they're the same then don't extrude new a point. */
1103 if (ptd.segments == 1 &&
1104 math::distance_squared(ptd.control_points.first(), ptd.control_points.last()) == 0.0f)
1105 {
1106 ptd.control_points.last() = pos;
1107 }
1108 else {
1109 ptd.control_points.append(pos);
1110 ptd.segments++;
1111 }
1112
1114 }
1115
1117 }
1118 case int(ModalKeyMode::Grab): {
1119 if (ptd.mode == OperatorMode::Idle) {
1120 ptd.start_position_2d = float2(event->mval);
1122
1124 }
1126 }
1127 case int(ModalKeyMode::Rotate): {
1128 if (ptd.mode == OperatorMode::Idle) {
1129 ptd.start_position_2d = float2(event->mval);
1131
1133 }
1135 }
1136 case int(ModalKeyMode::Scale): {
1137 if (ptd.mode == OperatorMode::Idle) {
1138 ptd.start_position_2d = float2(event->mval);
1140
1142 }
1144 }
1146 if (event->val != KM_RELEASE) {
1147 ptd.subdivision++;
1148 RNA_int_set(op->ptr, "subdivision", ptd.subdivision);
1149 }
1151 }
1153 if (event->val != KM_RELEASE) {
1154 ptd.subdivision--;
1155 ptd.subdivision = std::max(ptd.subdivision, 0);
1156 RNA_int_set(op->ptr, "subdivision", ptd.subdivision);
1157 }
1159 }
1160 }
1161
1163}
1164
1166{
1167 if (event->val == KM_RELEASE && ELEM(ptd.mode,
1174 {
1177 }
1178
1179 if (ptd.mode == OperatorMode::Idle && event->val == KM_PRESS) {
1180 const int ui_id = primitive_check_ui_hover(ptd, event);
1181 ptd.active_control_point_index = ui_id;
1182 if (ui_id == -1) {
1183 if (ptd.type != PrimitiveType::Polyline) {
1184 ptd.start_position_2d = float2(event->mval);
1186
1188
1190 }
1191 }
1192 else {
1193 const ControlPointType control_point_type = get_control_point_type(ptd, ui_id);
1194
1195 if (control_point_type == ControlPointType::JoinPoint) {
1199
1201 }
1202 else if (control_point_type == ControlPointType::HandlePoint) {
1203 ptd.start_position_2d = float2(event->mval);
1205
1207 }
1208
1210 }
1211 }
1212
1213 if (ptd.type == PrimitiveType::Polyline && ptd.mode == OperatorMode::Idle &&
1214 event->val == KM_PRESS)
1215 {
1218
1220 const float3 pos = ptd.placement.project(float2(event->mval));
1221
1222 /* If we have only two points and they're the same then don't extrude new a point. */
1223 if (ptd.segments == 1 &&
1224 math::distance_squared(ptd.control_points.first(), ptd.control_points.last()) == 0.0f)
1225 {
1226 ptd.control_points.last() = pos;
1227 }
1228 else {
1229 ptd.control_points.append(pos);
1230 ptd.segments++;
1231 }
1232 }
1233
1235}
1236
1238 const wmEvent *event)
1239{
1240 switch (ptd.mode) {
1243 break;
1244 }
1245 case OperatorMode::Grab: {
1247 break;
1248 }
1249 case OperatorMode::Drag: {
1251 break;
1252 }
1253 case OperatorMode::DragAll: {
1255 break;
1256 }
1259 break;
1260 }
1263 break;
1264 }
1265 case OperatorMode::Idle: {
1266 /* Do nothing. */
1267 break;
1268 }
1269 }
1270}
1271
1272/* Modal handler: Events handling during interactive part. */
1274{
1275 PrimitiveToolOperation &ptd = *reinterpret_cast<PrimitiveToolOperation *>(op->customdata);
1276
1277 /* Check for confirm before navigation. */
1278 if (event->type == EVT_MODAL_MAP) {
1279 if (event->val == int(ModalKeyMode::Confirm)) {
1281
1282 return OPERATOR_FINISHED;
1283 }
1284 }
1285
1286 const float3 pos = ptd.control_points.first();
1287 if (ED_view3d_navigation_do(C, ptd.vod, event, pos)) {
1288 if (ptd.vc.rv3d->rflag & RV3D_NAVIGATING) {
1290
1293
1295 }
1296 }
1297
1300
1301 if (event->type == EVT_MODAL_MAP) {
1302 const int return_val = grease_pencil_primitive_event_modal_map(C, op, ptd, event);
1303 if (return_val != OPERATOR_RUNNING_MODAL) {
1304 return return_val;
1305 }
1306 }
1307
1308 switch (event->type) {
1309 case LEFTMOUSE: {
1310 const int return_val = grease_pencil_primitive_mouse_event(ptd, event);
1311 if (return_val != OPERATOR_RUNNING_MODAL) {
1312 return return_val;
1313 }
1314
1315 break;
1316 }
1317 case RIGHTMOUSE: {
1318 if (event->val != KM_PRESS) {
1319 break;
1320 }
1321
1322 if (ptd.mode == OperatorMode::Idle) {
1325
1326 return OPERATOR_CANCELLED;
1327 }
1328 else {
1330
1332 break;
1333 }
1334 }
1335 }
1336
1337 /* Updating is done every event not just `MOUSEMOVE`. */
1340
1341 /* Updates indicator in header. */
1344
1345 /* Still running... */
1347}
1348
1349/* Cancel handler. */
1351{
1352 /* This is just a wrapper around exit() */
1354}
1355
1357 const int default_subdiv,
1358 const PrimitiveType default_type)
1359{
1360 static const EnumPropertyItem grease_pencil_primitive_type[] = {
1361 {int(PrimitiveType::Box), "BOX", 0, "Box", ""},
1362 {int(PrimitiveType::Line), "LINE", 0, "Line", ""},
1363 {int(PrimitiveType::Polyline), "POLYLINE", 0, "Polyline", ""},
1364 {int(PrimitiveType::Circle), "CIRCLE", 0, "Circle", ""},
1365 {int(PrimitiveType::Arc), "ARC", 0, "Arc", ""},
1366 {int(PrimitiveType::Curve), "CURVE", 0, "Curve", ""},
1367 {0, nullptr, 0, nullptr, nullptr},
1368 };
1369
1370 PropertyRNA *prop;
1371
1372 prop = RNA_def_int(ot->srna,
1373 "subdivision",
1374 default_subdiv,
1375 0,
1376 INT_MAX,
1377 "Subdivisions",
1378 "Number of subdivisions per segment",
1379 0,
1380 INT_MAX);
1382
1384 ot->srna, "type", grease_pencil_primitive_type, int(default_type), "Type", "Type of shape");
1385}
1386
1388{
1389 /* Identifiers. */
1390 ot->name = "Grease Pencil Line Shape";
1391 ot->idname = "GREASE_PENCIL_OT_primitive_line";
1392 ot->description = "Create predefined grease pencil stroke lines";
1393
1394 /* Callbacks. */
1398
1399 /* Flags. */
1401
1402 /* Properties and Flags. */
1403 grease_pencil_primitive_common_props(ot, 6, PrimitiveType::Line);
1404}
1405
1407{
1408 /* Identifiers. */
1409 ot->name = "Grease Pencil Polyline Shape";
1410 ot->idname = "GREASE_PENCIL_OT_primitive_polyline";
1411 ot->description = "Create predefined grease pencil stroke polylines";
1412
1413 /* Callbacks. */
1417
1418 /* Flags. */
1420
1421 /* Properties. */
1422 grease_pencil_primitive_common_props(ot, 6, PrimitiveType::Polyline);
1423}
1424
1426{
1427 /* Identifiers. */
1428 ot->name = "Grease Pencil Arc Shape";
1429 ot->idname = "GREASE_PENCIL_OT_primitive_arc";
1430 ot->description = "Create predefined grease pencil stroke arcs";
1431
1432 /* Callbacks. */
1436
1437 /* Flags. */
1439
1440 /* Properties. */
1441 grease_pencil_primitive_common_props(ot, 62, PrimitiveType::Arc);
1442}
1443
1445{
1446 /* Identifiers. */
1447 ot->name = "Grease Pencil Curve Shape";
1448 ot->idname = "GREASE_PENCIL_OT_primitive_curve";
1449 ot->description = "Create predefined grease pencil stroke curve shapes";
1450
1451 /* Callbacks. */
1455
1456 /* Flags. */
1458
1459 /* Properties. */
1460 grease_pencil_primitive_common_props(ot, 62, PrimitiveType::Curve);
1461}
1462
1464{
1465 /* Identifiers. */
1466 ot->name = "Grease Pencil Box Shape";
1467 ot->idname = "GREASE_PENCIL_OT_primitive_box";
1468 ot->description = "Create predefined grease pencil stroke boxes";
1469
1470 /* Callbacks. */
1474
1475 /* Flags. */
1477
1478 /* Properties. */
1479 grease_pencil_primitive_common_props(ot, 3, PrimitiveType::Box);
1480}
1481
1483{
1484 /* Identifiers. */
1485 ot->name = "Grease Pencil Circle Shape";
1486 ot->idname = "GREASE_PENCIL_OT_primitive_circle";
1487 ot->description = "Create predefined grease pencil stroke circles";
1488
1489 /* Callbacks. */
1493
1494 /* Flags. */
1496
1497 /* Properties. */
1498 grease_pencil_primitive_common_props(ot, 94, PrimitiveType::Circle);
1499}
1500
1501} // namespace blender::ed::greasepencil
1502
1504{
1505 using namespace blender::ed::greasepencil;
1506 WM_operatortype_append(GREASE_PENCIL_OT_primitive_line);
1507 WM_operatortype_append(GREASE_PENCIL_OT_primitive_polyline);
1508 WM_operatortype_append(GREASE_PENCIL_OT_primitive_arc);
1509 WM_operatortype_append(GREASE_PENCIL_OT_primitive_curve);
1510 WM_operatortype_append(GREASE_PENCIL_OT_primitive_box);
1511 WM_operatortype_append(GREASE_PENCIL_OT_primitive_circle);
1512}
1513
1515{
1516 using namespace blender::ed::greasepencil;
1517 static const EnumPropertyItem modal_items[] = {
1518 {int(ModalKeyMode::Cancel), "CANCEL", 0, "Cancel", ""},
1519 {int(ModalKeyMode::Confirm), "CONFIRM", 0, "Confirm", ""},
1520 {int(ModalKeyMode::Panning), "PANNING", 0, "Panning", ""},
1521 {int(ModalKeyMode::Extrude), "EXTRUDE", 0, "Extrude", ""},
1522 {int(ModalKeyMode::Grab), "GRAB", 0, "Grab", ""},
1523 {int(ModalKeyMode::Rotate), "ROTATE", 0, "Rotate", ""},
1524 {int(ModalKeyMode::Scale), "SCALE", 0, "Scale", ""},
1525 {int(ModalKeyMode::IncreaseSubdivision),
1526 "INCREASE_SUBDIVISION",
1527 0,
1528 "Increase Subdivision",
1529 ""},
1530 {int(ModalKeyMode::DecreaseSubdivision),
1531 "DECREASE_SUBDIVISION",
1532 0,
1533 "Decrease Subdivision",
1534 ""},
1535 {0, nullptr, 0, nullptr, nullptr},
1536 };
1537
1538 wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Primitive Tool Modal Map");
1539
1540 /* This function is called for each space-type, only needs to add map once. */
1541 if (keymap && keymap->modal_items) {
1542 return;
1543 }
1544
1545 keymap = WM_modalkeymap_ensure(keyconf, "Primitive Tool Modal Map", modal_items);
1546
1547 WM_modalkeymap_assign(keymap, "GREASE_PENCIL_OT_primitive_line");
1548 WM_modalkeymap_assign(keymap, "GREASE_PENCIL_OT_primitive_polyline");
1549 WM_modalkeymap_assign(keymap, "GREASE_PENCIL_OT_primitive_arc");
1550 WM_modalkeymap_assign(keymap, "GREASE_PENCIL_OT_primitive_curve");
1551 WM_modalkeymap_assign(keymap, "GREASE_PENCIL_OT_primitive_box");
1552 WM_modalkeymap_assign(keymap, "GREASE_PENCIL_OT_primitive_circle");
1553}
void BKE_brush_init_gpencil_settings(Brush *brush)
Definition brush.cc:563
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
void BKE_curvemapping_init(CurveMapping *cumap)
wmWindow * CTX_wm_window(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Main * CTX_data_main(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
Material * BKE_grease_pencil_object_material_ensure_from_active_input_brush(Main *bmain, Object *ob, Brush *brush)
General operations, lookup, etc. for materials.
int BKE_object_material_index_get(Object *ob, const Material *ma)
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:649
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
unsigned int uint
#define ELEM(...)
#define RPT_(msgid)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ GPPAINT_MODE_STROKE
@ GPPAINT_MODE_FILL
@ GPPAINT_MODE_BOTH
@ CURVE_TYPE_POLY
@ GP_STROKE_CAP_TYPE_ROUND
@ GP_MATERIAL_FILL_SHOW
@ GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE
@ GPPAINT_FLAG_USE_VERTEXCOLOR
@ RV3D_NAVIGATING
@ OP_IS_MODAL_CURSOR_REGION
@ OPERATOR_RUNNING_MODAL
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:966
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
#define REGION_DRAW_POST_VIEW
bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
blender::float2 ED_view3d_project_float_v2_m4(const ARegion *region, const float co[3], const blender::float4x4 &mat)
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
void ED_view3d_navigation_free(bContext *C, ViewOpsData *vod)
blender::float4x4 ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob)
bool ED_view3d_navigation_do(bContext *C, ViewOpsData *vod, const wmEvent *event, const float depth_loc_override[3])
ViewOpsData * ED_view3d_navigation_init(bContext *C, const wmKeyMapItem *kmi_merge)
void immEnd()
void immUnbindProgram()
void immAttr1f(uint attr_id, float x)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
GPUVertFormat * immVertexFormat()
void immAttr4f(uint attr_id, float x, float y, float z, float w)
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
@ GPU_PRIM_POINTS
@ GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR
void GPU_program_point_size(bool enable)
Definition gpu_state.cc:175
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
#define C
Definition RandGen.cpp:29
@ TH_GIZMO_B
@ TH_GIZMO_A
@ TH_GIZMO_PRIMARY
@ TH_GIZMO_SECONDARY
void UI_GetThemeColor4fv(int colorid, float col[4])
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
@ KM_ALT
Definition WM_types.hh:257
@ KM_SHIFT
Definition WM_types.hh:255
#define A
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
ChannelStorageType a
Definition BLI_color.hh:88
constexpr IndexRange drop_back(int64_t n) const
static constexpr IndexRange from_single(const int64_t index)
constexpr IndexRange index_range() const
constexpr int64_t size() const
Definition BLI_span.hh:494
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
constexpr IndexRange index_range() const
Definition BLI_span.hh:671
constexpr T & last(const int64_t n=0) const
Definition BLI_span.hh:690
bool add(const Key &key)
Definition BLI_set.hh:248
void add_multiple(Span< Key > keys)
Definition BLI_set.hh:268
constexpr const T & last(const int64_t n=0) const
Definition BLI_span.hh:326
OffsetIndices< int > points_by_curve() const
void remove_curves(const IndexMask &curves_to_delete, const AttributeFilter &attribute_filter)
MutableSpan< float > opacities_for_write()
MutableSpan< float > radii_for_write()
bke::CurvesGeometry & strokes_for_write()
MutableSpan< ColorGeometry4f > fill_colors_for_write()
MutableSpan< ColorGeometry4f > vertex_colors_for_write()
void set_texture_matrices(Span< float4x2 > matrices, const IndexMask &selection)
void cache_viewport_depths(Depsgraph *depsgraph, ARegion *region, View3D *view3d)
#define sinf(x)
#define cosf(x)
static bool is_cyclic(const Nurb *nu)
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
#define rot(x, k)
void ED_primitivetool_modal_keymap(wmKeyConfig *keyconf)
void ED_operatortypes_grease_pencil_primitives()
#define B
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
auto attribute_filter_from_skip_ref(const Span< StringRef > skip)
void fill_attribute_range_default(MutableAttributeAccessor dst_attributes, AttrDomain domain, const AttributeFilter &attribute_filter, IndexRange range)
static constexpr int control_point_center
int grease_pencil_draw_operator_invoke(bContext *C, wmOperator *op, const bool use_duplicate_previous_key)
static int control_points_per_segment(const PrimitiveToolOperation &ptd)
static constexpr float ui_tertiary_point_draw_size_px
static void grease_pencil_primitive_cancel(bContext *C, wmOperator *op)
static void grease_pencil_primitive_grab_update(PrimitiveToolOperation &ptd, const wmEvent *event)
static void grease_pencil_primitive_operator_update(PrimitiveToolOperation &ptd, const wmEvent *event)
static int grease_pencil_primitive_mouse_event(PrimitiveToolOperation &ptd, const wmEvent *event)
static void GREASE_PENCIL_OT_primitive_circle(wmOperatorType *ot)
static float2 snap_diagonals_box(float2 p)
static constexpr int control_point_first
static float2 snap_8_angles(float2 p)
float opacity_from_input_sample(const float pressure, const Brush *brush, const BrushGpencilSettings *settings)
static void grease_pencil_primitive_drag_update(PrimitiveToolOperation &ptd, const wmEvent *event)
static int grease_pencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *event)
float radius_from_input_sample(const RegionView3D *rv3d, const ARegion *region, const Brush *brush, const float pressure, const float3 location, const float4x4 to_world, const BrushGpencilSettings *settings)
static int grease_pencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void primitive_calulate_curve_positions(PrimitiveToolOperation &ptd, Span< float2 > control_points, MutableSpan< float2 > new_positions)
static void control_point_colors_and_sizes(const PrimitiveToolOperation &ptd, MutableSpan< ColorGeometry4f > colors, MutableSpan< float > sizes)
static void grease_pencil_primitive_extruding_update(PrimitiveToolOperation &ptd, const wmEvent *event)
static int grease_pencil_primitive_curve_points_number(PrimitiveToolOperation &ptd)
static void grease_pencil_primitive_update_view(bContext *C, PrimitiveToolOperation &ptd)
static int grease_pencil_primitive_event_modal_map(bContext *C, wmOperator *op, PrimitiveToolOperation &ptd, const wmEvent *event)
static void grease_pencil_primitive_draw(const bContext *, ARegion *, void *arg)
static void draw_control_points(PrimitiveToolOperation &ptd)
static void grease_pencil_primitive_update_curves(PrimitiveToolOperation &ptd)
static float2 primitive_center_of_mass(const PrimitiveToolOperation &ptd)
static void grease_pencil_primitive_drag_all_update(PrimitiveToolOperation &ptd, const wmEvent *event)
static constexpr float ui_secondary_point_draw_size_px
static constexpr float ui_point_hit_size_px
static constexpr int control_point_last
static constexpr float ui_point_max_hit_size_px
static void grease_pencil_primitive_init_curves(PrimitiveToolOperation &ptd)
static void grease_pencil_primitive_undo_curves(PrimitiveToolOperation &ptd)
static void GREASE_PENCIL_OT_primitive_line(wmOperatorType *ot)
static void grease_pencil_primitive_scale_all_update(PrimitiveToolOperation &ptd, const wmEvent *event)
static void primitive_calulate_curve_positions_2d(PrimitiveToolOperation &ptd, MutableSpan< float2 > new_positions)
static ControlPointType get_control_point_type(const PrimitiveToolOperation &ptd, const int point)
static constexpr float ui_primary_point_draw_size_px
static void grease_pencil_primitive_common_props(wmOperatorType *ot, const int default_subdiv, const PrimitiveType default_type)
static void grease_pencil_primitive_rotate_all_update(PrimitiveToolOperation &ptd, const wmEvent *event)
float4x2 calculate_texture_space(const Scene *scene, const ARegion *region, const float2 &mouse, const DrawingPlacement &placement)
static void grease_pencil_primitive_cursor_update(bContext *C, PrimitiveToolOperation &ptd, const wmEvent *event)
static void grease_pencil_primitive_load(PrimitiveToolOperation &ptd)
static void grease_pencil_primitive_status_indicators(bContext *C, wmOperator *op, PrimitiveToolOperation &ptd)
static void grease_pencil_primitive_exit(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_primitive_polyline(wmOperatorType *ot)
static void GREASE_PENCIL_OT_primitive_curve(wmOperatorType *ot)
static float2 primitive_local_to_screen(const PrimitiveToolOperation &ptd, const float3 &point)
static void grease_pencil_primitive_save(PrimitiveToolOperation &ptd)
static float2 snap_diagonals(float2 p)
static void GREASE_PENCIL_OT_primitive_box(wmOperatorType *ot)
static void GREASE_PENCIL_OT_primitive_arc(wmOperatorType *ot)
static int primitive_check_ui_hover(const PrimitiveToolOperation &ptd, const wmEvent *event)
T cos(const AngleRadianBase< T > &a)
T length(const VecBase< T, Size > &a)
T interpolate(const T &a, const T &b, const FactorT &t)
T atan2(const T &y, const T &x)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T sin(const AngleRadianBase< T > &a)
T mod(const T &a, const T &b)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 2, 2 > float2x2
VecBase< float, 2 > float2
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
int RNA_int_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
signed char int8_t
Definition stdint.h:75
struct ARegionType * type
struct CurveMapping * curve_sensitivity
struct CurveMapping * curve_strength
struct CurveMapping * curve_jitter
struct CurveMapping * curve_rand_pressure
struct CurveMapping * curve_rand_strength
struct CurveMapping * curve_rand_saturation
struct CurveMapping * curve_rand_hue
struct CurveMapping * curve_rand_uv
struct CurveMapping * curve_rand_value
float alpha
float rgb[3]
struct BrushGpencilSettings * gpencil_settings
struct CurveMapping * cur_primitive
struct ToolSettings * toolsettings
struct RenderData r
struct GP_Sculpt_Settings gp_sculpt
RegionView3D * rv3d
Definition ED_view3d.hh:76
ARegion * region
Definition ED_view3d.hh:73
Scene * scene
Definition ED_view3d.hh:69
wmWindow * win
Definition ED_view3d.hh:75
Object * obact
Definition ED_view3d.hh:71
short val
Definition WM_types.hh:724
int mval[2]
Definition WM_types.hh:728
uint8_t modifier
Definition WM_types.hh:739
short type
Definition WM_types.hh:722
const void * modal_items
const char * name
Definition WM_types.hh:990
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct wmOperatorType * type
struct PointerRNA * ptr
ccl_device_inline int abs(int x)
Definition util/math.h:120
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
@ WM_CURSOR_HAND
Definition wm_cursors.hh:22
@ WM_CURSOR_NSEW_SCROLL
Definition wm_cursors.hh:51
@ WM_CURSOR_CROSS
Definition wm_cursors.hh:26
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ RIGHTMOUSE
@ EVT_MODAL_MAP
@ LEFTMOUSE
wmOperatorType * ot
Definition wm_files.cc:4125
std::optional< std::string > WM_modalkeymap_operator_items_to_string(wmOperatorType *ot, const int propvalue, const bool compact)
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:933
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition wm_keymap.cc:960
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))