Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonioya <blendergit@gmail.com>2016-10-22 17:44:11 +0300
committerAntonioya <blendergit@gmail.com>2016-10-22 17:44:39 +0300
commit5765deecd42eedda780b88ed7448e4b1c185d0d8 (patch)
tree1a3f2123f4b8c94d6d30ab1ad314d7e400333d80 /source/blender/editors/gpencil/gpencil_paint.c
parent9d0ac94d52268ff34ce645035d4315d6018d02b9 (diff)
GPencil: New option to lock strokes to axis
Now, the strokes can be locked to a plane set in the cursor location. This option allow the artist to rotate the view and draw keeping the strokes flat over the surface. This option is similar to surface option but doesn't need a object. The option is only valid for 3D view and strokes in CURSOR mode.
Diffstat (limited to 'source/blender/editors/gpencil/gpencil_paint.c')
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c126
1 files changed, 104 insertions, 22 deletions
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index cc45cbd82af..c23bfb1ff60 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -40,6 +40,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_rand.h"
+#include "BLI_math_geom.h"
#include "BLT_translation.h"
@@ -160,6 +161,7 @@ typedef struct tGPsdata {
bGPDpalettecolor *palettecolor; /* current palette color */
bGPDbrush *brush; /* current drawing brush */
short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */
+ int lock_axis; /* lock drawing to one axis */
} tGPsdata;
/* ------ */
@@ -278,6 +280,64 @@ static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2])
return false;
}
+/* reproject the points of the stroke to a plane locked to axis to avoid stroke offset */
+static void gp_project_points_to_plane(RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis)
+{
+ float plane_normal[3];
+ float vn[3];
+
+ float ray[3];
+ float rpoint[3];
+
+ /* normal vector for a plane locked to axis */
+ zero_v3(plane_normal);
+ plane_normal[axis] = 1.0f;
+
+ /* Reproject the points in the plane */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+
+ /* get a vector from the point with the current view direction of the viewport */
+ ED_view3d_global_to_vector(rv3d, &pt->x, vn);
+
+ /* calculate line extrem point to create a ray that cross the plane */
+ mul_v3_fl(vn, -50.0f);
+ add_v3_v3v3(ray, &pt->x, vn);
+
+ /* if the line never intersect, the point is not changed */
+ if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
+ copy_v3_v3(&pt->x, rpoint);
+ }
+ }
+}
+
+/* reproject stroke to plane locked to axis in 3d cursor location */
+static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps)
+{
+ bGPdata *gpd = p->gpd;
+ float origin[3];
+ float cursor[3];
+ RegionView3D *rv3d = p->ar->regiondata;
+
+ /* verify the stroke mode is CURSOR 3d space mode */
+ if ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) == 0) {
+ return;
+ }
+ if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
+ return;
+ }
+ if ((*p->align_flag & GP_PROJECT_DEPTH_VIEW) || (*p->align_flag & GP_PROJECT_DEPTH_STROKE)) {
+ return;
+ }
+
+ /* get 3d cursor and set origin for locked axis only. Uses axis-1 because the enum for XYZ start with 1 */
+ gp_get_3d_reference(p, cursor);
+ zero_v3(origin);
+ origin[p->lock_axis - 1] = cursor[p->lock_axis - 1];
+
+ gp_project_points_to_plane(rv3d, gps, origin, p->lock_axis - 1);
+}
+
/* convert screen-coordinates to buffer-coordinates */
/* XXX this method needs a total overhaul! */
static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth)
@@ -581,6 +641,10 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
/* if parented change position relative to parent object */
if (gpl->parent != NULL) {
gp_apply_parent_point(gpl, pts);
@@ -679,7 +743,6 @@ static void gp_stroke_simplify(tGPsdata *p)
MEM_freeN(old_points);
}
-
/* make a new stroke from the buffer data */
static void gp_stroke_newfrombuffer(tGPsdata *p)
{
@@ -756,6 +819,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
/* if parented change position relative to parent object */
if (gpl->parent != NULL) {
gp_apply_parent_point(gpl, pt);
@@ -775,6 +842,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
/* if parented change position relative to parent object */
if (gpl->parent != NULL) {
gp_apply_parent_point(gpl, pt);
@@ -793,6 +864,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
/* if parented change position relative to parent object */
if (gpl->parent != NULL) {
gp_apply_parent_point(gpl, pt);
@@ -805,30 +880,30 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
}
else {
float *depth_arr = NULL;
-
+
/* get an array of depths, far depths are blended */
if (gpencil_project_check(p)) {
- int mval[2], mval_prev[2] = {0};
+ int mval[2], mval_prev[2] = { 0 };
int interp_depth = 0;
int found_depth = 0;
-
+
depth_arr = MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points");
-
+
for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size; i++, ptc++, pt++) {
copy_v2_v2_int(mval, &ptc->x);
-
+
if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr + i) == 0) &&
- (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
+ (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
{
interp_depth = true;
}
else {
found_depth = true;
}
-
+
copy_v2_v2_int(mval_prev, mval);
}
-
+
if (found_depth == false) {
/* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
for (i = gpd->sbuffer_size - 1; i >= 0; i--)
@@ -839,54 +914,54 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* remove all info between the valid endpoints */
int first_valid = 0;
int last_valid = 0;
-
+
for (i = 0; i < gpd->sbuffer_size; i++) {
if (depth_arr[i] != FLT_MAX)
break;
}
first_valid = i;
-
+
for (i = gpd->sbuffer_size - 1; i >= 0; i--) {
if (depth_arr[i] != FLT_MAX)
break;
}
last_valid = i;
-
+
/* invalidate non-endpoints, so only blend between first and last */
for (i = first_valid + 1; i < last_valid; i++)
depth_arr[i] = FLT_MAX;
-
+
interp_depth = true;
}
-
+
if (interp_depth) {
interp_sparse_array(depth_arr, gpd->sbuffer_size, FLT_MAX);
}
}
}
-
-
+
+
pt = gps->points;
-
+
/* convert all points (normal behavior) */
for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++, pt++) {
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
-
+
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
}
-
+
/* subdivide the stroke */
if (sublevel > 0) {
int totpoints = gps->totpoints;
for (i = 0; i < sublevel; i++) {
/* we're adding one new point between each pair of verts on each step */
totpoints += totpoints - 1;
-
+
gp_subdivide_stroke(gps, totpoints);
}
}
@@ -895,8 +970,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
gp_randomize_stroke(gps, brush);
}
- /* smooth stroke after subdiv - only if there's something to do
- * for each iteration, the factor is reduced to get a better smoothing without changing too much
+ /* smooth stroke after subdiv - only if there's something to do
+ * for each iteration, the factor is reduced to get a better smoothing without changing too much
* the original stroke
*/
if (brush->draw_smoothfac > 0.0f) {
@@ -909,6 +984,11 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
reduce += 0.25f; // reduce the factor
}
}
+
+ /* if axis locked, reproject to plane locked (only in 3d space) */
+ if (p->lock_axis > GP_LOCKAXIS_NONE) {
+ gp_reproject_toplane(p, gps);
+ }
/* if parented change position relative to parent object */
if (gpl->parent != NULL) {
gp_apply_parent(gpl, gps);
@@ -1467,6 +1547,8 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
bGPdata *pdata = p->gpd;
copy_v4_v4(pdata->scolor, palcolor->color);
pdata->sflag = palcolor->flag;
+ /* lock axis */
+ p->lock_axis = ts->gp_sculpt.lock_axis;
return 1;
}