42#include "RNA_prototypes.hh"
45#include "curve_fit_nd.h"
51#define STROKE_SAMPLE_DIST_MIN_PX 1
52#define STROKE_SAMPLE_DIST_MAX_PX 3
55#define STROKE_CYCLIC_DIST_PX 8
170 const float mval_fl[2],
171 float surface_offset,
173 float r_location_world[3],
174 float r_normal_world[3])
178 bool is_location_world_set =
false;
185 if (r_normal_world) {
188 is_location_world_set =
true;
193 if (depths && (
uint(mval_i[0]) < depths->
w) && (
uint(mval_i[1]) < depths->
h)) {
194 float depth_fl = 1.0f;
196 const double depth = double(depth_fl);
197 if ((depth > depths->
depth_range[0]) && (depth < depths->depth_range[1])) {
199 is_location_world_set =
true;
200 if (r_normal_world) {
204 if (surface_offset != 0.0f) {
208 madd_v3_v3fl(r_location_world, normal, offset * surface_offset);
209 if (r_normal_world) {
219 if (is_location_world_set) {
225 return is_location_world_set;
230 const float mval_fl[2],
231 const float surface_offset,
233 const float location_fallback_depth[3],
234 float r_location_world[3],
235 float r_location_local[3],
236 float r_normal_world[3],
237 float r_normal_local[3])
240 cdd, mval_i, mval_fl, surface_offset, radius, r_location_world, r_normal_world);
241 if (is_depth_found ==
false) {
243 cdd->
vc.
v3d, cdd->
vc.
region, location_fallback_depth, mval_fl, r_location_world);
257 return is_depth_found;
264 const float location_fallback_depth[3],
267 const int mval_i[2] = {int(selem->
mval[0]), int(selem->
mval[1])};
274 location_fallback_depth,
342 if (stroke_len == 0) {
354 const float location_zero[3] = {0};
355 const float *location_prev = location_zero;
389 if (stroke_len > 1) {
390 float(*coord_array)[3] =
static_cast<float(*)[3]
>(
391 MEM_mallocN(
sizeof(*coord_array) * stroke_len, __func__));
417 for (
int i = 0;
i < stroke_len;
i++) {
426 for (
int i = 0;
i < stroke_len;
i++) {
455 selem->
pressure =
event->tablet.pressure;
460 if (is_depth_found) {
475 for (
int i = 1;
i < n;
i++) {
481 if (is_depth_found ==
false) {
482 if (is_depth_found_substep) {
490 selem = selem_new_last;
491 *selem_new_last = selem_target;
515 float normal[3] = {0.0f};
522 float cross_a[3], cross_b[3];
541 const float mval_fl[2] = {float(event->
mval[0]), float(event->
mval[1])};
543 float location_no_offset[3];
636 const int curve_index,
638 const uint cubic_spline_len,
640 const int radius_index,
641 const float radius_max,
642 const float *cubic_spline,
643 const uint *corners_index,
644 const uint corners_index_len)
646 curves.resize(
curves.points_num() + cubic_spline_len, curve_index + 1);
659 const float *co = cubic_spline;
661 for (
const int64_t i : new_points) {
662 const float *handle_l = co + (dims * 0);
663 const float *pt = co + (dims * 1);
664 const float *handle_r = co + (dims * 2);
670 const float radius = (radius_index != -1) ?
673 radii.
span[
i] = radius;
682 uint i_start = 0, i_end = corners_index_len;
684 if ((corners_index_len >= 2) && !
is_cyclic) {
689 for (
const auto i :
IndexRange(i_start, i_end - i_start)) {
690 const int64_t corner_i = new_points[corners_index[
i]];
702 const int curve_index,
704 const uint cubic_spline_len,
706 const int radius_index,
707 const float radius_max,
708 const float *cubic_spline)
710 const int point_num = (cubic_spline_len - 2) * 3 + 4 + (
is_cyclic ? 2 : 0);
711 curves.resize(
curves.points_num() + point_num, curve_index + 1);
721 const float *pt = cubic_spline + (
is_cyclic ? 0 : dims);
723 for (
const int64_t i : new_points) {
724 const float radius = (radius_index != -1) ?
729 radii.
span[
i] = radius;
765 bool is_cyclic = (stroke_len > 2) && use_cyclic;
773 const int curve_index =
curves.curves_num();
786 const int radius_index = use_pressure_radius ? dims++ : -1;
790 float *cubic_spline =
nullptr;
791 uint cubic_spline_len = 0;
803 if (radius_index != -1) {
808 if ((co != coords) &&
UNLIKELY(memcmp(co, co - dims,
sizeof(
float) * dims) == 0)) {
815 uint *corners =
nullptr;
816 uint corners_len = 0;
820 const float corner_radius_min = error_threshold / 8;
821 const float corner_radius_max = error_threshold * 2;
822 const uint samples_max = 16;
824 curve_fit_corners_detect_fl(coords,
835 uint *corners_index =
nullptr;
836 uint corners_index_len = 0;
837 uint calc_flag = CURVE_FIT_CALC_HIGH_QUALIY;
839 if ((stroke_len > 2) && use_cyclic) {
840 calc_flag |= CURVE_FIT_CALC_CYCLIC;
849 result = curve_fit_cubic_to_points_refit_fl(coords,
864 result = curve_fit_cubic_to_points_fl(coords,
887 if (bezier_as_nurbs) {
888 bool is_cyclic_curve = calc_flag & CURVE_FIT_CALC_CYCLIC;
920 curves.nurbs_knots_modes_for_write()[curve_index] = knots_mode;
921 curves.nurbs_orders_for_write()[curve_index] = order;
927 (bezier_as_nurbs ? selection_attribute_names :
932 if (selection_name ==
".selection" || !bezier_as_nurbs) {
933 selection.
varray.set(curve_index,
true);
938 if (attributes.
contains(
"resolution")) {
939 curves.resolution_for_write()[curve_index] = 12;
952 ".selection_handle_left",
953 ".selection_handle_right"}),
954 curves.points_by_curve()[curve_index]);
964 ".selection_handle_left",
965 ".selection_handle_right"}),
978 curves.resize(
curves.points_num() + stroke_len, curve_index + 1);
997 positions[
i][2] = 0.0f;
1000 radii.
span[
i] = use_pressure_radius ? (selem->pressure * radius_range) + radius_min :
1008 selection.
varray.set(curve_index,
true);
1025 ".selection_handle_left",
1026 ".selection_handle_right"}),
1032 {
"curve_type",
".selection",
".selection_handle_left",
".selection_handle_right"}),
1037 curves.cyclic_for_write()[curve_index] =
true;
1066 const float mval_fl[2] = {float(event->
mval[0]), float(event->
mval[1])};
1082 const float *plane_no =
nullptr;
1083 const float *plane_co =
nullptr;
1087 plane_co = obedit->object_to_world().location();
1088 plane_no = obedit->object_to_world().ptr()[2];
1109 if (cdd->
depths !=
nullptr) {
1136 if (is_modal ==
false) {
1179 float len_3d = 0.0f, len_2d = 0.0f;
1192 scale_px = ((len_3d > 0.0f) && (len_2d > 0.0f)) ? (len_3d / len_2d) : 0.0f;
1199 bool use_cyclic =
false;
1203 const StrokeElem *selem, *selem_first, *selem_last;
1232 MEM_mallocN(
sizeof(*selem_array) * stroke_len, __func__));
1235 float len_3d = 0.0f;
1240 selem_array[0] = selem_prev;
1245 len_3d += len_3d_segment;
1246 lengths[
i] = len_3d;
1247 selem_array[
i] = selem;
1253 for (
i = 0;
i < stroke_len && lengths[
i] < len_taper_max;
i++) {
1254 const float pressure_new = selem_array[
i]->
pressure * (lengths[
i] / len_taper_max);
1261 const float len_taper_min = len_3d - len_taper_max;
1262 for (
i = stroke_len - 1;
i > 0 && lengths[
i] > len_taper_min;
i--) {
1263 const float pressure_new = selem_array[
i]->
pressure *
1264 ((len_3d - lengths[
i]) / len_taper_max);
1306 const float mval_fl[2] = {float(event->
mval[0]), float(event->
mval[1])};
1318 ot->name =
"Draw Curves";
1319 ot->idname = __func__;
1320 ot->description =
"Draw a freehand curve";
1339 "Error distance threshold (in object units)",
1353 ot->srna,
"corner_angle",
DEG2RADF(70.0f), 0.0f,
M_PI,
"Corner Angle",
"", 0.0f,
M_PI);
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
Main * CTX_data_main(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
Low-level operations for curves.
void BKE_report(ReportList *reports, eReportType type, const char *message)
void BLI_kdtree_nd_ free(KDTree *tree)
MINLINE float square_f(float a)
MINLINE float interpf(float target, float origin, float t)
void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL()
void * BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1)
void * BLI_mempool_calloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
#define ARRAY_SET_ITEMS(...)
#define BLT_I18NCONTEXT_AMOUNT
void DEG_id_tag_update(ID *id, unsigned int flags)
@ NURBS_KNOT_MODE_ENDPOINT_BEZIER
@ CURVE_PAINT_PROJECT_SURFACE
@ CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE
@ CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW
@ CURVE_PAINT_FIT_METHOD_REFIT
@ CURVE_PAINT_FIT_METHOD_SPLIT
@ CURVE_PAINT_FLAG_DEPTH_STROKE_ENDPOINTS
@ CURVE_PAINT_FLAG_DEPTH_STROKE_OFFSET_ABS
@ CURVE_PAINT_FLAG_CORNERS_DETECT
@ CURVE_PAINT_FLAG_PRESSURE_RADIUS
@ CURVE_PAINT_FLAG_DEPTH_ONLY_SELECTED
void ED_region_tag_redraw(ARegion *region)
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)
bool ED_view3d_depth_read_cached(const ViewDepths *vd, const int mval[2], int margin, float *r_depth)
void ED_view3d_depth_override(Depsgraph *depsgraph, ARegion *region, View3D *v3d, Object *obact, eV3DDepthOverrideMode mode, bool use_overlay, ViewDepths **r_depths)
void ED_view3d_win_to_3d(const View3D *v3d, const ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
bool ED_view3d_depth_read_cached_normal(const ARegion *region, const ViewDepths *depths, const int mval[2], float r_normal[3])
void ED_view3d_depths_free(ViewDepths *depths)
@ V3D_DEPTH_SELECTED_ONLY
bool ED_view3d_win_to_3d_on_plane(const ARegion *region, const float plane[4], const float mval[2], bool do_clip, float r_out[3])
void view3d_operator_needs_gpu(const bContext *C)
bool ED_view3d_depth_unproject_v3(const ARegion *region, const int mval[2], double depth, float r_location_world[3])
#define GPU_batch_uniform_3fv(batch, name, val)
void GPU_batch_program_set_builtin(blender::gpu::Batch *batch, eGPUBuiltinShader shader_id)
void GPU_batch_draw(blender::gpu::Batch *batch)
blender::gpu::Batch * GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT
#define GPU_matrix_mul(x)
void GPU_matrix_scale_1f(float factor)
void GPU_matrix_translate_3f(float x, float y, float z)
@ GPU_SHADER_3D_UNIFORM_COLOR
void GPU_blend(eGPUBlend blend)
void GPU_line_width(float width)
void GPU_line_smooth(bool enable)
void GPU_depth_test(eGPUDepthTest test)
#define RNA_BEGIN(sptr, itemptr, propname)
void UI_GetThemeColor3fv(int colorid, float col[3])
BPy_StructRNA * depsgraph
bool contains(StringRef attribute_id) const
GAttributeWriter lookup_or_add_for_write(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
#define STROKE_CYCLIC_DIST_PX
#define STROKE_SAMPLE_DIST_MIN_PX
#define STROKE_SAMPLE_DIST_MAX_PX
static bool is_cyclic(const Nurb *nu)
void * MEM_mallocN(size_t len, const char *str)
void * MEM_callocN(size_t len, const char *str)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
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 bool stroke_elem_project_fallback(const CurveDrawData *cdd, const int mval_i[2], const float mval_fl[2], const float surface_offset, const float radius, const float location_fallback_depth[3], float r_location_world[3], float r_location_local[3], float r_normal_world[3], float r_normal_local[3])
static void curve_draw_stroke_from_operator_elem(wmOperator *op, PointerRNA *itemptr)
void CURVES_OT_draw(wmOperatorType *ot)
static void create_Bezier(bke::CurvesGeometry &curves, bke::MutableAttributeAccessor &attributes, const CurveDrawData *cdd, const int curve_index, const bool is_cyclic, const uint cubic_spline_len, const int dims, const int radius_index, const float radius_max, const float *cubic_spline, const uint *corners_index, const uint corners_index_len)
void remove_selection_attributes(bke::MutableAttributeAccessor &attributes, Span< StringRef > selection_attribute_names)
static void create_NURBS(bke::CurvesGeometry &curves, bke::MutableAttributeAccessor &attributes, const CurveDrawData *cdd, const int curve_index, const bool is_cyclic, const uint cubic_spline_len, const int dims, const int radius_index, const float radius_max, const float *cubic_spline)
static bool stroke_elem_project(const CurveDrawData *cdd, const int mval_i[2], const float mval_fl[2], float surface_offset, const float radius, float r_location_world[3], float r_normal_world[3])
static wmOperatorStatus curves_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
static void curve_draw_exit(wmOperator *op)
Span< StringRef > get_curves_bezier_selection_attribute_names(const bke::CurvesGeometry &curves)
bool editable_curves_in_edit_mode_poll(bContext *C)
static void curve_draw_stroke_from_operator(wmOperator *op)
static void curve_draw_stroke_to_operator(wmOperator *op)
static void curve_draw_event_add(wmOperator *op, const wmEvent *event)
static void curve_draw_cancel(bContext *, wmOperator *op)
Span< StringRef > get_curves_selection_attribute_names(const bke::CurvesGeometry &curves)
static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event)
static float stroke_elem_radius(const CurveDrawData *cdd, const StrokeElem *selem)
static float stroke_elem_radius_from_pressure(const CurveDrawData *cdd, const float pressure)
static void stroke_elem_interp(StrokeElem *selem_out, const StrokeElem *selem_a, const StrokeElem *selem_b, float t)
static void curve_draw_stroke_3d(const bContext *, ARegion *, void *arg)
Span< StringRef > get_curves_all_selection_attribute_names()
static wmOperatorStatus curves_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus curves_draw_exec(bContext *C, wmOperator *op)
static void curve_draw_stroke_to_operator_elem(wmOperator *op, const StrokeElem *selem)
static bool stroke_elem_project_fallback_elem(const CurveDrawData *cdd, const float location_fallback_depth[3], StrokeElem *selem)
static void stroke_elem_pressure_set(const CurveDrawData *cdd, StrokeElem *selem, float pressure)
static void curve_draw_exec_precalc(wmOperator *op)
vector project(vector v, vector v_proj)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_collection_is_empty(PointerRNA *ptr, const char *name)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
void RNA_collection_add(PointerRNA *ptr, const char *name, PointerRNA *r_value)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float_distance(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision)
const EnumPropertyItem rna_enum_curve_fit_method_items[]
ARegionRuntimeHandle * runtime
ObjectRuntimeHandle * runtime
struct ToolSettings * toolsettings
VMutableArray< T > varray
MutableVArraySpan< T > span
struct blender::ed::curves::CurveDrawData::@365265160006023152172257310217306010206137013173 prev
bool use_surface_offset_absolute
BLI_mempool * stroke_elem_pool
float location_world_valid[3]
struct blender::ed::curves::CurveDrawData::@276072357045201012345345174065231345006163120323 radius
struct blender::ed::curves::CurveDrawData::@036040310350073216202326007002146267106306257306 sample
struct blender::ed::curves::CurveDrawData::@323351144070373022106163024031165221142052176357 project
struct ReportList * reports
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
#define ISMOUSE_MOTION(event_type)