sculpt-dev: roll brush update
* Wrote a little C++ library for working with arc length parameterized cubic splines. * Stroke samples are queued if a roll texture exists. That way we can build a stroke curve of sufficient length to cover all the verts in the brush radius.
This commit is contained in:
parent
cb22eae31b
commit
8786b5c0c0
|
@ -0,0 +1,642 @@
|
|||
#pragma once
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_compiler_compat.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_math_vec_types.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include <cstdio>
|
||||
#include <utility>
|
||||
|
||||
/*
|
||||
* Arc length parameterized spline library.
|
||||
*/
|
||||
namespace blender {
|
||||
/*
|
||||
Abstract curve interface.
|
||||
|
||||
template<typename Float> class Curve {
|
||||
using Vector = vec_base<Float, 2>;
|
||||
|
||||
public:
|
||||
Float length;
|
||||
|
||||
Vector evaluate(Float s);
|
||||
Vector derivative(Float s);
|
||||
Vector derivative2(Float s);
|
||||
Float curvature(float s);
|
||||
|
||||
void update();
|
||||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
comment: Reduce algebra script;
|
||||
|
||||
on factor;
|
||||
off period;
|
||||
|
||||
procedure bez(a, b);
|
||||
a + (b - a) * t;
|
||||
|
||||
lin := bez(k1, k2);
|
||||
quad := bez(lin, sub(k2=k3, k1=k2, lin));
|
||||
|
||||
cubic := bez(quad, sub(k3=k4, k2=k3, k1=k2, quad));
|
||||
dcubic := df(cubic, t);
|
||||
icubic := int(cubic, t);
|
||||
|
||||
x1 := 0;
|
||||
y1 := 0;
|
||||
|
||||
dx := sub(k1=x1, k2=x2, k3=x3, k4=x4, dcubic);
|
||||
dy := sub(k1=y1, k2=y2, k3=y3, k4=y4, dcubic);
|
||||
darc := sqrt(dx**2 + dy**2);
|
||||
|
||||
arcstep := darc*dt + 0.5*df(darc, t)*dt*dt;
|
||||
|
||||
gentran
|
||||
begin
|
||||
declare <<
|
||||
x1,x2,x3,x4 : float;
|
||||
y1,y2,y3,y4 : float;
|
||||
dt,t : float;
|
||||
>>;
|
||||
return eval(arcstep)
|
||||
end;
|
||||
|
||||
on fort;
|
||||
cubic;
|
||||
dcubic;
|
||||
icubic;
|
||||
arcstep;
|
||||
off fort;
|
||||
|
||||
*/
|
||||
template<typename Float, int axes = 2, int table_size = 512> class CubicBezier {
|
||||
using Vector = vec_base<Float, axes>;
|
||||
|
||||
public:
|
||||
Vector ps[4];
|
||||
|
||||
CubicBezier(Vector a, Vector b, Vector c, Vector d)
|
||||
{
|
||||
ps[0] = a;
|
||||
ps[1] = b;
|
||||
ps[2] = c;
|
||||
ps[3] = d;
|
||||
|
||||
deleted = false;
|
||||
_arc_to_t = new Float[table_size];
|
||||
}
|
||||
|
||||
~CubicBezier()
|
||||
{
|
||||
deleted = true;
|
||||
|
||||
if (_arc_to_t) {
|
||||
delete[] _arc_to_t;
|
||||
_arc_to_t = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CubicBezier()
|
||||
{
|
||||
deleted = false;
|
||||
_arc_to_t = new Float[table_size];
|
||||
}
|
||||
|
||||
CubicBezier(const CubicBezier &b)
|
||||
{
|
||||
_arc_to_t = new Float[table_size];
|
||||
*this = b;
|
||||
deleted = false;
|
||||
}
|
||||
|
||||
CubicBezier &operator=(const CubicBezier &b)
|
||||
{
|
||||
ps[0] = b.ps[0];
|
||||
ps[1] = b.ps[1];
|
||||
ps[2] = b.ps[2];
|
||||
ps[3] = b.ps[3];
|
||||
|
||||
length = b.length;
|
||||
|
||||
if (!_arc_to_t) {
|
||||
_arc_to_t = new Float[table_size];
|
||||
}
|
||||
|
||||
if (b._arc_to_t) {
|
||||
for (int i = 0; i < table_size; i++) {
|
||||
_arc_to_t[i] = b._arc_to_t[i];
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if 1
|
||||
CubicBezier(CubicBezier &&b)
|
||||
{
|
||||
*this = b;
|
||||
}
|
||||
|
||||
CubicBezier &operator=(CubicBezier &&b)
|
||||
{
|
||||
ps[0] = b.ps[0];
|
||||
ps[1] = b.ps[1];
|
||||
ps[2] = b.ps[2];
|
||||
ps[3] = b.ps[3];
|
||||
|
||||
length = b.length;
|
||||
|
||||
if (b._arc_to_t) {
|
||||
_arc_to_t = std::move(b._arc_to_t);
|
||||
b._arc_to_t = nullptr;
|
||||
}
|
||||
else {
|
||||
_arc_to_t = new Float[table_size];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
Float length;
|
||||
|
||||
void update()
|
||||
{
|
||||
Float t = 0.0, dt = 1.0 / (Float)table_size;
|
||||
Float s = 0.0;
|
||||
|
||||
if (!_arc_to_t) {
|
||||
_arc_to_t = new Float[table_size];
|
||||
}
|
||||
|
||||
auto table = _arc_to_t;
|
||||
|
||||
for (int i = 0; i < table_size; i++) {
|
||||
table[i] = -1.0;
|
||||
}
|
||||
|
||||
length = 0.0;
|
||||
|
||||
for (int i = 0; i < table_size; i++, t += dt) {
|
||||
Float dlen = 0.0;
|
||||
for (int j = 0; j < axes; j++) {
|
||||
float dv = dcubic(ps[0][j], ps[1][j], ps[2][j], ps[3][j], t);
|
||||
|
||||
dlen += dv * dv;
|
||||
}
|
||||
|
||||
dlen = sqrt(dlen) * dt;
|
||||
|
||||
length += dlen;
|
||||
}
|
||||
|
||||
const int samples = table_size;
|
||||
dt = 1.0 / (Float)samples;
|
||||
|
||||
t = 0.0;
|
||||
s = 0.0;
|
||||
|
||||
for (int i = 0; i < samples; i++, t += dt) {
|
||||
Float dlen = 0.0;
|
||||
for (int j = 0; j < axes; j++) {
|
||||
float dv = dcubic(ps[0][j], ps[1][j], ps[2][j], ps[3][j], t);
|
||||
|
||||
dlen += dv * dv;
|
||||
}
|
||||
|
||||
dlen = sqrt(dlen) * dt;
|
||||
|
||||
int j = (int)((s / length) * (Float)table_size * 0.999999);
|
||||
j = min_ii(j, table_size - 1);
|
||||
|
||||
table[j] = t;
|
||||
|
||||
s += dlen;
|
||||
}
|
||||
|
||||
table[0] = 0.0;
|
||||
table[table_size - 1] = 1.0;
|
||||
|
||||
#if 1
|
||||
/* Interpolate gaps in table. */
|
||||
for (int i = 0; i < table_size - 1; i++) {
|
||||
if (table[i] == -1.0 || table[i + 1] != -1.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int i1 = i;
|
||||
int i2 = i + 1;
|
||||
|
||||
while (table[i2] == -1.0) {
|
||||
i2++;
|
||||
}
|
||||
|
||||
int start = table[i1];
|
||||
int end = table[i2];
|
||||
Float dt2 = 1.0 / (i2 - i1);
|
||||
|
||||
for (int j = i1 + 1; j < i2; j++) {
|
||||
Float factor = (Float)(j - i1) * dt2;
|
||||
table[j] = start + (end - start) * factor;
|
||||
}
|
||||
|
||||
i = i2 - 1;
|
||||
}
|
||||
|
||||
# if 0
|
||||
for (int i = 0; i < table_size; i++) {
|
||||
printf("%.3f ", table[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
Vector evaluate(Float s)
|
||||
{
|
||||
Float t = arc_to_t(s);
|
||||
Vector r;
|
||||
|
||||
for (int i = 0; i < axes; i++) {
|
||||
r[i] = cubic(ps[0][i], ps[1][i], ps[2][i], ps[3][i], t);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
Vector derivative(Float s)
|
||||
{
|
||||
Float t = arc_to_t(s);
|
||||
Vector r;
|
||||
|
||||
for (int i = 0; i < axes; i++) {
|
||||
r[i] = dcubic(ps[0][i], ps[1][i], ps[2][i], ps[3][i], t) * length;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
Vector derivative2(Float s)
|
||||
{
|
||||
Float t = arc_to_t(s);
|
||||
Vector r;
|
||||
|
||||
for (int i = 0; i < axes; i++) {
|
||||
r[i] = d2cubic(ps[0][i], ps[1][i], ps[2][i], ps[3][i], t) * length;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
Float curvature(Float s)
|
||||
{
|
||||
/* Get signed curvature if in 2d. */
|
||||
if constexpr (axes == 2) {
|
||||
Vector dv1 = derivative(s);
|
||||
Vector dv2 = derivative2(s);
|
||||
|
||||
return (dv1[0] * dv2[1] - dv1[1] * dv2[0]) /
|
||||
powf(dv1[0] * dv1[0] + dv1[1] * dv1[1], 3.0 / 2.0);
|
||||
}
|
||||
else { /* Otherwise use magnitude of second derivative (this works because we are arc-length
|
||||
parameterized). */
|
||||
Vector dv2 = derivative2(s);
|
||||
Float len = 0.0;
|
||||
|
||||
for (int i = 0; i < axes; i++) {
|
||||
len += dv2[i] * dv2[i];
|
||||
}
|
||||
|
||||
return sqrt(len);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Float *_arc_to_t;
|
||||
bool deleted = false;
|
||||
|
||||
Float cubic(Float k1, Float k2, Float k3, Float k4, Float t)
|
||||
{
|
||||
return -(((3.0 * (t - 1.0) * k3 - k4 * t) * t - 3.0 * (t - 1.0) * (t - 1.0) * k2) * t +
|
||||
(t - 1) * (t - 1) * (t - 1) * k1);
|
||||
}
|
||||
|
||||
Float dcubic(Float k1, Float k2, Float k3, Float k4, Float t)
|
||||
{
|
||||
return -3.0 * ((t - 1.0) * (t - 1.0) * k1 - k4 * t * t + (3.0 * t - 2.0) * k3 * t -
|
||||
(3.0 * t - 1.0) * (t - 1.0) * k2);
|
||||
}
|
||||
|
||||
Float d2cubic(Float k1, Float k2, Float k3, Float k4, Float t)
|
||||
{
|
||||
return -6.0 * (k1 * t - k1 - 3.0 * k2 * t + 2.0 * k2 + 3.0 * k3 * t - k3 - k4 * t);
|
||||
}
|
||||
|
||||
Float clamp_s(Float s)
|
||||
{
|
||||
s = s < 0.0 ? 0.0 : s;
|
||||
s = s >= length ? length * 0.999999 : s;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
Float arc_to_t(Float s)
|
||||
{
|
||||
if (length == 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
s = clamp_s(s);
|
||||
|
||||
Float t = s * (Float)(table_size - 1) / length;
|
||||
|
||||
int i1 = floorf(t);
|
||||
int i2 = min_ii(i1 + 1, table_size - 1);
|
||||
|
||||
t -= (Float)i1;
|
||||
|
||||
Float s1 = _arc_to_t[i1];
|
||||
Float s2 = _arc_to_t[i2];
|
||||
|
||||
return s1 + (s2 - s1) * t;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Float, int axes = 2> class BezierSpline {
|
||||
using Vector = vec_base<Float, axes>;
|
||||
struct Segment {
|
||||
CubicBezier<Float, axes> bezier;
|
||||
Float start = 0.0;
|
||||
|
||||
Segment(const CubicBezier<Float> &bez)
|
||||
{
|
||||
bezier = bez;
|
||||
}
|
||||
|
||||
Segment(const Segment &b)
|
||||
{
|
||||
*this = b;
|
||||
}
|
||||
|
||||
Segment &operator=(const Segment &b)
|
||||
{
|
||||
bezier = b.bezier;
|
||||
start = b.start;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Segment()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
Float length = 0.0;
|
||||
bool deleted = false;
|
||||
blender::Vector<Segment> segments;
|
||||
|
||||
void clear()
|
||||
{
|
||||
segments.clear();
|
||||
}
|
||||
|
||||
BezierSpline()
|
||||
{
|
||||
}
|
||||
|
||||
~BezierSpline()
|
||||
{
|
||||
deleted = true;
|
||||
}
|
||||
|
||||
void add(CubicBezier<Float, axes> &bez)
|
||||
{
|
||||
need_update = true;
|
||||
|
||||
Segment seg;
|
||||
|
||||
seg.bezier = bez;
|
||||
segments.append(seg);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
need_update = false;
|
||||
|
||||
length = 0.0;
|
||||
for (Segment &seg : segments) {
|
||||
seg.start = length;
|
||||
length += seg.bezier.length;
|
||||
}
|
||||
}
|
||||
|
||||
Vector evaluate(Float s)
|
||||
{
|
||||
if (segments.size() == 0) {
|
||||
return Vector();
|
||||
}
|
||||
|
||||
if (s == 0.0) {
|
||||
return segments[0].bezier.ps[0];
|
||||
}
|
||||
|
||||
if (s >= length) {
|
||||
return segments[segments.size() - 1].bezier.ps[3];
|
||||
}
|
||||
|
||||
Segment *seg = get_segment(s);
|
||||
|
||||
return seg->bezier.evaluate(s - seg->start);
|
||||
}
|
||||
|
||||
Vector derivative(Float s)
|
||||
{
|
||||
if (segments.size() == 0) {
|
||||
return Vector();
|
||||
}
|
||||
|
||||
s = clamp_s(s);
|
||||
Segment *seg = get_segment(s);
|
||||
|
||||
return seg->bezier.derivative(s - seg->start);
|
||||
}
|
||||
|
||||
Vector derivative2(Float s)
|
||||
{
|
||||
if (segments.size() == 0) {
|
||||
return Vector();
|
||||
}
|
||||
|
||||
s = clamp_s(s);
|
||||
Segment *seg = get_segment(s);
|
||||
|
||||
return seg->bezier.derivative2(s - seg->start);
|
||||
}
|
||||
|
||||
Float curvature(Float s)
|
||||
{
|
||||
if (segments.size() == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
s = clamp_s(s);
|
||||
Segment *seg = get_segment(s);
|
||||
|
||||
return seg->bezier.curvature(s - seg->start);
|
||||
}
|
||||
|
||||
Vector closest_point(const Vector p, Float &r_s, Vector &r_tan, Float &r_dis)
|
||||
{
|
||||
const int steps = 5;
|
||||
Float s = 0.0, ds = length / steps;
|
||||
Float mindis = FLT_MAX;
|
||||
Vector minp;
|
||||
Float mins = 0.0;
|
||||
bool found = false;
|
||||
|
||||
Vector lastdv, lastp;
|
||||
Vector b, dvb;
|
||||
|
||||
for (int i = 0; i < steps + 1; i++, s += ds, lastp = b, lastdv = dvb) {
|
||||
b = evaluate(s);
|
||||
dvb = derivative(s);
|
||||
|
||||
if (i == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector dva = lastdv;
|
||||
Vector a = lastp;
|
||||
|
||||
// Vector dva = derivative(s);
|
||||
// Vector dvb = derivative(s + ds);
|
||||
// Vector a = evaluate(s);
|
||||
// Vector b = evaluate(s + ds);
|
||||
|
||||
Vector vec1 = a - p;
|
||||
Vector vec2 = b - p;
|
||||
|
||||
Float sign1 = _dot(vec1, dva);
|
||||
Float sign2 = _dot(vec2, dvb);
|
||||
|
||||
if ((sign1 < 0.0) == (sign2 < 0.0)) {
|
||||
found = true;
|
||||
|
||||
Float len = _dot(vec1, vec1);
|
||||
|
||||
if (len < mindis) {
|
||||
mindis = len;
|
||||
mins = s;
|
||||
minp = evaluate(s);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
|
||||
Float start = s - ds;
|
||||
Float end = s;
|
||||
Float mid = (start + end) * 0.5;
|
||||
const int binary_steps = 4;
|
||||
|
||||
for (int j = 0; j < binary_steps; j++) {
|
||||
Vector dvmid = derivative(mid);
|
||||
Vector vecmid = evaluate(mid) - p;
|
||||
Float sign_mid = _dot(vecmid, dvmid);
|
||||
|
||||
if ((sign_mid < 0.0) == (sign1 < 0.0)) {
|
||||
start = mid;
|
||||
}
|
||||
else {
|
||||
end = mid;
|
||||
}
|
||||
mid = (start + end) * 0.5;
|
||||
}
|
||||
|
||||
Vector p2 = evaluate(mid);
|
||||
Vector vec_mid = p2 - p;
|
||||
Float len = _dot(vec_mid, vec_mid);
|
||||
|
||||
if (len < mindis) {
|
||||
mindis = len;
|
||||
minp = p2;
|
||||
mins = mid;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
mins = 0.0;
|
||||
minp = evaluate(mins);
|
||||
Vector vec = minp - p;
|
||||
mindis = _dot(vec, vec);
|
||||
}
|
||||
|
||||
r_tan = derivative(mins);
|
||||
r_s = mins;
|
||||
r_dis = sqrtf(mindis);
|
||||
|
||||
return minp;
|
||||
}
|
||||
|
||||
void pop_front(int n = 1)
|
||||
{
|
||||
for (int i = 0; i < segments.size() - n; i++) {
|
||||
segments[i] = segments[i + n];
|
||||
}
|
||||
|
||||
segments.resize(segments.size() - n);
|
||||
update();
|
||||
}
|
||||
|
||||
private:
|
||||
bool need_update;
|
||||
|
||||
Float _dot(Vector a, Vector b)
|
||||
{
|
||||
Float sum = 0.0;
|
||||
|
||||
for (int i = 0; i < axes; i++) {
|
||||
sum += a[i] * b[i];
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
Float clamp_s(Float s)
|
||||
{
|
||||
s = s < 0.0 ? 0.0 : s;
|
||||
s = s >= length ? length * 0.999999 : s;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
Segment *get_segment(Float s)
|
||||
{
|
||||
// printf("\n");
|
||||
|
||||
for (Segment &seg : segments) {
|
||||
// printf("s: %f %f\n", seg.start, seg.start + seg.bezier.length);
|
||||
|
||||
if (s >= seg.start && s < seg.start + seg.bezier.length) {
|
||||
return &seg;
|
||||
}
|
||||
}
|
||||
|
||||
// printf("\n");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
using BezierSpline2f = BezierSpline<float, 2>;
|
||||
using BezierSpline3f = BezierSpline<float, 3>;
|
||||
} // namespace blender
|
|
@ -313,6 +313,7 @@ set(SRC
|
|||
BLI_sort.h
|
||||
BLI_sort.hh
|
||||
BLI_sort_utils.h
|
||||
BLI_arc_spline.hh
|
||||
BLI_span.hh
|
||||
BLI_stack.h
|
||||
BLI_stack.hh
|
||||
|
|
|
@ -53,7 +53,7 @@ set(SRC
|
|||
paint_image_proj.c
|
||||
paint_mask.c
|
||||
paint_ops.c
|
||||
paint_stroke.c
|
||||
paint_stroke.cc
|
||||
paint_utils.c
|
||||
paint_vertex.cc
|
||||
paint_vertex_color_ops.cc
|
||||
|
|
|
@ -16,7 +16,16 @@
|
|||
#include "DNA_scene_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace blender {
|
||||
template<typename Float, int axes> class BezierSpline;
|
||||
}
|
||||
|
||||
using BezierSpline2f = blender::BezierSpline<float, 2>;
|
||||
using BezierSpline3f = blender::BezierSpline<float, 3>;
|
||||
extern "C" {
|
||||
#else
|
||||
typedef struct BezierSpline2f BezierSpline2f;
|
||||
typedef struct BezierSpline3f BezierSpline3f;
|
||||
#endif
|
||||
|
||||
struct ARegion;
|
||||
|
@ -67,6 +76,14 @@ typedef struct PaintSample {
|
|||
float pressure;
|
||||
} PaintSample;
|
||||
|
||||
typedef struct PaintStrokePoint {
|
||||
float mouse_in[2], mouse_out[2];
|
||||
float location[3];
|
||||
float pressure, x_tilt, y_tilt;
|
||||
bool pen_flip;
|
||||
float size;
|
||||
} PaintStrokePoint;
|
||||
|
||||
typedef struct PaintStroke {
|
||||
void *mode_data;
|
||||
void *stroke_cursor;
|
||||
|
@ -84,6 +101,15 @@ typedef struct PaintStroke {
|
|||
/* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs
|
||||
* to smooth the stroke */
|
||||
PaintSample samples[PAINT_MAX_INPUT_SAMPLES];
|
||||
PaintStrokePoint points[PAINT_MAX_INPUT_SAMPLES];
|
||||
|
||||
BezierSpline2f *spline;
|
||||
BezierSpline3f *world_spline;
|
||||
|
||||
int num_points;
|
||||
int cur_point;
|
||||
int tot_points;
|
||||
|
||||
int num_samples;
|
||||
int cur_sample;
|
||||
int tot_samples;
|
||||
|
@ -623,6 +649,15 @@ void paint_delete_blur_kernel(BlurKernel *);
|
|||
bool paint_stroke_has_cubic(const PaintStroke *stroke);
|
||||
float bezier3_arclength_v2(const float control[4][2]);
|
||||
float bezier3_arclength_v3(const float control[4][3]);
|
||||
void evaluate_cubic_bezier(const float control[4][3], float t, float r_pos[3], float r_tangent[3]);
|
||||
|
||||
void paint_project_spline(struct bContext *C,
|
||||
struct StrokeCache *cache,
|
||||
struct PaintStroke *stroke);
|
||||
;
|
||||
void paint_calc_cubic_uv_v3(
|
||||
PaintStroke *stroke, struct StrokeCache *cache, const float co[3], float r_out[3], float r_tan[3]);
|
||||
float paint_stroke_spline_length(PaintStroke *stroke);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_arc_spline.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "PIL_time.h"
|
||||
|
@ -47,6 +48,8 @@
|
|||
#include <math.h>
|
||||
|
||||
//#define DEBUG_TIME
|
||||
using blender::float2;
|
||||
using blender::float3;
|
||||
|
||||
#ifdef DEBUG_TIME
|
||||
# include "PIL_time_utildefines.h"
|
||||
|
@ -55,77 +58,112 @@
|
|||
static void paint_stroke_add_sample(
|
||||
const Paint *paint, PaintStroke *stroke, float x, float y, float pressure);
|
||||
|
||||
//#define DRAW_DEBUG_VIS
|
||||
#define DRAW_DEBUG_VIS
|
||||
|
||||
static int paint_stroke_max_points(const Paint *paint, PaintStroke *stroke)
|
||||
{
|
||||
float s = max_ff(stroke->spacing, 0.05);
|
||||
|
||||
return stroke->has_cubic_stroke ? 8.0 : 1;
|
||||
return stroke->has_cubic_stroke ? (int)(1.0f / s + 4.5f) : 1;
|
||||
}
|
||||
|
||||
static int paint_stroke_max_samples(const Paint *paint, PaintStroke *stroke)
|
||||
{
|
||||
return CLAMPIS(paint->num_input_samples, 1, PAINT_MAX_INPUT_SAMPLES);
|
||||
}
|
||||
|
||||
#ifdef DRAW_DEBUG_VIS
|
||||
static void paint_brush_cubic_vis(const bContext *C, ARegion *region, void *userdata)
|
||||
{
|
||||
PaintStroke *stroke = userdata;
|
||||
PaintStroke *stroke = (PaintStroke *)userdata;
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
||||
if (!stroke->num_samples) {
|
||||
if (!ob || !ob->sculpt || !ob->sculpt->cache) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPU_line_smooth(true);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
GPU_line_smooth(false);
|
||||
GPU_depth_test(GPU_DEPTH_NONE);
|
||||
GPU_depth_mask(false);
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
|
||||
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
|
||||
immUniformColor4ub(0, 0, 0, 155);
|
||||
|
||||
GPU_point_size(12);
|
||||
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); // GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
|
||||
immUniformColor4ub(255, 150, 0, 185);
|
||||
|
||||
immBegin(GPU_PRIM_LINES, 6);
|
||||
immVertex2f(pos, stroke->mouse_cubic[0][0], stroke->mouse_cubic[0][1]);
|
||||
immVertex2f(pos, stroke->mouse_cubic[1][0], stroke->mouse_cubic[1][1]);
|
||||
immVertex3fv(pos, ss->cache->world_cubic[0]);
|
||||
immVertex3fv(pos, ss->cache->world_cubic[1]);
|
||||
|
||||
immVertex2f(pos, stroke->mouse_cubic[1][0], stroke->mouse_cubic[1][1]);
|
||||
immVertex2f(pos, stroke->mouse_cubic[2][0], stroke->mouse_cubic[2][1]);
|
||||
|
||||
immVertex2f(pos, stroke->mouse_cubic[2][0], stroke->mouse_cubic[2][1]);
|
||||
immVertex2f(pos, stroke->mouse_cubic[3][0], stroke->mouse_cubic[3][1]);
|
||||
immVertex3fv(pos, ss->cache->world_cubic[1]);
|
||||
immVertex3fv(pos, ss->cache->world_cubic[2]);
|
||||
|
||||
immVertex3fv(pos, ss->cache->world_cubic[2]);
|
||||
immVertex3fv(pos, ss->cache->world_cubic[3]);
|
||||
immEnd();
|
||||
|
||||
immBegin(GPU_PRIM_POINTS, 2);
|
||||
immVertex2f(pos, stroke->mouse_cubic[0][0], stroke->mouse_cubic[0][1]);
|
||||
// immVertex2f(pos, stroke->mouse_cubic[1][0], stroke->mouse_cubic[1][1]);
|
||||
// immVertex2f(pos, stroke->mouse_cubic[2][0], stroke->mouse_cubic[2][1]);
|
||||
immVertex2f(pos, stroke->mouse_cubic[3][0], stroke->mouse_cubic[3][1]);
|
||||
const int steps = 256;
|
||||
float t = 0.0f, dt = 1.0f / (float)(steps - 1);
|
||||
|
||||
immUniformColor4ub(45, 75, 255, 255);
|
||||
immBegin(GPU_PRIM_LINE_STRIP, steps);
|
||||
|
||||
for (int i = 0; i < steps; i++, t += dt) {
|
||||
float co[3], tan[3];
|
||||
|
||||
evaluate_cubic_bezier(ss->cache->world_cubic, t, co, tan);
|
||||
immVertex3fv(pos, co);
|
||||
}
|
||||
immEnd();
|
||||
|
||||
immUniformColor4ub(255, 0, 0, 155);
|
||||
immBegin(GPU_PRIM_LINE_STRIP, steps);
|
||||
|
||||
GPU_point_size(8);
|
||||
float s = 0.0f;
|
||||
float ds = stroke->world_spline->length / (steps - 1);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (i) {
|
||||
if (stroke->num_samples < 2) {
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < steps; i++, s += ds) {
|
||||
float mval[3], tan[3];
|
||||
# if 0
|
||||
float co[3];
|
||||
float2 p = stroke->spline->evaluate(s);
|
||||
|
||||
immBegin(GPU_PRIM_LINES, (stroke->num_samples - 1) * 2);
|
||||
mval[0] = p[0];
|
||||
mval[1] = p[1];
|
||||
mval[2] = 0.0f;
|
||||
|
||||
float3 loc(0.0, 0.0, 0.0);
|
||||
mul_v3_m4v3(loc, ob->obmat, loc);
|
||||
|
||||
ED_view3d_win_to_3d(CTX_wm_view3d(C), CTX_wm_region(C), loc, mval, co);
|
||||
# else
|
||||
float3 co = stroke->world_spline->evaluate(s);
|
||||
# endif
|
||||
|
||||
immVertex3fv(pos, co);
|
||||
}
|
||||
immEnd();
|
||||
|
||||
immUniformColor4ub(0, 255, 25, 255);
|
||||
|
||||
for (int is_points = 0; is_points < 2; is_points++) {
|
||||
immBegin(is_points ? GPU_PRIM_POINTS : GPU_PRIM_LINE_STRIP, stroke->num_points);
|
||||
for (int i = 0; i < stroke->num_points; i++) {
|
||||
int idx = (i + stroke->cur_point) % stroke->num_points;
|
||||
immVertex3fv(pos, stroke->points[idx].location);
|
||||
}
|
||||
else {
|
||||
immBegin(GPU_PRIM_POINTS, stroke->num_samples);
|
||||
}
|
||||
|
||||
for (int j = 0; j < stroke->num_samples; j++) {
|
||||
int j2 = (j + stroke->cur_sample) % stroke->num_samples;
|
||||
immVertex2f(pos, stroke->samples[j2].mouse[0], stroke->samples[j2].mouse[1]);
|
||||
|
||||
if (i && j < stroke->num_samples - 1) {
|
||||
int j3 = (j + stroke->cur_sample + 1) % stroke->num_samples;
|
||||
immVertex2f(pos, stroke->samples[j3].mouse[0], stroke->samples[j3].mouse[1]);
|
||||
}
|
||||
}
|
||||
|
||||
immEnd();
|
||||
}
|
||||
|
||||
immUniformColor4ub(0, 0, 255, 155);
|
||||
immBegin(GPU_PRIM_POINTS, 1);
|
||||
immVertex2fv(pos, stroke->samples[stroke->cur_sample].mouse);
|
||||
immUniformColor4ub(0, 0, 0, 155);
|
||||
|
||||
immBegin(GPU_PRIM_POINTS, 4);
|
||||
immVertex3fv(pos, ss->cache->world_cubic[0]);
|
||||
immVertex3fv(pos, ss->cache->world_cubic[1]);
|
||||
immVertex3fv(pos, ss->cache->world_cubic[2]);
|
||||
immVertex3fv(pos, ss->cache->world_cubic[3]);
|
||||
immEnd();
|
||||
|
||||
immUnbindProgram();
|
||||
|
@ -140,7 +178,7 @@ static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata
|
|||
{
|
||||
Paint *paint = BKE_paint_get_active_from_context(C);
|
||||
Brush *brush = BKE_paint_brush(paint);
|
||||
PaintStroke *stroke = customdata;
|
||||
PaintStroke *stroke = (PaintStroke *)customdata;
|
||||
|
||||
if (stroke && brush) {
|
||||
GPU_line_smooth(true);
|
||||
|
@ -170,7 +208,7 @@ static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata
|
|||
static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
|
||||
{
|
||||
Paint *paint = BKE_paint_get_active_from_context(C);
|
||||
PaintStroke *stroke = customdata;
|
||||
PaintStroke *stroke = (PaintStroke *)customdata;
|
||||
|
||||
GPU_line_smooth(true);
|
||||
|
||||
|
@ -294,27 +332,70 @@ static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode m
|
|||
return true;
|
||||
}
|
||||
|
||||
static void paint_stroke_add_point(const Paint *paint,
|
||||
PaintStroke *stroke,
|
||||
const float mouse_in[2],
|
||||
const float mouse_out[2],
|
||||
const float loc[3],
|
||||
float size,
|
||||
float pressure,
|
||||
bool pen_flip,
|
||||
float x_tilt,
|
||||
float y_tilt)
|
||||
{
|
||||
PaintStrokePoint *point = &stroke->points[stroke->cur_point];
|
||||
int max_points = paint_stroke_max_points(paint, stroke);
|
||||
|
||||
point->size = size;
|
||||
copy_v2_v2(point->mouse_in, mouse_in);
|
||||
copy_v2_v2(point->mouse_out, mouse_out);
|
||||
point->x_tilt = x_tilt;
|
||||
point->y_tilt = y_tilt;
|
||||
point->pen_flip = pen_flip;
|
||||
copy_v3_v3(point->location, loc);
|
||||
point->pressure = pressure;
|
||||
|
||||
stroke->cur_point++;
|
||||
if (stroke->cur_point >= max_points) {
|
||||
stroke->cur_point = 0;
|
||||
}
|
||||
if (stroke->num_points < max_points) {
|
||||
stroke->num_points++;
|
||||
}
|
||||
}
|
||||
|
||||
static void paint_brush_make_cubic(PaintStroke *stroke)
|
||||
{
|
||||
float a[2], b[2], c[2], d[2];
|
||||
int count = paint_stroke_max_points(NULL, stroke);
|
||||
|
||||
int ia = (stroke->cur_sample - 3 + stroke->num_samples) % stroke->num_samples;
|
||||
int id = (stroke->cur_sample - 2 + stroke->num_samples) % stroke->num_samples;
|
||||
if (stroke->num_points < 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
int ib = (stroke->cur_sample - 4 + stroke->num_samples) % stroke->num_samples;
|
||||
int ic = (stroke->cur_sample - 1 + stroke->num_samples) % stroke->num_samples;
|
||||
int cur = (stroke->cur_point - 1 + stroke->num_points) % stroke->num_points;
|
||||
|
||||
copy_v2_v2(a, stroke->samples[ia].mouse);
|
||||
copy_v2_v2(b, stroke->samples[ib].mouse);
|
||||
copy_v2_v2(c, stroke->samples[ic].mouse);
|
||||
copy_v2_v2(d, stroke->samples[id].mouse);
|
||||
int ia = (cur - 2 + stroke->num_points) % stroke->num_points;
|
||||
int id = (cur - 1 + stroke->num_points) % stroke->num_points;
|
||||
|
||||
float tmp[2];
|
||||
int ib = (cur - 3 + stroke->num_points) % stroke->num_points;
|
||||
int ic = (cur - 0 + stroke->num_points) % stroke->num_points;
|
||||
|
||||
copy_v2_v2(a, stroke->points[ia].mouse_out);
|
||||
copy_v2_v2(b, stroke->points[ib].mouse_out);
|
||||
copy_v2_v2(c, stroke->points[ic].mouse_out);
|
||||
copy_v2_v2(d, stroke->points[id].mouse_out);
|
||||
|
||||
float scale = 1.0;
|
||||
scale /= 3.0f;
|
||||
|
||||
float tmp1[2];
|
||||
float tmp2[2];
|
||||
#if 1
|
||||
sub_v2_v2v2(tmp, d, a);
|
||||
sub_v2_v2v2(b, a, b);
|
||||
interp_v2_v2v2(b, b, tmp, 0.5f);
|
||||
mul_v2_fl(b, 1.0f / 3.0f);
|
||||
sub_v2_v2v2(tmp1, d, a);
|
||||
sub_v2_v2v2(tmp2, a, b);
|
||||
interp_v2_v2v2(b, tmp1, tmp2, 0.5f);
|
||||
mul_v2_fl(b, scale);
|
||||
#else
|
||||
zero_v2(b);
|
||||
#endif
|
||||
|
@ -322,10 +403,10 @@ static void paint_brush_make_cubic(PaintStroke *stroke)
|
|||
add_v2_v2(b, a);
|
||||
|
||||
#if 1
|
||||
sub_v2_v2v2(tmp, a, d);
|
||||
sub_v2_v2v2(c, d, c);
|
||||
interp_v2_v2v2(c, c, tmp, 0.5f);
|
||||
mul_v2_fl(c, 1.0f / 3.0f);
|
||||
sub_v2_v2v2(tmp1, a, d);
|
||||
sub_v2_v2v2(tmp2, d, c);
|
||||
interp_v2_v2v2(c, tmp1, tmp2, 0.5f);
|
||||
mul_v2_fl(c, scale);
|
||||
#else
|
||||
zero_v2(c);
|
||||
#endif
|
||||
|
@ -344,6 +425,72 @@ static void paint_brush_make_cubic(PaintStroke *stroke)
|
|||
printf("c: %.2f: %.2f\n", c[0], c[1]);
|
||||
printf("d: %.2f: %.2f\n", d[0], d[1]);
|
||||
#endif
|
||||
|
||||
blender::CubicBezier<float, 2> bez(a, b, c, d);
|
||||
bez.update();
|
||||
stroke->spline->add(bez);
|
||||
|
||||
while (stroke->spline->segments.size() > paint_stroke_max_points(nullptr, stroke) + 1) {
|
||||
stroke->spline->pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void paint_project_spline(bContext *C, StrokeCache *cache, PaintStroke *stroke)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
||||
stroke->world_spline->clear();
|
||||
|
||||
for (auto &seg : stroke->spline->segments) {
|
||||
blender::CubicBezier<float, 3> bezier;
|
||||
float2 mvals[4];
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
mvals[i][j] = seg.bezier.ps[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (!SCULPT_stroke_get_location(C, bezier.ps[i], mvals[i], true)) {
|
||||
float loc[3];
|
||||
|
||||
mul_v3_m4v3(loc, ob->obmat, cache->true_location);
|
||||
|
||||
ED_view3d_win_to_3d(
|
||||
CTX_wm_view3d(C), CTX_wm_region(C), cache->true_location, mvals[i], bezier.ps[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bezier.update();
|
||||
|
||||
stroke->world_spline->add(bezier);
|
||||
}
|
||||
}
|
||||
|
||||
void paint_calc_cubic_uv_v3(
|
||||
PaintStroke *stroke, StrokeCache *cache, const float co[3], float r_out[3], float r_tan[3])
|
||||
{
|
||||
float3 tan;
|
||||
float3 p = stroke->world_spline->closest_point(co, r_out[0], tan, r_out[1]);
|
||||
|
||||
r_tan = tan;
|
||||
r_out[1] = len_v3v3(p, co);
|
||||
r_out[2] = 0.0f;
|
||||
|
||||
float3 vec = p - float3(co);
|
||||
float3 vec2;
|
||||
|
||||
cross_v3_v3v3(vec2, vec, tan);
|
||||
|
||||
if (dot_v3v3(vec2, cache->view_normal) < 0.0f) {
|
||||
r_out[1] = -r_out[1];
|
||||
}
|
||||
}
|
||||
|
||||
float paint_stroke_spline_length(struct PaintStroke *stroke)
|
||||
{
|
||||
return stroke->world_spline->length;
|
||||
}
|
||||
|
||||
bool paint_stroke_apply_subspacing(struct PaintStroke *stroke,
|
||||
|
@ -614,36 +761,7 @@ static void paint_brush_stroke_add_step(
|
|||
PointerRNA itemptr;
|
||||
float location[3];
|
||||
|
||||
const float *mouse_in;
|
||||
|
||||
if (stroke->has_cubic_stroke) {
|
||||
paint_stroke_add_sample(paint, stroke, mval[0], mval[1], pressure);
|
||||
paint_brush_make_cubic(stroke);
|
||||
}
|
||||
|
||||
float mousetemp[2];
|
||||
|
||||
if (stroke->has_cubic_stroke) {
|
||||
printf("\n");
|
||||
|
||||
for (int i = 0; i < stroke->num_samples; i++) {
|
||||
PaintSample *sample = stroke->samples + ((stroke->cur_sample + i) % stroke->num_samples);
|
||||
printf("%.2f %.2f\n", sample->mouse[0], sample->mouse[1]);
|
||||
}
|
||||
|
||||
mouse_in = mousetemp;
|
||||
|
||||
PaintSample *sample1 = stroke->samples +
|
||||
((stroke->cur_sample - 3 + stroke->num_samples) % stroke->num_samples);
|
||||
PaintSample *sample2 = stroke->samples +
|
||||
((stroke->cur_sample - 2 + stroke->num_samples) % stroke->num_samples);
|
||||
interp_v2_v2v2(mousetemp, sample1->mouse, sample2->mouse, 0.5f);
|
||||
|
||||
// copy_v2_v2(mousetemp, sample1->mouse);
|
||||
}
|
||||
else {
|
||||
mouse_in = mval;
|
||||
}
|
||||
const float *mouse_in = mval;
|
||||
|
||||
stroke->stroke_sample_index++;
|
||||
|
||||
|
@ -676,7 +794,7 @@ static void paint_brush_stroke_add_step(
|
|||
|
||||
/* copy last position -before- jittering, or space fill code
|
||||
* will create too many dabs */
|
||||
copy_v2_v2(stroke->last_mouse_position, mval);
|
||||
copy_v2_v2(stroke->last_mouse_position, mouse_in);
|
||||
|
||||
stroke->last_pressure2 = stroke->last_pressure;
|
||||
stroke->last_pressure = pressure;
|
||||
|
@ -702,25 +820,25 @@ static void paint_brush_stroke_add_step(
|
|||
factor *= pressure;
|
||||
}
|
||||
|
||||
BKE_brush_jitter_pos(scene, brush, mval, mouse_out);
|
||||
BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
|
||||
|
||||
/* XXX: meh, this is round about because
|
||||
* BKE_brush_jitter_pos isn't written in the best way to
|
||||
* be reused here */
|
||||
if (factor != 1.0f) {
|
||||
sub_v2_v2v2(delta, mouse_out, mval);
|
||||
sub_v2_v2v2(delta, mouse_out, mouse_in);
|
||||
mul_v2_fl(delta, factor);
|
||||
add_v2_v2v2(mouse_out, mval, delta);
|
||||
add_v2_v2v2(mouse_out, mouse_in, delta);
|
||||
}
|
||||
}
|
||||
else {
|
||||
copy_v2_v2(mouse_out, mval);
|
||||
copy_v2_v2(mouse_out, mouse_in);
|
||||
}
|
||||
|
||||
bool is_location_is_set;
|
||||
|
||||
ups->last_hit = paint_brush_update(
|
||||
C, brush, mode, stroke, mval, mouse_out, pressure, location, &is_location_is_set);
|
||||
C, brush, mode, stroke, mouse_in, mouse_out, pressure, location, &is_location_is_set);
|
||||
if (is_location_is_set) {
|
||||
copy_v3_v3(ups->last_location, location);
|
||||
}
|
||||
|
@ -740,17 +858,54 @@ static void paint_brush_stroke_add_step(
|
|||
|
||||
/* Add to stroke */
|
||||
if (add_step) {
|
||||
PaintStrokePoint *point;
|
||||
PaintStrokePoint temp;
|
||||
|
||||
paint_stroke_add_point(paint,
|
||||
stroke,
|
||||
mouse_in,
|
||||
mouse_out,
|
||||
location,
|
||||
ups->pixel_radius,
|
||||
pressure,
|
||||
stroke->pen_flip,
|
||||
stroke->x_tilt,
|
||||
stroke->y_tilt);
|
||||
|
||||
if (stroke->has_cubic_stroke) {
|
||||
if (stroke->num_points < paint_stroke_max_points(paint, stroke)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int cur = stroke->cur_point - (paint_stroke_max_points(paint, stroke) >> 1);
|
||||
|
||||
paint_brush_make_cubic(stroke);
|
||||
PaintStrokePoint *p1 = stroke->points + ((cur + stroke->num_points) % stroke->num_points);
|
||||
PaintStrokePoint *p2 = stroke->points +
|
||||
((cur - 1 + stroke->num_points) % stroke->num_points);
|
||||
|
||||
point = &temp;
|
||||
temp = *p1;
|
||||
|
||||
interp_v3_v3v3(temp.location, p1->location, p2->location, 0.5f);
|
||||
interp_v2_v2v2(temp.mouse_in, p1->mouse_in, p2->mouse_in, 0.5f);
|
||||
interp_v2_v2v2(temp.mouse_out, p1->mouse_out, p2->mouse_out, 0.5f);
|
||||
}
|
||||
else {
|
||||
point = stroke->points + ((stroke->cur_point - 1 + stroke->num_points) % stroke->num_points);
|
||||
}
|
||||
|
||||
RNA_collection_add(op->ptr, "stroke", &itemptr);
|
||||
RNA_float_set(&itemptr, "size", ups->pixel_radius);
|
||||
RNA_float_set_array(&itemptr, "location", location);
|
||||
RNA_float_set(&itemptr, "size", point->size);
|
||||
RNA_float_set_array(&itemptr, "location", point->location);
|
||||
/* Mouse coordinates modified by the stroke type options. */
|
||||
RNA_float_set_array(&itemptr, "mouse", mouse_out);
|
||||
RNA_float_set_array(&itemptr, "mouse", point->mouse_out);
|
||||
/* Original mouse coordinates. */
|
||||
RNA_float_set_array(&itemptr, "mouse_event", mval);
|
||||
RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip);
|
||||
RNA_float_set(&itemptr, "pressure", pressure);
|
||||
RNA_float_set(&itemptr, "x_tilt", stroke->x_tilt);
|
||||
RNA_float_set(&itemptr, "y_tilt", stroke->y_tilt);
|
||||
RNA_float_set_array(&itemptr, "mouse_event", point->mouse_in);
|
||||
RNA_boolean_set(&itemptr, "pen_flip", point->pen_flip);
|
||||
RNA_float_set(&itemptr, "pressure", point->pressure);
|
||||
RNA_float_set(&itemptr, "x_tilt", point->x_tilt);
|
||||
RNA_float_set(&itemptr, "y_tilt", point->y_tilt);
|
||||
|
||||
if (stroke->has_cubic_stroke) {
|
||||
RNA_float_set_array(&itemptr, "mouse_cubic", (float *)stroke->mouse_cubic);
|
||||
|
@ -1074,6 +1229,8 @@ static int paint_space_stroke(bContext *C,
|
|||
C, scene, stroke, pressure, dpressure, length);
|
||||
float mouse[2];
|
||||
|
||||
stroke->spacing = spacing;
|
||||
|
||||
if (length >= spacing) {
|
||||
if (use_scene_spacing) {
|
||||
float final_world_space_position[3];
|
||||
|
@ -1140,7 +1297,7 @@ PaintStroke *paint_stroke_new(bContext *C,
|
|||
int event_type)
|
||||
{
|
||||
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
|
||||
PaintStroke *stroke = (PaintStroke *)MEM_callocN(sizeof(PaintStroke), "PaintStroke");
|
||||
ToolSettings *toolsettings = CTX_data_tool_settings(C);
|
||||
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
|
||||
UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
|
||||
|
@ -1150,11 +1307,14 @@ PaintStroke *paint_stroke_new(bContext *C,
|
|||
float zoomx, zoomy;
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
|
||||
stroke->spline = MEM_new<blender::BezierSpline2f>("BezierSpline2f");
|
||||
stroke->world_spline = MEM_new<blender::BezierSpline3f>("BezierSpline3f");
|
||||
|
||||
ED_view3d_viewcontext_init(C, &stroke->vc, depsgraph);
|
||||
|
||||
#ifdef DRAW_DEBUG_VIS
|
||||
stroke->debug_draw_handle = ED_region_draw_cb_activate(
|
||||
region->type, paint_brush_cubic_vis, stroke, REGION_DRAW_POST_PIXEL);
|
||||
region->type, paint_brush_cubic_vis, stroke, REGION_DRAW_POST_VIEW);
|
||||
#endif
|
||||
|
||||
stroke->get_location = get_location;
|
||||
|
@ -1202,7 +1362,7 @@ PaintStroke *paint_stroke_new(bContext *C,
|
|||
BKE_curvemapping_init(p->cavity_curve);
|
||||
}
|
||||
|
||||
BKE_paint_set_overlay_override(br->overlay_flags);
|
||||
BKE_paint_set_overlay_override((eOverlayFlags)br->overlay_flags);
|
||||
|
||||
ups->start_pixel_radius = BKE_brush_size_get(CTX_data_scene(C), br, mode == PAINT_MODE_SCULPT);
|
||||
|
||||
|
@ -1216,12 +1376,15 @@ void paint_stroke_free(bContext *C, wmOperator *UNUSED(op), PaintStroke *stroke)
|
|||
rv3d->rflag &= ~RV3D_PAINTING;
|
||||
}
|
||||
|
||||
BKE_paint_set_overlay_override(0);
|
||||
BKE_paint_set_overlay_override((eOverlayFlags)0);
|
||||
|
||||
if (stroke == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
MEM_delete<blender::BezierSpline2f>(stroke->spline);
|
||||
MEM_delete<blender::BezierSpline3f>(stroke->world_spline);
|
||||
|
||||
UnifiedPaintSettings *ups = stroke->ups;
|
||||
ups->draw_anchored = false;
|
||||
ups->stroke_active = false;
|
||||
|
@ -1235,7 +1398,7 @@ void paint_stroke_free(bContext *C, wmOperator *UNUSED(op), PaintStroke *stroke)
|
|||
}
|
||||
|
||||
if (stroke->stroke_cursor) {
|
||||
WM_paint_cursor_end(stroke->stroke_cursor);
|
||||
WM_paint_cursor_end((wmPaintCursor *)stroke->stroke_cursor);
|
||||
}
|
||||
|
||||
BLI_freelistN(&stroke->line);
|
||||
|
@ -1297,7 +1460,7 @@ bool paint_space_stroke_enabled(Brush *br, ePaintMode mode)
|
|||
}
|
||||
|
||||
if (mode == PAINT_MODE_SCULPT_CURVES &&
|
||||
!curves_sculpt_brush_uses_spacing(br->curves_sculpt_tool)) {
|
||||
!curves_sculpt_brush_uses_spacing((eBrushCurvesSculptTool)br->curves_sculpt_tool)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1420,17 +1583,6 @@ bool paint_stroke_has_cubic(const PaintStroke *stroke)
|
|||
return stroke->has_cubic_stroke;
|
||||
}
|
||||
|
||||
static int paint_stroke_max_samples(const Paint *paint, PaintStroke *stroke)
|
||||
{
|
||||
int max_samples = CLAMPIS(paint->num_input_samples, 1, PAINT_MAX_INPUT_SAMPLES);
|
||||
|
||||
if (stroke->has_cubic_stroke) {
|
||||
max_samples = max_ii(max_samples, 6);
|
||||
}
|
||||
|
||||
return max_samples;
|
||||
}
|
||||
|
||||
static void paint_stroke_add_sample(
|
||||
const Paint *paint, PaintStroke *stroke, float x, float y, float pressure)
|
||||
{
|
||||
|
@ -1463,8 +1615,6 @@ static void paint_stroke_sample_average(const PaintStroke *stroke, PaintSample *
|
|||
|
||||
mul_v2_fl(average->mouse, 1.0f / stroke->num_samples);
|
||||
average->pressure /= stroke->num_samples;
|
||||
|
||||
// printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1753,12 +1903,13 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintS
|
|||
if (stroke->stroke_sample_index == 0) {
|
||||
stroke->last_mouse_position[0] = event->mval[0];
|
||||
stroke->last_mouse_position[1] = event->mval[1];
|
||||
|
||||
#if 0
|
||||
int max_samples = paint_stroke_max_samples(p, stroke);
|
||||
|
||||
for (int i = stroke->num_samples; i < max_samples; i++) {
|
||||
paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Tilt. */
|
||||
|
@ -1898,6 +2049,9 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintS
|
|||
/* we want the stroke to have the first daub at the start location
|
||||
* instead of waiting till we have moved the space distance */
|
||||
if (first_dab && paint_space_stroke_enabled(br, mode) && !(br->flag & BRUSH_SMOOTH_STROKE)) {
|
||||
stroke->spacing = paint_space_stroke_spacing(
|
||||
C, CTX_data_scene(C), stroke, 1.0f, sample_average.pressure);
|
||||
|
||||
stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
|
||||
paint_brush_stroke_add_step(C, op, stroke, sample_average.mouse, sample_average.pressure);
|
||||
redraw = true;
|
|
@ -1278,6 +1278,10 @@ static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(const SculptSessi
|
|||
int v1,
|
||||
int v2)
|
||||
{
|
||||
if (!ss->face_sets) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const MeshElemMap *vert_map = &ss->pmap->pmap[v1];
|
||||
int p1 = -1, p2 = -1;
|
||||
for (int i = 0; i < vert_map->count; i++) {
|
||||
|
@ -3770,10 +3774,7 @@ float bezier3_arclength_v2(const float control[4][2])
|
|||
|
||||
/* Evaluate bezier position and tangent at a specific parameter value
|
||||
* using the De Casteljau algorithm. */
|
||||
static void evaluate_cubic_bezier(const float control[4][3],
|
||||
float t,
|
||||
float r_pos[3],
|
||||
float r_tangent[3])
|
||||
void evaluate_cubic_bezier(const float control[4][3], float t, float r_pos[3], float r_tangent[3])
|
||||
{
|
||||
float layer1[3][3];
|
||||
interp_v3_v3v3(layer1[0], control[0], control[1], t);
|
||||
|
@ -4126,49 +4127,31 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
|
|||
float point_3d[3];
|
||||
point_3d[2] = 0.0f;
|
||||
|
||||
calc_cubic_uv_v3(ss->cache->world_cubic, SCULPT_vertex_co_get(ss, vertex), point_3d);
|
||||
// calc_cubic_uv_v3(ss->cache->world_cubic, SCULPT_vertex_co_get(ss, vertex), point_3d);
|
||||
float tan[3], curv[3];
|
||||
|
||||
float eps = 0.001;
|
||||
if (point_3d[0] < eps || point_3d[0] >= 1.0f - eps) {
|
||||
return 0.0f;
|
||||
}
|
||||
paint_calc_cubic_uv_v3(
|
||||
ss->cache->stroke, ss->cache, SCULPT_vertex_co_get(ss, vertex), point_3d, tan);
|
||||
|
||||
if (point_3d[1] >= ss->cache->radius) {
|
||||
// return 0.0f;
|
||||
}
|
||||
|
||||
float pos[3], tan[3];
|
||||
evaluate_cubic_bezier(ss->cache->world_cubic, point_3d[0], pos, tan);
|
||||
|
||||
float vec[3], vec2[3];
|
||||
|
||||
normalize_v3(tan);
|
||||
sub_v3_v3v3(vec, SCULPT_vertex_co_get(ss, vertex), pos);
|
||||
normalize_v3(vec);
|
||||
|
||||
cross_v3_v3v3(vec2, vec, tan);
|
||||
|
||||
if (dot_v3v3(vec2, ss->cache->view_normal) < 0.0) {
|
||||
point_3d[1] = (ss->cache->radius + point_3d[1]) * 0.5f;
|
||||
}
|
||||
else {
|
||||
point_3d[1] = (ss->cache->radius - point_3d[1]) * 0.5f;
|
||||
}
|
||||
point_3d[1] = (ss->cache->radius + point_3d[1]) * 0.5f;
|
||||
|
||||
/* Calc global distance. */
|
||||
float t1 = ss->cache->last_stroke_distance_t;
|
||||
float t2 = point_3d[0] * ss->cache->world_cubic_arclength / ss->cache->radius;
|
||||
float t2 = point_3d[0] / ss->cache->radius;
|
||||
|
||||
point_3d[0] = t1 + t2;
|
||||
point_3d[0] *= ss->cache->radius;
|
||||
|
||||
#if 0
|
||||
float color[4] = {point_3d[0], point_3d[0], point_3d[0], 1.0f};
|
||||
mul_v3_fl(color, 0.25f / ss->cache->radius);
|
||||
color[0] -= floorf(color[0]);
|
||||
color[1] -= floorf(color[1]);
|
||||
color[2] -= floorf(color[2]);
|
||||
if (SCULPT_has_colors(ss)) {
|
||||
float color[4] = {point_3d[0], point_3d[1], 0.0f, 1.0f};
|
||||
mul_v3_fl(color, 0.25f / ss->cache->radius);
|
||||
color[0] -= floorf(color[0]);
|
||||
color[1] -= floorf(color[1]);
|
||||
color[2] -= floorf(color[2]);
|
||||
|
||||
SCULPT_vertex_color_set(ss, vertex, color);
|
||||
SCULPT_vertex_color_set(ss, vertex, color);
|
||||
}
|
||||
|
||||
// avg = 0.0f;
|
||||
#endif
|
||||
|
@ -7378,6 +7361,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
|
|||
if (cache->has_cubic) {
|
||||
float mouse_cubic[4][2];
|
||||
|
||||
// paint_project_spline(C, cache,
|
||||
RNA_float_get_array(ptr, "mouse_cubic", (float *)mouse_cubic);
|
||||
|
||||
// printf("\n");
|
||||
|
@ -7407,7 +7391,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
|
|||
#endif
|
||||
}
|
||||
|
||||
cache->world_cubic_arclength = bezier3_arclength_v3(cache->world_cubic);
|
||||
cache->world_cubic_arclength = paint_stroke_spline_length(cache->stroke);
|
||||
cache->mouse_cubic_arclength = bezier3_arclength_v3(cache->mouse_cubic);
|
||||
}
|
||||
}
|
||||
|
@ -8360,6 +8344,10 @@ static void sculpt_stroke_update_step(bContext *C,
|
|||
cache->stroke_distance = paint_stroke_distance_get(stroke);
|
||||
|
||||
SCULPT_stroke_modifiers_check(C, ob, brush);
|
||||
if (stroke) {
|
||||
paint_project_spline(C, ss->cache, stroke);
|
||||
}
|
||||
|
||||
if (itemptr) {
|
||||
sculpt_update_cache_variants(C, sd, ob, itemptr);
|
||||
}
|
||||
|
@ -9471,7 +9459,7 @@ int SCULPT_vertex_valence_get(const struct SculptSession *ss, PBVHVertRef vertex
|
|||
|
||||
mv->valence = tot;
|
||||
}
|
||||
#if 0
|
||||
#if 0
|
||||
else {
|
||||
|
||||
int tot = 0;
|
||||
|
@ -9485,7 +9473,7 @@ int SCULPT_vertex_valence_get(const struct SculptSession *ss, PBVHVertRef vertex
|
|||
printf("%s: error: valence error!\n", __func__);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return mv->valence;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue