27#define PROF_TABLE_MAX 512
35 CurveProfile *profile = MEM_cnew<CurveProfile>(__func__);
38 profile->preset = preset;
69 for (
int i = 0; i < target->path_len; i++) {
70 target->path[i].profile = target;
93 profile->table =
nullptr;
94 profile->segments =
nullptr;
97 for (
int i = 0; i < profile->path_len; i++) {
98 profile->path[i].profile = profile;
113 const float delta[2])
115 short handle_type = (handle_1) ? point->h1 : point->h2;
116 float *handle_location = (handle_1) ? &point->h1_loc[0] : &point->h2_loc[0];
118 float start_position[2];
127 handle_location[0] += delta ? delta[0] : 0.0f;
128 handle_location[1] += delta ? delta[1] : 0.0f;
130 handle_location[0] = 0.125f * roundf(8.0f * handle_location[0]);
131 handle_location[1] = 0.125f * roundf(8.0f * handle_location[1]);
136 short other_handle_type = (handle_1) ? point->h2 : point->h1;
137 if (other_handle_type ==
HD_ALIGN) {
138 float *other_handle_location = (handle_1) ? &point->h2_loc[0] : &point->h1_loc[0];
139 other_handle_location[0] = 2.0f * point->x - handle_location[0];
140 other_handle_location[1] = 2.0f * point->y - handle_location[1];
144 if (!
equals_v2v2(handle_location, start_position)) {
153 const float delta[2])
156 if (point == &profile->path[profile->path_len - 1]) {
160 if (point == profile->path) {
163 float origx = point->x;
164 float origy = point->y;
166 point->x += delta[0];
167 point->y += delta[1];
169 point->x = 0.125f * roundf(8.0f * point->x);
170 point->y = 0.125f * roundf(8.0f * point->y);
175 point->x =
max_ff(point->x, profile->clip_rect.xmin);
176 point->x =
min_ff(point->x, profile->clip_rect.xmax);
177 point->y =
max_ff(point->y, profile->clip_rect.ymin);
178 point->y =
min_ff(point->y, profile->clip_rect.ymax);
183 point->h1_loc[0] += point->x - origx;
184 point->h1_loc[1] += point->y - origy;
187 point->h2_loc[0] += point->x - origx;
188 point->h2_loc[1] += point->y - origy;
191 if (point->x != origx || point->y != origy) {
200 if (profile->path_len <= 2) {
212 int i_delete =
int(point - profile->path);
217 memcpy(new_path + i_delete,
218 profile->path + i_delete + 1,
222 profile->path = new_path;
223 profile->path_len -= 1;
237 new_path[0] = profile->path[0];
238 for (; i_old < profile->path_len - 1; i_old++) {
239 if (!(profile->path[i_old].flag &
flag)) {
240 new_path[i_new] = profile->path[i_old];
247 new_path[i_new] = profile->path[i_old];
250 profile->path = new_path;
251 profile->path_len -= n_removed;
268 const float new_loc[2] = {
x, y};
278 for (
int i = 0; i < profile->path_len - 1; i++) {
279 const float loc1[2] = {profile->path[i].
x, profile->path[i].y};
280 const float loc2[2] = {profile->path[i + 1].x, profile->path[i + 1].y};
283 if (distance < min_distance) {
294 for (
int i_new = 0, i_old = 0; i_new < profile->path_len; i_new++) {
295 if (i_new != i_insert) {
297 new_path[i_new] = profile->path[i_old];
298 new_path[i_new].
flag &= ~PROF_SELECT;
304 char new_handle_type = (new_path[i_new - 1].
h2 ==
HD_VECT &&
305 profile->path[i_insert].h1 ==
HD_VECT) ?
309 new_pt = &new_path[i_new];
317 profile->path = new_path;
323 for (
int i = 0; i < profile->path_len; i++) {
325 profile->path[i].
h1 = type_1;
326 profile->path[i].h2 = type_2;
339 point_init(&new_point, point->
y, point->x, point->flag, point->h2, point->h1);
346 if (profile->path_len == 2) {
352 for (
int i = 0; i < profile->path_len; i++) {
353 int i_reversed = profile->path_len - i - 1;
356 new_path[i_reversed].
profile = profile;
360 new_path[i_reversed].
h1_loc[0] = profile->path[i].h2_loc[1];
361 new_path[i_reversed].
h1_loc[1] = profile->path[i].h2_loc[0];
364 new_path[i_reversed].
h2_loc[0] = profile->path[i].h1_loc[1];
365 new_path[i_reversed].
h2_loc[1] = profile->path[i].h1_loc[0];
371 profile->path = new_path;
379 int n = profile->path_len;
383 for (
int i = 1; i < n - 2; i++) {
384 const float x = 1.0f - (0.5f * (1.0f -
cosf(
float(i /
float(n - 3)) *
M_PI_2)));
385 const float y = 0.5f + 0.5f *
sinf(
float((i /
float(n - 3)) *
M_PI_2));
398 int n = profile->path_len;
407 float n_steps_x = (n % 2 == 0) ? n : (n - 1);
408 float n_steps_y = (n % 2 == 0) ? (n - 2) : (n - 1);
410 for (
int i = 0; i < n; i++) {
411 int step_x = (i + 1) / 2;
413 const float x = 1.0f - (
float(2 * step_x) / n_steps_x);
414 const float y =
float(2 * step_y) / n_steps_y;
421 profile->view_rect = profile->clip_rect;
431 profile->path_len = 2;
435 if (profile->segments_len < 4) {
437 profile->path_len = 5;
440 profile->path_len = profile->segments_len + 1;
444 profile->path_len = 13;
447 profile->path_len = 11;
451 if (profile->segments_len == 0) {
453 profile->path_len = 17;
456 profile->path_len = profile->segments_len + 1;
505 profile->flag &= ~PROF_DIRTY_PRESET;
508 for (
int i = 0; i < profile->path_len; i++) {
509 profile->path[i].profile = profile;
513 profile->table =
nullptr;
525 const int resolution = 16;
528 return std::clamp((profile->path_len - 1) * resolution + 1, 1,
PROF_TABLE_MAX);
552 float *point_loc = &point->x;
555 const float *prev_loc, *next_loc;
556 if (prev ==
nullptr) {
558 pt[0] = 2.0f * point_loc[0] - next_loc[0];
559 pt[1] = 2.0f * point_loc[1] - next_loc[1];
566 if (
next ==
nullptr) {
568 pt[0] = 2.0f * point_loc[0] - prev_loc[0];
569 pt[1] = 2.0f * point_loc[1] - prev_loc[1];
576 float dvec_a[2], dvec_b[2];
580 float len_a =
len_v2(dvec_a);
581 float len_b =
len_v2(dvec_b);
591 tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
592 tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;
618 for (
int i = 1; i < path_len - 1; i++) {
633 float start_handle_direction[2], end_handle_direction[2];
635 sub_v2_v2v2(start_handle_direction, path[i_edge].h2_loc, &path[i_edge].x);
637 sub_v2_v2v2(end_handle_direction, &path[i_edge + 1].x, path[i_edge + 1].h1_loc);
639 return angle_v2v2(start_handle_direction, end_handle_direction);
658 if (a->point_curvature >
b->point_curvature) {
680 bool sample_straight_edges,
684 int totpoints = profile->path_len;
687 int totedges = totpoints - 1;
694 for (
int i = 0; i < totedges; i++) {
705 if (n_segments >= totedges) {
706 if (sample_straight_edges) {
709 int n_common = n_segments / totedges;
710 n_left = n_segments % totedges;
715 for (
int i = 0; i < totedges; i++) {
716 n_samples[i] = n_common;
723 int n_curved_edges = 0;
724 for (
int i = 0; i < totedges; i++) {
730 n_curved_edges = (n_curved_edges == 0) ? totedges : n_curved_edges;
733 n_left = n_segments - (totedges - n_curved_edges);
734 int n_common = n_left / n_curved_edges;
736 for (
int i = 0; i < totedges; i++) {
740 n_samples[i] += n_common;
749 n_left -= n_common * n_curved_edges;
758 for (
int i = 0; i < n_left; i++) {
768 for (
int i_sample = 0, i = 0; i < totedges; i++) {
769 if (n_samples[i] > 0) {
771 r_samples[i_sample].
h1 = path[i].
h1;
772 r_samples[i_sample].
h2 = path[i].
h2;
774 for (
int j = i_sample + 1; j < i_sample + n_samples[i]; j++) {
775 r_samples[j].
flag = 0;
784 path[i + 1].h1_loc[0],
786 &r_samples[i_sample].x,
791 path[i + 1].h1_loc[1],
793 &r_samples[i_sample].y,
797 i_sample += n_samples[i];
810 profile->clip_rect = profile->view_rect;
812 profile->path_len = 2;
815 profile->path[0].x = 1.0f;
816 profile->path[0].y = 0.0f;
817 profile->path[0].profile = profile;
818 profile->path[1].x = 1.0f;
819 profile->path[1].y = 1.0f;
820 profile->path[1].profile = profile;
822 profile->changed_timestamp = 0;
827 if (segments_len != profile->segments_len) {
830 profile->segments_len = segments_len;
846 return len_v2v2(&profile->table[i].x, &profile->table[i + 1].x);
856 float total_length = 0;
858 total_length +=
len_v2v2(&profile->table[i].x, &profile->table[i + 1].x);
876 const float segment_length = total_length / n_segments;
878 float distance_to_previous_table_point = 0.0f;
882 r_samples[0].
x = profile->table[0].x;
883 r_samples[0].
y = profile->table[0].y;
886 float segment_left = segment_length;
887 for (
int i = 1; i < n_segments; i++) {
889 while (distance_to_next_table_point < segment_left) {
890 segment_left -= distance_to_next_table_point;
893 distance_to_previous_table_point = 0.0f;
896 float factor = (distance_to_previous_table_point + segment_left) /
897 (distance_to_previous_table_point + distance_to_next_table_point);
898 r_samples[i].
x =
interpf(profile->table[i_table + 1].x, profile->table[i_table].x, factor);
899 r_samples[i].
y =
interpf(profile->table[i_table + 1].y, profile->table[i_table].y, factor);
901#ifdef DEBUG_CURVEPROFILE_EVALUATE
902 printf(
"segment_left: %.3f\n", segment_left);
903 printf(
"i_table: %d\n", i_table);
904 printf(
"distance_to_previous_table_point: %.3f\n", distance_to_previous_table_point);
905 printf(
"distance_to_next_table_point: %.3f\n", distance_to_next_table_point);
906 printf(
"Interpolating with factor %.3f from (%.3f, %.3f) to (%.3f, %.3f)\n\n",
908 profile->table[i_table].x,
909 profile->table[i_table].y,
910 profile->table[i_table + 1].x,
911 profile->table[i_table + 1].y);
915 distance_to_next_table_point -= segment_left;
916 distance_to_previous_table_point += segment_left;
917 segment_left = segment_length;
936 new_table[n_samples - 1].
x = 0.0f;
937 new_table[n_samples - 1].
y = 1.0f;
940 profile->table = new_table;
949 int n_samples = profile->segments_len;
950 if (n_samples <= 0) {
965 profile->segments = new_table;
971 const rctf *clipr = &profile->clip_rect;
973 profile->changed_timestamp++;
979 for (
int i = 0; i < profile->path_len; i++) {
989 profile->view_rect.xmin = profile->clip_rect.xmin;
990 profile->view_rect.xmax = profile->clip_rect.xmax;
993 profile->view_rect.ymin = profile->clip_rect.ymin;
994 profile->view_rect.ymax = profile->clip_rect.ymax;
1001 for (
int i = 0; i < profile->path_len - 1; i++) {
1018 if (profile->segments_len > 0) {
1024 float length_portion,
1029 const float requested_length = length_portion * total_length;
1033 float length_traveled = 0.0f;
1034 while (length_traveled < requested_length) {
1040 if (length_traveled + new_length >= requested_length) {
1043 length_traveled += new_length;
1050 float lerp_factor = (requested_length - length_traveled) / distance_to_next_point;
1052#ifdef DEBUG_CURVEPROFILE_EVALUATE
1053 printf(
"CURVEPROFILE EVALUATE\n");
1054 printf(
" length portion input: %f\n",
double(length_portion));
1055 printf(
" requested path length: %f\n",
double(requested_length));
1056 printf(
" distance to next point: %f\n",
double(distance_to_next_point));
1057 printf(
" length traveled: %f\n",
double(length_traveled));
1058 printf(
" lerp-factor: %f\n",
double(lerp_factor));
1059 printf(
" ith point (%f, %f)\n",
double(profile->path[i].x),
double(profile->path[i].y));
1060 printf(
" next point(%f, %f)\n",
double(profile->path[i + 1].x),
double(profile->path[i + 1].y));
1063 *x_out =
interpf(profile->table[i].x, profile->table[i + 1].x, lerp_factor);
1064 *y_out =
interpf(profile->table[i].y, profile->table[i + 1].y, lerp_factor);
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
@ PROF_UPDATE_REMOVE_DOUBLES
MINLINE float max_ff(float a, float b)
MINLINE float pow2f(float x)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float min_ff(float a, float b)
MINLINE float interpf(float target, float origin, float t)
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v2_v2v2fl(float r[2], const float a[2], const float b[2], float f)
float angle_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
#define UNUSED_VARS_NDEBUG(...)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
@ PROF_SAMPLE_EVEN_LENGTHS
@ PROF_SAMPLE_STRAIGHT_EDGES
Read Guarded memory(de)allocation.
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
local_group_size(16, 16) .push_constant(Type b
static float bezt_edge_handle_angle(const CurveProfilePoint *path, int i_edge)
static float curveprofile_total_length(const CurveProfile *profile)
void BKE_curveprofile_init(CurveProfile *profile, short segments_len)
static void create_samples_even_spacing(CurveProfile *profile, int n_segments, CurveProfilePoint *r_samples)
void BKE_curveprofile_evaluate_length_portion(const CurveProfile *profile, float length_portion, float *x_out, float *y_out)
bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *point)
CurveProfilePoint * BKE_curveprofile_insert(CurveProfile *profile, float x, float y)
void BKE_curveprofile_copy_data(CurveProfile *target, const CurveProfile *profile)
void BKE_curveprofile_selected_handle_set(CurveProfile *profile, int type_1, int type_2)
static void curveprofile_build_steps(CurveProfile *profile)
bool BKE_curveprofile_move_handle(CurveProfilePoint *point, const bool handle_1, const bool snap, const float delta[2])
bool BKE_curveprofile_move_point(CurveProfile *profile, CurveProfilePoint *point, const bool snap, const float delta[2])
static void curveprofile_build_supports(CurveProfile *profile)
static void curveprofile_make_table(CurveProfile *profile)
void BKE_curveprofile_reset(CurveProfile *profile)
static void calculate_path_handles(CurveProfilePoint *path, int path_len)
static CurveProfilePoint mirror_point(const CurveProfilePoint *point)
static bool is_curved_edge(CurveProfilePoint *path, int i)
int BKE_curveprofile_table_size(const CurveProfile *profile)
void BKE_curveprofile_free_data(CurveProfile *profile)
void BKE_curveprofile_blend_write(BlendWriter *writer, const CurveProfile *profile)
void BKE_curveprofile_blend_read(BlendDataReader *reader, CurveProfile *profile)
void BKE_curveprofile_remove_by_flag(CurveProfile *profile, const short flag)
void BKE_curveprofile_reset_view(CurveProfile *profile)
static void point_calculate_handle(CurveProfilePoint *point, const CurveProfilePoint *prev, const CurveProfilePoint *next)
CurveProfile * BKE_curveprofile_add(eCurveProfilePresets preset)
void BKE_curveprofile_reverse(CurveProfile *profile)
static void point_init(CurveProfilePoint *point, float x, float y, short flag, char h1, char h2)
CurveProfile * BKE_curveprofile_copy(const CurveProfile *profile)
static void create_samples(CurveProfile *profile, int n_segments, bool sample_straight_edges, CurveProfilePoint *r_samples)
void BKE_curveprofile_free(CurveProfile *profile)
static float curveprofile_distance_to_next_table_point(const CurveProfile *profile, int i)
void BKE_curveprofile_update(CurveProfile *profile, const int update_flags)
static int sort_points_curvature(const void *in_a, const void *in_b)
static void curveprofile_make_segments_table(CurveProfile *profile)
void BKE_curveprofile_set_defaults(CurveProfile *profile)
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
void *(* MEM_mallocN)(size_t len, const char *str)
void MEM_freeN(void *vmemh)
void *(* MEM_callocN)(size_t len, const char *str)
void *(* MEM_dupallocN)(const void *vmemh)
vector snap(vector a, vector b)
float distance(float a, float b)
struct CurveProfile * profile