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:
authorCampbell Barton <ideasman42@gmail.com>2019-04-17 07:17:24 +0300
committerCampbell Barton <ideasman42@gmail.com>2019-04-17 07:21:24 +0300
commite12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch)
tree8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/gpencil
parentb3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff)
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/gpencil')
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt78
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c1924
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c4191
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c1850
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c852
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c2099
-rw-r--r--source/blender/editors/gpencil/gpencil_add_stroke.c321
-rw-r--r--source/blender/editors/gpencil/gpencil_armature.c1113
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c3502
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c2816
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c4192
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c7454
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c2485
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h551
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c1931
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c909
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c450
-rw-r--r--source/blender/editors/gpencil/gpencil_ops_versioning.c267
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c6758
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c3081
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c2296
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c207
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c3928
23 files changed, 26590 insertions, 26665 deletions
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index fa91ffd1e72..5573c88c710 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -16,58 +16,58 @@
# ***** END GPL LICENSE BLOCK *****
set(INC
- ../include
- ../../blenfont
- ../../blenkernel
- ../../blenlib
- ../../blentranslation
- ../../depsgraph
- ../../imbuf
- ../../gpu
- ../../makesdna
- ../../makesrna
- ../../windowmanager
- ../../../../intern/guardedalloc
- ../../../../intern/glew-mx
+ ../include
+ ../../blenfont
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../depsgraph
+ ../../imbuf
+ ../../gpu
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
- ${GLEW_INCLUDE_PATH}
+ ${GLEW_INCLUDE_PATH}
)
set(SRC
- annotate_draw.c
- annotate_paint.c
- drawgpencil.c
- editaction_gpencil.c
- gpencil_add_monkey.c
- gpencil_add_stroke.c
- gpencil_armature.c
- gpencil_brush.c
- gpencil_convert.c
- gpencil_data.c
- gpencil_edit.c
- gpencil_fill.c
- gpencil_interpolate.c
- gpencil_merge.c
- gpencil_ops.c
- gpencil_ops_versioning.c
- gpencil_paint.c
- gpencil_primitive.c
- gpencil_select.c
- gpencil_undo.c
- gpencil_utils.c
+ annotate_draw.c
+ annotate_paint.c
+ drawgpencil.c
+ editaction_gpencil.c
+ gpencil_add_monkey.c
+ gpencil_add_stroke.c
+ gpencil_armature.c
+ gpencil_brush.c
+ gpencil_convert.c
+ gpencil_data.c
+ gpencil_edit.c
+ gpencil_fill.c
+ gpencil_interpolate.c
+ gpencil_merge.c
+ gpencil_ops.c
+ gpencil_ops_versioning.c
+ gpencil_paint.c
+ gpencil_primitive.c
+ gpencil_select.c
+ gpencil_undo.c
+ gpencil_utils.c
- gpencil_intern.h
+ gpencil_intern.h
)
set(LIB
- bf_blenkernel
- bf_blenlib
+ bf_blenkernel
+ bf_blenlib
)
if(WITH_INTERNATIONAL)
- add_definitions(-DWITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
endif()
add_definitions(${GL_DEFINITIONS})
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 2a7f9a715ad..a7fa51350ba 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -21,7 +21,6 @@
* \ingroup edgpencil
*/
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -73,418 +72,436 @@
/* ----- General Defines ------ */
/* flags for sflag */
typedef enum eDrawStrokeFlags {
- /** don't draw status info */
- GP_DRAWDATA_NOSTATUS = (1 << 0),
- /** only draw 3d-strokes */
- GP_DRAWDATA_ONLY3D = (1 << 1),
- /** only draw 'canvas' strokes */
- GP_DRAWDATA_ONLYV2D = (1 << 2),
- /** only draw 'image' strokes */
- GP_DRAWDATA_ONLYI2D = (1 << 3),
- /** special hack for drawing strokes in Image Editor (weird coordinates) */
- GP_DRAWDATA_IEDITHACK = (1 << 4),
- /** don't draw xray in 3D view (which is default) */
- GP_DRAWDATA_NO_XRAY = (1 << 5),
- /** no onionskins should be drawn (for animation playback) */
- GP_DRAWDATA_NO_ONIONS = (1 << 6),
+ /** don't draw status info */
+ GP_DRAWDATA_NOSTATUS = (1 << 0),
+ /** only draw 3d-strokes */
+ GP_DRAWDATA_ONLY3D = (1 << 1),
+ /** only draw 'canvas' strokes */
+ GP_DRAWDATA_ONLYV2D = (1 << 2),
+ /** only draw 'image' strokes */
+ GP_DRAWDATA_ONLYI2D = (1 << 3),
+ /** special hack for drawing strokes in Image Editor (weird coordinates) */
+ GP_DRAWDATA_IEDITHACK = (1 << 4),
+ /** don't draw xray in 3D view (which is default) */
+ GP_DRAWDATA_NO_XRAY = (1 << 5),
+ /** no onionskins should be drawn (for animation playback) */
+ GP_DRAWDATA_NO_ONIONS = (1 << 6),
} eDrawStrokeFlags;
-
/* ----- Tool Buffer Drawing ------ */
/* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
-static void gp_draw_stroke_buffer(
- const tGPspoint *points, int totpoints, short thickness,
- short dflag, short sflag, float ink[4])
+static void gp_draw_stroke_buffer(const tGPspoint *points,
+ int totpoints,
+ short thickness,
+ short dflag,
+ short sflag,
+ float ink[4])
{
- int draw_points = 0;
-
- /* error checking */
- if ((points == NULL) || (totpoints <= 0))
- return;
-
- /* check if buffer can be drawn */
- if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
- return;
-
- if (sflag & GP_STROKE_ERASER) {
- /* don't draw stroke at all! */
- return;
- }
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- const tGPspoint *pt = points;
-
- if (totpoints == 1) {
- /* if drawing a single point, draw it larger */
- GPU_point_size((float)(thickness + 2) * points->pressure);
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- immUniformColor3fvAlpha(ink, ink[3]);
- immBegin(GPU_PRIM_POINTS, 1);
- immVertex2fv(pos, &pt->x);
- }
- else {
- float oldpressure = points[0].pressure;
-
- /* draw stroke curve */
- GPU_line_width(max_ff(oldpressure * thickness, 1.0));
-
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor3fvAlpha(ink, ink[3]);
-
- immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints);
-
- for (int i = 0; i < totpoints; i++, pt++) {
- /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
- * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
- */
- if (fabsf(pt->pressure - oldpressure) > 0.2f) {
- /* need to have 2 points to avoid immEnd assert error */
- if (draw_points < 2) {
- immVertex2fv(pos, &(pt - 1)->x);
- }
-
- immEnd();
- draw_points = 0;
-
- GPU_line_width(max_ff(pt->pressure * thickness, 1.0f));
- immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1);
-
- /* need to roll-back one point to ensure that there are no gaps in the stroke */
- if (i != 0) {
- immVertex2fv(pos, &(pt - 1)->x);
- draw_points++;
- }
-
- oldpressure = pt->pressure; /* reset our threshold */
- }
-
- /* now the point we want */
- immVertex2fv(pos, &pt->x);
- draw_points++;
- }
- /* need to have 2 points to avoid immEnd assert error */
- if (draw_points < 2) {
- immVertex2fv(pos, &(pt - 1)->x);
- }
- }
-
- immEnd();
- immUnbindProgram();
+ int draw_points = 0;
+
+ /* error checking */
+ if ((points == NULL) || (totpoints <= 0))
+ return;
+
+ /* check if buffer can be drawn */
+ if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
+ return;
+
+ if (sflag & GP_STROKE_ERASER) {
+ /* don't draw stroke at all! */
+ return;
+ }
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ const tGPspoint *pt = points;
+
+ if (totpoints == 1) {
+ /* if drawing a single point, draw it larger */
+ GPU_point_size((float)(thickness + 2) * points->pressure);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ immUniformColor3fvAlpha(ink, ink[3]);
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2fv(pos, &pt->x);
+ }
+ else {
+ float oldpressure = points[0].pressure;
+
+ /* draw stroke curve */
+ GPU_line_width(max_ff(oldpressure * thickness, 1.0));
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(ink, ink[3]);
+
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints);
+
+ for (int i = 0; i < totpoints; i++, pt++) {
+ /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
+ * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
+ */
+ if (fabsf(pt->pressure - oldpressure) > 0.2f) {
+ /* need to have 2 points to avoid immEnd assert error */
+ if (draw_points < 2) {
+ immVertex2fv(pos, &(pt - 1)->x);
+ }
+
+ immEnd();
+ draw_points = 0;
+
+ GPU_line_width(max_ff(pt->pressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1);
+
+ /* need to roll-back one point to ensure that there are no gaps in the stroke */
+ if (i != 0) {
+ immVertex2fv(pos, &(pt - 1)->x);
+ draw_points++;
+ }
+
+ oldpressure = pt->pressure; /* reset our threshold */
+ }
+
+ /* now the point we want */
+ immVertex2fv(pos, &pt->x);
+ draw_points++;
+ }
+ /* need to have 2 points to avoid immEnd assert error */
+ if (draw_points < 2) {
+ immVertex2fv(pos, &(pt - 1)->x);
+ }
+ }
+
+ immEnd();
+ immUnbindProgram();
}
/* --------- 2D Stroke Drawing Helpers --------- */
/* change in parameter list */
-static void gp_calc_2d_stroke_fxy(const float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
+static void gp_calc_2d_stroke_fxy(
+ const float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
{
- if (sflag & GP_STROKE_2DSPACE) {
- r_co[0] = pt[0];
- r_co[1] = pt[1];
- }
- else if (sflag & GP_STROKE_2DIMAGE) {
- const float x = (float)((pt[0] * winx) + offsx);
- const float y = (float)((pt[1] * winy) + offsy);
-
- r_co[0] = x;
- r_co[1] = y;
- }
- else {
- const float x = (float)(pt[0] / 100 * winx) + offsx;
- const float y = (float)(pt[1] / 100 * winy) + offsy;
-
- r_co[0] = x;
- r_co[1] = y;
- }
+ if (sflag & GP_STROKE_2DSPACE) {
+ r_co[0] = pt[0];
+ r_co[1] = pt[1];
+ }
+ else if (sflag & GP_STROKE_2DIMAGE) {
+ const float x = (float)((pt[0] * winx) + offsx);
+ const float y = (float)((pt[1] * winy) + offsy);
+
+ r_co[0] = x;
+ r_co[1] = y;
+ }
+ else {
+ const float x = (float)(pt[0] / 100 * winx) + offsx;
+ const float y = (float)(pt[1] / 100 * winy) + offsy;
+
+ r_co[0] = x;
+ r_co[1] = y;
+ }
}
/* ----- Existing Strokes Drawing (3D and Point) ------ */
/* draw a given stroke - just a single dot (only one point) */
-static void gp_draw_stroke_point(
- const bGPDspoint *points, short thickness, short UNUSED(dflag), short sflag,
- int offsx, int offsy, int winx, int winy, const float ink[4])
+static void gp_draw_stroke_point(const bGPDspoint *points,
+ short thickness,
+ short UNUSED(dflag),
+ short sflag,
+ int offsx,
+ int offsy,
+ int winx,
+ int winy,
+ const float ink[4])
{
- const bGPDspoint *pt = points;
+ const bGPDspoint *pt = points;
- /* get final position using parent matrix */
- float fpt[3];
- copy_v3_v3(fpt, &pt->x);
+ /* get final position using parent matrix */
+ float fpt[3];
+ copy_v3_v3(fpt, &pt->x);
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- if (sflag & GP_STROKE_3DSPACE) {
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- }
- else {
- immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ if (sflag & GP_STROKE_3DSPACE) {
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- /* get 2D coordinates of point */
- float co[3] = { 0.0f };
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
- copy_v3_v3(fpt, co);
- }
+ /* get 2D coordinates of point */
+ float co[3] = {0.0f};
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
+ copy_v3_v3(fpt, co);
+ }
- /* set color */
- immUniformColor3fvAlpha(ink, ink[3]);
+ /* set color */
+ immUniformColor3fvAlpha(ink, ink[3]);
- /* set point thickness (since there's only one of these) */
- immUniform1f("size", (float)(thickness + 2) * pt->pressure);
+ /* set point thickness (since there's only one of these) */
+ immUniform1f("size", (float)(thickness + 2) * pt->pressure);
- immBegin(GPU_PRIM_POINTS, 1);
- immVertex3fv(pos, fpt);
- immEnd();
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(pos, fpt);
+ immEnd();
- immUnbindProgram();
+ immUnbindProgram();
}
/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
-static void gp_draw_stroke_3d(
- const bGPDspoint *points, int totpoints, short thickness,
- short UNUSED(sflag), const float ink[4], bool cyclic)
+static void gp_draw_stroke_3d(const bGPDspoint *points,
+ int totpoints,
+ short thickness,
+ short UNUSED(sflag),
+ const float ink[4],
+ bool cyclic)
{
- float curpressure = points[0].pressure;
- float cyclic_fpt[3];
- int draw_points = 0;
-
- /* if cyclic needs one vertex more */
- int cyclic_add = 0;
- if (cyclic) {
- cyclic_add++;
- }
-
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- immUniformColor3fvAlpha(ink, ink[3]);
-
- /* draw stroke curve */
- GPU_line_width(max_ff(curpressure * thickness, 1.0f));
- immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
- const bGPDspoint *pt = points;
- for (int i = 0; i < totpoints; i++, pt++) {
- /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
- * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
- * Note: we want more visible levels of pressures when thickness is bigger.
- */
- if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
- /* if the pressure changes before get at least 2 vertices,
- * need to repeat last point to avoid assert in immEnd() */
- if (draw_points < 2) {
- const bGPDspoint *pt2 = pt - 1;
- immVertex3fv(pos, &pt2->x);
- }
- immEnd();
- draw_points = 0;
-
- curpressure = pt->pressure;
- GPU_line_width(max_ff(curpressure * thickness, 1.0f));
- immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1 + cyclic_add);
-
- /* need to roll-back one point to ensure that there are no gaps in the stroke */
- if (i != 0) {
- const bGPDspoint *pt2 = pt - 1;
- immVertex3fv(pos, &pt2->x);
- draw_points++;
- }
- }
-
- /* now the point we want */
- immVertex3fv(pos, &pt->x);
- draw_points++;
-
- if (cyclic && i == 0) {
- /* save first point to use in cyclic */
- copy_v3_v3(cyclic_fpt, &pt->x);
- }
- }
-
- if (cyclic) {
- /* draw line to first point to complete the cycle */
- immVertex3fv(pos, cyclic_fpt);
- draw_points++;
- }
-
- /* if less of two points, need to repeat last point to avoid assert in immEnd() */
- if (draw_points < 2) {
- const bGPDspoint *pt2 = pt - 1;
- immVertex3fv(pos, &pt2->x);
- }
-
- immEnd();
- immUnbindProgram();
+ float curpressure = points[0].pressure;
+ float cyclic_fpt[3];
+ int draw_points = 0;
+
+ /* if cyclic needs one vertex more */
+ int cyclic_add = 0;
+ if (cyclic) {
+ cyclic_add++;
+ }
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(ink, ink[3]);
+
+ /* draw stroke curve */
+ GPU_line_width(max_ff(curpressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
+ const bGPDspoint *pt = points;
+ for (int i = 0; i < totpoints; i++, pt++) {
+ /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
+ * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
+ * Note: we want more visible levels of pressures when thickness is bigger.
+ */
+ if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
+ /* if the pressure changes before get at least 2 vertices,
+ * need to repeat last point to avoid assert in immEnd() */
+ if (draw_points < 2) {
+ const bGPDspoint *pt2 = pt - 1;
+ immVertex3fv(pos, &pt2->x);
+ }
+ immEnd();
+ draw_points = 0;
+
+ curpressure = pt->pressure;
+ GPU_line_width(max_ff(curpressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1 + cyclic_add);
+
+ /* need to roll-back one point to ensure that there are no gaps in the stroke */
+ if (i != 0) {
+ const bGPDspoint *pt2 = pt - 1;
+ immVertex3fv(pos, &pt2->x);
+ draw_points++;
+ }
+ }
+
+ /* now the point we want */
+ immVertex3fv(pos, &pt->x);
+ draw_points++;
+
+ if (cyclic && i == 0) {
+ /* save first point to use in cyclic */
+ copy_v3_v3(cyclic_fpt, &pt->x);
+ }
+ }
+
+ if (cyclic) {
+ /* draw line to first point to complete the cycle */
+ immVertex3fv(pos, cyclic_fpt);
+ draw_points++;
+ }
+
+ /* if less of two points, need to repeat last point to avoid assert in immEnd() */
+ if (draw_points < 2) {
+ const bGPDspoint *pt2 = pt - 1;
+ immVertex3fv(pos, &pt2->x);
+ }
+
+ immEnd();
+ immUnbindProgram();
}
/* ----- Fancy 2D-Stroke Drawing ------ */
/* draw a given stroke in 2d */
-static void gp_draw_stroke_2d(
- const bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
- int offsx, int offsy, int winx, int winy, const float ink[4])
+static void gp_draw_stroke_2d(const bGPDspoint *points,
+ int totpoints,
+ short thickness_s,
+ short dflag,
+ short sflag,
+ int offsx,
+ int offsy,
+ int winx,
+ int winy,
+ const float ink[4])
{
- /* otherwise thickness is twice that of the 3D view */
- float thickness = (float)thickness_s * 0.5f;
-
- /* strokes in Image Editor need a scale factor, since units there are not pixels! */
- float scalefac = 1.0f;
- if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
- scalefac = 0.001f;
- }
-
- /* tessellation code - draw stroke as series of connected quads (triangle strips in fact) with connection
- * edges rotated to minimize shrinking artifacts, and rounded endcaps
- */
- {
- const bGPDspoint *pt1, *pt2;
- float s0[2], s1[2]; /* segment 'center' points */
- float pm[2]; /* normal from previous segment. */
- int i;
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor3fvAlpha(ink, ink[3]);
- immBegin(GPU_PRIM_TRI_STRIP, totpoints * 2 + 4);
-
- /* get x and y coordinates from first point */
- gp_calc_2d_stroke_fxy(&points->x, sflag, offsx, offsy, winx, winy, s0);
-
- for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
- float t0[2], t1[2]; /* tessellated coordinates */
- float m1[2], m2[2]; /* gradient and normal */
- float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
- float pthick; /* thickness at segment point */
-
- /* get x and y coordinates from point2 (point1 has already been computed in previous iteration). */
- gp_calc_2d_stroke_fxy(&pt2->x, sflag, offsx, offsy, winx, winy, s1);
-
- /* calculate gradient and normal - 'angle'=(ny/nx) */
- m1[1] = s1[1] - s0[1];
- m1[0] = s1[0] - s0[0];
- normalize_v2(m1);
- m2[1] = -m1[0];
- m2[0] = m1[1];
-
- /* always use pressure from first point here */
- pthick = (pt1->pressure * thickness * scalefac);
-
- /* if the first segment, start of segment is segment's normal */
- if (i == 0) {
- /* draw start cap first
- * - make points slightly closer to center (about halfway across)
- */
- mt[0] = m2[0] * pthick * 0.5f;
- mt[1] = m2[1] * pthick * 0.5f;
- sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
- sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
-
- t0[0] = sc[0] - mt[0];
- t0[1] = sc[1] - mt[1];
- t1[0] = sc[0] + mt[0];
- t1[1] = sc[1] + mt[1];
-
- /* First two points of cap. */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
-
- /* calculate points for start of segment */
- mt[0] = m2[0] * pthick;
- mt[1] = m2[1] * pthick;
-
- t0[0] = s0[0] - mt[0];
- t0[1] = s0[1] - mt[1];
- t1[0] = s0[0] + mt[0];
- t1[1] = s0[1] + mt[1];
-
- /* Last two points of start cap (and first two points of first segment). */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
- }
- /* if not the first segment, use bisector of angle between segments */
- else {
- float mb[2]; /* bisector normal */
- float athick, dfac; /* actual thickness, difference between thicknesses */
-
- /* calculate gradient of bisector (as average of normals) */
- mb[0] = (pm[0] + m2[0]) / 2;
- mb[1] = (pm[1] + m2[1]) / 2;
- normalize_v2(mb);
-
- /* calculate gradient to apply
- * - as basis, use just pthick * bisector gradient
- * - if cross-section not as thick as it should be, add extra padding to fix it
- */
- mt[0] = mb[0] * pthick;
- mt[1] = mb[1] * pthick;
- athick = len_v2(mt);
- dfac = pthick - (athick * 2);
-
- if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
- mt[0] += (mb[0] * dfac);
- mt[1] += (mb[1] * dfac);
- }
-
- /* calculate points for start of segment */
- t0[0] = s0[0] - mt[0];
- t0[1] = s0[1] - mt[1];
- t1[0] = s0[0] + mt[0];
- t1[1] = s0[1] + mt[1];
-
- /* Last two points of previous segment, and first two points of current segment. */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
- }
-
- /* if last segment, also draw end of segment (defined as segment's normal) */
- if (i == totpoints - 2) {
- /* for once, we use second point's pressure (otherwise it won't be drawn) */
- pthick = (pt2->pressure * thickness * scalefac);
-
- /* calculate points for end of segment */
- mt[0] = m2[0] * pthick;
- mt[1] = m2[1] * pthick;
-
- t0[0] = s1[0] - mt[0];
- t0[1] = s1[1] - mt[1];
- t1[0] = s1[0] + mt[0];
- t1[1] = s1[1] + mt[1];
-
- /* Last two points of last segment (and first two points of end cap). */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
-
- /* draw end cap as last step
- * - make points slightly closer to center (about halfway across)
- */
- mt[0] = m2[0] * pthick * 0.5f;
- mt[1] = m2[1] * pthick * 0.5f;
- sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
- sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
-
- t0[0] = sc[0] - mt[0];
- t0[1] = sc[1] - mt[1];
- t1[0] = sc[0] + mt[0];
- t1[1] = sc[1] + mt[1];
-
- /* Last two points of end cap. */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
- }
-
- /* store computed point2 coordinates as point1 ones of next segment. */
- copy_v2_v2(s0, s1);
- /* store stroke's 'natural' normal for next stroke to use */
- copy_v2_v2(pm, m2);
- }
-
- immEnd();
- immUnbindProgram();
- }
+ /* otherwise thickness is twice that of the 3D view */
+ float thickness = (float)thickness_s * 0.5f;
+
+ /* strokes in Image Editor need a scale factor, since units there are not pixels! */
+ float scalefac = 1.0f;
+ if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
+ scalefac = 0.001f;
+ }
+
+ /* tessellation code - draw stroke as series of connected quads (triangle strips in fact) with connection
+ * edges rotated to minimize shrinking artifacts, and rounded endcaps
+ */
+ {
+ const bGPDspoint *pt1, *pt2;
+ float s0[2], s1[2]; /* segment 'center' points */
+ float pm[2]; /* normal from previous segment. */
+ int i;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(ink, ink[3]);
+ immBegin(GPU_PRIM_TRI_STRIP, totpoints * 2 + 4);
+
+ /* get x and y coordinates from first point */
+ gp_calc_2d_stroke_fxy(&points->x, sflag, offsx, offsy, winx, winy, s0);
+
+ for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
+ float t0[2], t1[2]; /* tessellated coordinates */
+ float m1[2], m2[2]; /* gradient and normal */
+ float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
+ float pthick; /* thickness at segment point */
+
+ /* get x and y coordinates from point2 (point1 has already been computed in previous iteration). */
+ gp_calc_2d_stroke_fxy(&pt2->x, sflag, offsx, offsy, winx, winy, s1);
+
+ /* calculate gradient and normal - 'angle'=(ny/nx) */
+ m1[1] = s1[1] - s0[1];
+ m1[0] = s1[0] - s0[0];
+ normalize_v2(m1);
+ m2[1] = -m1[0];
+ m2[0] = m1[1];
+
+ /* always use pressure from first point here */
+ pthick = (pt1->pressure * thickness * scalefac);
+
+ /* if the first segment, start of segment is segment's normal */
+ if (i == 0) {
+ /* draw start cap first
+ * - make points slightly closer to center (about halfway across)
+ */
+ mt[0] = m2[0] * pthick * 0.5f;
+ mt[1] = m2[1] * pthick * 0.5f;
+ sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
+ sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
+
+ t0[0] = sc[0] - mt[0];
+ t0[1] = sc[1] - mt[1];
+ t1[0] = sc[0] + mt[0];
+ t1[1] = sc[1] + mt[1];
+
+ /* First two points of cap. */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+
+ /* calculate points for start of segment */
+ mt[0] = m2[0] * pthick;
+ mt[1] = m2[1] * pthick;
+
+ t0[0] = s0[0] - mt[0];
+ t0[1] = s0[1] - mt[1];
+ t1[0] = s0[0] + mt[0];
+ t1[1] = s0[1] + mt[1];
+
+ /* Last two points of start cap (and first two points of first segment). */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+ }
+ /* if not the first segment, use bisector of angle between segments */
+ else {
+ float mb[2]; /* bisector normal */
+ float athick, dfac; /* actual thickness, difference between thicknesses */
+
+ /* calculate gradient of bisector (as average of normals) */
+ mb[0] = (pm[0] + m2[0]) / 2;
+ mb[1] = (pm[1] + m2[1]) / 2;
+ normalize_v2(mb);
+
+ /* calculate gradient to apply
+ * - as basis, use just pthick * bisector gradient
+ * - if cross-section not as thick as it should be, add extra padding to fix it
+ */
+ mt[0] = mb[0] * pthick;
+ mt[1] = mb[1] * pthick;
+ athick = len_v2(mt);
+ dfac = pthick - (athick * 2);
+
+ if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
+ mt[0] += (mb[0] * dfac);
+ mt[1] += (mb[1] * dfac);
+ }
+
+ /* calculate points for start of segment */
+ t0[0] = s0[0] - mt[0];
+ t0[1] = s0[1] - mt[1];
+ t1[0] = s0[0] + mt[0];
+ t1[1] = s0[1] + mt[1];
+
+ /* Last two points of previous segment, and first two points of current segment. */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+ }
+
+ /* if last segment, also draw end of segment (defined as segment's normal) */
+ if (i == totpoints - 2) {
+ /* for once, we use second point's pressure (otherwise it won't be drawn) */
+ pthick = (pt2->pressure * thickness * scalefac);
+
+ /* calculate points for end of segment */
+ mt[0] = m2[0] * pthick;
+ mt[1] = m2[1] * pthick;
+
+ t0[0] = s1[0] - mt[0];
+ t0[1] = s1[1] - mt[1];
+ t1[0] = s1[0] + mt[0];
+ t1[1] = s1[1] + mt[1];
+
+ /* Last two points of last segment (and first two points of end cap). */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+
+ /* draw end cap as last step
+ * - make points slightly closer to center (about halfway across)
+ */
+ mt[0] = m2[0] * pthick * 0.5f;
+ mt[1] = m2[1] * pthick * 0.5f;
+ sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
+ sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
+
+ t0[0] = sc[0] - mt[0];
+ t0[1] = sc[1] - mt[1];
+ t1[0] = sc[0] + mt[0];
+ t1[1] = sc[1] + mt[1];
+
+ /* Last two points of end cap. */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+ }
+
+ /* store computed point2 coordinates as point1 ones of next segment. */
+ copy_v2_v2(s0, s1);
+ /* store stroke's 'natural' normal for next stroke to use */
+ copy_v2_v2(pm, m2);
+ }
+
+ immEnd();
+ immUnbindProgram();
+ }
}
/* ----- Strokes Drawing ------ */
@@ -492,484 +509,507 @@ static void gp_draw_stroke_2d(
/* Helper for doing all the checks on whether a stroke can be drawn */
static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
{
- /* skip stroke if it isn't in the right display space for this drawing context */
- /* 1) 3D Strokes */
- if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
- return false;
- if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
- return false;
-
- /* 2) Screen Space 2D Strokes */
- if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
- return false;
- if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
- return false;
-
- /* 3) Image Space (2D) */
- if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
- return false;
- if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
- return false;
-
- /* skip stroke if it doesn't have any valid data */
- if ((gps->points == NULL) || (gps->totpoints < 1))
- return false;
-
- /* stroke can be drawn */
- return true;
+ /* skip stroke if it isn't in the right display space for this drawing context */
+ /* 1) 3D Strokes */
+ if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
+ return false;
+
+ /* 2) Screen Space 2D Strokes */
+ if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
+ return false;
+
+ /* 3) Image Space (2D) */
+ if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
+ return false;
+
+ /* skip stroke if it doesn't have any valid data */
+ if ((gps->points == NULL) || (gps->totpoints < 1))
+ return false;
+
+ /* stroke can be drawn */
+ return true;
}
/* draw a set of strokes */
-static void gp_draw_strokes(
- bGPdata *UNUSED(gpd), bGPDlayer *UNUSED(gpl), const bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
- int dflag, short lthick, const float color[4])
+static void gp_draw_strokes(bGPdata *UNUSED(gpd),
+ bGPDlayer *UNUSED(gpl),
+ const bGPDframe *gpf,
+ int offsx,
+ int offsy,
+ int winx,
+ int winy,
+ int dflag,
+ short lthick,
+ const float color[4])
{
- GPU_enable_program_point_size();
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* check if stroke can be drawn */
- if (gp_can_draw_stroke(gps, dflag) == false) {
- continue;
- }
-
- /* check which stroke-drawer to use */
- if (dflag & GP_DRAWDATA_ONLY3D) {
- const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
- int mask_orig = 0;
-
- if (no_xray) {
- glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
- glDepthMask(0);
- GPU_depth_test(true);
-
- /* first arg is normally rv3d->dist, but this isn't
- * available here and seems to work quite well without */
- bglPolygonOffset(1.0f, 1.0f);
- }
-
- /* 3D Lines - OpenGL primitives-based */
- if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color);
- }
- else {
- gp_draw_stroke_3d(
- gps->points, gps->totpoints, lthick, gps->flag,
- color, gps->flag & GP_STROKE_CYCLIC);
- }
-
- if (no_xray) {
- glDepthMask(mask_orig);
- GPU_depth_test(false);
-
- bglPolygonOffset(0.0, 0.0);
- }
- }
- else {
- /* 2D Strokes... */
- if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color);
- }
- else {
- gp_draw_stroke_2d(
- gps->points, gps->totpoints, lthick, dflag, gps->flag,
- offsx, offsy, winx, winy, color);
- }
- }
- }
-
- GPU_disable_program_point_size();
+ GPU_enable_program_point_size();
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* check if stroke can be drawn */
+ if (gp_can_draw_stroke(gps, dflag) == false) {
+ continue;
+ }
+
+ /* check which stroke-drawer to use */
+ if (dflag & GP_DRAWDATA_ONLY3D) {
+ const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
+ int mask_orig = 0;
+
+ if (no_xray) {
+ glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
+ glDepthMask(0);
+ GPU_depth_test(true);
+
+ /* first arg is normally rv3d->dist, but this isn't
+ * available here and seems to work quite well without */
+ bglPolygonOffset(1.0f, 1.0f);
+ }
+
+ /* 3D Lines - OpenGL primitives-based */
+ if (gps->totpoints == 1) {
+ gp_draw_stroke_point(
+ gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color);
+ }
+ else {
+ gp_draw_stroke_3d(
+ gps->points, gps->totpoints, lthick, gps->flag, color, gps->flag & GP_STROKE_CYCLIC);
+ }
+
+ if (no_xray) {
+ glDepthMask(mask_orig);
+ GPU_depth_test(false);
+
+ bglPolygonOffset(0.0, 0.0);
+ }
+ }
+ else {
+ /* 2D Strokes... */
+ if (gps->totpoints == 1) {
+ gp_draw_stroke_point(
+ gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color);
+ }
+ else {
+ gp_draw_stroke_2d(gps->points,
+ gps->totpoints,
+ lthick,
+ dflag,
+ gps->flag,
+ offsx,
+ offsy,
+ winx,
+ winy,
+ color);
+ }
+ }
+ }
+
+ GPU_disable_program_point_size();
}
/* Draw selected verts for strokes being edited */
-static void gp_draw_strokes_edit(
- bGPdata *gpd, bGPDlayer *gpl, const bGPDframe *gpf,
- int offsx, int offsy, int winx, int winy,
- short dflag, short UNUSED(lflag), float alpha)
+static void gp_draw_strokes_edit(bGPdata *gpd,
+ bGPDlayer *gpl,
+ const bGPDframe *gpf,
+ int offsx,
+ int offsy,
+ int winx,
+ int winy,
+ short dflag,
+ short UNUSED(lflag),
+ float alpha)
{
- /* if alpha 0 do not draw */
- if (alpha == 0.0f)
- return;
-
- const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
- int mask_orig = 0;
-
- /* set up depth masks... */
- if (dflag & GP_DRAWDATA_ONLY3D) {
- if (no_xray) {
- glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
- glDepthMask(0);
- GPU_depth_test(true);
-
- /* first arg is normally rv3d->dist, but this isn't
- * available here and seems to work quite well without */
- bglPolygonOffset(1.0f, 1.0f);
- }
- }
-
- GPU_enable_program_point_size();
-
- /* draw stroke verts */
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* check if stroke can be drawn */
- if (gp_can_draw_stroke(gps, dflag) == false)
- continue;
-
- /* Optimisation: only draw points for selected strokes
- * We assume that selected points can only occur in
- * strokes that are selected too.
- */
- if ((gps->flag & GP_STROKE_SELECT) == 0)
- continue;
-
- /* Get size of verts:
- * - The selected state needs to be larger than the unselected state so that
- * they stand out more.
- * - We use the theme setting for size of the unselected verts
- */
- float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
- float vsize;
- if ((int)bsize > 8) {
- vsize = 10.0f;
- bsize = 8.0f;
- }
- else {
- vsize = bsize + 2;
- }
-
- float selectColor[4];
- UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
- selectColor[3] = alpha;
-
- GPUVertFormat *format = immVertexFormat();
- uint pos; /* specified later */
- uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- if (gps->flag & GP_STROKE_3DSPACE) {
- pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
- }
- else {
- pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR);
- }
-
- immBegin(GPU_PRIM_POINTS, gps->totpoints);
-
- /* Draw start and end point differently if enabled stroke direction hint */
- bool show_direction_hint = (gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1);
-
- /* Draw all the stroke points (selected or not) */
- bGPDspoint *pt = gps->points;
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- /* size and color first */
- if (show_direction_hint && i == 0) {
- /* start point in green bigger */
- immAttr3f(color, 0.0f, 1.0f, 0.0f);
- immAttr1f(size, vsize + 4);
- }
- else if (show_direction_hint && (i == gps->totpoints - 1)) {
- /* end point in red smaller */
- immAttr3f(color, 1.0f, 0.0f, 0.0f);
- immAttr1f(size, vsize + 1);
- }
- else if (pt->flag & GP_SPOINT_SELECT) {
- immAttr3fv(color, selectColor);
- immAttr1f(size, vsize);
- }
- else {
- immAttr3fv(color, gpl->color);
- immAttr1f(size, bsize);
- }
-
- /* then position */
- if (gps->flag & GP_STROKE_3DSPACE) {
- immVertex3fv(pos, &pt->x);
- }
- else {
- float co[2];
- gp_calc_2d_stroke_fxy(&pt->x, gps->flag, offsx, offsy, winx, winy, co);
- immVertex2fv(pos, co);
- }
- }
-
- immEnd();
- immUnbindProgram();
- }
-
- GPU_disable_program_point_size();
-
- /* clear depth mask */
- if (dflag & GP_DRAWDATA_ONLY3D) {
- if (no_xray) {
- glDepthMask(mask_orig);
- GPU_depth_test(false);
-
- bglPolygonOffset(0.0, 0.0);
+ /* if alpha 0 do not draw */
+ if (alpha == 0.0f)
+ return;
+
+ const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
+ int mask_orig = 0;
+
+ /* set up depth masks... */
+ if (dflag & GP_DRAWDATA_ONLY3D) {
+ if (no_xray) {
+ glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
+ glDepthMask(0);
+ GPU_depth_test(true);
+
+ /* first arg is normally rv3d->dist, but this isn't
+ * available here and seems to work quite well without */
+ bglPolygonOffset(1.0f, 1.0f);
+ }
+ }
+
+ GPU_enable_program_point_size();
+
+ /* draw stroke verts */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* check if stroke can be drawn */
+ if (gp_can_draw_stroke(gps, dflag) == false)
+ continue;
+
+ /* Optimisation: only draw points for selected strokes
+ * We assume that selected points can only occur in
+ * strokes that are selected too.
+ */
+ if ((gps->flag & GP_STROKE_SELECT) == 0)
+ continue;
+
+ /* Get size of verts:
+ * - The selected state needs to be larger than the unselected state so that
+ * they stand out more.
+ * - We use the theme setting for size of the unselected verts
+ */
+ float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
+ float vsize;
+ if ((int)bsize > 8) {
+ vsize = 10.0f;
+ bsize = 8.0f;
+ }
+ else {
+ vsize = bsize + 2;
+ }
+
+ float selectColor[4];
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
+ selectColor[3] = alpha;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos; /* specified later */
+ uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ }
+ else {
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR);
+ }
+
+ immBegin(GPU_PRIM_POINTS, gps->totpoints);
+
+ /* Draw start and end point differently if enabled stroke direction hint */
+ bool show_direction_hint = (gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1);
+
+ /* Draw all the stroke points (selected or not) */
+ bGPDspoint *pt = gps->points;
+ for (int i = 0; i < gps->totpoints; i++, pt++) {
+ /* size and color first */
+ if (show_direction_hint && i == 0) {
+ /* start point in green bigger */
+ immAttr3f(color, 0.0f, 1.0f, 0.0f);
+ immAttr1f(size, vsize + 4);
+ }
+ else if (show_direction_hint && (i == gps->totpoints - 1)) {
+ /* end point in red smaller */
+ immAttr3f(color, 1.0f, 0.0f, 0.0f);
+ immAttr1f(size, vsize + 1);
+ }
+ else if (pt->flag & GP_SPOINT_SELECT) {
+ immAttr3fv(color, selectColor);
+ immAttr1f(size, vsize);
+ }
+ else {
+ immAttr3fv(color, gpl->color);
+ immAttr1f(size, bsize);
+ }
+
+ /* then position */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ immVertex3fv(pos, &pt->x);
+ }
+ else {
+ float co[2];
+ gp_calc_2d_stroke_fxy(&pt->x, gps->flag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
+ }
+ }
+
+ immEnd();
+ immUnbindProgram();
+ }
+
+ GPU_disable_program_point_size();
+
+ /* clear depth mask */
+ if (dflag & GP_DRAWDATA_ONLY3D) {
+ if (no_xray) {
+ glDepthMask(mask_orig);
+ GPU_depth_test(false);
+
+ bglPolygonOffset(0.0, 0.0);
#if 0
- glDisable(GL_POLYGON_OFFSET_LINE);
- glPolygonOffset(0, 0);
+ glDisable(GL_POLYGON_OFFSET_LINE);
+ glPolygonOffset(0, 0);
#endif
- }
- }
+ }
+ }
}
/* ----- General Drawing ------ */
/* draw onion-skinning for a layer */
-static void gp_draw_onionskins(
- bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
- int UNUSED(cfra), int dflag)
+static void gp_draw_onionskins(bGPdata *gpd,
+ bGPDlayer *gpl,
+ bGPDframe *gpf,
+ int offsx,
+ int offsy,
+ int winx,
+ int winy,
+ int UNUSED(cfra),
+ int dflag)
{
- const float alpha = 1.0f;
- float color[4];
-
- /* 1) Draw Previous Frames First */
- copy_v3_v3(color, gpl->gcolor_prev);
-
- if (gpl->gstep > 0) {
- bGPDframe *gf;
- float fac;
-
- /* draw previous frames first */
- for (gf = gpf->prev; gf; gf = gf->prev) {
- /* check if frame is drawable */
- if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
- /* alpha decreases with distance from curframe index */
- fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
- color[3] = alpha * fac * 0.66f;
- gp_draw_strokes(
- gpd, gpl, gf, offsx, offsy, winx, winy, dflag,
- gpl->thickness, color);
- }
- else
- break;
- }
- }
- else if (gpl->gstep == 0) {
- /* draw the strokes for the ghost frames (at half of the alpha set by user) */
- if (gpf->prev) {
- color[3] = (alpha / 7);
- gp_draw_strokes(
- gpd, gpl, gpf->prev, offsx, offsy, winx, winy, dflag,
- gpl->thickness, color);
- }
- }
- else {
- /* don't draw - disabled */
- }
-
-
- /* 2) Now draw next frames */
- copy_v3_v3(color, gpl->gcolor_next);
-
- if (gpl->gstep_next > 0) {
- bGPDframe *gf;
- float fac;
-
- /* now draw next frames */
- for (gf = gpf->next; gf; gf = gf->next) {
- /* check if frame is drawable */
- if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) {
- /* alpha decreases with distance from curframe index */
- fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
- color[3] = alpha * fac * 0.66f;
- gp_draw_strokes(
- gpd, gpl, gf, offsx, offsy, winx, winy, dflag,
- gpl->thickness, color);
- }
- else
- break;
- }
- }
- else if (gpl->gstep_next == 0) {
- /* draw the strokes for the ghost frames (at half of the alpha set by user) */
- if (gpf->next) {
- color[3] = (alpha / 4);
- gp_draw_strokes(
- gpd, gpl, gpf->next, offsx, offsy, winx, winy, dflag,
- gpl->thickness, color);
- }
- }
- else {
- /* don't draw - disabled */
- }
-
+ const float alpha = 1.0f;
+ float color[4];
+
+ /* 1) Draw Previous Frames First */
+ copy_v3_v3(color, gpl->gcolor_prev);
+
+ if (gpl->gstep > 0) {
+ bGPDframe *gf;
+ float fac;
+
+ /* draw previous frames first */
+ for (gf = gpf->prev; gf; gf = gf->prev) {
+ /* check if frame is drawable */
+ if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
+ /* alpha decreases with distance from curframe index */
+ fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
+ color[3] = alpha * fac * 0.66f;
+ gp_draw_strokes(gpd, gpl, gf, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
+ }
+ else
+ break;
+ }
+ }
+ else if (gpl->gstep == 0) {
+ /* draw the strokes for the ghost frames (at half of the alpha set by user) */
+ if (gpf->prev) {
+ color[3] = (alpha / 7);
+ gp_draw_strokes(gpd, gpl, gpf->prev, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
+ }
+ }
+ else {
+ /* don't draw - disabled */
+ }
+
+ /* 2) Now draw next frames */
+ copy_v3_v3(color, gpl->gcolor_next);
+
+ if (gpl->gstep_next > 0) {
+ bGPDframe *gf;
+ float fac;
+
+ /* now draw next frames */
+ for (gf = gpf->next; gf; gf = gf->next) {
+ /* check if frame is drawable */
+ if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) {
+ /* alpha decreases with distance from curframe index */
+ fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
+ color[3] = alpha * fac * 0.66f;
+ gp_draw_strokes(gpd, gpl, gf, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
+ }
+ else
+ break;
+ }
+ }
+ else if (gpl->gstep_next == 0) {
+ /* draw the strokes for the ghost frames (at half of the alpha set by user) */
+ if (gpf->next) {
+ color[3] = (alpha / 4);
+ gp_draw_strokes(gpd, gpl, gpf->next, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
+ }
+ }
+ else {
+ /* don't draw - disabled */
+ }
}
/* loop over gpencil data layers, drawing them */
static void gp_draw_data_layers(
- bGPdata *gpd, int offsx, int offsy, int winx, int winy,
- int cfra, int dflag, float alpha)
+ bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha)
{
- float ink[4];
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* verify never thickness is less than 1 */
- CLAMP_MIN(gpl->thickness, 1.0f);
- short lthick = gpl->thickness;
-
- /* apply layer opacity */
- copy_v3_v3(ink, gpl->color);
- ink[3] = gpl->opacity;
-
- /* don't draw layer if hidden */
- if (gpl->flag & GP_LAYER_HIDE)
- continue;
-
- /* get frame to draw */
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV);
- if (gpf == NULL)
- continue;
-
- /* set basic stroke thickness */
- GPU_line_width(lthick);
-
- /* Add layer drawing settings to the set of "draw flags"
- * NOTE: If the setting doesn't apply, it *must* be cleared,
- * as dflag's carry over from the previous layer
- */
-
- /* xray... */
- SET_FLAG_FROM_TEST(dflag, gpl->flag & GP_LAYER_NO_XRAY, GP_DRAWDATA_NO_XRAY);
-
- /* Draw 'onionskins' (frame left + right) */
- if (gpl->onion_flag & GP_LAYER_ONIONSKIN) {
- gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag);
- }
-
- /* draw the strokes already in active frame */
- gp_draw_strokes(gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, lthick, ink);
-
- /* Draw verts of selected strokes
- * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
- * - locked layers can't be edited, so there's no point showing these verts
- * as they will have no bearings on what gets edited
- * - only show when in editmode, since operators shouldn't work otherwise
- * (NOTE: doing it this way means that the toggling editmode shows visible change immediately)
- */
- /* XXX: perhaps we don't want to show these when users are drawing... */
- if ((G.f & G_FLAG_RENDER_VIEWPORT) == 0 &&
- (gpl->flag & GP_LAYER_LOCKED) == 0 &&
- (gpd->flag & GP_DATA_STROKE_EDITMODE))
- {
- gp_draw_strokes_edit(gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, alpha);
- }
-
- /* Check if may need to draw the active stroke cache, only if this layer is the active layer
- * that is being edited. (Stroke buffer is currently stored in gp-data)
- */
- if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
- (gpf->flag & GP_FRAME_PAINT))
- {
- /* Buffer stroke needs to be drawn with a different linestyle
- * to help differentiate them from normal strokes.
- *
- * It should also be noted that sbuffer contains temporary point types
- * i.e. tGPspoints NOT bGPDspoints
- */
- gp_draw_stroke_buffer(
- gpd->runtime.sbuffer,
- gpd->runtime.sbuffer_size, lthick,
- dflag, gpd->runtime.sbuffer_sflag, ink);
- }
- }
+ float ink[4];
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* verify never thickness is less than 1 */
+ CLAMP_MIN(gpl->thickness, 1.0f);
+ short lthick = gpl->thickness;
+
+ /* apply layer opacity */
+ copy_v3_v3(ink, gpl->color);
+ ink[3] = gpl->opacity;
+
+ /* don't draw layer if hidden */
+ if (gpl->flag & GP_LAYER_HIDE)
+ continue;
+
+ /* get frame to draw */
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV);
+ if (gpf == NULL)
+ continue;
+
+ /* set basic stroke thickness */
+ GPU_line_width(lthick);
+
+ /* Add layer drawing settings to the set of "draw flags"
+ * NOTE: If the setting doesn't apply, it *must* be cleared,
+ * as dflag's carry over from the previous layer
+ */
+
+ /* xray... */
+ SET_FLAG_FROM_TEST(dflag, gpl->flag & GP_LAYER_NO_XRAY, GP_DRAWDATA_NO_XRAY);
+
+ /* Draw 'onionskins' (frame left + right) */
+ if (gpl->onion_flag & GP_LAYER_ONIONSKIN) {
+ gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag);
+ }
+
+ /* draw the strokes already in active frame */
+ gp_draw_strokes(gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, lthick, ink);
+
+ /* Draw verts of selected strokes
+ * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
+ * - locked layers can't be edited, so there's no point showing these verts
+ * as they will have no bearings on what gets edited
+ * - only show when in editmode, since operators shouldn't work otherwise
+ * (NOTE: doing it this way means that the toggling editmode shows visible change immediately)
+ */
+ /* XXX: perhaps we don't want to show these when users are drawing... */
+ if ((G.f & G_FLAG_RENDER_VIEWPORT) == 0 && (gpl->flag & GP_LAYER_LOCKED) == 0 &&
+ (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
+ gp_draw_strokes_edit(gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, alpha);
+ }
+
+ /* Check if may need to draw the active stroke cache, only if this layer is the active layer
+ * that is being edited. (Stroke buffer is currently stored in gp-data)
+ */
+ if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
+ (gpf->flag & GP_FRAME_PAINT)) {
+ /* Buffer stroke needs to be drawn with a different linestyle
+ * to help differentiate them from normal strokes.
+ *
+ * It should also be noted that sbuffer contains temporary point types
+ * i.e. tGPspoints NOT bGPDspoints
+ */
+ gp_draw_stroke_buffer(gpd->runtime.sbuffer,
+ gpd->runtime.sbuffer_size,
+ lthick,
+ dflag,
+ gpd->runtime.sbuffer_sflag,
+ ink);
+ }
+ }
}
/* draw a short status message in the top-right corner */
static void gp_draw_status_text(const bGPdata *gpd, ARegion *ar)
{
- rcti rect;
+ rcti rect;
- /* Cannot draw any status text when drawing OpenGL Renders */
- if (G.f & G_FLAG_RENDER_VIEWPORT)
- return;
+ /* Cannot draw any status text when drawing OpenGL Renders */
+ if (G.f & G_FLAG_RENDER_VIEWPORT)
+ return;
- /* Get bounds of region - Necessary to avoid problems with region overlap */
- ED_region_visible_rect(ar, &rect);
+ /* Get bounds of region - Necessary to avoid problems with region overlap */
+ ED_region_visible_rect(ar, &rect);
- /* for now, this should only be used to indicate when we are in stroke editmode */
- if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
- const char *printable = IFACE_("GPencil Stroke Editing");
- float printable_size[2];
+ /* for now, this should only be used to indicate when we are in stroke editmode */
+ if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ const char *printable = IFACE_("GPencil Stroke Editing");
+ float printable_size[2];
- int font_id = BLF_default();
+ int font_id = BLF_default();
- BLF_width_and_height(font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
+ BLF_width_and_height(
+ font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
- int xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
- int yco = (rect.ymax - U.widget_unit);
+ int xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
+ int yco = (rect.ymax - U.widget_unit);
- /* text label */
- UI_FontThemeColor(font_id, TH_TEXT_HI);
+ /* text label */
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
#ifdef WITH_INTERNATIONAL
- BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
#else
- BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
#endif
- /* grease pencil icon... */
- // XXX: is this too intrusive?
- GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- GPU_blend(true);
+ /* grease pencil icon... */
+ // XXX: is this too intrusive?
+ GPU_blend_set_func_separate(
+ GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
- xco -= U.widget_unit;
- yco -= (int)printable_size[1] / 2;
+ xco -= U.widget_unit;
+ yco -= (int)printable_size[1] / 2;
- UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
+ UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
- GPU_blend(false);
- }
+ GPU_blend(false);
+ }
}
/* draw grease-pencil datablock */
static void gp_draw_data(
- bGPdata *gpd, int offsx, int offsy, int winx, int winy,
- int cfra, int dflag, float alpha)
+ bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha)
{
- /* turn on smooth lines (i.e. anti-aliasing) */
- GPU_line_smooth(true);
+ /* turn on smooth lines (i.e. anti-aliasing) */
+ GPU_line_smooth(true);
- /* turn on alpha-blending */
- GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- GPU_blend(true);
+ /* turn on alpha-blending */
+ GPU_blend_set_func_separate(
+ GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
- /* draw! */
- gp_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ /* draw! */
+ gp_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
- /* turn off alpha blending, then smooth lines */
- GPU_blend(false); // alpha blending
- GPU_line_smooth(false); // smooth lines
+ /* turn off alpha blending, then smooth lines */
+ GPU_blend(false); // alpha blending
+ GPU_line_smooth(false); // smooth lines
}
/* if we have strokes for scenes (3d view)/clips (movie clip editor)
* and objects/tracks, multiple data blocks have to be drawn */
-static void gp_draw_data_all(
- Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy,
- int cfra, int dflag, const char spacetype)
+static void gp_draw_data_all(Scene *scene,
+ bGPdata *gpd,
+ int offsx,
+ int offsy,
+ int winx,
+ int winy,
+ int cfra,
+ int dflag,
+ const char spacetype)
{
- bGPdata *gpd_source = NULL;
- float alpha = 1.0f;
-
- if (scene) {
- if (spacetype == SPACE_VIEW3D) {
- gpd_source = (scene->gpd ? scene->gpd : NULL);
- }
- else if (spacetype == SPACE_CLIP && scene->clip) {
- /* currently drawing only gpencil data from either clip or track,
- * but not both - XXX fix logic behind */
- gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
- }
-
- if (gpd_source) {
- gp_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag, alpha);
- }
- }
-
- /* scene/clip data has already been drawn, only object/track data is drawn here
- * if gpd_source == gpd, we don't have any object/track data and we can skip */
- if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
- gp_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
- }
+ bGPdata *gpd_source = NULL;
+ float alpha = 1.0f;
+
+ if (scene) {
+ if (spacetype == SPACE_VIEW3D) {
+ gpd_source = (scene->gpd ? scene->gpd : NULL);
+ }
+ else if (spacetype == SPACE_CLIP && scene->clip) {
+ /* currently drawing only gpencil data from either clip or track,
+ * but not both - XXX fix logic behind */
+ gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
+ }
+
+ if (gpd_source) {
+ gp_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ }
+ }
+
+ /* scene/clip data has already been drawn, only object/track data is drawn here
+ * if gpd_source == gpd, we don't have any object/track data and we can skip */
+ if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
+ gp_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ }
}
/* ----- Grease Pencil Sketches Drawing API ------ */
@@ -983,66 +1023,67 @@ static void gp_draw_data_all(
/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
void ED_annotation_draw_2dimage(const bContext *C)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
-
- int offsx, offsy, sizex, sizey;
- int dflag = GP_DRAWDATA_NOSTATUS;
-
- bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX
- if (gpd == NULL) return;
-
- /* calculate rect */
- switch (sa->spacetype) {
- case SPACE_IMAGE: /* image */
- case SPACE_CLIP: /* clip */
- {
- /* just draw using standard scaling (settings here are currently ignored anyways) */
- /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
- offsx = 0;
- offsy = 0;
- sizex = ar->winx;
- sizey = ar->winy;
-
- wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax);
-
- dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK;
- break;
- }
- case SPACE_SEQ: /* sequence */
- {
- /* just draw using standard scaling (settings here are currently ignored anyways) */
- offsx = 0;
- offsy = 0;
- sizex = ar->winx;
- sizey = ar->winy;
-
- /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated
- * and everything moved to standard View2d
- */
- dflag |= GP_DRAWDATA_ONLYV2D;
- break;
- }
- default: /* for spacetype not yet handled */
- offsx = 0;
- offsy = 0;
- sizex = ar->winx;
- sizey = ar->winy;
-
- dflag |= GP_DRAWDATA_ONLYI2D;
- break;
- }
-
- if (ED_screen_animation_playing(wm)) {
- /* Don't show onion-skins during animation playback/scrub (i.e. it obscures the poses)
- * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes). */
- dflag |= GP_DRAWDATA_NO_ONIONS;
- }
-
- /* draw it! */
- gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+
+ int offsx, offsy, sizex, sizey;
+ int dflag = GP_DRAWDATA_NOSTATUS;
+
+ bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX
+ if (gpd == NULL)
+ return;
+
+ /* calculate rect */
+ switch (sa->spacetype) {
+ case SPACE_IMAGE: /* image */
+ case SPACE_CLIP: /* clip */
+ {
+ /* just draw using standard scaling (settings here are currently ignored anyways) */
+ /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
+ offsx = 0;
+ offsy = 0;
+ sizex = ar->winx;
+ sizey = ar->winy;
+
+ wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax);
+
+ dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK;
+ break;
+ }
+ case SPACE_SEQ: /* sequence */
+ {
+ /* just draw using standard scaling (settings here are currently ignored anyways) */
+ offsx = 0;
+ offsy = 0;
+ sizex = ar->winx;
+ sizey = ar->winy;
+
+ /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated
+ * and everything moved to standard View2d
+ */
+ dflag |= GP_DRAWDATA_ONLYV2D;
+ break;
+ }
+ default: /* for spacetype not yet handled */
+ offsx = 0;
+ offsy = 0;
+ sizex = ar->winx;
+ sizey = ar->winy;
+
+ dflag |= GP_DRAWDATA_ONLYI2D;
+ break;
+ }
+
+ if (ED_screen_animation_playing(wm)) {
+ /* Don't show onion-skins during animation playback/scrub (i.e. it obscures the poses)
+ * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes). */
+ dflag |= GP_DRAWDATA_NO_ONIONS;
+ }
+
+ /* draw it! */
+ gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
}
/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly
@@ -1050,95 +1091,96 @@ void ED_annotation_draw_2dimage(const bContext *C)
* second time with onlyv2d=false for screen-aligned strokes */
void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- int dflag = 0;
-
- /* check that we have grease-pencil stuff to draw */
- if (sa == NULL) return;
- bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX
- if (gpd == NULL) return;
-
- /* special hack for Image Editor */
- /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
- if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP))
- dflag |= GP_DRAWDATA_IEDITHACK;
-
- /* draw it! */
- if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
- if (ED_screen_animation_playing(wm)) dflag |= GP_DRAWDATA_NO_ONIONS;
-
- gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
-
- /* draw status text (if in screen/pixel-space) */
- if (!onlyv2d) {
- gp_draw_status_text(gpd, ar);
- }
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ int dflag = 0;
+
+ /* check that we have grease-pencil stuff to draw */
+ if (sa == NULL)
+ return;
+ bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX
+ if (gpd == NULL)
+ return;
+
+ /* special hack for Image Editor */
+ /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
+ if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP))
+ dflag |= GP_DRAWDATA_IEDITHACK;
+
+ /* draw it! */
+ if (onlyv2d)
+ dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
+ if (ED_screen_animation_playing(wm))
+ dflag |= GP_DRAWDATA_NO_ONIONS;
+
+ gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
+
+ /* draw status text (if in screen/pixel-space) */
+ if (!onlyv2d) {
+ gp_draw_status_text(gpd, ar);
+ }
}
-
/* draw annotations sketches to specified 3d-view assuming that matrices are already set correctly
* Note: this gets called twice - first time with only3d=true to draw 3d-strokes,
* second time with only3d=false for screen-aligned strokes */
void ED_annotation_draw_view3d(
- Scene *scene, struct Depsgraph *depsgraph,
- View3D *v3d, ARegion *ar,
- bool only3d)
+ Scene *scene, struct Depsgraph *depsgraph, View3D *v3d, ARegion *ar, bool only3d)
{
- int dflag = 0;
- RegionView3D *rv3d = ar->regiondata;
- int offsx, offsy, winx, winy;
-
- /* check that we have grease-pencil stuff to draw */
- /* XXX: Hardcoded reference here may get out of sync if we change how we fetch annotation data */
- bGPdata *gpd = scene->gpd;
- if (gpd == NULL) return;
-
- /* when rendering to the offscreen buffer we don't want to
- * deal with the camera border, otherwise map the coords to the camera border. */
- if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_FLAG_RENDER_VIEWPORT)) {
- rctf rectf;
- ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */
-
- offsx = round_fl_to_int(rectf.xmin);
- offsy = round_fl_to_int(rectf.ymin);
- winx = round_fl_to_int(rectf.xmax - rectf.xmin);
- winy = round_fl_to_int(rectf.ymax - rectf.ymin);
- }
- else {
- offsx = 0;
- offsy = 0;
- winx = ar->winx;
- winy = ar->winy;
- }
-
- /* set flags */
- if (only3d) {
- /* 3D strokes/3D space:
- * - only 3D space points
- * - don't status text either (as it's the wrong space)
- */
- dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
- }
-
- if (v3d->flag2 & V3D_HIDE_OVERLAYS) {
- /* don't draw status text when "only render" flag is set */
- dflag |= GP_DRAWDATA_NOSTATUS;
- }
-
- /* draw it! */
- gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
+ int dflag = 0;
+ RegionView3D *rv3d = ar->regiondata;
+ int offsx, offsy, winx, winy;
+
+ /* check that we have grease-pencil stuff to draw */
+ /* XXX: Hardcoded reference here may get out of sync if we change how we fetch annotation data */
+ bGPdata *gpd = scene->gpd;
+ if (gpd == NULL)
+ return;
+
+ /* when rendering to the offscreen buffer we don't want to
+ * deal with the camera border, otherwise map the coords to the camera border. */
+ if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_FLAG_RENDER_VIEWPORT)) {
+ rctf rectf;
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */
+
+ offsx = round_fl_to_int(rectf.xmin);
+ offsy = round_fl_to_int(rectf.ymin);
+ winx = round_fl_to_int(rectf.xmax - rectf.xmin);
+ winy = round_fl_to_int(rectf.ymax - rectf.ymin);
+ }
+ else {
+ offsx = 0;
+ offsy = 0;
+ winx = ar->winx;
+ winy = ar->winy;
+ }
+
+ /* set flags */
+ if (only3d) {
+ /* 3D strokes/3D space:
+ * - only 3D space points
+ * - don't status text either (as it's the wrong space)
+ */
+ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
+ }
+
+ if (v3d->flag2 & V3D_HIDE_OVERLAYS) {
+ /* don't draw status text when "only render" flag is set */
+ dflag |= GP_DRAWDATA_NOSTATUS;
+ }
+
+ /* draw it! */
+ gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
}
void ED_annotation_draw_ex(
- Scene *scene, bGPdata *gpd,
- int winx, int winy, const int cfra, const char spacetype)
+ Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
{
- int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D;
+ int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D;
- gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype);
+ gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype);
}
/* ************************************************** */
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index bfbf319b1c6..4933f081790 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -21,7 +21,6 @@
* \ingroup edgpencil
*/
-
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
@@ -61,7 +60,6 @@
#include "ED_view3d.h"
#include "ED_clip.h"
-
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_state.h"
@@ -81,132 +79,131 @@
/* values for tGPsdata->status */
typedef enum eGPencil_PaintStatus {
- GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
- GP_STATUS_PAINTING, /* a stroke is in progress */
- GP_STATUS_ERROR, /* something wasn't correctly set up */
- GP_STATUS_DONE, /* painting done */
- GP_STATUS_CAPTURE /* capture event, but cancel */
+ GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
+ GP_STATUS_PAINTING, /* a stroke is in progress */
+ GP_STATUS_ERROR, /* something wasn't correctly set up */
+ GP_STATUS_DONE, /* painting done */
+ GP_STATUS_CAPTURE /* capture event, but cancel */
} eGPencil_PaintStatus;
/* Return flags for adding points to stroke buffer */
typedef enum eGP_StrokeAdd_Result {
- GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */
- GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */
- GP_STROKEADD_NORMAL, /* point was successfully added */
- GP_STROKEADD_FULL, /* cannot add any more points to buffer */
+ GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */
+ GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */
+ GP_STROKEADD_NORMAL, /* point was successfully added */
+ GP_STROKEADD_FULL, /* cannot add any more points to buffer */
} eGP_StrokeAdd_Result;
/* Runtime flags */
typedef enum eGPencil_PaintFlags {
- GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
- GP_PAINTFLAG_STROKEADDED = (1 << 1),
- GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
- GP_PAINTFLAG_SELECTMASK = (1 << 3),
+ GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
+ GP_PAINTFLAG_STROKEADDED = (1 << 1),
+ GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
+ GP_PAINTFLAG_SELECTMASK = (1 << 3),
} eGPencil_PaintFlags;
-
/* Temporary 'Stroke' Operation data
* "p" = op->customdata
*/
typedef struct tGPsdata {
- Main *bmain;
- /** current scene from context. */
- Scene *scene;
- struct Depsgraph *depsgraph;
-
- /** window where painting originated. */
- wmWindow *win;
- /** area where painting originated. */
- ScrArea *sa;
- /** region where painting originated. */
- ARegion *ar;
- /** needed for GP_STROKE_2DSPACE. */
- View2D *v2d;
- /** for using the camera rect within the 3d view. */
- rctf *subrect;
- rctf subrect_data;
-
- /** settings to pass to gp_points_to_xy(). */
- GP_SpaceConversion gsc;
-
- /** pointer to owner of gp-datablock. */
- PointerRNA ownerPtr;
- /** gp-datablock layer comes from. */
- bGPdata *gpd;
- /** layer we're working on. */
- bGPDlayer *gpl;
- /** frame we're working on. */
- bGPDframe *gpf;
-
- /** projection-mode flags (toolsettings - eGPencil_Placement_Flags) */
- char *align_flag;
-
- /** current status of painting. */
- eGPencil_PaintStatus status;
- /** mode for painting. */
- eGPencil_PaintModes paintmode;
- /** flags that can get set during runtime (eGPencil_PaintFlags) */
- eGPencil_PaintFlags flags;
-
- /** radius of influence for eraser. */
- short radius;
-
- /** current mouse-position. */
- float mval[2];
- /** previous recorded mouse-position. */
- float mvalo[2];
-
- /** current stylus pressure. */
- float pressure;
- /** previous stylus pressure. */
- float opressure;
-
- /* These need to be doubles, as (at least under unix) they are in seconds since epoch,
- * float (and its 7 digits precision) is definitively not enough here!
- * double, with its 15 digits precision, ensures us millisecond precision for a few centuries at least.
- */
- /** Used when converting to path. */
- double inittime;
- /** Used when converting to path. */
- double curtime;
- /** Used when converting to path. */
- double ocurtime;
-
- /** Inverted transformation matrix applying when converting coords from screen-space
- * to region space. */
- float imat[4][4];
- float mat[4][4];
-
- /** custom color - hack for enforcing a particular color for track/mask editing. */
- float custom_color[4];
-
- /** radial cursor data for drawing eraser. */
- void *erasercursor;
-
- /** 1: line horizontal, 2: line vertical, other: not defined, second element position. */
- short straight[2];
-
- /** key used for invoking the operator. */
- short keymodifier;
+ Main *bmain;
+ /** current scene from context. */
+ Scene *scene;
+ struct Depsgraph *depsgraph;
+
+ /** window where painting originated. */
+ wmWindow *win;
+ /** area where painting originated. */
+ ScrArea *sa;
+ /** region where painting originated. */
+ ARegion *ar;
+ /** needed for GP_STROKE_2DSPACE. */
+ View2D *v2d;
+ /** for using the camera rect within the 3d view. */
+ rctf *subrect;
+ rctf subrect_data;
+
+ /** settings to pass to gp_points_to_xy(). */
+ GP_SpaceConversion gsc;
+
+ /** pointer to owner of gp-datablock. */
+ PointerRNA ownerPtr;
+ /** gp-datablock layer comes from. */
+ bGPdata *gpd;
+ /** layer we're working on. */
+ bGPDlayer *gpl;
+ /** frame we're working on. */
+ bGPDframe *gpf;
+
+ /** projection-mode flags (toolsettings - eGPencil_Placement_Flags) */
+ char *align_flag;
+
+ /** current status of painting. */
+ eGPencil_PaintStatus status;
+ /** mode for painting. */
+ eGPencil_PaintModes paintmode;
+ /** flags that can get set during runtime (eGPencil_PaintFlags) */
+ eGPencil_PaintFlags flags;
+
+ /** radius of influence for eraser. */
+ short radius;
+
+ /** current mouse-position. */
+ float mval[2];
+ /** previous recorded mouse-position. */
+ float mvalo[2];
+
+ /** current stylus pressure. */
+ float pressure;
+ /** previous stylus pressure. */
+ float opressure;
+
+ /* These need to be doubles, as (at least under unix) they are in seconds since epoch,
+ * float (and its 7 digits precision) is definitively not enough here!
+ * double, with its 15 digits precision, ensures us millisecond precision for a few centuries at least.
+ */
+ /** Used when converting to path. */
+ double inittime;
+ /** Used when converting to path. */
+ double curtime;
+ /** Used when converting to path. */
+ double ocurtime;
+
+ /** Inverted transformation matrix applying when converting coords from screen-space
+ * to region space. */
+ float imat[4][4];
+ float mat[4][4];
+
+ /** custom color - hack for enforcing a particular color for track/mask editing. */
+ float custom_color[4];
+
+ /** radial cursor data for drawing eraser. */
+ void *erasercursor;
+
+ /** 1: line horizontal, 2: line vertical, other: not defined, second element position. */
+ short straight[2];
+
+ /** key used for invoking the operator. */
+ short keymodifier;
} tGPsdata;
/* ------ */
/* Macros for accessing sensitivity thresholds... */
/* minimum number of pixels mouse should move before new point created */
-#define MIN_MANHATTEN_PX (U.gp_manhattendist)
+#define MIN_MANHATTEN_PX (U.gp_manhattendist)
/* minimum length of new segment before new point can be added */
-#define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
+#define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
static bool gp_stroke_added_check(tGPsdata *p)
{
- return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED);
+ return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED);
}
static void gp_stroke_added_enable(tGPsdata *p)
{
- BLI_assert(p->gpf->strokes.last != NULL);
- p->flags |= GP_PAINTFLAG_STROKEADDED;
+ BLI_assert(p->gpf->strokes.last != NULL);
+ p->flags |= GP_PAINTFLAG_STROKEADDED;
}
/* ------ */
@@ -220,43 +217,42 @@ static void gp_session_validatebuffer(tGPsdata *p);
/* check if context is suitable for drawing */
static bool gpencil_draw_poll(bContext *C)
{
- /* if is inside grease pencil draw mode cannot use annotations */
- Object *obact = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
- if ((sa) && (sa->spacetype == SPACE_VIEW3D)) {
- if ((obact) && (obact->type == OB_GPENCIL) &&
- (obact->mode == OB_MODE_PAINT_GPENCIL))
- {
- CTX_wm_operator_poll_msg_set(C, "Annotation cannot be used in grease pencil draw mode");
- return false;
- }
- }
-
- if (ED_operator_regionactive(C)) {
- /* check if current context can support GPencil data */
- if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
- /* check if Grease Pencil isn't already running */
- if (ED_gpencil_session_active() == 0)
- return true;
- else
- CTX_wm_operator_poll_msg_set(C, "Annotation operator is already active");
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
- }
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Active region not set");
- }
-
- return false;
+ /* if is inside grease pencil draw mode cannot use annotations */
+ Object *obact = CTX_data_active_object(C);
+ ScrArea *sa = CTX_wm_area(C);
+ if ((sa) && (sa->spacetype == SPACE_VIEW3D)) {
+ if ((obact) && (obact->type == OB_GPENCIL) && (obact->mode == OB_MODE_PAINT_GPENCIL)) {
+ CTX_wm_operator_poll_msg_set(C, "Annotation cannot be used in grease pencil draw mode");
+ return false;
+ }
+ }
+
+ if (ED_operator_regionactive(C)) {
+ /* check if current context can support GPencil data */
+ if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
+ /* check if Grease Pencil isn't already running */
+ if (ED_gpencil_session_active() == 0)
+ return true;
+ else
+ CTX_wm_operator_poll_msg_set(C, "Annotation operator is already active");
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
+ }
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ }
+
+ return false;
}
/* check if projecting strokes into 3d-geometry in the 3D-View */
static bool gpencil_project_check(tGPsdata *p)
{
- bGPdata *gpd = p->gpd;
- return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)));
+ bGPdata *gpd = p->gpd;
+ return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) &&
+ (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)));
}
/* ******************************************* */
@@ -267,10 +263,10 @@ static bool gpencil_project_check(tGPsdata *p)
/* get the reference point for stroke-point conversions */
static void gp_get_3d_reference(tGPsdata *p, float vec[3])
{
- const float *fp = p->scene->cursor.location;
+ const float *fp = p->scene->cursor.location;
- /* use 3D-cursor */
- copy_v3_v3(vec, fp);
+ /* use 3D-cursor */
+ copy_v3_v3(vec, fp);
}
/* Stroke Editing ---------------------------- */
@@ -278,91 +274,92 @@ static void gp_get_3d_reference(tGPsdata *p, float vec[3])
/* check if the current mouse position is suitable for adding a new point */
static bool gp_stroke_filtermval(tGPsdata *p, const float mval[2], float pmval[2])
{
- int dx = (int)fabsf(mval[0] - pmval[0]);
- int dy = (int)fabsf(mval[1] - pmval[1]);
-
- /* if buffer is empty, just let this go through (i.e. so that dots will work) */
- if (p->gpd->runtime.sbuffer_size == 0)
- return true;
-
- /* check if mouse moved at least certain distance on both axes (best case)
- * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
- */
- else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX))
- return true;
-
- /* check if the distance since the last point is significant enough
- * - prevents points being added too densely
- * - distance here doesn't use sqrt to prevent slowness... we should still be safe from overflows though
- */
- else if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX)
- return true;
-
- /* mouse 'didn't move' */
- else
- return false;
+ int dx = (int)fabsf(mval[0] - pmval[0]);
+ int dy = (int)fabsf(mval[1] - pmval[1]);
+
+ /* if buffer is empty, just let this go through (i.e. so that dots will work) */
+ if (p->gpd->runtime.sbuffer_size == 0)
+ return true;
+
+ /* check if mouse moved at least certain distance on both axes (best case)
+ * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
+ */
+ else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX))
+ return true;
+
+ /* check if the distance since the last point is significant enough
+ * - prevents points being added too densely
+ * - distance here doesn't use sqrt to prevent slowness... we should still be safe from overflows though
+ */
+ else if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX)
+ return true;
+
+ /* mouse 'didn't move' */
+ else
+ return false;
}
/* convert screen-coordinates to buffer-coordinates */
static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[3], float *depth)
{
- bGPdata *gpd = p->gpd;
-
- /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
- if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
- int mval_i[2];
- round_v2i_v2fl(mval_i, mval);
- if (gpencil_project_check(p) && (ED_view3d_autodist_simple(p->ar, mval_i, out, 0, depth))) {
- /* projecting onto 3D-Geometry
- * - nothing more needs to be done here, since view_autodist_simple() has already done it
- */
- }
- else {
- float mval_prj[2];
- float rvec[3], dvec[3];
- float zfac;
-
- /* Current method just converts each point in screen-coordinates to
- * 3D-coordinates using the 3D-cursor as reference. In general, this
- * works OK, but it could of course be improved.
- *
- * TODO:
- * - investigate using nearest point(s) on a previous stroke as
- * reference point instead or as offset, for easier stroke matching
- */
-
- gp_get_3d_reference(p, rvec);
- zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL);
-
- if (ED_view3d_project_float_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- float mval_f[2];
- sub_v2_v2v2(mval_f, mval_prj, mval);
- ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac);
- sub_v3_v3v3(out, rvec, dvec);
- }
- else {
- zero_v3(out);
- }
- }
- }
-
- /* 2d - on 'canvas' (assume that p->v2d is set) */
- else if ((gpd->runtime.sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
- UI_view2d_region_to_view(p->v2d, mval[0], mval[1], &out[0], &out[1]);
- mul_v3_m4v3(out, p->imat, out);
- }
-
- /* 2d - relative to screen (viewport area) */
- else {
- if (p->subrect == NULL) { /* normal 3D view */
- out[0] = (float)(mval[0]) / (float)(p->ar->winx) * 100;
- out[1] = (float)(mval[1]) / (float)(p->ar->winy) * 100;
- }
- else { /* camera view, use subrect */
- out[0] = ((mval[0] - p->subrect->xmin) / BLI_rctf_size_x(p->subrect)) * 100;
- out[1] = ((mval[1] - p->subrect->ymin) / BLI_rctf_size_y(p->subrect)) * 100;
- }
- }
+ bGPdata *gpd = p->gpd;
+
+ /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
+ if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, mval);
+ if (gpencil_project_check(p) && (ED_view3d_autodist_simple(p->ar, mval_i, out, 0, depth))) {
+ /* projecting onto 3D-Geometry
+ * - nothing more needs to be done here, since view_autodist_simple() has already done it
+ */
+ }
+ else {
+ float mval_prj[2];
+ float rvec[3], dvec[3];
+ float zfac;
+
+ /* Current method just converts each point in screen-coordinates to
+ * 3D-coordinates using the 3D-cursor as reference. In general, this
+ * works OK, but it could of course be improved.
+ *
+ * TODO:
+ * - investigate using nearest point(s) on a previous stroke as
+ * reference point instead or as offset, for easier stroke matching
+ */
+
+ gp_get_3d_reference(p, rvec);
+ zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL);
+
+ if (ED_view3d_project_float_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
+ V3D_PROJ_RET_OK) {
+ float mval_f[2];
+ sub_v2_v2v2(mval_f, mval_prj, mval);
+ ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(out, rvec, dvec);
+ }
+ else {
+ zero_v3(out);
+ }
+ }
+ }
+
+ /* 2d - on 'canvas' (assume that p->v2d is set) */
+ else if ((gpd->runtime.sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
+ UI_view2d_region_to_view(p->v2d, mval[0], mval[1], &out[0], &out[1]);
+ mul_v3_m4v3(out, p->imat, out);
+ }
+
+ /* 2d - relative to screen (viewport area) */
+ else {
+ if (p->subrect == NULL) { /* normal 3D view */
+ out[0] = (float)(mval[0]) / (float)(p->ar->winx) * 100;
+ out[1] = (float)(mval[1]) / (float)(p->ar->winy) * 100;
+ }
+ else { /* camera view, use subrect */
+ out[0] = ((mval[0] - p->subrect->xmin) / BLI_rctf_size_x(p->subrect)) * 100;
+ out[1] = ((mval[1] - p->subrect->ymin) / BLI_rctf_size_y(p->subrect)) * 100;
+ }
+ }
}
/* Apply smooth to buffer while drawing
@@ -376,188 +373,187 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[
*/
static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
{
- bGPdata *gpd = p->gpd;
- short num_points = gpd->runtime.sbuffer_size;
-
- /* Do nothing if not enough points to smooth out */
- if ((num_points < 3) || (idx < 3) || (inf == 0.0f)) {
- return;
- }
-
- tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
- float steps = 4.0f;
- if (idx < 4) {
- steps--;
- }
-
- tGPspoint *pta = idx >= 4 ? &points[idx - 4] : NULL;
- tGPspoint *ptb = idx >= 3 ? &points[idx - 3] : NULL;
- tGPspoint *ptc = idx >= 2 ? &points[idx - 2] : NULL;
- tGPspoint *ptd = &points[idx - 1];
-
- float sco[2] = { 0.0f };
- float a[2], b[2], c[2], d[2];
- const float average_fac = 1.0f / steps;
-
- /* Compute smoothed coordinate by taking the ones nearby */
- if (pta) {
- copy_v2_v2(a, &pta->x);
- madd_v2_v2fl(sco, a, average_fac);
- }
- if (ptb) {
- copy_v2_v2(b, &ptb->x);
- madd_v2_v2fl(sco, b, average_fac);
- }
- if (ptc) {
- copy_v2_v2(c, &ptc->x);
- madd_v2_v2fl(sco, c, average_fac);
- }
- if (ptd) {
- copy_v2_v2(d, &ptd->x);
- madd_v2_v2fl(sco, d, average_fac);
- }
-
- /* Based on influence factor, blend between original and optimal smoothed coordinate */
- interp_v2_v2v2(c, c, sco, inf);
- copy_v2_v2(&ptc->x, c);
+ bGPdata *gpd = p->gpd;
+ short num_points = gpd->runtime.sbuffer_size;
+
+ /* Do nothing if not enough points to smooth out */
+ if ((num_points < 3) || (idx < 3) || (inf == 0.0f)) {
+ return;
+ }
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ float steps = 4.0f;
+ if (idx < 4) {
+ steps--;
+ }
+
+ tGPspoint *pta = idx >= 4 ? &points[idx - 4] : NULL;
+ tGPspoint *ptb = idx >= 3 ? &points[idx - 3] : NULL;
+ tGPspoint *ptc = idx >= 2 ? &points[idx - 2] : NULL;
+ tGPspoint *ptd = &points[idx - 1];
+
+ float sco[2] = {0.0f};
+ float a[2], b[2], c[2], d[2];
+ const float average_fac = 1.0f / steps;
+
+ /* Compute smoothed coordinate by taking the ones nearby */
+ if (pta) {
+ copy_v2_v2(a, &pta->x);
+ madd_v2_v2fl(sco, a, average_fac);
+ }
+ if (ptb) {
+ copy_v2_v2(b, &ptb->x);
+ madd_v2_v2fl(sco, b, average_fac);
+ }
+ if (ptc) {
+ copy_v2_v2(c, &ptc->x);
+ madd_v2_v2fl(sco, c, average_fac);
+ }
+ if (ptd) {
+ copy_v2_v2(d, &ptd->x);
+ madd_v2_v2fl(sco, d, average_fac);
+ }
+
+ /* Based on influence factor, blend between original and optimal smoothed coordinate */
+ interp_v2_v2v2(c, c, sco, inf);
+ copy_v2_v2(&ptc->x, c);
}
/* add current stroke-point to buffer (returns whether point was successfully added) */
-static short gp_stroke_addpoint(
- tGPsdata *p, const float mval[2], float pressure, double curtime)
+static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
{
- bGPdata *gpd = p->gpd;
- tGPspoint *pt;
- ToolSettings *ts = p->scene->toolsettings;
-
- /* check painting mode */
- if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
- /* straight lines only - i.e. only store start and end point in buffer */
- if (gpd->runtime.sbuffer_size == 0) {
- /* first point in buffer (start point) */
- pt = (tGPspoint *)(gpd->runtime.sbuffer);
-
- /* store settings */
- copy_v2_v2(&pt->x, mval);
- /* T44932 - Pressure vals are unreliable, so ignore for now */
- pt->pressure = 1.0f;
- pt->strength = 1.0f;
- pt->time = (float)(curtime - p->inittime);
-
- /* increment buffer size */
- gpd->runtime.sbuffer_size++;
- }
- else {
- /* just reset the endpoint to the latest value
- * - assume that pointers for this are always valid...
- */
- pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
-
- /* store settings */
- copy_v2_v2(&pt->x, mval);
- /* T44932 - Pressure vals are unreliable, so ignore for now */
- pt->pressure = 1.0f;
- pt->strength = 1.0f;
- pt->time = (float)(curtime - p->inittime);
-
- /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
- gpd->runtime.sbuffer_size = 2;
- }
-
- /* can keep carrying on this way :) */
- return GP_STROKEADD_NORMAL;
- }
- else if (p->paintmode == GP_PAINTMODE_DRAW) { /* normal drawing */
- /* check if still room in buffer */
- if (gpd->runtime.sbuffer_size >= GP_STROKE_BUFFER_MAX)
- return GP_STROKEADD_OVERFLOW;
-
- /* get pointer to destination point */
- pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size);
-
- /* store settings */
- copy_v2_v2(&pt->x, mval);
- pt->pressure = pressure;
- /* unused for annotations, but initialise for easier conversions to GP Object */
- pt->strength = 1.0f;
-
- /* point time */
- pt->time = (float)(curtime - p->inittime);
-
- /* increment counters */
- gpd->runtime.sbuffer_size++;
- /* smooth while drawing previous points with a reduction factor for previous */
- for (int s = 0; s < 3; s++) {
- gp_smooth_buffer(p, 0.5f * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_size - s);
- }
-
- /* check if another operation can still occur */
- if (gpd->runtime.sbuffer_size == GP_STROKE_BUFFER_MAX)
- return GP_STROKEADD_FULL;
- else
- return GP_STROKEADD_NORMAL;
- }
- else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
- /* get pointer to destination point */
- pt = (tGPspoint *)(gpd->runtime.sbuffer);
-
- /* store settings */
- copy_v2_v2(&pt->x, mval);
- /* T44932 - Pressure vals are unreliable, so ignore for now */
- pt->pressure = 1.0f;
- pt->strength = 1.0f;
- pt->time = (float)(curtime - p->inittime);
-
- /* if there's stroke for this poly line session add (or replace last) point
- * to stroke. This allows to draw lines more interactively (see new segment
- * during mouse slide, e.g.)
- */
- if (gp_stroke_added_check(p)) {
- bGPDstroke *gps = p->gpf->strokes.last;
- bGPDspoint *pts;
-
- /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
- if (gpd->runtime.sbuffer_size == 0) {
- gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
- gps->totpoints++;
- }
-
- pts = &gps->points[gps->totpoints - 1];
-
- /* special case for poly lines: normally,
- * depth is needed only when creating new stroke from buffer,
- * but poly lines are converting to stroke instantly,
- * so initialize depth buffer before converting coordinates
- */
- if (gpencil_project_check(p)) {
- View3D *v3d = p->sa->spacedata.first;
-
- view3d_region_operator_needs_opengl(p->win, p->ar);
- ED_view3d_autodist_init(
- p->depsgraph, p->ar, v3d, (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
- }
-
- /* convert screen-coordinates to appropriate coordinates (and store them) */
- gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
-
- /* copy pressure and time */
- pts->pressure = pt->pressure;
- pts->strength = pt->strength;
- pts->time = pt->time;
-
- /* force fill recalc */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- }
-
- /* increment counters */
- if (gpd->runtime.sbuffer_size == 0)
- gpd->runtime.sbuffer_size++;
-
- return GP_STROKEADD_NORMAL;
- }
-
- /* return invalid state for now... */
- return GP_STROKEADD_INVALID;
+ bGPdata *gpd = p->gpd;
+ tGPspoint *pt;
+ ToolSettings *ts = p->scene->toolsettings;
+
+ /* check painting mode */
+ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
+ /* straight lines only - i.e. only store start and end point in buffer */
+ if (gpd->runtime.sbuffer_size == 0) {
+ /* first point in buffer (start point) */
+ pt = (tGPspoint *)(gpd->runtime.sbuffer);
+
+ /* store settings */
+ copy_v2_v2(&pt->x, mval);
+ /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ pt->time = (float)(curtime - p->inittime);
+
+ /* increment buffer size */
+ gpd->runtime.sbuffer_size++;
+ }
+ else {
+ /* just reset the endpoint to the latest value
+ * - assume that pointers for this are always valid...
+ */
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
+
+ /* store settings */
+ copy_v2_v2(&pt->x, mval);
+ /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ pt->time = (float)(curtime - p->inittime);
+
+ /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
+ gpd->runtime.sbuffer_size = 2;
+ }
+
+ /* can keep carrying on this way :) */
+ return GP_STROKEADD_NORMAL;
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW) { /* normal drawing */
+ /* check if still room in buffer */
+ if (gpd->runtime.sbuffer_size >= GP_STROKE_BUFFER_MAX)
+ return GP_STROKEADD_OVERFLOW;
+
+ /* get pointer to destination point */
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size);
+
+ /* store settings */
+ copy_v2_v2(&pt->x, mval);
+ pt->pressure = pressure;
+ /* unused for annotations, but initialise for easier conversions to GP Object */
+ pt->strength = 1.0f;
+
+ /* point time */
+ pt->time = (float)(curtime - p->inittime);
+
+ /* increment counters */
+ gpd->runtime.sbuffer_size++;
+ /* smooth while drawing previous points with a reduction factor for previous */
+ for (int s = 0; s < 3; s++) {
+ gp_smooth_buffer(p, 0.5f * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_size - s);
+ }
+
+ /* check if another operation can still occur */
+ if (gpd->runtime.sbuffer_size == GP_STROKE_BUFFER_MAX)
+ return GP_STROKEADD_FULL;
+ else
+ return GP_STROKEADD_NORMAL;
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+ /* get pointer to destination point */
+ pt = (tGPspoint *)(gpd->runtime.sbuffer);
+
+ /* store settings */
+ copy_v2_v2(&pt->x, mval);
+ /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ pt->time = (float)(curtime - p->inittime);
+
+ /* if there's stroke for this poly line session add (or replace last) point
+ * to stroke. This allows to draw lines more interactively (see new segment
+ * during mouse slide, e.g.)
+ */
+ if (gp_stroke_added_check(p)) {
+ bGPDstroke *gps = p->gpf->strokes.last;
+ bGPDspoint *pts;
+
+ /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
+ if (gpd->runtime.sbuffer_size == 0) {
+ gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ gps->totpoints++;
+ }
+
+ pts = &gps->points[gps->totpoints - 1];
+
+ /* special case for poly lines: normally,
+ * depth is needed only when creating new stroke from buffer,
+ * but poly lines are converting to stroke instantly,
+ * so initialize depth buffer before converting coordinates
+ */
+ if (gpencil_project_check(p)) {
+ View3D *v3d = p->sa->spacedata.first;
+
+ view3d_region_operator_needs_opengl(p->win, p->ar);
+ ED_view3d_autodist_init(
+ p->depsgraph, p->ar, v3d, (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
+ }
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
+
+ /* copy pressure and time */
+ pts->pressure = pt->pressure;
+ pts->strength = pt->strength;
+ pts->time = pt->time;
+
+ /* force fill recalc */
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ }
+
+ /* increment counters */
+ if (gpd->runtime.sbuffer_size == 0)
+ gpd->runtime.sbuffer_size++;
+
+ return GP_STROKEADD_NORMAL;
+ }
+
+ /* return invalid state for now... */
+ return GP_STROKEADD_INVALID;
}
/* simplify a stroke (in buffer) before storing it
@@ -566,266 +562,270 @@ static short gp_stroke_addpoint(
*/
static void gp_stroke_simplify(tGPsdata *p)
{
- bGPdata *gpd = p->gpd;
- tGPspoint *old_points = (tGPspoint *)gpd->runtime.sbuffer;
- short num_points = gpd->runtime.sbuffer_size;
- short flag = gpd->runtime.sbuffer_sflag;
- short i, j;
-
- /* only simplify if simplification is enabled, and we're not doing a straight line */
- if (!(U.gp_settings & GP_PAINT_DOSIMPLIFY) || (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT))
- return;
-
- /* don't simplify if less than 4 points in buffer */
- if ((num_points <= 4) || (old_points == NULL))
- return;
-
- /* clear buffer (but don't free mem yet) so that we can write to it
- * - firstly set sbuffer to NULL, so a new one is allocated
- * - secondly, reset flag after, as it gets cleared auto
- */
- gpd->runtime.sbuffer = NULL;
- gp_session_validatebuffer(p);
- gpd->runtime.sbuffer_sflag = flag;
+ bGPdata *gpd = p->gpd;
+ tGPspoint *old_points = (tGPspoint *)gpd->runtime.sbuffer;
+ short num_points = gpd->runtime.sbuffer_size;
+ short flag = gpd->runtime.sbuffer_sflag;
+ short i, j;
+
+ /* only simplify if simplification is enabled, and we're not doing a straight line */
+ if (!(U.gp_settings & GP_PAINT_DOSIMPLIFY) || (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT))
+ return;
+
+ /* don't simplify if less than 4 points in buffer */
+ if ((num_points <= 4) || (old_points == NULL))
+ return;
+
+ /* clear buffer (but don't free mem yet) so that we can write to it
+ * - firstly set sbuffer to NULL, so a new one is allocated
+ * - secondly, reset flag after, as it gets cleared auto
+ */
+ gpd->runtime.sbuffer = NULL;
+ gp_session_validatebuffer(p);
+ gpd->runtime.sbuffer_sflag = flag;
/* macro used in loop to get position of new point
* - used due to the mixture of datatypes in use here
*/
#define GP_SIMPLIFY_AVPOINT(offs, sfac) \
- { \
- co[0] += (float)(old_points[offs].x * sfac); \
- co[1] += (float)(old_points[offs].y * sfac); \
- pressure += old_points[offs].pressure * sfac; \
- time += old_points[offs].time * sfac; \
- } (void)0
-
- /* XXX Here too, do not lose start and end points! */
- gp_stroke_addpoint(p, &old_points->x, old_points->pressure, p->inittime + (double)old_points->time);
- for (i = 0, j = 0; i < num_points; i++) {
- if (i - j == 3) {
- float co[2], pressure, time;
- float mco[2];
-
- /* initialize values */
- co[0] = 0.0f;
- co[1] = 0.0f;
- pressure = 0.0f;
- time = 0.0f;
-
- /* using macro, calculate new point */
- GP_SIMPLIFY_AVPOINT(j, -0.25f);
- GP_SIMPLIFY_AVPOINT(j + 1, 0.75f);
- GP_SIMPLIFY_AVPOINT(j + 2, 0.75f);
- GP_SIMPLIFY_AVPOINT(j + 3, -0.25f);
-
- /* set values for adding */
- mco[0] = co[0];
- mco[1] = co[1];
-
- /* ignore return values on this... assume to be ok for now */
- gp_stroke_addpoint(p, mco, pressure, p->inittime + (double)time);
-
- j += 2;
- }
- }
- gp_stroke_addpoint(
- p, &old_points[num_points - 1].x, old_points[num_points - 1].pressure,
- p->inittime + (double)old_points[num_points - 1].time);
-
- /* free old buffer */
- MEM_freeN(old_points);
+ { \
+ co[0] += (float)(old_points[offs].x * sfac); \
+ co[1] += (float)(old_points[offs].y * sfac); \
+ pressure += old_points[offs].pressure * sfac; \
+ time += old_points[offs].time * sfac; \
+ } \
+ (void)0
+
+ /* XXX Here too, do not lose start and end points! */
+ gp_stroke_addpoint(
+ p, &old_points->x, old_points->pressure, p->inittime + (double)old_points->time);
+ for (i = 0, j = 0; i < num_points; i++) {
+ if (i - j == 3) {
+ float co[2], pressure, time;
+ float mco[2];
+
+ /* initialize values */
+ co[0] = 0.0f;
+ co[1] = 0.0f;
+ pressure = 0.0f;
+ time = 0.0f;
+
+ /* using macro, calculate new point */
+ GP_SIMPLIFY_AVPOINT(j, -0.25f);
+ GP_SIMPLIFY_AVPOINT(j + 1, 0.75f);
+ GP_SIMPLIFY_AVPOINT(j + 2, 0.75f);
+ GP_SIMPLIFY_AVPOINT(j + 3, -0.25f);
+
+ /* set values for adding */
+ mco[0] = co[0];
+ mco[1] = co[1];
+
+ /* ignore return values on this... assume to be ok for now */
+ gp_stroke_addpoint(p, mco, pressure, p->inittime + (double)time);
+
+ j += 2;
+ }
+ }
+ gp_stroke_addpoint(p,
+ &old_points[num_points - 1].x,
+ old_points[num_points - 1].pressure,
+ p->inittime + (double)old_points[num_points - 1].time);
+
+ /* free old buffer */
+ MEM_freeN(old_points);
}
/* make a new stroke from the buffer data */
static void gp_stroke_newfrombuffer(tGPsdata *p)
{
- bGPdata *gpd = p->gpd;
- bGPDlayer *gpl = p->gpl;
- bGPDstroke *gps;
- bGPDspoint *pt;
- tGPspoint *ptc;
- ToolSettings *ts = p->scene->toolsettings;
-
- int i, totelem;
- /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
- int depth_margin = (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
-
- /* get total number of points to allocate space for
- * - drawing straight-lines only requires the endpoints
- */
- if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)
- totelem = (gpd->runtime.sbuffer_size >= 2) ? 2 : gpd->runtime.sbuffer_size;
- else
- totelem = gpd->runtime.sbuffer_size;
-
- /* exit with error if no valid points from this stroke */
- if (totelem == 0) {
- if (G.debug & G_DEBUG)
- printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", gpd->runtime.sbuffer_size);
- return;
- }
-
- /* special case for poly line -- for already added stroke during session
- * coordinates are getting added to stroke immediately to allow more
- * interactive behavior
- */
- if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
- if (gp_stroke_added_check(p)) {
- return;
- }
- }
-
- /* allocate memory for a new stroke */
- gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
-
- /* copy appropriate settings for stroke */
- gps->totpoints = totelem;
- gps->thickness = gpl->thickness;
- gps->gradient_f = 1.0f;
- gps->gradient_s[0] = 1.0f;
- gps->gradient_s[1] = 1.0f;
- gps->flag = gpd->runtime.sbuffer_sflag;
- gps->inittime = p->inittime;
-
- /* enable recalculation flag by default (only used if hq fill) */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* allocate enough memory for a continuous array for storage points */
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
- gps->tot_triangles = 0;
-
- /* set pointer to first non-initialized point */
- pt = gps->points + (gps->totpoints - totelem);
-
- /* copy points from the buffer to the stroke */
- if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
- /* straight lines only -> only endpoints */
- {
- /* first point */
- ptc = gpd->runtime.sbuffer;
-
- /* convert screen-coordinates to appropriate coordinates (and store them) */
- gp_stroke_convertcoords(p, &ptc->x, &pt->x, 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;
-
- pt++;
- }
-
- if (totelem == 2) {
- /* last point if applicable */
- ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_size - 1);
-
- /* convert screen-coordinates to appropriate coordinates (and store them) */
- gp_stroke_convertcoords(p, &ptc->x, &pt->x, 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;
- }
- }
- else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
- /* first point */
- ptc = gpd->runtime.sbuffer;
-
- /* convert screen-coordinates to appropriate coordinates (and store them) */
- gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
-
- /* copy pressure and time */
- pt->pressure = ptc->pressure;
- pt->strength = ptc->strength;
- pt->time = ptc->time;
- }
- else {
- float *depth_arr = NULL;
-
- /* get an array of depths, far depths are blended */
- if (gpencil_project_check(p)) {
- int mval_i[2], mval_prev[2] = { 0 };
- int interp_depth = 0;
- int found_depth = 0;
-
- depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_size, "depth_points");
-
- for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size; i++, ptc++, pt++) {
- round_v2i_v2fl(mval_i, &ptc->x);
-
- if ((ED_view3d_autodist_depth(p->ar, mval_i, depth_margin, depth_arr + i) == 0) &&
- (i && (ED_view3d_autodist_depth_seg(p->ar, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
- {
- interp_depth = true;
- }
- else {
- found_depth = true;
- }
-
- copy_v2_v2_int(mval_prev, mval_i);
- }
-
- if (found_depth == false) {
- /* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
- for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--)
- depth_arr[i] = 0.9999f;
- }
- else {
- if (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) {
- /* remove all info between the valid endpoints */
- int first_valid = 0;
- int last_valid = 0;
-
- for (i = 0; i < gpd->runtime.sbuffer_size; i++) {
- if (depth_arr[i] != FLT_MAX)
- break;
- }
- first_valid = i;
-
- for (i = gpd->runtime.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->runtime.sbuffer_size, FLT_MAX);
- }
- }
- }
-
-
- pt = gps->points;
-
- /* convert all points (normal behavior) */
- for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.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;
- }
-
- if (depth_arr)
- MEM_freeN(depth_arr);
- }
-
- /* add stroke to frame */
- BLI_addtail(&p->gpf->strokes, gps);
- gp_stroke_added_enable(p);
+ bGPdata *gpd = p->gpd;
+ bGPDlayer *gpl = p->gpl;
+ bGPDstroke *gps;
+ bGPDspoint *pt;
+ tGPspoint *ptc;
+ ToolSettings *ts = p->scene->toolsettings;
+
+ int i, totelem;
+ /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
+ int depth_margin = (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
+
+ /* get total number of points to allocate space for
+ * - drawing straight-lines only requires the endpoints
+ */
+ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)
+ totelem = (gpd->runtime.sbuffer_size >= 2) ? 2 : gpd->runtime.sbuffer_size;
+ else
+ totelem = gpd->runtime.sbuffer_size;
+
+ /* exit with error if no valid points from this stroke */
+ if (totelem == 0) {
+ if (G.debug & G_DEBUG)
+ printf("Error: No valid points in stroke buffer to convert (tot=%d)\n",
+ gpd->runtime.sbuffer_size);
+ return;
+ }
+
+ /* special case for poly line -- for already added stroke during session
+ * coordinates are getting added to stroke immediately to allow more
+ * interactive behavior
+ */
+ if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+ if (gp_stroke_added_check(p)) {
+ return;
+ }
+ }
+
+ /* allocate memory for a new stroke */
+ gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
+
+ /* copy appropriate settings for stroke */
+ gps->totpoints = totelem;
+ gps->thickness = gpl->thickness;
+ gps->gradient_f = 1.0f;
+ gps->gradient_s[0] = 1.0f;
+ gps->gradient_s[1] = 1.0f;
+ gps->flag = gpd->runtime.sbuffer_sflag;
+ gps->inittime = p->inittime;
+
+ /* enable recalculation flag by default (only used if hq fill) */
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* allocate enough memory for a continuous array for storage points */
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->tot_triangles = 0;
+
+ /* set pointer to first non-initialized point */
+ pt = gps->points + (gps->totpoints - totelem);
+
+ /* copy points from the buffer to the stroke */
+ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
+ /* straight lines only -> only endpoints */
+ {
+ /* first point */
+ ptc = gpd->runtime.sbuffer;
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, 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;
+
+ pt++;
+ }
+
+ if (totelem == 2) {
+ /* last point if applicable */
+ ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_size - 1);
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, 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;
+ }
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+ /* first point */
+ ptc = gpd->runtime.sbuffer;
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+
+ /* copy pressure and time */
+ pt->pressure = ptc->pressure;
+ pt->strength = ptc->strength;
+ pt->time = ptc->time;
+ }
+ else {
+ float *depth_arr = NULL;
+
+ /* get an array of depths, far depths are blended */
+ if (gpencil_project_check(p)) {
+ int mval_i[2], mval_prev[2] = {0};
+ int interp_depth = 0;
+ int found_depth = 0;
+
+ depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_size, "depth_points");
+
+ for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size; i++, ptc++, pt++) {
+ round_v2i_v2fl(mval_i, &ptc->x);
+
+ if ((ED_view3d_autodist_depth(p->ar, mval_i, depth_margin, depth_arr + i) == 0) &&
+ (i && (ED_view3d_autodist_depth_seg(
+ p->ar, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
+ interp_depth = true;
+ }
+ else {
+ found_depth = true;
+ }
+
+ copy_v2_v2_int(mval_prev, mval_i);
+ }
+
+ if (found_depth == false) {
+ /* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
+ for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--)
+ depth_arr[i] = 0.9999f;
+ }
+ else {
+ if (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) {
+ /* remove all info between the valid endpoints */
+ int first_valid = 0;
+ int last_valid = 0;
+
+ for (i = 0; i < gpd->runtime.sbuffer_size; i++) {
+ if (depth_arr[i] != FLT_MAX)
+ break;
+ }
+ first_valid = i;
+
+ for (i = gpd->runtime.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->runtime.sbuffer_size, FLT_MAX);
+ }
+ }
+ }
+
+ pt = gps->points;
+
+ /* convert all points (normal behavior) */
+ for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.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;
+ }
+
+ if (depth_arr)
+ MEM_freeN(depth_arr);
+ }
+
+ /* add stroke to frame */
+ BLI_addtail(&p->gpf->strokes, gps);
+ gp_stroke_added_enable(p);
}
/* --- 'Eraser' for 'Paint' Tool ------ */
@@ -835,186 +835,186 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
*/
static void gp_free_stroke(bGPDframe *gpf, bGPDstroke *gps)
{
- if (gps->points) {
- MEM_freeN(gps->points);
- }
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
- if (gps->triangles) {
- MEM_freeN(gps->triangles);
- }
+ if (gps->triangles) {
+ MEM_freeN(gps->triangles);
+ }
- BLI_freelinkN(&gpf->strokes, gps);
+ BLI_freelinkN(&gpf->strokes, gps);
}
-
/* which which point is infront (result should only be used for comparison) */
static float view3d_point_depth(const RegionView3D *rv3d, const float co[3])
{
- if (rv3d->is_persp) {
- return ED_view3d_calc_zfac(rv3d, co, NULL);
- }
- else {
- return -dot_v3v3(rv3d->viewinv[2], co);
- }
+ if (rv3d->is_persp) {
+ return ED_view3d_calc_zfac(rv3d, co, NULL);
+ }
+ else {
+ return -dot_v3v3(rv3d->viewinv[2], co);
+ }
}
/* only erase stroke points that are visible (3d view) */
-static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y)
+static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
+ const bGPDspoint *pt,
+ const int x,
+ const int y)
{
- if ((p->sa->spacetype == SPACE_VIEW3D) &&
- (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH))
- {
- RegionView3D *rv3d = p->ar->regiondata;
- const int mval_i[2] = {x, y};
- float mval_3d[3];
-
- if (ED_view3d_autodist_simple(p->ar, mval_i, mval_3d, 0, NULL)) {
- const float depth_mval = view3d_point_depth(rv3d, mval_3d);
- const float depth_pt = view3d_point_depth(rv3d, &pt->x);
-
- if (depth_pt > depth_mval) {
- return true;
- }
- }
- }
- return false;
+ if ((p->sa->spacetype == SPACE_VIEW3D) && (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH)) {
+ RegionView3D *rv3d = p->ar->regiondata;
+ const int mval_i[2] = {x, y};
+ float mval_3d[3];
+
+ if (ED_view3d_autodist_simple(p->ar, mval_i, mval_3d, 0, NULL)) {
+ const float depth_mval = view3d_point_depth(rv3d, mval_3d);
+ const float depth_pt = view3d_point_depth(rv3d, &pt->x);
+
+ if (depth_pt > depth_mval) {
+ return true;
+ }
+ }
+ }
+ return false;
}
/* eraser tool - evaluation per stroke */
/* TODO: this could really do with some optimization (KD-Tree/BVH?) */
-static void gp_stroke_eraser_dostroke(
- tGPsdata *p,
- bGPDframe *gpf, bGPDstroke *gps,
- const float mval[2], const float mvalo[2],
- const int radius, const rcti *rect)
+static void gp_stroke_eraser_dostroke(tGPsdata *p,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ const float mval[2],
+ const float mvalo[2],
+ const int radius,
+ const rcti *rect)
{
- bGPDspoint *pt1, *pt2;
- int pc1[2] = {0};
- int pc2[2] = {0};
- int i;
- int mval_i[2];
- round_v2i_v2fl(mval_i, mval);
-
- if (gps->totpoints == 0) {
- /* just free stroke */
- gp_free_stroke(gpf, gps);
- }
- else if (gps->totpoints == 1) {
- /* only process if it hasn't been masked out... */
- if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
- gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
-
- /* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
- /* only check if point is inside */
- if (len_v2v2_int(mval_i, pc1) <= radius) {
- /* free stroke */
- gp_free_stroke(gpf, gps);
- }
- }
- }
- }
- else {
- /* Perform culling? */
- bool do_cull = false;
-
- /* Clear Tags
- *
- * Note: It's better this way, as we are sure that
- * we don't miss anything, though things will be
- * slightly slower as a result
- */
- for (i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- pt->flag &= ~GP_SPOINT_TAG;
- }
-
- /* First Pass: Loop over the points in the stroke
- * 1) Thin out parts of the stroke under the brush
- * 2) Tag "too thin" parts for removal (in second pass)
- */
- for (i = 0; (i + 1) < gps->totpoints; i++) {
- /* get points to work with */
- pt1 = gps->points + i;
- pt2 = gps->points + i + 1;
-
- /* only process if it hasn't been masked out... */
- if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
- continue;
-
- gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
- gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
-
- /* Check that point segment of the boundbox of the eraser stroke */
- if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
- ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1])))
- {
- /* Check if point segment of stroke had anything to do with
- * eraser region (either within stroke painted, or on its lines)
- * - this assumes that linewidth is irrelevant
- */
- if (gp_stroke_inside_circle(mval, mvalo, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
- if ((gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
- (gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false))
- {
- /* Edge is affected - Check individual points now */
- if (len_v2v2_int(mval_i, pc1) <= radius) {
- pt1->flag |= GP_SPOINT_TAG;
- }
- if (len_v2v2_int(mval_i, pc2) <= radius) {
- pt2->flag |= GP_SPOINT_TAG;
- }
- do_cull = true;
- }
- }
- }
- }
-
- /* Second Pass: Remove any points that are tagged */
- if (do_cull) {
- gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
- }
- }
+ bGPDspoint *pt1, *pt2;
+ int pc1[2] = {0};
+ int pc2[2] = {0};
+ int i;
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, mval);
+
+ if (gps->totpoints == 0) {
+ /* just free stroke */
+ gp_free_stroke(gpf, gps);
+ }
+ else if (gps->totpoints == 1) {
+ /* only process if it hasn't been masked out... */
+ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
+ gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
+
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ /* free stroke */
+ gp_free_stroke(gpf, gps);
+ }
+ }
+ }
+ }
+ else {
+ /* Perform culling? */
+ bool do_cull = false;
+
+ /* Clear Tags
+ *
+ * Note: It's better this way, as we are sure that
+ * we don't miss anything, though things will be
+ * slightly slower as a result
+ */
+ for (i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ pt->flag &= ~GP_SPOINT_TAG;
+ }
+
+ /* First Pass: Loop over the points in the stroke
+ * 1) Thin out parts of the stroke under the brush
+ * 2) Tag "too thin" parts for removal (in second pass)
+ */
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+ /* get points to work with */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ /* only process if it hasn't been masked out... */
+ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
+ continue;
+
+ gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
+ gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
+
+ /* Check that point segment of the boundbox of the eraser stroke */
+ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
+ /* Check if point segment of stroke had anything to do with
+ * eraser region (either within stroke painted, or on its lines)
+ * - this assumes that linewidth is irrelevant
+ */
+ if (gp_stroke_inside_circle(mval, mvalo, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ if ((gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
+ (gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) {
+ /* Edge is affected - Check individual points now */
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ pt1->flag |= GP_SPOINT_TAG;
+ }
+ if (len_v2v2_int(mval_i, pc2) <= radius) {
+ pt2->flag |= GP_SPOINT_TAG;
+ }
+ do_cull = true;
+ }
+ }
+ }
+ }
+
+ /* Second Pass: Remove any points that are tagged */
+ if (do_cull) {
+ gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
+ }
+ }
}
/* erase strokes which fall under the eraser strokes */
static void gp_stroke_doeraser(tGPsdata *p)
{
- bGPDframe *gpf = p->gpf;
- bGPDstroke *gps, *gpn;
- rcti rect;
-
- /* rect is rectangle of eraser */
- rect.xmin = p->mval[0] - p->radius;
- rect.ymin = p->mval[1] - p->radius;
- rect.xmax = p->mval[0] + p->radius;
- rect.ymax = p->mval[1] + p->radius;
-
- if (p->sa->spacetype == SPACE_VIEW3D) {
- if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) {
- View3D *v3d = p->sa->spacedata.first;
- view3d_region_operator_needs_opengl(p->win, p->ar);
- ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, 0);
- }
- }
-
- /* loop over strokes of active layer only (session init already took care of ensuring validity),
- * checking segments for intersections to remove
- */
- for (gps = gpf->strokes.first; gps; gps = gpn) {
- gpn = gps->next;
- /* Not all strokes in the datablock may be valid in the current editor/context
- * (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
- */
- if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
- gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->mvalo, p->radius, &rect);
- }
- }
+ bGPDframe *gpf = p->gpf;
+ bGPDstroke *gps, *gpn;
+ rcti rect;
+
+ /* rect is rectangle of eraser */
+ rect.xmin = p->mval[0] - p->radius;
+ rect.ymin = p->mval[1] - p->radius;
+ rect.xmax = p->mval[0] + p->radius;
+ rect.ymax = p->mval[1] + p->radius;
+
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) {
+ View3D *v3d = p->sa->spacedata.first;
+ view3d_region_operator_needs_opengl(p->win, p->ar);
+ ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, 0);
+ }
+ }
+
+ /* loop over strokes of active layer only (session init already took care of ensuring validity),
+ * checking segments for intersections to remove
+ */
+ for (gps = gpf->strokes.first; gps; gps = gpn) {
+ gpn = gps->next;
+ /* Not all strokes in the datablock may be valid in the current editor/context
+ * (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
+ */
+ if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
+ gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->mvalo, p->radius, &rect);
+ }
+ }
}
/* ******************************************* */
@@ -1023,462 +1023,456 @@ static void gp_stroke_doeraser(tGPsdata *p)
/* clear the session buffers (call this before AND after a paint operation) */
static void gp_session_validatebuffer(tGPsdata *p)
{
- bGPdata *gpd = p->gpd;
-
- /* clear memory of buffer (or allocate it if starting a new session) */
- if (gpd->runtime.sbuffer) {
- /* printf("\t\tGP - reset sbuffer\n"); */
- memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
- }
- else {
- /* printf("\t\tGP - allocate sbuffer\n"); */
- gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
- }
-
- /* reset indices */
- gpd->runtime.sbuffer_size = 0;
-
- /* reset flags */
- gpd->runtime.sbuffer_sflag = 0;
-
- /* reset inittime */
- p->inittime = 0.0;
+ bGPdata *gpd = p->gpd;
+
+ /* clear memory of buffer (or allocate it if starting a new session) */
+ if (gpd->runtime.sbuffer) {
+ /* printf("\t\tGP - reset sbuffer\n"); */
+ memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
+ }
+ else {
+ /* printf("\t\tGP - allocate sbuffer\n"); */
+ gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX,
+ "gp_session_strokebuffer");
+ }
+
+ /* reset indices */
+ gpd->runtime.sbuffer_size = 0;
+
+ /* reset flags */
+ gpd->runtime.sbuffer_sflag = 0;
+
+ /* reset inittime */
+ p->inittime = 0.0;
}
/* (re)init new painting data */
static bool gp_session_initdata(bContext *C, tGPsdata *p)
{
- Main *bmain = CTX_data_main(C);
- bGPdata **gpd_ptr = NULL;
- ScrArea *curarea = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- /* make sure the active view (at the starting time) is a 3d-view */
- if (curarea == NULL) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: No active view for painting\n");
- return 0;
- }
-
- /* pass on current scene and window */
- p->bmain = CTX_data_main(C);
- p->scene = CTX_data_scene(C);
- p->depsgraph = CTX_data_depsgraph(C);
- p->win = CTX_wm_window(C);
-
- unit_m4(p->imat);
- unit_m4(p->mat);
-
- switch (curarea->spacetype) {
- /* supported views first */
- case SPACE_VIEW3D:
- {
- /* View3D *v3d = curarea->spacedata.first; */
- /* RegionView3D *rv3d = ar->regiondata; */
-
- /* set current area
- * - must verify that region data is 3D-view (and not something else)
- */
- /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
- p->sa = curarea;
- p->ar = ar;
- p->align_flag = &ts->annotate_v3d_align;
-
- if (ar->regiondata == NULL) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: 3D-View active region doesn't have any region data, so cannot be drawable\n");
- return 0;
- }
- break;
- }
- case SPACE_NODE:
- {
- /* SpaceNode *snode = curarea->spacedata.first; */
-
- /* set current area */
- p->sa = curarea;
- p->ar = ar;
- p->v2d = &ar->v2d;
- p->align_flag = &ts->gpencil_v2d_align;
- break;
- }
- case SPACE_SEQ:
- {
- SpaceSeq *sseq = curarea->spacedata.first;
-
- /* set current area */
- p->sa = curarea;
- p->ar = ar;
- p->v2d = &ar->v2d;
- p->align_flag = &ts->gpencil_seq_align;
-
- /* check that gpencil data is allowed to be drawn */
- if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil\n");
- return 0;
- }
- break;
- }
- case SPACE_IMAGE:
- {
- /* SpaceImage *sima = curarea->spacedata.first; */
-
- /* set the current area */
- p->sa = curarea;
- p->ar = ar;
- p->v2d = &ar->v2d;
- p->align_flag = &ts->gpencil_ima_align;
- break;
- }
- case SPACE_CLIP:
- {
- SpaceClip *sc = curarea->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (clip == NULL) {
- p->status = GP_STATUS_ERROR;
- return false;
- }
-
- /* set the current area */
- p->sa = curarea;
- p->ar = ar;
- p->v2d = &ar->v2d;
- p->align_flag = &ts->gpencil_v2d_align;
-
- invert_m4_m4(p->imat, sc->unistabmat);
-
- /* custom color for new layer */
- p->custom_color[0] = 1.0f;
- p->custom_color[1] = 0.0f;
- p->custom_color[2] = 0.5f;
- p->custom_color[3] = 0.9f;
-
- if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
- int framenr = ED_space_clip_get_clip_frame_number(sc);
- MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
- MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL;
-
- if (marker) {
- p->imat[3][0] -= marker->pos[0];
- p->imat[3][1] -= marker->pos[1];
- }
- else {
- p->status = GP_STATUS_ERROR;
- return false;
- }
- }
-
- invert_m4_m4(p->mat, p->imat);
- copy_m4_m4(p->gsc.mat, p->mat);
- break;
- }
- /* unsupported views */
- default:
- {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: Annotations are not supported in this editor\n");
- return 0;
- }
- }
-
- /* get gp-data */
- gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr);
- if ((gpd_ptr == NULL) || !ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: Current context doesn't allow for any Annotation data\n");
- return 0;
- }
- else {
- /* if no existing GPencil block exists, add one */
- if (*gpd_ptr == NULL) {
- bGPdata *gpd = BKE_gpencil_data_addnew(bmain, "Annotations");
- *gpd_ptr = gpd;
-
- /* mark datablock as being used for annotations */
- gpd->flag |= GP_DATA_ANNOTATIONS;
- }
- p->gpd = *gpd_ptr;
- }
-
- if (ED_gpencil_session_active() == 0) {
- /* initialize undo stack,
- * also, existing undo stack would make buffer drawn
- */
- gpencil_undo_init(p->gpd);
- }
-
- /* clear out buffer (stored in gp-data), in case something contaminated it */
- gp_session_validatebuffer(p);
-
- return 1;
+ Main *bmain = CTX_data_main(C);
+ bGPdata **gpd_ptr = NULL;
+ ScrArea *curarea = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ /* make sure the active view (at the starting time) is a 3d-view */
+ if (curarea == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: No active view for painting\n");
+ return 0;
+ }
+
+ /* pass on current scene and window */
+ p->bmain = CTX_data_main(C);
+ p->scene = CTX_data_scene(C);
+ p->depsgraph = CTX_data_depsgraph(C);
+ p->win = CTX_wm_window(C);
+
+ unit_m4(p->imat);
+ unit_m4(p->mat);
+
+ switch (curarea->spacetype) {
+ /* supported views first */
+ case SPACE_VIEW3D: {
+ /* View3D *v3d = curarea->spacedata.first; */
+ /* RegionView3D *rv3d = ar->regiondata; */
+
+ /* set current area
+ * - must verify that region data is 3D-view (and not something else)
+ */
+ /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
+ p->sa = curarea;
+ p->ar = ar;
+ p->align_flag = &ts->annotate_v3d_align;
+
+ if (ar->regiondata == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf(
+ "Error: 3D-View active region doesn't have any region data, so cannot be "
+ "drawable\n");
+ return 0;
+ }
+ break;
+ }
+ case SPACE_NODE: {
+ /* SpaceNode *snode = curarea->spacedata.first; */
+
+ /* set current area */
+ p->sa = curarea;
+ p->ar = ar;
+ p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_v2d_align;
+ break;
+ }
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = curarea->spacedata.first;
+
+ /* set current area */
+ p->sa = curarea;
+ p->ar = ar;
+ p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_seq_align;
+
+ /* check that gpencil data is allowed to be drawn */
+ if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil\n");
+ return 0;
+ }
+ break;
+ }
+ case SPACE_IMAGE: {
+ /* SpaceImage *sima = curarea->spacedata.first; */
+
+ /* set the current area */
+ p->sa = curarea;
+ p->ar = ar;
+ p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_ima_align;
+ break;
+ }
+ case SPACE_CLIP: {
+ SpaceClip *sc = curarea->spacedata.first;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+
+ if (clip == NULL) {
+ p->status = GP_STATUS_ERROR;
+ return false;
+ }
+
+ /* set the current area */
+ p->sa = curarea;
+ p->ar = ar;
+ p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_v2d_align;
+
+ invert_m4_m4(p->imat, sc->unistabmat);
+
+ /* custom color for new layer */
+ p->custom_color[0] = 1.0f;
+ p->custom_color[1] = 0.0f;
+ p->custom_color[2] = 0.5f;
+ p->custom_color[3] = 0.9f;
+
+ if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+ MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
+ MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL;
+
+ if (marker) {
+ p->imat[3][0] -= marker->pos[0];
+ p->imat[3][1] -= marker->pos[1];
+ }
+ else {
+ p->status = GP_STATUS_ERROR;
+ return false;
+ }
+ }
+
+ invert_m4_m4(p->mat, p->imat);
+ copy_m4_m4(p->gsc.mat, p->mat);
+ break;
+ }
+ /* unsupported views */
+ default: {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: Annotations are not supported in this editor\n");
+ return 0;
+ }
+ }
+
+ /* get gp-data */
+ gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr);
+ if ((gpd_ptr == NULL) || !ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: Current context doesn't allow for any Annotation data\n");
+ return 0;
+ }
+ else {
+ /* if no existing GPencil block exists, add one */
+ if (*gpd_ptr == NULL) {
+ bGPdata *gpd = BKE_gpencil_data_addnew(bmain, "Annotations");
+ *gpd_ptr = gpd;
+
+ /* mark datablock as being used for annotations */
+ gpd->flag |= GP_DATA_ANNOTATIONS;
+ }
+ p->gpd = *gpd_ptr;
+ }
+
+ if (ED_gpencil_session_active() == 0) {
+ /* initialize undo stack,
+ * also, existing undo stack would make buffer drawn
+ */
+ gpencil_undo_init(p->gpd);
+ }
+
+ /* clear out buffer (stored in gp-data), in case something contaminated it */
+ gp_session_validatebuffer(p);
+
+ return 1;
}
/* init new painting session */
static tGPsdata *gp_session_initpaint(bContext *C)
{
- tGPsdata *p = NULL;
-
- /* create new context data */
- p = MEM_callocN(sizeof(tGPsdata), "Annotation Drawing Data");
-
- /* Try to initialise context data
- * WARNING: This may not always succeed (e.g. using GP in an annotation-only context)
- */
- if (gp_session_initdata(C, p) == 0) {
- /* Invalid state - Exit
- * NOTE: It should be safe to just free the data, since failing context checks should
- * only happen when no data has been allocated.
- */
- MEM_freeN(p);
- return NULL;
- }
-
- /* Radius for eraser circle is defined in userprefs */
- /* NOTE: we do this here, so that if we exit immediately,
- * erase size won't get lost
- */
- p->radius = U.gp_eraser;
-
- /* return context data for running paint operator */
- return p;
+ tGPsdata *p = NULL;
+
+ /* create new context data */
+ p = MEM_callocN(sizeof(tGPsdata), "Annotation Drawing Data");
+
+ /* Try to initialise context data
+ * WARNING: This may not always succeed (e.g. using GP in an annotation-only context)
+ */
+ if (gp_session_initdata(C, p) == 0) {
+ /* Invalid state - Exit
+ * NOTE: It should be safe to just free the data, since failing context checks should
+ * only happen when no data has been allocated.
+ */
+ MEM_freeN(p);
+ return NULL;
+ }
+
+ /* Radius for eraser circle is defined in userprefs */
+ /* NOTE: we do this here, so that if we exit immediately,
+ * erase size won't get lost
+ */
+ p->radius = U.gp_eraser;
+
+ /* return context data for running paint operator */
+ return p;
}
/* cleanup after a painting session */
static void gp_session_cleanup(tGPsdata *p)
{
- bGPdata *gpd = (p) ? p->gpd : NULL;
-
- /* error checking */
- if (gpd == NULL)
- return;
-
- /* free stroke buffer */
- if (gpd->runtime.sbuffer) {
- /* printf("\t\tGP - free sbuffer\n"); */
- MEM_freeN(gpd->runtime.sbuffer);
- gpd->runtime.sbuffer = NULL;
- }
-
- /* clear flags */
- gpd->runtime.sbuffer_size = 0;
- gpd->runtime.sbuffer_sflag = 0;
- p->inittime = 0.0;
+ bGPdata *gpd = (p) ? p->gpd : NULL;
+
+ /* error checking */
+ if (gpd == NULL)
+ return;
+
+ /* free stroke buffer */
+ if (gpd->runtime.sbuffer) {
+ /* printf("\t\tGP - free sbuffer\n"); */
+ MEM_freeN(gpd->runtime.sbuffer);
+ gpd->runtime.sbuffer = NULL;
+ }
+
+ /* clear flags */
+ gpd->runtime.sbuffer_size = 0;
+ gpd->runtime.sbuffer_sflag = 0;
+ p->inittime = 0.0;
}
static void gp_session_free(tGPsdata *p)
{
- MEM_freeN(p);
+ MEM_freeN(p);
}
-
/* init new stroke */
static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Depsgraph *depsgraph)
{
- Scene *scene = p->scene;
- ToolSettings *ts = scene->toolsettings;
-
- /* get active layer (or add a new one if non-existent) */
- p->gpl = BKE_gpencil_layer_getactive(p->gpd);
- if (p->gpl == NULL) {
- /* tag for annotations */
- p->gpd->flag |= GP_DATA_ANNOTATIONS;
- p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("Note"), true);
-
- if (p->custom_color[3])
- copy_v3_v3(p->gpl->color, p->custom_color);
- }
- if (p->gpl->flag & GP_LAYER_LOCKED) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: Cannot paint on locked layer\n");
- return;
- }
-
- /* get active frame (add a new one if not matching frame) */
- if (paintmode == GP_PAINTMODE_ERASER) {
- /* Eraser mode:
- * 1) Only allow erasing on the active layer (unlike for 3d-art Grease Pencil),
- * since we won't be exposing layer locking in the UI
- * 2) Ensure that p->gpf refers to the frame used for the active layer
- * (to avoid problems with other tools which expect it to exist)
- */
- bool has_layer_to_erase = false;
-
- if (gpencil_layer_is_editable(p->gpl)) {
- /* Ensure that there's stuff to erase here (not including selection mask below)... */
- if (p->gpl->actframe && p->gpl->actframe->strokes.first) {
- has_layer_to_erase = true;
- }
- }
-
- /* Ensure active frame is set correctly... */
- p->gpf = p->gpl->actframe;
-
- /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
- * (though this is only available in editmode)
- */
- if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
- if (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
- p->flags |= GP_PAINTFLAG_SELECTMASK;
- }
- }
-
- if (has_layer_to_erase == false) {
- p->status = GP_STATUS_CAPTURE;
- //if (G.debug & G_DEBUG)
- printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n");
- return;
- }
- }
- else {
- /* Drawing Modes - Add a new frame if needed on the active layer */
- short add_frame_mode = GP_GETFRAME_ADD_NEW;
-
- if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
- add_frame_mode = GP_GETFRAME_ADD_COPY;
- else
- add_frame_mode = GP_GETFRAME_ADD_NEW;
-
- p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
-
- if (p->gpf == NULL) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: No frame created (gpencil_paint_init)\n");
- return;
- }
- else {
- p->gpf->flag |= GP_FRAME_PAINT;
- }
- }
-
- /* set 'eraser' for this stroke if using eraser */
- p->paintmode = paintmode;
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER;
-
- /* check if we should respect depth while erasing */
- if (p->sa->spacetype == SPACE_VIEW3D) {
- if (p->gpl->flag & GP_LAYER_NO_XRAY) {
- p->flags |= GP_PAINTFLAG_V3D_ERASER_DEPTH;
- }
- }
- }
- else {
- /* disable eraser flags - so that we can switch modes during a session */
- p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER;
-
- if (p->sa->spacetype == SPACE_VIEW3D) {
- if (p->gpl->flag & GP_LAYER_NO_XRAY) {
- p->flags &= ~GP_PAINTFLAG_V3D_ERASER_DEPTH;
- }
- }
- }
-
- /* set 'initial run' flag, which is only used to denote when a new stroke is starting */
- p->flags |= GP_PAINTFLAG_FIRSTRUN;
-
-
- /* when drawing in the camera view, in 2D space, set the subrect */
- p->subrect = NULL;
- if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
- if (p->sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = p->sa->spacedata.first;
- RegionView3D *rv3d = p->ar->regiondata;
-
- /* for camera view set the subrect */
- if (rv3d->persp == RV3D_CAMOB) {
- /* no shift */
- ED_view3d_calc_camera_border(p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true);
- p->subrect = &p->subrect_data;
- }
- }
- }
-
- /* init stroke point space-conversion settings... */
- p->gsc.gpd = p->gpd;
- p->gsc.gpl = p->gpl;
-
- p->gsc.sa = p->sa;
- p->gsc.ar = p->ar;
- p->gsc.v2d = p->v2d;
-
- p->gsc.subrect_data = p->subrect_data;
- p->gsc.subrect = p->subrect;
-
- copy_m4_m4(p->gsc.mat, p->mat);
-
-
- /* check if points will need to be made in view-aligned space */
- if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
- switch (p->sa->spacetype) {
- case SPACE_VIEW3D:
- {
- p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
- break;
- }
- case SPACE_NODE:
- case SPACE_SEQ:
- case SPACE_IMAGE:
- case SPACE_CLIP:
- {
- p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE;
- break;
- }
- }
- }
+ Scene *scene = p->scene;
+ ToolSettings *ts = scene->toolsettings;
+
+ /* get active layer (or add a new one if non-existent) */
+ p->gpl = BKE_gpencil_layer_getactive(p->gpd);
+ if (p->gpl == NULL) {
+ /* tag for annotations */
+ p->gpd->flag |= GP_DATA_ANNOTATIONS;
+ p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("Note"), true);
+
+ if (p->custom_color[3])
+ copy_v3_v3(p->gpl->color, p->custom_color);
+ }
+ if (p->gpl->flag & GP_LAYER_LOCKED) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: Cannot paint on locked layer\n");
+ return;
+ }
+
+ /* get active frame (add a new one if not matching frame) */
+ if (paintmode == GP_PAINTMODE_ERASER) {
+ /* Eraser mode:
+ * 1) Only allow erasing on the active layer (unlike for 3d-art Grease Pencil),
+ * since we won't be exposing layer locking in the UI
+ * 2) Ensure that p->gpf refers to the frame used for the active layer
+ * (to avoid problems with other tools which expect it to exist)
+ */
+ bool has_layer_to_erase = false;
+
+ if (gpencil_layer_is_editable(p->gpl)) {
+ /* Ensure that there's stuff to erase here (not including selection mask below)... */
+ if (p->gpl->actframe && p->gpl->actframe->strokes.first) {
+ has_layer_to_erase = true;
+ }
+ }
+
+ /* Ensure active frame is set correctly... */
+ p->gpf = p->gpl->actframe;
+
+ /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
+ * (though this is only available in editmode)
+ */
+ if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ if (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
+ p->flags |= GP_PAINTFLAG_SELECTMASK;
+ }
+ }
+
+ if (has_layer_to_erase == false) {
+ p->status = GP_STATUS_CAPTURE;
+ //if (G.debug & G_DEBUG)
+ printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n");
+ return;
+ }
+ }
+ else {
+ /* Drawing Modes - Add a new frame if needed on the active layer */
+ short add_frame_mode = GP_GETFRAME_ADD_NEW;
+
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
+ add_frame_mode = GP_GETFRAME_ADD_COPY;
+ else
+ add_frame_mode = GP_GETFRAME_ADD_NEW;
+
+ p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
+
+ if (p->gpf == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: No frame created (gpencil_paint_init)\n");
+ return;
+ }
+ else {
+ p->gpf->flag |= GP_FRAME_PAINT;
+ }
+ }
+
+ /* set 'eraser' for this stroke if using eraser */
+ p->paintmode = paintmode;
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER;
+
+ /* check if we should respect depth while erasing */
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->gpl->flag & GP_LAYER_NO_XRAY) {
+ p->flags |= GP_PAINTFLAG_V3D_ERASER_DEPTH;
+ }
+ }
+ }
+ else {
+ /* disable eraser flags - so that we can switch modes during a session */
+ p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER;
+
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->gpl->flag & GP_LAYER_NO_XRAY) {
+ p->flags &= ~GP_PAINTFLAG_V3D_ERASER_DEPTH;
+ }
+ }
+ }
+
+ /* set 'initial run' flag, which is only used to denote when a new stroke is starting */
+ p->flags |= GP_PAINTFLAG_FIRSTRUN;
+
+ /* when drawing in the camera view, in 2D space, set the subrect */
+ p->subrect = NULL;
+ if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = p->sa->spacedata.first;
+ RegionView3D *rv3d = p->ar->regiondata;
+
+ /* for camera view set the subrect */
+ if (rv3d->persp == RV3D_CAMOB) {
+ /* no shift */
+ ED_view3d_calc_camera_border(
+ p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true);
+ p->subrect = &p->subrect_data;
+ }
+ }
+ }
+
+ /* init stroke point space-conversion settings... */
+ p->gsc.gpd = p->gpd;
+ p->gsc.gpl = p->gpl;
+
+ p->gsc.sa = p->sa;
+ p->gsc.ar = p->ar;
+ p->gsc.v2d = p->v2d;
+
+ p->gsc.subrect_data = p->subrect_data;
+ p->gsc.subrect = p->subrect;
+
+ copy_m4_m4(p->gsc.mat, p->mat);
+
+ /* check if points will need to be made in view-aligned space */
+ if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
+ switch (p->sa->spacetype) {
+ case SPACE_VIEW3D: {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
+ break;
+ }
+ case SPACE_NODE:
+ case SPACE_SEQ:
+ case SPACE_IMAGE:
+ case SPACE_CLIP: {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE;
+ break;
+ }
+ }
+ }
}
/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
static void gp_paint_strokeend(tGPsdata *p)
{
- ToolSettings *ts = p->scene->toolsettings;
- /* for surface sketching, need to set the right OpenGL context stuff so that
- * the conversions will project the values correctly...
- */
- if (gpencil_project_check(p)) {
- View3D *v3d = p->sa->spacedata.first;
-
- /* need to restore the original projection settings before packing up */
- view3d_region_operator_needs_opengl(p->win, p->ar);
- ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
- }
-
- /* check if doing eraser or not */
- if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
- /* simplify stroke before transferring? */
- gp_stroke_simplify(p);
-
- /* transfer stroke to frame */
- gp_stroke_newfrombuffer(p);
- }
-
- /* clean up buffer now */
- gp_session_validatebuffer(p);
+ ToolSettings *ts = p->scene->toolsettings;
+ /* for surface sketching, need to set the right OpenGL context stuff so that
+ * the conversions will project the values correctly...
+ */
+ if (gpencil_project_check(p)) {
+ View3D *v3d = p->sa->spacedata.first;
+
+ /* need to restore the original projection settings before packing up */
+ view3d_region_operator_needs_opengl(p->win, p->ar);
+ ED_view3d_autodist_init(
+ p->depsgraph, p->ar, v3d, (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
+ }
+
+ /* check if doing eraser or not */
+ if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
+ /* simplify stroke before transferring? */
+ gp_stroke_simplify(p);
+
+ /* transfer stroke to frame */
+ gp_stroke_newfrombuffer(p);
+ }
+
+ /* clean up buffer now */
+ gp_session_validatebuffer(p);
}
/* finish off stroke painting operation */
static void gp_paint_cleanup(tGPsdata *p)
{
- /* p->gpd==NULL happens when stroke failed to initialize,
- * for example when GP is hidden in current space (sergey)
- */
- if (p->gpd) {
- /* finish off a stroke */
- gp_paint_strokeend(p);
- }
-
- /* "unlock" frame */
- if (p->gpf)
- p->gpf->flag &= ~GP_FRAME_PAINT;
+ /* p->gpd==NULL happens when stroke failed to initialize,
+ * for example when GP is hidden in current space (sergey)
+ */
+ if (p->gpd) {
+ /* finish off a stroke */
+ gp_paint_strokeend(p);
+ }
+
+ /* "unlock" frame */
+ if (p->gpf)
+ p->gpf->flag &= ~GP_FRAME_PAINT;
}
/* ------------------------------- */
@@ -1486,216 +1480,227 @@ static void gp_paint_cleanup(tGPsdata *p)
/* Helper callback for drawing the cursor itself */
static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
{
- tGPsdata *p = (tGPsdata *)p_ptr;
+ tGPsdata *p = (tGPsdata *)p_ptr;
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- GPUVertFormat *format = immVertexFormat();
- const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ GPUVertFormat *format = immVertexFormat();
+ const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- GPU_line_smooth(true);
- GPU_blend(true);
- GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(
+ GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- immUniformColor4ub(255, 100, 100, 20);
- imm_draw_circle_fill_2d(shdr_pos, x, y, p->radius, 40);
+ immUniformColor4ub(255, 100, 100, 20);
+ imm_draw_circle_fill_2d(shdr_pos, x, y, p->radius, 40);
- immUnbindProgram();
+ immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
- immUniform1i("colors_len", 0); /* "simple" mode */
- immUniform1f("dash_width", 12.0f);
- immUniform1f("dash_factor", 0.5f);
+ immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniform1f("dash_width", 12.0f);
+ immUniform1f("dash_factor", 0.5f);
- imm_draw_circle_wire_2d(
- shdr_pos, x, y, p->radius,
- /* XXX Dashed shader gives bad results with sets of small segments currently,
- * temp hack around the issue. :( */
- max_ii(8, p->radius / 2)); /* was fixed 40 */
+ imm_draw_circle_wire_2d(
+ shdr_pos,
+ x,
+ y,
+ p->radius,
+ /* XXX Dashed shader gives bad results with sets of small segments currently,
+ * temp hack around the issue. :( */
+ max_ii(8, p->radius / 2)); /* was fixed 40 */
- immUnbindProgram();
+ immUnbindProgram();
- GPU_blend(false);
- GPU_line_smooth(false);
- }
+ GPU_blend(false);
+ GPU_line_smooth(false);
+ }
}
/* Turn brush cursor in 3D view on/off */
static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable)
{
- if (p->erasercursor && !enable) {
- /* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
- p->erasercursor = NULL;
- }
- else if (enable && !p->erasercursor) {
- /* enable cursor */
- p->erasercursor = WM_paint_cursor_activate(
- CTX_wm_manager(C),
- SPACE_TYPE_ANY, RGN_TYPE_ANY,
- NULL, /* XXX */
- gpencil_draw_eraser, p);
- }
+ if (p->erasercursor && !enable) {
+ /* clear cursor */
+ WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
+ p->erasercursor = NULL;
+ }
+ else if (enable && !p->erasercursor) {
+ /* enable cursor */
+ p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ NULL, /* XXX */
+ gpencil_draw_eraser,
+ p);
+ }
}
/* Check if tablet eraser is being used (when processing events) */
static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
{
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- return (wmtab->Active == EVT_TABLET_ERASER);
- }
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+ return (wmtab->Active == EVT_TABLET_ERASER);
+ }
- return false;
+ return false;
}
/* ------------------------------- */
static void gpencil_draw_exit(bContext *C, wmOperator *op)
{
- tGPsdata *p = op->customdata;
-
- /* restore cursor to indicate end of drawing */
- WM_cursor_modal_restore(CTX_wm_window(C));
-
- /* don't assume that operator data exists at all */
- if (p) {
- /* check size of buffer before cleanup, to determine if anything happened here */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- /* turn off radial brush cursor */
- gpencil_draw_toggle_eraser_cursor(C, p, false);
- }
-
- /* always store the new eraser size to be used again next time
- * NOTE: Do this even when not in eraser mode, as eraser may
- * have been toggled at some point.
- */
- U.gp_eraser = p->radius;
-
- /* clear undo stack */
- gpencil_undo_finish();
-
- /* cleanup */
- gp_paint_cleanup(p);
- gp_session_cleanup(p);
- gp_session_free(p);
- p = NULL;
- }
-
- op->customdata = NULL;
+ tGPsdata *p = op->customdata;
+
+ /* restore cursor to indicate end of drawing */
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ /* don't assume that operator data exists at all */
+ if (p) {
+ /* check size of buffer before cleanup, to determine if anything happened here */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ /* turn off radial brush cursor */
+ gpencil_draw_toggle_eraser_cursor(C, p, false);
+ }
+
+ /* always store the new eraser size to be used again next time
+ * NOTE: Do this even when not in eraser mode, as eraser may
+ * have been toggled at some point.
+ */
+ U.gp_eraser = p->radius;
+
+ /* clear undo stack */
+ gpencil_undo_finish();
+
+ /* cleanup */
+ gp_paint_cleanup(p);
+ gp_session_cleanup(p);
+ gp_session_free(p);
+ p = NULL;
+ }
+
+ op->customdata = NULL;
}
static void gpencil_draw_cancel(bContext *C, wmOperator *op)
{
- /* this is just a wrapper around exit() */
- gpencil_draw_exit(C, op);
+ /* this is just a wrapper around exit() */
+ gpencil_draw_exit(C, op);
}
/* ------------------------------- */
-
static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGPsdata *p;
- eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
-
- /* check context */
- p = op->customdata = gp_session_initpaint(C);
- if ((p == NULL) || (p->status == GP_STATUS_ERROR)) {
- /* something wasn't set correctly in context */
- gpencil_draw_exit(C, op);
- return 0;
- }
-
- /* init painting data */
- gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C));
- if (p->status == GP_STATUS_ERROR) {
- gpencil_draw_exit(C, op);
- return 0;
- }
-
- if (event != NULL) {
- p->keymodifier = event->keymodifier;
- }
- else {
- p->keymodifier = -1;
- }
-
- /* everything is now setup ok */
- return 1;
+ tGPsdata *p;
+ eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
+
+ /* check context */
+ p = op->customdata = gp_session_initpaint(C);
+ if ((p == NULL) || (p->status == GP_STATUS_ERROR)) {
+ /* something wasn't set correctly in context */
+ gpencil_draw_exit(C, op);
+ return 0;
+ }
+
+ /* init painting data */
+ gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C));
+ if (p->status == GP_STATUS_ERROR) {
+ gpencil_draw_exit(C, op);
+ return 0;
+ }
+
+ if (event != NULL) {
+ p->keymodifier = event->keymodifier;
+ }
+ else {
+ p->keymodifier = -1;
+ }
+
+ /* everything is now setup ok */
+ return 1;
}
-
/* ------------------------------- */
/* ensure that the correct cursor icon is set */
static void gpencil_draw_cursor_set(tGPsdata *p)
{
- if (p->paintmode == GP_PAINTMODE_ERASER)
- WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
- else
- WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
+ if (p->paintmode == GP_PAINTMODE_ERASER)
+ WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ else
+ WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
}
/* update UI indicators of status, including cursor and header prints */
static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
{
- /* header prints */
- switch (p->status) {
- case GP_STATUS_PAINTING:
- switch (p->paintmode) {
- case GP_PAINTMODE_DRAW_POLY:
- /* Provide usage tips, since this is modal, and unintuitive without hints */
- ED_workspace_status_text(C, IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | "
- "ESC/Enter to end (or click outside this area)"));
- break;
- default:
- /* Do nothing - the others are self explanatory, exit quickly once the mouse is released
- * Showing any text would just be annoying as it would flicker.
- */
- break;
- }
- break;
-
- case GP_STATUS_IDLING:
- /* print status info */
- switch (p->paintmode) {
- case GP_PAINTMODE_ERASER:
- ED_workspace_status_text(C, IFACE_("Annotation Eraser: Hold and drag LMB or RMB to erase | "
- "ESC/Enter to end (or click outside this area)"));
- break;
- case GP_PAINTMODE_DRAW_STRAIGHT:
- ED_workspace_status_text(C, IFACE_("Annotation Line Draw: Hold and drag LMB to draw | "
- "ESC/Enter to end (or click outside this area)"));
- break;
- case GP_PAINTMODE_DRAW:
- ED_workspace_status_text(C, IFACE_("Annotation Freehand Draw: Hold and drag LMB to draw | "
- "E/ESC/Enter to end (or click outside this area)"));
- break;
- case GP_PAINTMODE_DRAW_POLY:
- ED_workspace_status_text(C, IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | "
- "ESC/Enter to end (or click outside this area)"));
- break;
-
- default: /* unhandled future cases */
- ED_workspace_status_text(C, IFACE_("Annotation Session: ESC/Enter to end (or click outside this area)"));
- break;
- }
- break;
-
- case GP_STATUS_ERROR:
- case GP_STATUS_DONE:
- case GP_STATUS_CAPTURE:
- /* clear status string */
- ED_workspace_status_text(C, NULL);
- break;
- }
+ /* header prints */
+ switch (p->status) {
+ case GP_STATUS_PAINTING:
+ switch (p->paintmode) {
+ case GP_PAINTMODE_DRAW_POLY:
+ /* Provide usage tips, since this is modal, and unintuitive without hints */
+ ED_workspace_status_text(
+ C,
+ IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ default:
+ /* Do nothing - the others are self explanatory, exit quickly once the mouse is released
+ * Showing any text would just be annoying as it would flicker.
+ */
+ break;
+ }
+ break;
+
+ case GP_STATUS_IDLING:
+ /* print status info */
+ switch (p->paintmode) {
+ case GP_PAINTMODE_ERASER:
+ ED_workspace_status_text(C,
+ IFACE_("Annotation Eraser: Hold and drag LMB or RMB to erase | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ case GP_PAINTMODE_DRAW_STRAIGHT:
+ ED_workspace_status_text(C,
+ IFACE_("Annotation Line Draw: Hold and drag LMB to draw | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ case GP_PAINTMODE_DRAW:
+ ED_workspace_status_text(C,
+ IFACE_("Annotation Freehand Draw: Hold and drag LMB to draw | "
+ "E/ESC/Enter to end (or click outside this area)"));
+ break;
+ case GP_PAINTMODE_DRAW_POLY:
+ ED_workspace_status_text(
+ C,
+ IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+
+ default: /* unhandled future cases */
+ ED_workspace_status_text(
+ C, IFACE_("Annotation Session: ESC/Enter to end (or click outside this area)"));
+ break;
+ }
+ break;
+
+ case GP_STATUS_ERROR:
+ case GP_STATUS_DONE:
+ case GP_STATUS_CAPTURE:
+ /* clear status string */
+ ED_workspace_status_text(C, NULL);
+ break;
+ }
}
/* ------------------------------- */
@@ -1703,169 +1708,170 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
/* create a new stroke point at the point indicated by the painting context */
static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
{
- /* handle drawing/erasing -> test for erasing first */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- /* do 'live' erasing now */
- gp_stroke_doeraser(p);
-
- /* store used values */
- p->mvalo[0] = p->mval[0];
- p->mvalo[1] = p->mval[1];
- p->opressure = p->pressure;
- }
- /* only add current point to buffer if mouse moved (even though we got an event, it might be just noise) */
- else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) {
- /* try to add point */
- short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
-
- /* handle errors while adding point */
- if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
- /* finish off old stroke */
- gp_paint_strokeend(p);
- /* And start a new one!!! Else, projection errors! */
- gp_paint_initstroke(p, p->paintmode, depsgraph);
-
- /* start a new stroke, starting from previous point */
- /* XXX Must manually reset inittime... */
- /* XXX We only need to reuse previous point if overflow! */
- if (ok == GP_STROKEADD_OVERFLOW) {
- p->inittime = p->ocurtime;
- gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime);
- }
- else {
- p->inittime = p->curtime;
- }
- gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
- }
- else if (ok == GP_STROKEADD_INVALID) {
- /* the painting operation cannot continue... */
- BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke");
- p->status = GP_STATUS_ERROR;
-
- if (G.debug & G_DEBUG)
- printf("Error: Grease-Pencil Paint - Add Point Invalid\n");
- return;
- }
-
- /* store used values */
- p->mvalo[0] = p->mval[0];
- p->mvalo[1] = p->mval[1];
- p->opressure = p->pressure;
- p->ocurtime = p->curtime;
- }
+ /* handle drawing/erasing -> test for erasing first */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ /* do 'live' erasing now */
+ gp_stroke_doeraser(p);
+
+ /* store used values */
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ p->opressure = p->pressure;
+ }
+ /* only add current point to buffer if mouse moved (even though we got an event, it might be just noise) */
+ else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) {
+ /* try to add point */
+ short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+
+ /* handle errors while adding point */
+ if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
+ /* finish off old stroke */
+ gp_paint_strokeend(p);
+ /* And start a new one!!! Else, projection errors! */
+ gp_paint_initstroke(p, p->paintmode, depsgraph);
+
+ /* start a new stroke, starting from previous point */
+ /* XXX Must manually reset inittime... */
+ /* XXX We only need to reuse previous point if overflow! */
+ if (ok == GP_STROKEADD_OVERFLOW) {
+ p->inittime = p->ocurtime;
+ gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime);
+ }
+ else {
+ p->inittime = p->curtime;
+ }
+ gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+ }
+ else if (ok == GP_STROKEADD_INVALID) {
+ /* the painting operation cannot continue... */
+ BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke");
+ p->status = GP_STATUS_ERROR;
+
+ if (G.debug & G_DEBUG)
+ printf("Error: Grease-Pencil Paint - Add Point Invalid\n");
+ return;
+ }
+
+ /* store used values */
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ p->opressure = p->pressure;
+ p->ocurtime = p->curtime;
+ }
}
/* handle draw event */
-static void annotation_draw_apply_event(wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y)
+static void annotation_draw_apply_event(
+ wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y)
{
- tGPsdata *p = op->customdata;
- PointerRNA itemptr;
- float mousef[2];
- int tablet = 0;
-
- /* convert from window-space to area-space mouse coordinates
- * add any x,y override position for fake events
- */
- p->mval[0] = (float)event->mval[0] - x;
- p->mval[1] = (float)event->mval[1] - y;
-
- /* verify key status for straight lines */
- if ((event->ctrl > 0) || (event->alt > 0)) {
- if (p->straight[0] == 0) {
- int dx = abs((int)(p->mval[0] - p->mvalo[0]));
- int dy = abs((int)(p->mval[1] - p->mvalo[1]));
- if ((dx > 0) || (dy > 0)) {
- /* check mouse direction to replace the other coordinate with previous values */
- if (dx >= dy) {
- /* horizontal */
- p->straight[0] = 1;
- p->straight[1] = p->mval[1]; /* save y */
- }
- else {
- /* vertical */
- p->straight[0] = 2;
- p->straight[1] = p->mval[0]; /* save x */
- }
- }
- }
- }
- else {
- p->straight[0] = 0;
- }
-
- p->curtime = PIL_check_seconds_timer();
-
- /* handle pressure sensitivity (which is supplied by tablets) */
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
-
- tablet = (wmtab->Active != EVT_TABLET_NONE);
- p->pressure = wmtab->Pressure;
-
- /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
- * The pen has to float over the tablet surface, resulting in
- * zero pressure (T47101). Ignore pressure values if floating
- * (i.e. "effectively zero" pressure), and only when the "active"
- * end is the stylus (i.e. the default when not eraser)
- */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
- p->pressure = 1.0f;
- }
- }
- }
- else {
- /* No tablet data -> No pressure info is available */
- p->pressure = 1.0f;
- }
-
- /* special exception for start of strokes (i.e. maybe for just a dot) */
- if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
- p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
-
- p->mvalo[0] = p->mval[0];
- p->mvalo[1] = p->mval[1];
- p->opressure = p->pressure;
- p->inittime = p->ocurtime = p->curtime;
- p->straight[0] = 0;
- p->straight[1] = 0;
-
- /* special exception here for too high pressure values on first touch in
- * windows for some tablets, then we just skip first touch...
- */
- if (tablet && (p->pressure >= 0.99f))
- return;
- }
-
- /* check if alt key is pressed and limit to straight lines */
- if ((p->paintmode != GP_PAINTMODE_ERASER) && (p->straight[0] != 0)) {
- if (p->straight[0] == 1) {
- /* horizontal */
- p->mval[1] = p->straight[1]; /* replace y */
- }
- else {
- /* vertical */
- p->mval[0] = p->straight[1]; /* replace x */
- }
- }
-
- /* fill in stroke data (not actually used directly by gpencil_draw_apply) */
- RNA_collection_add(op->ptr, "stroke", &itemptr);
-
- mousef[0] = p->mval[0];
- mousef[1] = p->mval[1];
- RNA_float_set_array(&itemptr, "mouse", mousef);
- RNA_float_set(&itemptr, "pressure", p->pressure);
- RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN) != 0);
-
- RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
-
- /* apply the current latest drawing point */
- gpencil_draw_apply(op, p, depsgraph);
-
- /* force refresh */
- /* just active area for now, since doing whole screen is too slow */
- ED_region_tag_redraw(p->ar);
+ tGPsdata *p = op->customdata;
+ PointerRNA itemptr;
+ float mousef[2];
+ int tablet = 0;
+
+ /* convert from window-space to area-space mouse coordinates
+ * add any x,y override position for fake events
+ */
+ p->mval[0] = (float)event->mval[0] - x;
+ p->mval[1] = (float)event->mval[1] - y;
+
+ /* verify key status for straight lines */
+ if ((event->ctrl > 0) || (event->alt > 0)) {
+ if (p->straight[0] == 0) {
+ int dx = abs((int)(p->mval[0] - p->mvalo[0]));
+ int dy = abs((int)(p->mval[1] - p->mvalo[1]));
+ if ((dx > 0) || (dy > 0)) {
+ /* check mouse direction to replace the other coordinate with previous values */
+ if (dx >= dy) {
+ /* horizontal */
+ p->straight[0] = 1;
+ p->straight[1] = p->mval[1]; /* save y */
+ }
+ else {
+ /* vertical */
+ p->straight[0] = 2;
+ p->straight[1] = p->mval[0]; /* save x */
+ }
+ }
+ }
+ }
+ else {
+ p->straight[0] = 0;
+ }
+
+ p->curtime = PIL_check_seconds_timer();
+
+ /* handle pressure sensitivity (which is supplied by tablets) */
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+
+ tablet = (wmtab->Active != EVT_TABLET_NONE);
+ p->pressure = wmtab->Pressure;
+
+ /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
+ * The pen has to float over the tablet surface, resulting in
+ * zero pressure (T47101). Ignore pressure values if floating
+ * (i.e. "effectively zero" pressure), and only when the "active"
+ * end is the stylus (i.e. the default when not eraser)
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
+ p->pressure = 1.0f;
+ }
+ }
+ }
+ else {
+ /* No tablet data -> No pressure info is available */
+ p->pressure = 1.0f;
+ }
+
+ /* special exception for start of strokes (i.e. maybe for just a dot) */
+ if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
+ p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
+
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ p->opressure = p->pressure;
+ p->inittime = p->ocurtime = p->curtime;
+ p->straight[0] = 0;
+ p->straight[1] = 0;
+
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets, then we just skip first touch...
+ */
+ if (tablet && (p->pressure >= 0.99f))
+ return;
+ }
+
+ /* check if alt key is pressed and limit to straight lines */
+ if ((p->paintmode != GP_PAINTMODE_ERASER) && (p->straight[0] != 0)) {
+ if (p->straight[0] == 1) {
+ /* horizontal */
+ p->mval[1] = p->straight[1]; /* replace y */
+ }
+ else {
+ /* vertical */
+ p->mval[0] = p->straight[1]; /* replace x */
+ }
+ }
+
+ /* fill in stroke data (not actually used directly by gpencil_draw_apply) */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ mousef[0] = p->mval[0];
+ mousef[1] = p->mval[1];
+ RNA_float_set_array(&itemptr, "mouse", mousef);
+ RNA_float_set(&itemptr, "pressure", p->pressure);
+ RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN) != 0);
+
+ RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
+
+ /* apply the current latest drawing point */
+ gpencil_draw_apply(op, p, depsgraph);
+
+ /* force refresh */
+ /* just active area for now, since doing whole screen is too slow */
+ ED_region_tag_redraw(p->ar);
}
/* ------------------------------- */
@@ -1873,74 +1879,74 @@ static void annotation_draw_apply_event(wmOperator *op, const wmEvent *event, De
/* operator 'redo' (i.e. after changing some properties, but also for repeat last) */
static int gpencil_draw_exec(bContext *C, wmOperator *op)
{
- tGPsdata *p = NULL;
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
-
- /* printf("GPencil - Starting Re-Drawing\n"); */
-
- /* try to initialize context data needed while drawing */
- if (!gpencil_draw_init(C, op, NULL)) {
- if (op->customdata) MEM_freeN(op->customdata);
- /* printf("\tGP - no valid data\n"); */
- return OPERATOR_CANCELLED;
- }
- else
- p = op->customdata;
-
- /* printf("\tGP - Start redrawing stroke\n"); */
-
- /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement),
- * setting the relevant values in context at each step, then applying
- */
- RNA_BEGIN (op->ptr, itemptr, "stroke")
- {
- float mousef[2];
-
- /* printf("\t\tGP - stroke elem\n"); */
-
- /* get relevant data for this point from stroke */
- RNA_float_get_array(&itemptr, "mouse", mousef);
- p->mval[0] = (int)mousef[0];
- p->mval[1] = (int)mousef[1];
- p->pressure = RNA_float_get(&itemptr, "pressure");
- p->curtime = (double)RNA_float_get(&itemptr, "time") + p->inittime;
-
- if (RNA_boolean_get(&itemptr, "is_start")) {
- /* if first-run flag isn't set already (i.e. not true first stroke),
- * then we must terminate the previous one first before continuing
- */
- if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
- /* TODO: both of these ops can set error-status, but we probably don't need to worry */
- gp_paint_strokeend(p);
- gp_paint_initstroke(p, p->paintmode, depsgraph);
- }
- }
-
- /* if first run, set previous data too */
- if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
- p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
-
- p->mvalo[0] = p->mval[0];
- p->mvalo[1] = p->mval[1];
- p->opressure = p->pressure;
- p->ocurtime = p->curtime;
- }
-
- /* apply this data as necessary now (as per usual) */
- gpencil_draw_apply(op, p, depsgraph);
- }
- RNA_END;
-
- /* printf("\tGP - done\n"); */
-
- /* cleanup */
- gpencil_draw_exit(C, op);
-
- /* refreshes */
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
-
- /* done */
- return OPERATOR_FINISHED;
+ tGPsdata *p = NULL;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ /* printf("GPencil - Starting Re-Drawing\n"); */
+
+ /* try to initialize context data needed while drawing */
+ if (!gpencil_draw_init(C, op, NULL)) {
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ /* printf("\tGP - no valid data\n"); */
+ return OPERATOR_CANCELLED;
+ }
+ else
+ p = op->customdata;
+
+ /* printf("\tGP - Start redrawing stroke\n"); */
+
+ /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement),
+ * setting the relevant values in context at each step, then applying
+ */
+ RNA_BEGIN (op->ptr, itemptr, "stroke") {
+ float mousef[2];
+
+ /* printf("\t\tGP - stroke elem\n"); */
+
+ /* get relevant data for this point from stroke */
+ RNA_float_get_array(&itemptr, "mouse", mousef);
+ p->mval[0] = (int)mousef[0];
+ p->mval[1] = (int)mousef[1];
+ p->pressure = RNA_float_get(&itemptr, "pressure");
+ p->curtime = (double)RNA_float_get(&itemptr, "time") + p->inittime;
+
+ if (RNA_boolean_get(&itemptr, "is_start")) {
+ /* if first-run flag isn't set already (i.e. not true first stroke),
+ * then we must terminate the previous one first before continuing
+ */
+ if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
+ /* TODO: both of these ops can set error-status, but we probably don't need to worry */
+ gp_paint_strokeend(p);
+ gp_paint_initstroke(p, p->paintmode, depsgraph);
+ }
+ }
+
+ /* if first run, set previous data too */
+ if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
+ p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
+
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ p->opressure = p->pressure;
+ p->ocurtime = p->curtime;
+ }
+
+ /* apply this data as necessary now (as per usual) */
+ gpencil_draw_apply(op, p, depsgraph);
+ }
+ RNA_END;
+
+ /* printf("\tGP - done\n"); */
+
+ /* cleanup */
+ gpencil_draw_exit(C, op);
+
+ /* refreshes */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* done */
+ return OPERATOR_FINISHED;
}
/* ------------------------------- */
@@ -1948,521 +1954,540 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
/* start of interactive drawing part of operator */
static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *ob = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
- tGPsdata *p = NULL;
-
- /* support for tablets eraser pen */
- if (gpencil_is_tablet_eraser_active(event)) {
- RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER);
- }
-
- /* if try to do annotations with a gp object selected, first
- * unselect the object to avoid conflicts.
- * The solution is not perfect but we can keep running the annotations while
- * found a better solution.
- */
- if (sa && sa->spacetype == SPACE_VIEW3D) {
- if ((ob != NULL) && (ob->type == OB_GPENCIL)) {
- ob->mode = OB_MODE_OBJECT;
- bGPdata *gpd = (bGPdata *)ob->data;
- ED_gpencil_setup_modes(C, gpd, 0);
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- ViewLayer *view_layer = CTX_data_view_layer(C);
- BKE_view_layer_base_deselect_all(view_layer);
- view_layer->basact = NULL;
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- }
- }
-
- if (G.debug & G_DEBUG)
- printf("GPencil - Starting Drawing\n");
-
- /* try to initialize context data needed while drawing */
- if (!gpencil_draw_init(C, op, event)) {
- if (op->customdata)
- MEM_freeN(op->customdata);
- if (G.debug & G_DEBUG)
- printf("\tGP - no valid data\n");
- return OPERATOR_CANCELLED;
- }
- else
- p = op->customdata;
-
- /* if empty erase capture and finish */
- if (p->status == GP_STATUS_CAPTURE) {
- gpencil_draw_exit(C, op);
-
- BKE_report(op->reports, RPT_ERROR, "Nothing to erase");
- return OPERATOR_FINISHED;
- }
-
- /* TODO: set any additional settings that we can take from the events?
- * TODO? if tablet is erasing, force eraser to be on? */
-
- /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
-
- /* if eraser is on, draw radial aid */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- gpencil_draw_toggle_eraser_cursor(C, p, true);
- }
- /* set cursor
- * NOTE: This may change later (i.e. intentionally via brush toggle,
- * or unintentionally if the user scrolls outside the area)...
- */
- gpencil_draw_cursor_set(p);
-
- /* only start drawing immediately if we're allowed to do so... */
- if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
- /* hotkey invoked - start drawing */
- /* printf("\tGP - set first spot\n"); */
- p->status = GP_STATUS_PAINTING;
-
- /* handle the initial drawing - i.e. for just doing a simple dot */
- annotation_draw_apply_event(op, event, CTX_data_depsgraph(C), 0.0f, 0.0f);
- op->flag |= OP_IS_MODAL_CURSOR_REGION;
- }
- else {
- /* toolbar invoked - don't start drawing yet... */
- /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */
- op->flag |= OP_IS_MODAL_CURSOR_REGION;
- }
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
- /* add a modal handler for this operator, so that we can then draw continuous strokes */
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
+ Object *ob = CTX_data_active_object(C);
+ ScrArea *sa = CTX_wm_area(C);
+ Scene *scene = CTX_data_scene(C);
+ tGPsdata *p = NULL;
+
+ /* support for tablets eraser pen */
+ if (gpencil_is_tablet_eraser_active(event)) {
+ RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER);
+ }
+
+ /* if try to do annotations with a gp object selected, first
+ * unselect the object to avoid conflicts.
+ * The solution is not perfect but we can keep running the annotations while
+ * found a better solution.
+ */
+ if (sa && sa->spacetype == SPACE_VIEW3D) {
+ if ((ob != NULL) && (ob->type == OB_GPENCIL)) {
+ ob->mode = OB_MODE_OBJECT;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ ED_gpencil_setup_modes(C, gpd, 0);
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ BKE_view_layer_base_deselect_all(view_layer);
+ view_layer->basact = NULL;
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ }
+ }
+
+ if (G.debug & G_DEBUG)
+ printf("GPencil - Starting Drawing\n");
+
+ /* try to initialize context data needed while drawing */
+ if (!gpencil_draw_init(C, op, event)) {
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ if (G.debug & G_DEBUG)
+ printf("\tGP - no valid data\n");
+ return OPERATOR_CANCELLED;
+ }
+ else
+ p = op->customdata;
+
+ /* if empty erase capture and finish */
+ if (p->status == GP_STATUS_CAPTURE) {
+ gpencil_draw_exit(C, op);
+
+ BKE_report(op->reports, RPT_ERROR, "Nothing to erase");
+ return OPERATOR_FINISHED;
+ }
+
+ /* TODO: set any additional settings that we can take from the events?
+ * TODO? if tablet is erasing, force eraser to be on? */
+
+ /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
+
+ /* if eraser is on, draw radial aid */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ gpencil_draw_toggle_eraser_cursor(C, p, true);
+ }
+ /* set cursor
+ * NOTE: This may change later (i.e. intentionally via brush toggle,
+ * or unintentionally if the user scrolls outside the area)...
+ */
+ gpencil_draw_cursor_set(p);
+
+ /* only start drawing immediately if we're allowed to do so... */
+ if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
+ /* hotkey invoked - start drawing */
+ /* printf("\tGP - set first spot\n"); */
+ p->status = GP_STATUS_PAINTING;
+
+ /* handle the initial drawing - i.e. for just doing a simple dot */
+ annotation_draw_apply_event(op, event, CTX_data_depsgraph(C), 0.0f, 0.0f);
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+ else {
+ /* toolbar invoked - don't start drawing yet... */
+ /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ /* add a modal handler for this operator, so that we can then draw continuous strokes */
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
static bool gpencil_area_exists(bContext *C, ScrArea *sa_test)
{
- bScreen *sc = CTX_wm_screen(C);
- return (BLI_findindex(&sc->areabase, sa_test) != -1);
+ bScreen *sc = CTX_wm_screen(C);
+ return (BLI_findindex(&sc->areabase, sa_test) != -1);
}
static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
{
- tGPsdata *p = op->customdata;
+ tGPsdata *p = op->customdata;
- /* we must check that we're still within the area that we're set up to work from
- * otherwise we could crash (see bug #20586)
- */
- if (CTX_wm_area(C) != p->sa) {
- printf("\t\t\tGP - wrong area execution abort!\n");
- p->status = GP_STATUS_ERROR;
- }
+ /* we must check that we're still within the area that we're set up to work from
+ * otherwise we could crash (see bug #20586)
+ */
+ if (CTX_wm_area(C) != p->sa) {
+ printf("\t\t\tGP - wrong area execution abort!\n");
+ p->status = GP_STATUS_ERROR;
+ }
- /* printf("\t\tGP - start stroke\n"); */
+ /* printf("\t\tGP - start stroke\n"); */
- /* we may need to set up paint env again if we're resuming */
- /* XXX: watch it with the paintmode! in future,
- * it'd be nice to allow changing paint-mode when in sketching-sessions */
+ /* we may need to set up paint env again if we're resuming */
+ /* XXX: watch it with the paintmode! in future,
+ * it'd be nice to allow changing paint-mode when in sketching-sessions */
- if (gp_session_initdata(C, p))
- gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C));
+ if (gp_session_initdata(C, p))
+ gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C));
- if (p->status != GP_STATUS_ERROR) {
- p->status = GP_STATUS_PAINTING;
- op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
- }
+ if (p->status != GP_STATUS_ERROR) {
+ p->status = GP_STATUS_PAINTING;
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
- return op->customdata;
+ return op->customdata;
}
static void gpencil_stroke_end(wmOperator *op)
{
- tGPsdata *p = op->customdata;
+ tGPsdata *p = op->customdata;
- gp_paint_cleanup(p);
+ gp_paint_cleanup(p);
- gpencil_undo_push(p->gpd);
+ gpencil_undo_push(p->gpd);
- gp_session_cleanup(p);
+ gp_session_cleanup(p);
- p->status = GP_STATUS_IDLING;
- op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
- p->gpd = NULL;
- p->gpl = NULL;
- p->gpf = NULL;
+ p->gpd = NULL;
+ p->gpl = NULL;
+ p->gpf = NULL;
}
/* add events for missing mouse movements when the artist draw very fast */
-static void annotation_add_missing_events(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p)
+static void annotation_add_missing_events(bContext *C,
+ wmOperator *op,
+ const wmEvent *event,
+ tGPsdata *p)
{
- float pt[2], a[2], b[2];
- float factor = 10.0f;
-
- copy_v2_v2(a, p->mvalo);
- b[0] = (float)event->mval[0] + 1.0f;
- b[1] = (float)event->mval[1] + 1.0f;
-
- /* get distance in pixels */
- float dist = len_v2v2(a, b);
-
- /* for very small distances, add a half way point */
- if (dist <= 2.0f) {
- interp_v2_v2v2(pt, a, b, 0.5f);
- sub_v2_v2v2(pt, b, pt);
- /* create fake event */
- annotation_draw_apply_event(op, event, CTX_data_depsgraph(C), pt[0], pt[1]);
- }
- else if (dist >= factor) {
- int slices = 2 + (int)((dist - 1.0) / factor);
- float n = 1.0f / slices;
- for (int i = 1; i < slices; i++) {
- interp_v2_v2v2(pt, a, b, n * i);
- sub_v2_v2v2(pt, b, pt);
- /* create fake event */
- annotation_draw_apply_event(
- op, event, CTX_data_depsgraph(C),
- pt[0], pt[1]);
- }
- }
+ float pt[2], a[2], b[2];
+ float factor = 10.0f;
+
+ copy_v2_v2(a, p->mvalo);
+ b[0] = (float)event->mval[0] + 1.0f;
+ b[1] = (float)event->mval[1] + 1.0f;
+
+ /* get distance in pixels */
+ float dist = len_v2v2(a, b);
+
+ /* for very small distances, add a half way point */
+ if (dist <= 2.0f) {
+ interp_v2_v2v2(pt, a, b, 0.5f);
+ sub_v2_v2v2(pt, b, pt);
+ /* create fake event */
+ annotation_draw_apply_event(op, event, CTX_data_depsgraph(C), pt[0], pt[1]);
+ }
+ else if (dist >= factor) {
+ int slices = 2 + (int)((dist - 1.0) / factor);
+ float n = 1.0f / slices;
+ for (int i = 1; i < slices; i++) {
+ interp_v2_v2v2(pt, a, b, n * i);
+ sub_v2_v2v2(pt, b, pt);
+ /* create fake event */
+ annotation_draw_apply_event(op, event, CTX_data_depsgraph(C), pt[0], pt[1]);
+ }
+ }
}
/* events handling during interactive drawing part of operator */
static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGPsdata *p = op->customdata;
- /* default exit state - pass through to support MMB view nav, etc. */
- int estate = OPERATOR_PASS_THROUGH;
-
- /* if (event->type == NDOF_MOTION)
- * return OPERATOR_PASS_THROUGH;
- * -------------------------------
- * [mce] Not quite what I was looking
- * for, but a good start! GP continues to
- * draw on the screen while the 3D mouse
- * moves the viewpoint. Problem is that
- * the stroke is converted to 3D only after
- * it is finished. This approach should work
- * better in tools that immediately apply
- * in 3D space.
- */
-
- if (p->status == GP_STATUS_IDLING) {
- ARegion *ar = CTX_wm_region(C);
- p->ar = ar;
- }
-
- /* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */
- if (ISKEYBOARD(event->type)) {
- if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) {
- /* allow some keys:
- * - for frame changing [#33412]
- * - for undo (during sketching sessions)
- */
- }
- else if (ELEM(event->type, PAD0, PAD1, PAD2, PAD3, PAD4, PAD5, PAD6, PAD7, PAD8, PAD9)) {
- /* allow numpad keys so that camera/view manipulations can still take place
- * - PAD0 in particular is really important for Grease Pencil drawing,
- * as animators may be working "to camera", so having this working
- * is essential for ensuring that they can quickly return to that view
- */
- }
- else if ((event->type == BKEY) && (event->val == KM_RELEASE)) {
- /* Add Blank Frame
- * - Since this operator is non-modal, we can just call it here, and keep going...
- * - This operator is especially useful when animating
- */
- WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL);
- estate = OPERATOR_RUNNING_MODAL;
- }
- else {
- estate = OPERATOR_RUNNING_MODAL;
- }
- }
-
- //printf("\tGP - handle modal event...\n");
-
- /* exit painting mode (and/or end current stroke)
- * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647]
- */
- if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) {
- /* exit() ends the current stroke before cleaning up */
- /* printf("\t\tGP - end of paint op + end of stroke\n"); */
- p->status = GP_STATUS_DONE;
- estate = OPERATOR_FINISHED;
- }
-
- /* toggle painting mode upon mouse-button movement
- * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
- * - RIGHTMOUSE = polyline (hotkey) / eraser (all)
- * (Disabling RIGHTMOUSE case here results in bugs like [#32647])
- * also making sure we have a valid event value, to not exit too early
- */
- if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) {
- /* if painting, end stroke */
- if (p->status == GP_STATUS_PAINTING) {
- int sketch = 0;
-
- /* basically, this should be mouse-button up = end stroke
- * BUT, polyline drawing is an exception -- all knots should be added during one session
- */
- sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY);
-
- if (sketch) {
- /* end stroke only, and then wait to resume painting soon */
- /* printf("\t\tGP - end stroke only\n"); */
- gpencil_stroke_end(op);
-
- /* If eraser mode is on, turn it off after the stroke finishes
- * NOTE: This just makes it nicer to work with drawing sessions
- */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- p->paintmode = RNA_enum_get(op->ptr, "mode");
-
- /* if the original mode was *still* eraser,
- * we'll let it say for now, since this gives
- * users an opportunity to have visual feedback
- * when adjusting eraser size
- */
- if (p->paintmode != GP_PAINTMODE_ERASER) {
- /* turn off cursor...
- * NOTE: this should be enough for now
- * Just hiding this makes it seem like
- * you can paint again...
- */
- gpencil_draw_toggle_eraser_cursor(C, p, false);
- }
- }
-
- /* we've just entered idling state, so this event was processed (but no others yet) */
- estate = OPERATOR_RUNNING_MODAL;
-
- /* stroke could be smoothed, send notifier to refresh screen */
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
- }
- else {
- /* printf("\t\tGP - end of stroke + op\n"); */
- p->status = GP_STATUS_DONE;
- estate = OPERATOR_FINISHED;
- }
- }
- else if (event->val == KM_PRESS) {
- bool in_bounds = false;
-
- /* Check if we're outside the bounds of the active region
- * NOTE: An exception here is that if launched from the toolbar,
- * whatever region we're now in should become the new region
- */
- if ((p->ar) && (p->ar->regiontype == RGN_TYPE_TOOLS)) {
- /* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
-
- if (G.debug & G_DEBUG) {
- printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
- current_region, p->ar, event->x, event->y,
- p->sa->totrct.xmin, p->sa->totrct.ymin, p->sa->totrct.xmax, p->sa->totrct.ymax);
- }
-
- if (current_region) {
- /* Assume that since we found the cursor in here, it is in bounds
- * and that this should be the region that we begin drawing in
- */
- p->ar = current_region;
- in_bounds = true;
- }
- else {
- /* Out of bounds, or invalid in some other way */
- p->status = GP_STATUS_ERROR;
- estate = OPERATOR_CANCELLED;
-
- if (G.debug & G_DEBUG)
- printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__);
- }
- }
- else if (p->ar) {
- rcti region_rect;
-
- /* Perform bounds check using */
- ED_region_visible_rect(p->ar, &region_rect);
- in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
- }
- else {
- /* No region */
- p->status = GP_STATUS_ERROR;
- estate = OPERATOR_CANCELLED;
-
- if (G.debug & G_DEBUG)
- printf("%s: No active region found in GP Paint session data\n", __func__);
- }
-
- if (in_bounds) {
- /* Switch paintmode (temporarily if need be) based on which button was used
- * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
- */
- if ((event->type == RIGHTMOUSE) || gpencil_is_tablet_eraser_active(event)) {
- /* turn on eraser */
- p->paintmode = GP_PAINTMODE_ERASER;
- }
- else if (event->type == LEFTMOUSE) {
- /* restore drawmode to default */
- p->paintmode = RNA_enum_get(op->ptr, "mode");
- }
-
- gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
-
- /* not painting, so start stroke (this should be mouse-button down) */
- p = gpencil_stroke_begin(C, op);
-
- if (p->status == GP_STATUS_ERROR) {
- estate = OPERATOR_CANCELLED;
- }
- }
- else if (p->status != GP_STATUS_ERROR) {
- /* User clicked outside bounds of window while idling, so exit paintmode
- * NOTE: Don't enter this case if an error occurred while finding the
- * region (as above)
- */
- p->status = GP_STATUS_DONE;
- estate = OPERATOR_FINISHED;
- }
- }
- else if (event->val == KM_RELEASE) {
- p->status = GP_STATUS_IDLING;
- op->flag |= OP_IS_MODAL_CURSOR_REGION;
- }
- }
-
- /* handle mode-specific events */
- if (p->status == GP_STATUS_PAINTING) {
- /* handle painting mouse-movements? */
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
- /* handle drawing event */
- if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
- annotation_add_missing_events(C, op, event, p);
- }
-
- annotation_draw_apply_event(op, event, CTX_data_depsgraph(C), 0.0f, 0.0f);
-
- /* finish painting operation if anything went wrong just now */
- if (p->status == GP_STATUS_ERROR) {
- printf("\t\t\t\tGP - add error done!\n");
- estate = OPERATOR_CANCELLED;
- }
- else {
- /* event handled, so just tag as running modal */
- /* printf("\t\t\t\tGP - add point handled!\n"); */
- estate = OPERATOR_RUNNING_MODAL;
- }
- }
- /* eraser size */
- else if ((p->paintmode == GP_PAINTMODE_ERASER) &&
- ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS))
- {
- /* just resize the brush (local version)
- * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys
- */
- /* printf("\t\tGP - resize eraser\n"); */
- switch (event->type) {
- case WHEELDOWNMOUSE: /* larger */
- case PADPLUSKEY:
- p->radius += 5;
- break;
-
- case WHEELUPMOUSE: /* smaller */
- case PADMINUS:
- p->radius -= 5;
-
- if (p->radius <= 0)
- p->radius = 1;
- break;
- }
-
- /* force refresh */
- /* just active area for now, since doing whole screen is too slow */
- ED_region_tag_redraw(p->ar);
-
- /* event handled, so just tag as running modal */
- estate = OPERATOR_RUNNING_MODAL;
- }
- /* there shouldn't be any other events, but just in case there are, let's swallow them
- * (i.e. to prevent problems with undo)
- */
- else {
- /* swallow event to save ourselves trouble */
- estate = OPERATOR_RUNNING_MODAL;
- }
- }
-
- /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
- if (0 == gpencil_area_exists(C, p->sa))
- estate = OPERATOR_CANCELLED;
- else {
- /* update status indicators - cursor, header, etc. */
- gpencil_draw_status_indicators(C, p);
- /* cursor may have changed outside our control - T44084 */
- gpencil_draw_cursor_set(p);
- }
-
- /* process last operations before exiting */
- switch (estate) {
- case OPERATOR_FINISHED:
- /* one last flush before we're done */
- gpencil_draw_exit(C, op);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
- break;
-
- case OPERATOR_CANCELLED:
- gpencil_draw_exit(C, op);
- break;
-
- case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
- /* event doesn't need to be handled */
+ tGPsdata *p = op->customdata;
+ /* default exit state - pass through to support MMB view nav, etc. */
+ int estate = OPERATOR_PASS_THROUGH;
+
+ /* if (event->type == NDOF_MOTION)
+ * return OPERATOR_PASS_THROUGH;
+ * -------------------------------
+ * [mce] Not quite what I was looking
+ * for, but a good start! GP continues to
+ * draw on the screen while the 3D mouse
+ * moves the viewpoint. Problem is that
+ * the stroke is converted to 3D only after
+ * it is finished. This approach should work
+ * better in tools that immediately apply
+ * in 3D space.
+ */
+
+ if (p->status == GP_STATUS_IDLING) {
+ ARegion *ar = CTX_wm_region(C);
+ p->ar = ar;
+ }
+
+ /* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */
+ if (ISKEYBOARD(event->type)) {
+ if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) {
+ /* allow some keys:
+ * - for frame changing [#33412]
+ * - for undo (during sketching sessions)
+ */
+ }
+ else if (ELEM(event->type, PAD0, PAD1, PAD2, PAD3, PAD4, PAD5, PAD6, PAD7, PAD8, PAD9)) {
+ /* allow numpad keys so that camera/view manipulations can still take place
+ * - PAD0 in particular is really important for Grease Pencil drawing,
+ * as animators may be working "to camera", so having this working
+ * is essential for ensuring that they can quickly return to that view
+ */
+ }
+ else if ((event->type == BKEY) && (event->val == KM_RELEASE)) {
+ /* Add Blank Frame
+ * - Since this operator is non-modal, we can just call it here, and keep going...
+ * - This operator is especially useful when animating
+ */
+ WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL);
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ //printf("\tGP - handle modal event...\n");
+
+ /* exit painting mode (and/or end current stroke)
+ * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647]
+ */
+ if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) {
+ /* exit() ends the current stroke before cleaning up */
+ /* printf("\t\tGP - end of paint op + end of stroke\n"); */
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+
+ /* toggle painting mode upon mouse-button movement
+ * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
+ * - RIGHTMOUSE = polyline (hotkey) / eraser (all)
+ * (Disabling RIGHTMOUSE case here results in bugs like [#32647])
+ * also making sure we have a valid event value, to not exit too early
+ */
+ if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) {
+ /* if painting, end stroke */
+ if (p->status == GP_STATUS_PAINTING) {
+ int sketch = 0;
+
+ /* basically, this should be mouse-button up = end stroke
+ * BUT, polyline drawing is an exception -- all knots should be added during one session
+ */
+ sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY);
+
+ if (sketch) {
+ /* end stroke only, and then wait to resume painting soon */
+ /* printf("\t\tGP - end stroke only\n"); */
+ gpencil_stroke_end(op);
+
+ /* If eraser mode is on, turn it off after the stroke finishes
+ * NOTE: This just makes it nicer to work with drawing sessions
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ p->paintmode = RNA_enum_get(op->ptr, "mode");
+
+ /* if the original mode was *still* eraser,
+ * we'll let it say for now, since this gives
+ * users an opportunity to have visual feedback
+ * when adjusting eraser size
+ */
+ if (p->paintmode != GP_PAINTMODE_ERASER) {
+ /* turn off cursor...
+ * NOTE: this should be enough for now
+ * Just hiding this makes it seem like
+ * you can paint again...
+ */
+ gpencil_draw_toggle_eraser_cursor(C, p, false);
+ }
+ }
+
+ /* we've just entered idling state, so this event was processed (but no others yet) */
+ estate = OPERATOR_RUNNING_MODAL;
+
+ /* stroke could be smoothed, send notifier to refresh screen */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ }
+ else {
+ /* printf("\t\tGP - end of stroke + op\n"); */
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+ }
+ else if (event->val == KM_PRESS) {
+ bool in_bounds = false;
+
+ /* Check if we're outside the bounds of the active region
+ * NOTE: An exception here is that if launched from the toolbar,
+ * whatever region we're now in should become the new region
+ */
+ if ((p->ar) && (p->ar->regiontype == RGN_TYPE_TOOLS)) {
+ /* Change to whatever region is now under the mouse */
+ ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
+
+ if (G.debug & G_DEBUG) {
+ printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
+ current_region,
+ p->ar,
+ event->x,
+ event->y,
+ p->sa->totrct.xmin,
+ p->sa->totrct.ymin,
+ p->sa->totrct.xmax,
+ p->sa->totrct.ymax);
+ }
+
+ if (current_region) {
+ /* Assume that since we found the cursor in here, it is in bounds
+ * and that this should be the region that we begin drawing in
+ */
+ p->ar = current_region;
+ in_bounds = true;
+ }
+ else {
+ /* Out of bounds, or invalid in some other way */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__);
+ }
+ }
+ else if (p->ar) {
+ rcti region_rect;
+
+ /* Perform bounds check using */
+ ED_region_visible_rect(p->ar, &region_rect);
+ in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
+ }
+ else {
+ /* No region */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: No active region found in GP Paint session data\n", __func__);
+ }
+
+ if (in_bounds) {
+ /* Switch paintmode (temporarily if need be) based on which button was used
+ * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
+ */
+ if ((event->type == RIGHTMOUSE) || gpencil_is_tablet_eraser_active(event)) {
+ /* turn on eraser */
+ p->paintmode = GP_PAINTMODE_ERASER;
+ }
+ else if (event->type == LEFTMOUSE) {
+ /* restore drawmode to default */
+ p->paintmode = RNA_enum_get(op->ptr, "mode");
+ }
+
+ gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
+
+ /* not painting, so start stroke (this should be mouse-button down) */
+ p = gpencil_stroke_begin(C, op);
+
+ if (p->status == GP_STATUS_ERROR) {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ else if (p->status != GP_STATUS_ERROR) {
+ /* User clicked outside bounds of window while idling, so exit paintmode
+ * NOTE: Don't enter this case if an error occurred while finding the
+ * region (as above)
+ */
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+ }
+ else if (event->val == KM_RELEASE) {
+ p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+ }
+
+ /* handle mode-specific events */
+ if (p->status == GP_STATUS_PAINTING) {
+ /* handle painting mouse-movements? */
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
+ /* handle drawing event */
+ if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
+ annotation_add_missing_events(C, op, event, p);
+ }
+
+ annotation_draw_apply_event(op, event, CTX_data_depsgraph(C), 0.0f, 0.0f);
+
+ /* finish painting operation if anything went wrong just now */
+ if (p->status == GP_STATUS_ERROR) {
+ printf("\t\t\t\tGP - add error done!\n");
+ estate = OPERATOR_CANCELLED;
+ }
+ else {
+ /* event handled, so just tag as running modal */
+ /* printf("\t\t\t\tGP - add point handled!\n"); */
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ }
+ /* eraser size */
+ else if ((p->paintmode == GP_PAINTMODE_ERASER) &&
+ ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS)) {
+ /* just resize the brush (local version)
+ * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys
+ */
+ /* printf("\t\tGP - resize eraser\n"); */
+ switch (event->type) {
+ case WHEELDOWNMOUSE: /* larger */
+ case PADPLUSKEY:
+ p->radius += 5;
+ break;
+
+ case WHEELUPMOUSE: /* smaller */
+ case PADMINUS:
+ p->radius -= 5;
+
+ if (p->radius <= 0)
+ p->radius = 1;
+ break;
+ }
+
+ /* force refresh */
+ /* just active area for now, since doing whole screen is too slow */
+ ED_region_tag_redraw(p->ar);
+
+ /* event handled, so just tag as running modal */
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ /* there shouldn't be any other events, but just in case there are, let's swallow them
+ * (i.e. to prevent problems with undo)
+ */
+ else {
+ /* swallow event to save ourselves trouble */
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
+ if (0 == gpencil_area_exists(C, p->sa))
+ estate = OPERATOR_CANCELLED;
+ else {
+ /* update status indicators - cursor, header, etc. */
+ gpencil_draw_status_indicators(C, p);
+ /* cursor may have changed outside our control - T44084 */
+ gpencil_draw_cursor_set(p);
+ }
+
+ /* process last operations before exiting */
+ switch (estate) {
+ case OPERATOR_FINISHED:
+ /* one last flush before we're done */
+ gpencil_draw_exit(C, op);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ break;
+
+ case OPERATOR_CANCELLED:
+ gpencil_draw_exit(C, op);
+ break;
+
+ case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
+ /* event doesn't need to be handled */
#if 0
- printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n",
- event->type, event->type == MIDDLEMOUSE, event->type==MOUSEMOVE);
+ printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n",
+ event->type, event->type == MIDDLEMOUSE, event->type==MOUSEMOVE);
#endif
- break;
- }
+ break;
+ }
- /* return status code */
- return estate;
+ /* return status code */
+ return estate;
}
/* ------------------------------- */
static const EnumPropertyItem prop_gpencil_drawmodes[] = {
- {GP_PAINTMODE_DRAW, "DRAW", 0, "Draw Freehand", "Draw freehand stroke(s)"},
- {GP_PAINTMODE_DRAW_STRAIGHT, "DRAW_STRAIGHT", 0, "Draw Straight Lines", "Draw straight line segment(s)"},
- {GP_PAINTMODE_DRAW_POLY, "DRAW_POLY", 0, "Draw Poly Line", "Click to place endpoints of straight line segments (connected)"},
- {GP_PAINTMODE_ERASER, "ERASER", 0, "Eraser", "Erase Annotation strokes"},
- {0, NULL, 0, NULL, NULL},
+ {GP_PAINTMODE_DRAW, "DRAW", 0, "Draw Freehand", "Draw freehand stroke(s)"},
+ {GP_PAINTMODE_DRAW_STRAIGHT,
+ "DRAW_STRAIGHT",
+ 0,
+ "Draw Straight Lines",
+ "Draw straight line segment(s)"},
+ {GP_PAINTMODE_DRAW_POLY,
+ "DRAW_POLY",
+ 0,
+ "Draw Poly Line",
+ "Click to place endpoints of straight line segments (connected)"},
+ {GP_PAINTMODE_ERASER, "ERASER", 0, "Eraser", "Erase Annotation strokes"},
+ {0, NULL, 0, NULL, NULL},
};
void GPENCIL_OT_annotate(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Annotation Draw";
- ot->idname = "GPENCIL_OT_annotate";
- ot->description = "Make annotations on the active data";
-
- /* api callbacks */
- ot->exec = gpencil_draw_exec;
- ot->invoke = gpencil_draw_invoke;
- ot->modal = gpencil_draw_modal;
- ot->cancel = gpencil_draw_cancel;
- ot->poll = gpencil_draw_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* settings for drawing */
- ot->prop = RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
-
- prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- /* NOTE: wait for input is enabled by default,
- * so that all UI code can work properly without needing users to know about this */
- prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Wait for first click instead of painting immediately");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Annotation Draw";
+ ot->idname = "GPENCIL_OT_annotate";
+ ot->description = "Make annotations on the active data";
+
+ /* api callbacks */
+ ot->exec = gpencil_draw_exec;
+ ot->invoke = gpencil_draw_invoke;
+ ot->modal = gpencil_draw_modal;
+ ot->cancel = gpencil_draw_cancel;
+ ot->poll = gpencil_draw_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* settings for drawing */
+ ot->prop = RNA_def_enum(
+ ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
+
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ /* NOTE: wait for input is enabled by default,
+ * so that all UI code can work properly without needing users to know about this */
+ prop = RNA_def_boolean(ot->srna,
+ "wait_for_input",
+ true,
+ "Wait for Input",
+ "Wait for first click instead of painting immediately");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 711962400ff..24bdbcc4cba 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -21,7 +21,6 @@
* \ingroup edgpencil
*/
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -84,31 +83,29 @@
/* ----- General Defines ------ */
/* flags for sflag */
typedef enum eDrawStrokeFlags {
- /** don't draw status info */
- GP_DRAWDATA_NOSTATUS = (1 << 0),
- /** only draw 3d-strokes */
- GP_DRAWDATA_ONLY3D = (1 << 1),
- /** only draw 'canvas' strokes */
- GP_DRAWDATA_ONLYV2D = (1 << 2),
- /** only draw 'image' strokes */
- GP_DRAWDATA_ONLYI2D = (1 << 3),
- /** special hack for drawing strokes in Image Editor (weird coordinates) */
- GP_DRAWDATA_IEDITHACK = (1 << 4),
- /** don't draw xray in 3D view (which is default) */
- GP_DRAWDATA_NO_XRAY = (1 << 5),
- /** no onionskins should be drawn (for animation playback) */
- GP_DRAWDATA_NO_ONIONS = (1 << 6),
- /** draw strokes as "volumetric" circular billboards */
- GP_DRAWDATA_VOLUMETRIC = (1 << 7),
- /** fill insides/bounded-regions of strokes */
- GP_DRAWDATA_FILL = (1 << 8),
+ /** don't draw status info */
+ GP_DRAWDATA_NOSTATUS = (1 << 0),
+ /** only draw 3d-strokes */
+ GP_DRAWDATA_ONLY3D = (1 << 1),
+ /** only draw 'canvas' strokes */
+ GP_DRAWDATA_ONLYV2D = (1 << 2),
+ /** only draw 'image' strokes */
+ GP_DRAWDATA_ONLYI2D = (1 << 3),
+ /** special hack for drawing strokes in Image Editor (weird coordinates) */
+ GP_DRAWDATA_IEDITHACK = (1 << 4),
+ /** don't draw xray in 3D view (which is default) */
+ GP_DRAWDATA_NO_XRAY = (1 << 5),
+ /** no onionskins should be drawn (for animation playback) */
+ GP_DRAWDATA_NO_ONIONS = (1 << 6),
+ /** draw strokes as "volumetric" circular billboards */
+ GP_DRAWDATA_VOLUMETRIC = (1 << 7),
+ /** fill insides/bounded-regions of strokes */
+ GP_DRAWDATA_FILL = (1 << 8),
} eDrawStrokeFlags;
-
-
/* thickness above which we should use special drawing */
#if 0
-#define GP_DRAWTHICKNESS_SPECIAL 3
+# define GP_DRAWTHICKNESS_SPECIAL 3
#endif
/* conversion utility (float --> normalized unsigned byte) */
@@ -119,644 +116,697 @@ typedef enum eDrawStrokeFlags {
static void gp_set_point_uniform_color(const bGPDspoint *pt, const float ink[4])
{
- float alpha = ink[3] * pt->strength;
- CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- immUniformColor3fvAlpha(ink, alpha);
+ float alpha = ink[3] * pt->strength;
+ CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
+ immUniformColor3fvAlpha(ink, alpha);
}
static void gp_set_point_varying_color(const bGPDspoint *pt, const float ink[4], uint attr_id)
{
- float alpha = ink[3] * pt->strength;
- CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- immAttr4ub(attr_id, F2UB(ink[0]), F2UB(ink[1]), F2UB(ink[2]), F2UB(alpha));
+ float alpha = ink[3] * pt->strength;
+ CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
+ immAttr4ub(attr_id, F2UB(ink[0]), F2UB(ink[1]), F2UB(ink[2]), F2UB(alpha));
}
/* --------- 2D Stroke Drawing Helpers --------- */
/* change in parameter list */
-static void gp_calc_2d_stroke_fxy(const float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
+static void gp_calc_2d_stroke_fxy(
+ const float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
{
- if (sflag & GP_STROKE_2DSPACE) {
- r_co[0] = pt[0];
- r_co[1] = pt[1];
- }
- else if (sflag & GP_STROKE_2DIMAGE) {
- const float x = (float)((pt[0] * winx) + offsx);
- const float y = (float)((pt[1] * winy) + offsy);
-
- r_co[0] = x;
- r_co[1] = y;
- }
- else {
- const float x = (float)(pt[0] / 100 * winx) + offsx;
- const float y = (float)(pt[1] / 100 * winy) + offsy;
-
- r_co[0] = x;
- r_co[1] = y;
- }
+ if (sflag & GP_STROKE_2DSPACE) {
+ r_co[0] = pt[0];
+ r_co[1] = pt[1];
+ }
+ else if (sflag & GP_STROKE_2DIMAGE) {
+ const float x = (float)((pt[0] * winx) + offsx);
+ const float y = (float)((pt[1] * winy) + offsy);
+
+ r_co[0] = x;
+ r_co[1] = y;
+ }
+ else {
+ const float x = (float)(pt[0] / 100 * winx) + offsx;
+ const float y = (float)(pt[1] / 100 * winy) + offsy;
+
+ r_co[0] = x;
+ r_co[1] = y;
+ }
}
/* ----------- Volumetric Strokes --------------- */
/* draw a 2D strokes in "volumetric" style */
-static void gp_draw_stroke_volumetric_2d(
- const bGPDspoint *points, int totpoints, short thickness,
- short UNUSED(dflag), short sflag,
- int offsx, int offsy, int winx, int winy,
- const float diff_mat[4][4], const float ink[4])
+static void gp_draw_stroke_volumetric_2d(const bGPDspoint *points,
+ int totpoints,
+ short thickness,
+ short UNUSED(dflag),
+ short sflag,
+ int offsx,
+ int offsy,
+ int winx,
+ int winy,
+ const float diff_mat[4][4],
+ const float ink[4])
{
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
-
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
- GPU_enable_program_point_size();
- immBegin(GPU_PRIM_POINTS, totpoints);
-
- const bGPDspoint *pt = points;
- for (int i = 0; i < totpoints; i++, pt++) {
- /* transform position to 2D */
- float co[2];
- float fpt[3];
-
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
-
- gp_set_point_varying_color(pt, ink, color);
- immAttr1f(size, pt->pressure * thickness); /* TODO: scale based on view transform */
- immVertex2f(pos, co[0], co[1]);
- }
-
- immEnd();
- immUnbindProgram();
- GPU_disable_program_point_size();
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(
+ format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ GPU_enable_program_point_size();
+ immBegin(GPU_PRIM_POINTS, totpoints);
+
+ const bGPDspoint *pt = points;
+ for (int i = 0; i < totpoints; i++, pt++) {
+ /* transform position to 2D */
+ float co[2];
+ float fpt[3];
+
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
+
+ gp_set_point_varying_color(pt, ink, color);
+ immAttr1f(size, pt->pressure * thickness); /* TODO: scale based on view transform */
+ immVertex2f(pos, co[0], co[1]);
+ }
+
+ immEnd();
+ immUnbindProgram();
+ GPU_disable_program_point_size();
}
/* draw a 3D stroke in "volumetric" style */
-static void gp_draw_stroke_volumetric_3d(
- const bGPDspoint *points, int totpoints, short thickness,
- const float ink[4])
+static void gp_draw_stroke_volumetric_3d(const bGPDspoint *points,
+ int totpoints,
+ short thickness,
+ const float ink[4])
{
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
-
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
- GPU_enable_program_point_size();
- immBegin(GPU_PRIM_POINTS, totpoints);
-
- const bGPDspoint *pt = points;
- for (int i = 0; i < totpoints && pt; i++, pt++) {
- gp_set_point_varying_color(pt, ink, color);
- /* TODO: scale based on view transform */
- immAttr1f(size, pt->pressure * thickness);
- /* we can adjust size in vertex shader based on view/projection! */
- immVertex3fv(pos, &pt->x);
- }
-
- immEnd();
- immUnbindProgram();
- GPU_disable_program_point_size();
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(
+ format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ GPU_enable_program_point_size();
+ immBegin(GPU_PRIM_POINTS, totpoints);
+
+ const bGPDspoint *pt = points;
+ for (int i = 0; i < totpoints && pt; i++, pt++) {
+ gp_set_point_varying_color(pt, ink, color);
+ /* TODO: scale based on view transform */
+ immAttr1f(size, pt->pressure * thickness);
+ /* we can adjust size in vertex shader based on view/projection! */
+ immVertex3fv(pos, &pt->x);
+ }
+
+ immEnd();
+ immUnbindProgram();
+ GPU_disable_program_point_size();
}
-
/* --------------- Stroke Fills ----------------- */
/* calc bounding box in 2d using flat projection data */
-static void gp_calc_2d_bounding_box(const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], bool expand)
+static void gp_calc_2d_bounding_box(
+ const float (*points2d)[2], int totpoints, float minv[2], float maxv[2], bool expand)
{
- copy_v2_v2(minv, points2d[0]);
- copy_v2_v2(maxv, points2d[0]);
-
- for (int i = 1; i < totpoints; i++) {
- /* min */
- if (points2d[i][0] < minv[0]) {
- minv[0] = points2d[i][0];
- }
- if (points2d[i][1] < minv[1]) {
- minv[1] = points2d[i][1];
- }
- /* max */
- if (points2d[i][0] > maxv[0]) {
- maxv[0] = points2d[i][0];
- }
- if (points2d[i][1] > maxv[1]) {
- maxv[1] = points2d[i][1];
- }
- }
- /* If not expanded, use a perfect square */
- if (expand == false) {
- if (maxv[0] > maxv[1]) {
- maxv[1] = maxv[0];
- }
- else {
- maxv[0] = maxv[1];
- }
- }
+ copy_v2_v2(minv, points2d[0]);
+ copy_v2_v2(maxv, points2d[0]);
+
+ for (int i = 1; i < totpoints; i++) {
+ /* min */
+ if (points2d[i][0] < minv[0]) {
+ minv[0] = points2d[i][0];
+ }
+ if (points2d[i][1] < minv[1]) {
+ minv[1] = points2d[i][1];
+ }
+ /* max */
+ if (points2d[i][0] > maxv[0]) {
+ maxv[0] = points2d[i][0];
+ }
+ if (points2d[i][1] > maxv[1]) {
+ maxv[1] = points2d[i][1];
+ }
+ }
+ /* If not expanded, use a perfect square */
+ if (expand == false) {
+ if (maxv[0] > maxv[1]) {
+ maxv[1] = maxv[0];
+ }
+ else {
+ maxv[0] = maxv[1];
+ }
+ }
}
/* calc texture coordinates using flat projected points */
-static void gp_calc_stroke_text_coordinates(const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], float(*r_uv)[2])
+static void gp_calc_stroke_text_coordinates(
+ const float (*points2d)[2], int totpoints, float minv[2], float maxv[2], float (*r_uv)[2])
{
- float d[2];
- d[0] = maxv[0] - minv[0];
- d[1] = maxv[1] - minv[1];
- for (int i = 0; i < totpoints; i++) {
- r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0];
- r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1];
- }
+ float d[2];
+ d[0] = maxv[0] - minv[0];
+ d[1] = maxv[1] - minv[1];
+ for (int i = 0; i < totpoints; i++) {
+ r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0];
+ r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1];
+ }
}
/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */
static void gp_triangulate_stroke_fill(bGPDstroke *gps)
{
- BLI_assert(gps->totpoints >= 3);
-
- /* allocate memory for temporary areas */
- gps->tot_triangles = gps->totpoints - 2;
- uint (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
- float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
- float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
-
- int direction = 0;
-
- /* convert to 2d and triangulate */
- BKE_gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
- BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles);
-
- /* calc texture coordinates automatically */
- float minv[2];
- float maxv[2];
- /* first needs bounding box data */
- gp_calc_2d_bounding_box((const float(*)[2])points2d, gps->totpoints, minv, maxv, false);
- /* calc uv data */
- gp_calc_stroke_text_coordinates((const float(*)[2])points2d, gps->totpoints, minv, maxv, uv);
-
- /* Number of triangles */
- gps->tot_triangles = gps->totpoints - 2;
- /* save triangulation data in stroke cache */
- if (gps->tot_triangles > 0) {
- if (gps->triangles == NULL) {
- gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, "GP Stroke triangulation");
- }
- else {
- gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
- }
-
- for (int i = 0; i < gps->tot_triangles; i++) {
- bGPDtriangle *stroke_triangle = &gps->triangles[i];
- memcpy(stroke_triangle->verts, tmp_triangles[i], sizeof(uint[3]));
- /* copy texture coordinates */
- copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]);
- copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]);
- copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]);
- }
- }
- else {
- /* No triangles needed - Free anything allocated previously */
- if (gps->triangles)
- MEM_freeN(gps->triangles);
-
- gps->triangles = NULL;
- }
-
- /* disable recalculation flag */
- if (gps->flag & GP_STROKE_RECALC_GEOMETRY) {
- gps->flag &= ~GP_STROKE_RECALC_GEOMETRY;
- }
-
- /* clear memory */
- MEM_SAFE_FREE(tmp_triangles);
- MEM_SAFE_FREE(points2d);
- MEM_SAFE_FREE(uv);
+ BLI_assert(gps->totpoints >= 3);
+
+ /* allocate memory for temporary areas */
+ gps->tot_triangles = gps->totpoints - 2;
+ uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles,
+ "GP Stroke temp triangulation");
+ float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints,
+ "GP Stroke temp 2d points");
+ float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
+
+ int direction = 0;
+
+ /* convert to 2d and triangulate */
+ BKE_gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
+ BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles);
+
+ /* calc texture coordinates automatically */
+ float minv[2];
+ float maxv[2];
+ /* first needs bounding box data */
+ gp_calc_2d_bounding_box((const float(*)[2])points2d, gps->totpoints, minv, maxv, false);
+ /* calc uv data */
+ gp_calc_stroke_text_coordinates((const float(*)[2])points2d, gps->totpoints, minv, maxv, uv);
+
+ /* Number of triangles */
+ gps->tot_triangles = gps->totpoints - 2;
+ /* save triangulation data in stroke cache */
+ if (gps->tot_triangles > 0) {
+ if (gps->triangles == NULL) {
+ gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles,
+ "GP Stroke triangulation");
+ }
+ else {
+ gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
+ }
+
+ for (int i = 0; i < gps->tot_triangles; i++) {
+ bGPDtriangle *stroke_triangle = &gps->triangles[i];
+ memcpy(stroke_triangle->verts, tmp_triangles[i], sizeof(uint[3]));
+ /* copy texture coordinates */
+ copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]);
+ copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]);
+ copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]);
+ }
+ }
+ else {
+ /* No triangles needed - Free anything allocated previously */
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+
+ gps->triangles = NULL;
+ }
+
+ /* disable recalculation flag */
+ if (gps->flag & GP_STROKE_RECALC_GEOMETRY) {
+ gps->flag &= ~GP_STROKE_RECALC_GEOMETRY;
+ }
+
+ /* clear memory */
+ MEM_SAFE_FREE(tmp_triangles);
+ MEM_SAFE_FREE(points2d);
+ MEM_SAFE_FREE(uv);
}
/* add a new fill point and texture coordinates to vertex buffer */
-static void gp_add_filldata_tobuffer(
- const bGPDspoint *pt, const float uv[2], uint pos, uint texcoord, short flag,
- int offsx, int offsy, int winx, int winy, const float diff_mat[4][4])
+static void gp_add_filldata_tobuffer(const bGPDspoint *pt,
+ const float uv[2],
+ uint pos,
+ uint texcoord,
+ short flag,
+ int offsx,
+ int offsy,
+ int winx,
+ int winy,
+ const float diff_mat[4][4])
{
- float fpt[3];
- float co[2];
-
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- /* if 2d, need conversion */
- if (!(flag & GP_STROKE_3DSPACE)) {
- gp_calc_2d_stroke_fxy(fpt, flag, offsx, offsy, winx, winy, co);
- copy_v2_v2(fpt, co);
- fpt[2] = 0.0f; /* 2d always is z=0.0f */
- }
-
- immAttr2f(texcoord, uv[0], uv[1]); /* texture coordinates */
- immVertex3fv(pos, fpt); /* position */
+ float fpt[3];
+ float co[2];
+
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* if 2d, need conversion */
+ if (!(flag & GP_STROKE_3DSPACE)) {
+ gp_calc_2d_stroke_fxy(fpt, flag, offsx, offsy, winx, winy, co);
+ copy_v2_v2(fpt, co);
+ fpt[2] = 0.0f; /* 2d always is z=0.0f */
+ }
+
+ immAttr2f(texcoord, uv[0], uv[1]); /* texture coordinates */
+ immVertex3fv(pos, fpt); /* position */
}
#if 0 /* GPXX disabled, not used in annotations */
/* assign image texture for filling stroke */
static int gp_set_filling_texture(Image *image, short flag)
{
- ImBuf *ibuf;
- uint *bind = &image->bindcode[TEXTARGET_TEXTURE_2D];
- int error = GL_NO_ERROR;
- ImageUser iuser = { NULL };
- void *lock;
-
- iuser.ok = true;
-
- ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
-
- if (ibuf == NULL || ibuf->rect == NULL) {
- BKE_image_release_ibuf(image, ibuf, NULL);
- return (int)GL_INVALID_OPERATION;
- }
-
- GPU_create_gl_tex(
- bind, ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, GL_TEXTURE_2D,
- false, false, image);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- if (flag & GP_STYLE_COLOR_TEX_CLAMP) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
- }
- else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- }
- BKE_image_release_ibuf(image, ibuf, NULL);
-
- return error;
+ ImBuf *ibuf;
+ uint *bind = &image->bindcode[TEXTARGET_TEXTURE_2D];
+ int error = GL_NO_ERROR;
+ ImageUser iuser = { NULL };
+ void *lock;
+
+ iuser.ok = true;
+
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+
+ if (ibuf == NULL || ibuf->rect == NULL) {
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ return (int)GL_INVALID_OPERATION;
+ }
+
+ GPU_create_gl_tex(
+ bind, ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, GL_TEXTURE_2D,
+ false, false, image);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ if (flag & GP_STYLE_COLOR_TEX_CLAMP) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ }
+ else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ }
+ BKE_image_release_ibuf(image, ibuf, NULL);
+
+ return error;
}
#endif
/* draw fills for shapes */
-static void gp_draw_stroke_fill(
- bGPdata *gpd, bGPDstroke *gps,
- int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float color[4])
+static void gp_draw_stroke_fill(bGPdata *gpd,
+ bGPDstroke *gps,
+ int offsx,
+ int offsy,
+ int winx,
+ int winy,
+ const float diff_mat[4][4],
+ const float color[4])
{
- BLI_assert(gps->totpoints >= 3);
- Material *ma = gpd->mat[gps->mat_nr];
- MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL;
-
- /* Calculate triangles cache for filling area (must be done only after changes) */
- if ((gps->flag & GP_STROKE_RECALC_GEOMETRY) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
- gp_triangulate_stroke_fill(gps);
- }
- BLI_assert(gps->tot_triangles >= 1);
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_GPENCIL_FILL);
-
- immUniformColor4fv(color);
- immUniform4fv("color2", gp_style->mix_rgba);
- immUniform1i("fill_type", gp_style->fill_style);
- immUniform1f("mix_factor", gp_style->mix_factor);
-
- immUniform1f("gradient_angle", gp_style->gradient_angle);
- immUniform1f("gradient_radius", gp_style->gradient_radius);
- immUniform1f("pattern_gridsize", gp_style->pattern_gridsize);
- immUniform2fv("gradient_scale", gp_style->gradient_scale);
- immUniform2fv("gradient_shift", gp_style->gradient_shift);
-
- immUniform1f("texture_angle", gp_style->texture_angle);
- immUniform2fv("texture_scale", gp_style->texture_scale);
- immUniform2fv("texture_offset", gp_style->texture_offset);
- immUniform1f("texture_opacity", gp_style->texture_opacity);
- immUniform1i("t_mix", (gp_style->flag & GP_STYLE_COLOR_TEX_MIX) != 0);
- immUniform1i("t_flip", (gp_style->flag & GP_STYLE_COLOR_FLIP_FILL) != 0);
+ BLI_assert(gps->totpoints >= 3);
+ Material *ma = gpd->mat[gps->mat_nr];
+ MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL;
+
+ /* Calculate triangles cache for filling area (must be done only after changes) */
+ if ((gps->flag & GP_STROKE_RECALC_GEOMETRY) || (gps->tot_triangles == 0) ||
+ (gps->triangles == NULL)) {
+ gp_triangulate_stroke_fill(gps);
+ }
+ BLI_assert(gps->tot_triangles >= 1);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_GPENCIL_FILL);
+
+ immUniformColor4fv(color);
+ immUniform4fv("color2", gp_style->mix_rgba);
+ immUniform1i("fill_type", gp_style->fill_style);
+ immUniform1f("mix_factor", gp_style->mix_factor);
+
+ immUniform1f("gradient_angle", gp_style->gradient_angle);
+ immUniform1f("gradient_radius", gp_style->gradient_radius);
+ immUniform1f("pattern_gridsize", gp_style->pattern_gridsize);
+ immUniform2fv("gradient_scale", gp_style->gradient_scale);
+ immUniform2fv("gradient_shift", gp_style->gradient_shift);
+
+ immUniform1f("texture_angle", gp_style->texture_angle);
+ immUniform2fv("texture_scale", gp_style->texture_scale);
+ immUniform2fv("texture_offset", gp_style->texture_offset);
+ immUniform1f("texture_opacity", gp_style->texture_opacity);
+ immUniform1i("t_mix", (gp_style->flag & GP_STYLE_COLOR_TEX_MIX) != 0);
+ immUniform1i("t_flip", (gp_style->flag & GP_STYLE_COLOR_FLIP_FILL) != 0);
#if 0 /* GPXX disabled, not used in annotations */
- /* image texture */
- if ((gp_style->fill_style == GP_STYLE_FILL_STYLE_TEXTURE) || (gp_style->flag & GP_STYLE_COLOR_TEX_MIX)) {
- gp_set_filling_texture(gp_style->ima, gp_style->flag);
- }
+ /* image texture */
+ if ((gp_style->fill_style == GP_STYLE_FILL_STYLE_TEXTURE) || (gp_style->flag & GP_STYLE_COLOR_TEX_MIX)) {
+ gp_set_filling_texture(gp_style->ima, gp_style->flag);
+ }
#endif
- /* Draw all triangles for filling the polygon (cache must be calculated before) */
- immBegin(GPU_PRIM_TRIS, gps->tot_triangles * 3);
- /* TODO: use batch instead of immediate mode, to share vertices */
-
- const bGPDtriangle *stroke_triangle = gps->triangles;
- for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
- for (int j = 0; j < 3; j++) {
- gp_add_filldata_tobuffer(
- &gps->points[stroke_triangle->verts[j]], stroke_triangle->uv[j],
- pos, texcoord, gps->flag,
- offsx, offsy, winx, winy, diff_mat);
- }
- }
-
- immEnd();
- immUnbindProgram();
+ /* Draw all triangles for filling the polygon (cache must be calculated before) */
+ immBegin(GPU_PRIM_TRIS, gps->tot_triangles * 3);
+ /* TODO: use batch instead of immediate mode, to share vertices */
+
+ const bGPDtriangle *stroke_triangle = gps->triangles;
+ for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
+ for (int j = 0; j < 3; j++) {
+ gp_add_filldata_tobuffer(&gps->points[stroke_triangle->verts[j]],
+ stroke_triangle->uv[j],
+ pos,
+ texcoord,
+ gps->flag,
+ offsx,
+ offsy,
+ winx,
+ winy,
+ diff_mat);
+ }
+ }
+
+ immEnd();
+ immUnbindProgram();
}
/* ----- Existing Strokes Drawing (3D and Point) ------ */
/* draw a given stroke - just a single dot (only one point) */
-static void gp_draw_stroke_point(
- const bGPDspoint *points, short thickness, short UNUSED(dflag), short sflag,
- int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float ink[4])
+static void gp_draw_stroke_point(const bGPDspoint *points,
+ short thickness,
+ short UNUSED(dflag),
+ short sflag,
+ int offsx,
+ int offsy,
+ int winx,
+ int winy,
+ const float diff_mat[4][4],
+ const float ink[4])
{
- const bGPDspoint *pt = points;
+ const bGPDspoint *pt = points;
- /* get final position using parent matrix */
- float fpt[3];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* get final position using parent matrix */
+ float fpt[3];
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- if (sflag & GP_STROKE_3DSPACE) {
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- }
- else {
- immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ if (sflag & GP_STROKE_3DSPACE) {
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- /* get 2D coordinates of point */
- float co[3] = { 0.0f };
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
- copy_v3_v3(fpt, co);
- }
+ /* get 2D coordinates of point */
+ float co[3] = {0.0f};
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
+ copy_v3_v3(fpt, co);
+ }
- gp_set_point_uniform_color(pt, ink);
- /* set point thickness (since there's only one of these) */
- immUniform1f("size", (float)(thickness + 2) * pt->pressure);
+ gp_set_point_uniform_color(pt, ink);
+ /* set point thickness (since there's only one of these) */
+ immUniform1f("size", (float)(thickness + 2) * pt->pressure);
- immBegin(GPU_PRIM_POINTS, 1);
- immVertex3fv(pos, fpt);
- immEnd();
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(pos, fpt);
+ immEnd();
- immUnbindProgram();
+ immUnbindProgram();
}
/* draw a given stroke in 3d (i.e. in 3d-space) */
static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4], bool cyclic)
{
- bGPDspoint *points = tgpw->gps->points;
- int totpoints = tgpw->gps->totpoints;
-
- const float viewport[2] = { (float)tgpw->winx, (float)tgpw->winy };
- float curpressure = points[0].pressure;
- float fpt[3];
-
- /* if cyclic needs more vertex */
- int cyclic_add = (cyclic) ? 1 : 0;
-
- GPUVertFormat *format = immVertexFormat();
- const struct {
- uint pos, color, thickness;
- } attr_id = {
- .pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT),
- .color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT),
- .thickness = GPU_vertformat_attr_add(format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT),
- };
-
- immBindBuiltinProgram(GPU_SHADER_GPENCIL_STROKE);
- immUniform2fv("Viewport", viewport);
- immUniform1f("pixsize", tgpw->rv3d->pixsize);
- float obj_scale = tgpw->ob ? (tgpw->ob->scale[0] + tgpw->ob->scale[1] + tgpw->ob->scale[2]) / 3.0f : 1.0f;
-
- immUniform1f("objscale", obj_scale);
- int keep_size = (int)((tgpw->gpd) && (tgpw->gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
- immUniform1i("keep_size", keep_size);
- immUniform1f("pixfactor", tgpw->gpd->pixfactor);
- /* xray mode always to 3D space to avoid wrong zdepth calculation (T60051) */
- immUniform1i("xraymode", GP_XRAY_3DSPACE);
- immUniform1i("caps_start", (int)tgpw->gps->caps[0]);
- immUniform1i("caps_end", (int)tgpw->gps->caps[1]);
- immUniform1i("fill_stroke", (int)tgpw->is_fill_stroke);
-
- /* draw stroke curve */
- GPU_line_width(max_ff(curpressure * thickness, 1.0f));
- immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, totpoints + cyclic_add + 2);
- const bGPDspoint *pt = points;
-
- for (int i = 0; i < totpoints; i++, pt++) {
- /* first point for adjacency (not drawn) */
- if (i == 0) {
- gp_set_point_varying_color(points, ink, attr_id.color);
-
- if ((cyclic) && (totpoints > 2)) {
- immAttr1f(attr_id.thickness, max_ff((points + totpoints - 1)->pressure * thickness, 1.0f));
- mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 1)->x);
- }
- else {
- immAttr1f(attr_id.thickness, max_ff((points + 1)->pressure * thickness, 1.0f));
- mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x);
- }
- immVertex3fv(attr_id.pos, fpt);
- }
- /* set point */
- gp_set_point_varying_color(pt, ink, attr_id.color);
- immAttr1f(attr_id.thickness, max_ff(pt->pressure * thickness, 1.0f));
- mul_v3_m4v3(fpt, tgpw->diff_mat, &pt->x);
- immVertex3fv(attr_id.pos, fpt);
- }
-
- if (cyclic && totpoints > 2) {
- /* draw line to first point to complete the cycle */
- immAttr1f(attr_id.thickness, max_ff(points->pressure * thickness, 1.0f));
- mul_v3_m4v3(fpt, tgpw->diff_mat, &points->x);
- immVertex3fv(attr_id.pos, fpt);
-
- /* now add adjacency point (not drawn) */
- immAttr1f(attr_id.thickness, max_ff((points + 1)->pressure * thickness, 1.0f));
- mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x);
- immVertex3fv(attr_id.pos, fpt);
- }
- /* last adjacency point (not drawn) */
- else {
- gp_set_point_varying_color(points + totpoints - 2, ink, attr_id.color);
- immAttr1f(attr_id.thickness, max_ff((points + totpoints - 2)->pressure * thickness, 1.0f));
- mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 2)->x);
- immVertex3fv(attr_id.pos, fpt);
- }
-
- immEnd();
- immUnbindProgram();
+ bGPDspoint *points = tgpw->gps->points;
+ int totpoints = tgpw->gps->totpoints;
+
+ const float viewport[2] = {(float)tgpw->winx, (float)tgpw->winy};
+ float curpressure = points[0].pressure;
+ float fpt[3];
+
+ /* if cyclic needs more vertex */
+ int cyclic_add = (cyclic) ? 1 : 0;
+
+ GPUVertFormat *format = immVertexFormat();
+ const struct {
+ uint pos, color, thickness;
+ } attr_id = {
+ .pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT),
+ .color = GPU_vertformat_attr_add(
+ format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT),
+ .thickness = GPU_vertformat_attr_add(format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT),
+ };
+
+ immBindBuiltinProgram(GPU_SHADER_GPENCIL_STROKE);
+ immUniform2fv("Viewport", viewport);
+ immUniform1f("pixsize", tgpw->rv3d->pixsize);
+ float obj_scale = tgpw->ob ?
+ (tgpw->ob->scale[0] + tgpw->ob->scale[1] + tgpw->ob->scale[2]) / 3.0f :
+ 1.0f;
+
+ immUniform1f("objscale", obj_scale);
+ int keep_size = (int)((tgpw->gpd) && (tgpw->gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
+ immUniform1i("keep_size", keep_size);
+ immUniform1f("pixfactor", tgpw->gpd->pixfactor);
+ /* xray mode always to 3D space to avoid wrong zdepth calculation (T60051) */
+ immUniform1i("xraymode", GP_XRAY_3DSPACE);
+ immUniform1i("caps_start", (int)tgpw->gps->caps[0]);
+ immUniform1i("caps_end", (int)tgpw->gps->caps[1]);
+ immUniform1i("fill_stroke", (int)tgpw->is_fill_stroke);
+
+ /* draw stroke curve */
+ GPU_line_width(max_ff(curpressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, totpoints + cyclic_add + 2);
+ const bGPDspoint *pt = points;
+
+ for (int i = 0; i < totpoints; i++, pt++) {
+ /* first point for adjacency (not drawn) */
+ if (i == 0) {
+ gp_set_point_varying_color(points, ink, attr_id.color);
+
+ if ((cyclic) && (totpoints > 2)) {
+ immAttr1f(attr_id.thickness, max_ff((points + totpoints - 1)->pressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 1)->x);
+ }
+ else {
+ immAttr1f(attr_id.thickness, max_ff((points + 1)->pressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x);
+ }
+ immVertex3fv(attr_id.pos, fpt);
+ }
+ /* set point */
+ gp_set_point_varying_color(pt, ink, attr_id.color);
+ immAttr1f(attr_id.thickness, max_ff(pt->pressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &pt->x);
+ immVertex3fv(attr_id.pos, fpt);
+ }
+
+ if (cyclic && totpoints > 2) {
+ /* draw line to first point to complete the cycle */
+ immAttr1f(attr_id.thickness, max_ff(points->pressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &points->x);
+ immVertex3fv(attr_id.pos, fpt);
+
+ /* now add adjacency point (not drawn) */
+ immAttr1f(attr_id.thickness, max_ff((points + 1)->pressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x);
+ immVertex3fv(attr_id.pos, fpt);
+ }
+ /* last adjacency point (not drawn) */
+ else {
+ gp_set_point_varying_color(points + totpoints - 2, ink, attr_id.color);
+ immAttr1f(attr_id.thickness, max_ff((points + totpoints - 2)->pressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 2)->x);
+ immVertex3fv(attr_id.pos, fpt);
+ }
+
+ immEnd();
+ immUnbindProgram();
}
/* ----- Fancy 2D-Stroke Drawing ------ */
/* draw a given stroke in 2d */
-static void gp_draw_stroke_2d(
- const bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
- bool UNUSED(debug), int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float ink[4])
+static void gp_draw_stroke_2d(const bGPDspoint *points,
+ int totpoints,
+ short thickness_s,
+ short dflag,
+ short sflag,
+ bool UNUSED(debug),
+ int offsx,
+ int offsy,
+ int winx,
+ int winy,
+ const float diff_mat[4][4],
+ const float ink[4])
{
- /* otherwise thickness is twice that of the 3D view */
- float thickness = (float)thickness_s * 0.5f;
-
- /* strokes in Image Editor need a scale factor, since units there are not pixels! */
- float scalefac = 1.0f;
- if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
- scalefac = 0.001f;
- }
-
- /* TODO: fancy++ with the magic of shaders */
-
- /* tessellation code - draw stroke as series of connected quads (triangle strips in fact) with connection
- * edges rotated to minimize shrinking artifacts, and rounded endcaps
- */
- {
- const bGPDspoint *pt1, *pt2;
- float s0[2], s1[2]; /* segment 'center' points */
- float pm[2]; /* normal from previous segment. */
- int i;
- float fpt[3];
-
- GPUVertFormat *format = immVertexFormat();
- const struct {
- uint pos, color;
- } attr_id = {
- .pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT),
- .color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT),
- };
-
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- immBegin(GPU_PRIM_TRI_STRIP, totpoints * 2 + 4);
-
- /* get x and y coordinates from first point */
- mul_v3_m4v3(fpt, diff_mat, &points->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
-
- for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
- float t0[2], t1[2]; /* tessellated coordinates */
- float m1[2], m2[2]; /* gradient and normal */
- float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
- float pthick; /* thickness at segment point */
-
- /* get x and y coordinates from point2 (point1 has already been computed in previous iteration). */
- mul_v3_m4v3(fpt, diff_mat, &pt2->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1);
-
- /* calculate gradient and normal - 'angle'=(ny/nx) */
- m1[1] = s1[1] - s0[1];
- m1[0] = s1[0] - s0[0];
- normalize_v2(m1);
- m2[1] = -m1[0];
- m2[0] = m1[1];
-
- /* always use pressure from first point here */
- pthick = (pt1->pressure * thickness * scalefac);
-
- /* color of point */
- gp_set_point_varying_color(pt1, ink, attr_id.color);
-
- /* if the first segment, start of segment is segment's normal */
- if (i == 0) {
- /* draw start cap first
- * - make points slightly closer to center (about halfway across)
- */
- mt[0] = m2[0] * pthick * 0.5f;
- mt[1] = m2[1] * pthick * 0.5f;
- sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
- sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
-
- t0[0] = sc[0] - mt[0];
- t0[1] = sc[1] - mt[1];
- t1[0] = sc[0] + mt[0];
- t1[1] = sc[1] + mt[1];
-
- /* First two points of cap. */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
-
- /* calculate points for start of segment */
- mt[0] = m2[0] * pthick;
- mt[1] = m2[1] * pthick;
-
- t0[0] = s0[0] - mt[0];
- t0[1] = s0[1] - mt[1];
- t1[0] = s0[0] + mt[0];
- t1[1] = s0[1] + mt[1];
-
- /* Last two points of start cap (and first two points of first segment). */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
- }
- /* if not the first segment, use bisector of angle between segments */
- else {
- float mb[2]; /* bisector normal */
- float athick, dfac; /* actual thickness, difference between thicknesses */
-
- /* calculate gradient of bisector (as average of normals) */
- mb[0] = (pm[0] + m2[0]) / 2;
- mb[1] = (pm[1] + m2[1]) / 2;
- normalize_v2(mb);
-
- /* calculate gradient to apply
- * - as basis, use just pthick * bisector gradient
- * - if cross-section not as thick as it should be, add extra padding to fix it
- */
- mt[0] = mb[0] * pthick;
- mt[1] = mb[1] * pthick;
- athick = len_v2(mt);
- dfac = pthick - (athick * 2);
-
- if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
- mt[0] += (mb[0] * dfac);
- mt[1] += (mb[1] * dfac);
- }
-
- /* calculate points for start of segment */
- t0[0] = s0[0] - mt[0];
- t0[1] = s0[1] - mt[1];
- t1[0] = s0[0] + mt[0];
- t1[1] = s0[1] + mt[1];
-
- /* Last two points of previous segment, and first two points of current segment. */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
- }
-
- /* if last segment, also draw end of segment (defined as segment's normal) */
- if (i == totpoints - 2) {
- /* for once, we use second point's pressure (otherwise it won't be drawn) */
- pthick = (pt2->pressure * thickness * scalefac);
-
- /* color of point */
- gp_set_point_varying_color(pt2, ink, attr_id.color);
-
- /* calculate points for end of segment */
- mt[0] = m2[0] * pthick;
- mt[1] = m2[1] * pthick;
-
- t0[0] = s1[0] - mt[0];
- t0[1] = s1[1] - mt[1];
- t1[0] = s1[0] + mt[0];
- t1[1] = s1[1] + mt[1];
-
- /* Last two points of last segment (and first two points of end cap). */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
-
- /* draw end cap as last step
- * - make points slightly closer to center (about halfway across)
- */
- mt[0] = m2[0] * pthick * 0.5f;
- mt[1] = m2[1] * pthick * 0.5f;
- sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
- sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
-
- t0[0] = sc[0] - mt[0];
- t0[1] = sc[1] - mt[1];
- t1[0] = sc[0] + mt[0];
- t1[1] = sc[1] + mt[1];
-
- /* Last two points of end cap. */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
- }
-
- /* store computed point2 coordinates as point1 ones of next segment. */
- copy_v2_v2(s0, s1);
- /* store stroke's 'natural' normal for next stroke to use */
- copy_v2_v2(pm, m2);
- }
-
- immEnd();
- immUnbindProgram();
- }
+ /* otherwise thickness is twice that of the 3D view */
+ float thickness = (float)thickness_s * 0.5f;
+
+ /* strokes in Image Editor need a scale factor, since units there are not pixels! */
+ float scalefac = 1.0f;
+ if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
+ scalefac = 0.001f;
+ }
+
+ /* TODO: fancy++ with the magic of shaders */
+
+ /* tessellation code - draw stroke as series of connected quads (triangle strips in fact) with connection
+ * edges rotated to minimize shrinking artifacts, and rounded endcaps
+ */
+ {
+ const bGPDspoint *pt1, *pt2;
+ float s0[2], s1[2]; /* segment 'center' points */
+ float pm[2]; /* normal from previous segment. */
+ int i;
+ float fpt[3];
+
+ GPUVertFormat *format = immVertexFormat();
+ const struct {
+ uint pos, color;
+ } attr_id = {
+ .pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT),
+ .color = GPU_vertformat_attr_add(
+ format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT),
+ };
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GPU_PRIM_TRI_STRIP, totpoints * 2 + 4);
+
+ /* get x and y coordinates from first point */
+ mul_v3_m4v3(fpt, diff_mat, &points->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
+
+ for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
+ float t0[2], t1[2]; /* tessellated coordinates */
+ float m1[2], m2[2]; /* gradient and normal */
+ float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
+ float pthick; /* thickness at segment point */
+
+ /* get x and y coordinates from point2 (point1 has already been computed in previous iteration). */
+ mul_v3_m4v3(fpt, diff_mat, &pt2->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1);
+
+ /* calculate gradient and normal - 'angle'=(ny/nx) */
+ m1[1] = s1[1] - s0[1];
+ m1[0] = s1[0] - s0[0];
+ normalize_v2(m1);
+ m2[1] = -m1[0];
+ m2[0] = m1[1];
+
+ /* always use pressure from first point here */
+ pthick = (pt1->pressure * thickness * scalefac);
+
+ /* color of point */
+ gp_set_point_varying_color(pt1, ink, attr_id.color);
+
+ /* if the first segment, start of segment is segment's normal */
+ if (i == 0) {
+ /* draw start cap first
+ * - make points slightly closer to center (about halfway across)
+ */
+ mt[0] = m2[0] * pthick * 0.5f;
+ mt[1] = m2[1] * pthick * 0.5f;
+ sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
+ sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
+
+ t0[0] = sc[0] - mt[0];
+ t0[1] = sc[1] - mt[1];
+ t1[0] = sc[0] + mt[0];
+ t1[1] = sc[1] + mt[1];
+
+ /* First two points of cap. */
+ immVertex2fv(attr_id.pos, t0);
+ immVertex2fv(attr_id.pos, t1);
+
+ /* calculate points for start of segment */
+ mt[0] = m2[0] * pthick;
+ mt[1] = m2[1] * pthick;
+
+ t0[0] = s0[0] - mt[0];
+ t0[1] = s0[1] - mt[1];
+ t1[0] = s0[0] + mt[0];
+ t1[1] = s0[1] + mt[1];
+
+ /* Last two points of start cap (and first two points of first segment). */
+ immVertex2fv(attr_id.pos, t0);
+ immVertex2fv(attr_id.pos, t1);
+ }
+ /* if not the first segment, use bisector of angle between segments */
+ else {
+ float mb[2]; /* bisector normal */
+ float athick, dfac; /* actual thickness, difference between thicknesses */
+
+ /* calculate gradient of bisector (as average of normals) */
+ mb[0] = (pm[0] + m2[0]) / 2;
+ mb[1] = (pm[1] + m2[1]) / 2;
+ normalize_v2(mb);
+
+ /* calculate gradient to apply
+ * - as basis, use just pthick * bisector gradient
+ * - if cross-section not as thick as it should be, add extra padding to fix it
+ */
+ mt[0] = mb[0] * pthick;
+ mt[1] = mb[1] * pthick;
+ athick = len_v2(mt);
+ dfac = pthick - (athick * 2);
+
+ if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
+ mt[0] += (mb[0] * dfac);
+ mt[1] += (mb[1] * dfac);
+ }
+
+ /* calculate points for start of segment */
+ t0[0] = s0[0] - mt[0];
+ t0[1] = s0[1] - mt[1];
+ t1[0] = s0[0] + mt[0];
+ t1[1] = s0[1] + mt[1];
+
+ /* Last two points of previous segment, and first two points of current segment. */
+ immVertex2fv(attr_id.pos, t0);
+ immVertex2fv(attr_id.pos, t1);
+ }
+
+ /* if last segment, also draw end of segment (defined as segment's normal) */
+ if (i == totpoints - 2) {
+ /* for once, we use second point's pressure (otherwise it won't be drawn) */
+ pthick = (pt2->pressure * thickness * scalefac);
+
+ /* color of point */
+ gp_set_point_varying_color(pt2, ink, attr_id.color);
+
+ /* calculate points for end of segment */
+ mt[0] = m2[0] * pthick;
+ mt[1] = m2[1] * pthick;
+
+ t0[0] = s1[0] - mt[0];
+ t0[1] = s1[1] - mt[1];
+ t1[0] = s1[0] + mt[0];
+ t1[1] = s1[1] + mt[1];
+
+ /* Last two points of last segment (and first two points of end cap). */
+ immVertex2fv(attr_id.pos, t0);
+ immVertex2fv(attr_id.pos, t1);
+
+ /* draw end cap as last step
+ * - make points slightly closer to center (about halfway across)
+ */
+ mt[0] = m2[0] * pthick * 0.5f;
+ mt[1] = m2[1] * pthick * 0.5f;
+ sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
+ sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
+
+ t0[0] = sc[0] - mt[0];
+ t0[1] = sc[1] - mt[1];
+ t1[0] = sc[0] + mt[0];
+ t1[1] = sc[1] + mt[1];
+
+ /* Last two points of end cap. */
+ immVertex2fv(attr_id.pos, t0);
+ immVertex2fv(attr_id.pos, t1);
+ }
+
+ /* store computed point2 coordinates as point1 ones of next segment. */
+ copy_v2_v2(s0, s1);
+ /* store stroke's 'natural' normal for next stroke to use */
+ copy_v2_v2(pm, m2);
+ }
+
+ immEnd();
+ immUnbindProgram();
+ }
}
/* ----- Strokes Drawing ------ */
@@ -764,335 +814,371 @@ static void gp_draw_stroke_2d(
/* Helper for doing all the checks on whether a stroke can be drawn */
static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
{
- /* skip stroke if it isn't in the right display space for this drawing context */
- /* 1) 3D Strokes */
- if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
- return false;
- if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
- return false;
-
- /* 2) Screen Space 2D Strokes */
- if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
- return false;
- if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
- return false;
-
- /* 3) Image Space (2D) */
- if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
- return false;
- if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
- return false;
-
- /* skip stroke if it doesn't have any valid data */
- if ((gps->points == NULL) || (gps->totpoints < 1))
- return false;
-
- /* stroke can be drawn */
- return true;
+ /* skip stroke if it isn't in the right display space for this drawing context */
+ /* 1) 3D Strokes */
+ if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
+ return false;
+
+ /* 2) Screen Space 2D Strokes */
+ if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
+ return false;
+
+ /* 3) Image Space (2D) */
+ if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
+ return false;
+
+ /* skip stroke if it doesn't have any valid data */
+ if ((gps->points == NULL) || (gps->totpoints < 1))
+ return false;
+
+ /* stroke can be drawn */
+ return true;
}
/* draw a set of strokes */
static void gp_draw_strokes(tGPDdraw *tgpw)
{
- float tcolor[4];
- float tfill[4];
- short sthickness;
- float ink[4];
-
- GPU_enable_program_point_size();
-
- for (bGPDstroke *gps = tgpw->t_gpf->strokes.first; gps; gps = gps->next) {
- /* check if stroke can be drawn */
- if (gp_can_draw_stroke(gps, tgpw->dflag) == false) {
- continue;
- }
- /* check if the color is visible */
- Material *ma = tgpw->gpd->mat[gps->mat_nr];
- MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL;
-
- if ((gp_style == NULL) ||
- (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
- /* if onion and ghost flag do not draw*/
- (tgpw->onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN)))
- {
- continue;
- }
-
- /* if disable fill, the colors with fill must be omitted too except fill boundary strokes */
- if ((tgpw->disable_fill == 1) &&
- (gp_style->fill_rgba[3] > 0.0f) &&
- ((gps->flag & GP_STROKE_NOFILL) == 0))
- {
- continue;
- }
-
- /* calculate thickness */
- sthickness = gps->thickness + tgpw->lthick;
-
- if (tgpw->is_fill_stroke) {
- sthickness = (short)max_ii(1, sthickness / 2);
- }
-
- if (sthickness <= 0) {
- continue;
- }
-
- /* check which stroke-drawer to use */
- if (tgpw->dflag & GP_DRAWDATA_ONLY3D) {
- const int no_xray = (tgpw->dflag & GP_DRAWDATA_NO_XRAY);
- int mask_orig = 0;
-
- if (no_xray) {
- glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
- glDepthMask(0);
- GPU_depth_test(true);
-
- /* first arg is normally rv3d->dist, but this isn't
- * available here and seems to work quite well without */
- bglPolygonOffset(1.0f, 1.0f);
- }
-
- /* 3D Fill */
- //if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
- if ((gps->totpoints >= 3) && (tgpw->disable_fill != 1)) {
- /* set color using material, tint color and opacity */
- interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
- tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity;
- if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
- const float *color;
- if (!tgpw->onion) {
- color = tfill;
- }
- else {
- if (tgpw->custonion) {
- color = tgpw->tintcolor;
- }
- else {
- ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]);
- color = tfill;
- }
- }
- gp_draw_stroke_fill(
- tgpw->gpd, gps,
- tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, color);
- }
- }
-
- /* 3D Stroke */
- /* set color using material tint color and opacity */
- if (!tgpw->onion) {
- interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
- tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity;
- copy_v4_v4(ink, tcolor);
- }
- else {
- if (tgpw->custonion) {
- copy_v4_v4(ink, tgpw->tintcolor);
- }
- else {
- ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity);
- copy_v4_v4(ink, tcolor);
- }
- }
- if (gp_style->mode == GP_STYLE_MODE_DOTS) {
- /* volumetric stroke drawing */
- if (tgpw->disable_fill != 1) {
- gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink);
- }
- }
- else {
- /* 3D Lines - OpenGL primitives-based */
- if (gps->totpoints == 1) {
- if (tgpw->disable_fill != 1) {
- gp_draw_stroke_point(
- gps->points, sthickness, tgpw->dflag, gps->flag,
- tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy,
- tgpw->diff_mat, ink);
- }
- }
- else {
- tgpw->gps = gps;
- gp_draw_stroke_3d(tgpw, sthickness, ink, gps->flag & GP_STROKE_CYCLIC);
- }
- }
- if (no_xray) {
- glDepthMask(mask_orig);
- GPU_depth_test(false);
-
- bglPolygonOffset(0.0, 0.0);
- }
- }
- else {
- /* 2D - Fill */
- if (gps->totpoints >= 3) {
- /* set color using material, tint color and opacity */
- interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
- tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity;
- if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
- const float *color;
- if (!tgpw->onion) {
- color = tfill;
- }
- else {
- if (tgpw->custonion) {
- color = tgpw->tintcolor;
- }
- else {
- ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]);
- color = tfill;
- }
- }
- gp_draw_stroke_fill(
- tgpw->gpd, gps,
- tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, color);
- }
- }
-
- /* 2D Strokes... */
- /* set color using material, tint color and opacity */
- if (!tgpw->onion) {
- interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
- tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity;
- copy_v4_v4(ink, tcolor);
- }
- else {
- if (tgpw->custonion) {
- copy_v4_v4(ink, tgpw->tintcolor);
- }
- else {
- ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity);
- copy_v4_v4(ink, tcolor);
- }
- }
- if (gp_style->mode == GP_STYLE_MODE_DOTS) {
- /* blob/disk-based "volumetric" drawing */
- gp_draw_stroke_volumetric_2d(
- gps->points, gps->totpoints, sthickness, tgpw->dflag, gps->flag,
- tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, ink);
- }
- else {
- /* normal 2D strokes */
- if (gps->totpoints == 1) {
- gp_draw_stroke_point(
- gps->points, sthickness, tgpw->dflag, gps->flag,
- tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy,
- tgpw->diff_mat, ink);
- }
- else {
- gp_draw_stroke_2d(
- gps->points, gps->totpoints, sthickness, tgpw->dflag, gps->flag, false,
- tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, ink);
- }
- }
- }
- }
-
- GPU_disable_program_point_size();
+ float tcolor[4];
+ float tfill[4];
+ short sthickness;
+ float ink[4];
+
+ GPU_enable_program_point_size();
+
+ for (bGPDstroke *gps = tgpw->t_gpf->strokes.first; gps; gps = gps->next) {
+ /* check if stroke can be drawn */
+ if (gp_can_draw_stroke(gps, tgpw->dflag) == false) {
+ continue;
+ }
+ /* check if the color is visible */
+ Material *ma = tgpw->gpd->mat[gps->mat_nr];
+ MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL;
+
+ if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
+ /* if onion and ghost flag do not draw*/
+ (tgpw->onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN))) {
+ continue;
+ }
+
+ /* if disable fill, the colors with fill must be omitted too except fill boundary strokes */
+ if ((tgpw->disable_fill == 1) && (gp_style->fill_rgba[3] > 0.0f) &&
+ ((gps->flag & GP_STROKE_NOFILL) == 0)) {
+ continue;
+ }
+
+ /* calculate thickness */
+ sthickness = gps->thickness + tgpw->lthick;
+
+ if (tgpw->is_fill_stroke) {
+ sthickness = (short)max_ii(1, sthickness / 2);
+ }
+
+ if (sthickness <= 0) {
+ continue;
+ }
+
+ /* check which stroke-drawer to use */
+ if (tgpw->dflag & GP_DRAWDATA_ONLY3D) {
+ const int no_xray = (tgpw->dflag & GP_DRAWDATA_NO_XRAY);
+ int mask_orig = 0;
+
+ if (no_xray) {
+ glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
+ glDepthMask(0);
+ GPU_depth_test(true);
+
+ /* first arg is normally rv3d->dist, but this isn't
+ * available here and seems to work quite well without */
+ bglPolygonOffset(1.0f, 1.0f);
+ }
+
+ /* 3D Fill */
+ //if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
+ if ((gps->totpoints >= 3) && (tgpw->disable_fill != 1)) {
+ /* set color using material, tint color and opacity */
+ interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
+ tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity;
+ if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
+ const float *color;
+ if (!tgpw->onion) {
+ color = tfill;
+ }
+ else {
+ if (tgpw->custonion) {
+ color = tgpw->tintcolor;
+ }
+ else {
+ ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]);
+ color = tfill;
+ }
+ }
+ gp_draw_stroke_fill(tgpw->gpd,
+ gps,
+ tgpw->offsx,
+ tgpw->offsy,
+ tgpw->winx,
+ tgpw->winy,
+ tgpw->diff_mat,
+ color);
+ }
+ }
+
+ /* 3D Stroke */
+ /* set color using material tint color and opacity */
+ if (!tgpw->onion) {
+ interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
+ tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity;
+ copy_v4_v4(ink, tcolor);
+ }
+ else {
+ if (tgpw->custonion) {
+ copy_v4_v4(ink, tgpw->tintcolor);
+ }
+ else {
+ ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity);
+ copy_v4_v4(ink, tcolor);
+ }
+ }
+ if (gp_style->mode == GP_STYLE_MODE_DOTS) {
+ /* volumetric stroke drawing */
+ if (tgpw->disable_fill != 1) {
+ gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink);
+ }
+ }
+ else {
+ /* 3D Lines - OpenGL primitives-based */
+ if (gps->totpoints == 1) {
+ if (tgpw->disable_fill != 1) {
+ gp_draw_stroke_point(gps->points,
+ sthickness,
+ tgpw->dflag,
+ gps->flag,
+ tgpw->offsx,
+ tgpw->offsy,
+ tgpw->winx,
+ tgpw->winy,
+ tgpw->diff_mat,
+ ink);
+ }
+ }
+ else {
+ tgpw->gps = gps;
+ gp_draw_stroke_3d(tgpw, sthickness, ink, gps->flag & GP_STROKE_CYCLIC);
+ }
+ }
+ if (no_xray) {
+ glDepthMask(mask_orig);
+ GPU_depth_test(false);
+
+ bglPolygonOffset(0.0, 0.0);
+ }
+ }
+ else {
+ /* 2D - Fill */
+ if (gps->totpoints >= 3) {
+ /* set color using material, tint color and opacity */
+ interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
+ tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity;
+ if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
+ const float *color;
+ if (!tgpw->onion) {
+ color = tfill;
+ }
+ else {
+ if (tgpw->custonion) {
+ color = tgpw->tintcolor;
+ }
+ else {
+ ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]);
+ color = tfill;
+ }
+ }
+ gp_draw_stroke_fill(tgpw->gpd,
+ gps,
+ tgpw->offsx,
+ tgpw->offsy,
+ tgpw->winx,
+ tgpw->winy,
+ tgpw->diff_mat,
+ color);
+ }
+ }
+
+ /* 2D Strokes... */
+ /* set color using material, tint color and opacity */
+ if (!tgpw->onion) {
+ interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
+ tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity;
+ copy_v4_v4(ink, tcolor);
+ }
+ else {
+ if (tgpw->custonion) {
+ copy_v4_v4(ink, tgpw->tintcolor);
+ }
+ else {
+ ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity);
+ copy_v4_v4(ink, tcolor);
+ }
+ }
+ if (gp_style->mode == GP_STYLE_MODE_DOTS) {
+ /* blob/disk-based "volumetric" drawing */
+ gp_draw_stroke_volumetric_2d(gps->points,
+ gps->totpoints,
+ sthickness,
+ tgpw->dflag,
+ gps->flag,
+ tgpw->offsx,
+ tgpw->offsy,
+ tgpw->winx,
+ tgpw->winy,
+ tgpw->diff_mat,
+ ink);
+ }
+ else {
+ /* normal 2D strokes */
+ if (gps->totpoints == 1) {
+ gp_draw_stroke_point(gps->points,
+ sthickness,
+ tgpw->dflag,
+ gps->flag,
+ tgpw->offsx,
+ tgpw->offsy,
+ tgpw->winx,
+ tgpw->winy,
+ tgpw->diff_mat,
+ ink);
+ }
+ else {
+ gp_draw_stroke_2d(gps->points,
+ gps->totpoints,
+ sthickness,
+ tgpw->dflag,
+ gps->flag,
+ false,
+ tgpw->offsx,
+ tgpw->offsy,
+ tgpw->winx,
+ tgpw->winy,
+ tgpw->diff_mat,
+ ink);
+ }
+ }
+ }
+ }
+
+ GPU_disable_program_point_size();
}
/* ----- General Drawing ------ */
-
/* draw interpolate strokes (used only while operator is running) */
void ED_gp_draw_interpolation(const bContext *C, tGPDinterpolate *tgpi, const int type)
{
- tGPDdraw tgpw;
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = ar->regiondata;
- tGPDinterpolate_layer *tgpil;
- Object *obact = CTX_data_active_object(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
-
- float color[4];
-
- UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, color);
- color[3] = 0.6f;
- int dflag = 0;
- /* if 3d stuff, enable flags */
- if (type == REGION_DRAW_POST_VIEW) {
- dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
- }
-
- tgpw.rv3d = rv3d;
- tgpw.depsgraph = depsgraph;
- tgpw.ob = obact;
- tgpw.gpd = tgpi->gpd;
- tgpw.offsx = 0;
- tgpw.offsy = 0;
- tgpw.winx = tgpi->ar->winx;
- tgpw.winy = tgpi->ar->winy;
- tgpw.dflag = dflag;
-
- /* turn on alpha-blending */
- GPU_blend(true);
- for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
- /* calculate parent position */
- ED_gpencil_parent_location(depsgraph, obact, tgpi->gpd, tgpil->gpl, tgpw.diff_mat);
- if (tgpil->interFrame) {
- tgpw.gpl = tgpil->gpl;
- tgpw.gpf = tgpil->interFrame;
- tgpw.t_gpf = tgpil->interFrame;
-
- tgpw.lthick = tgpil->gpl->line_change;
- tgpw.opacity = 1.0;
- copy_v4_v4(tgpw.tintcolor, color);
- tgpw.onion = true;
- tgpw.custonion = true;
-
- gp_draw_strokes(&tgpw);
- }
- }
- GPU_blend(false);
+ tGPDdraw tgpw;
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+ tGPDinterpolate_layer *tgpil;
+ Object *obact = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ float color[4];
+
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, color);
+ color[3] = 0.6f;
+ int dflag = 0;
+ /* if 3d stuff, enable flags */
+ if (type == REGION_DRAW_POST_VIEW) {
+ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
+ }
+
+ tgpw.rv3d = rv3d;
+ tgpw.depsgraph = depsgraph;
+ tgpw.ob = obact;
+ tgpw.gpd = tgpi->gpd;
+ tgpw.offsx = 0;
+ tgpw.offsy = 0;
+ tgpw.winx = tgpi->ar->winx;
+ tgpw.winy = tgpi->ar->winy;
+ tgpw.dflag = dflag;
+
+ /* turn on alpha-blending */
+ GPU_blend(true);
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ /* calculate parent position */
+ ED_gpencil_parent_location(depsgraph, obact, tgpi->gpd, tgpil->gpl, tgpw.diff_mat);
+ if (tgpil->interFrame) {
+ tgpw.gpl = tgpil->gpl;
+ tgpw.gpf = tgpil->interFrame;
+ tgpw.t_gpf = tgpil->interFrame;
+
+ tgpw.lthick = tgpil->gpl->line_change;
+ tgpw.opacity = 1.0;
+ copy_v4_v4(tgpw.tintcolor, color);
+ tgpw.onion = true;
+ tgpw.custonion = true;
+
+ gp_draw_strokes(&tgpw);
+ }
+ }
+ GPU_blend(false);
}
/* wrapper to draw strokes for filling operator */
void ED_gp_draw_fill(tGPDdraw *tgpw)
{
- gp_draw_strokes(tgpw);
+ gp_draw_strokes(tgpw);
}
/* draw a short status message in the top-right corner */
static void UNUSED_FUNCTION(gp_draw_status_text)(const bGPdata *gpd, ARegion *ar)
{
- rcti rect;
+ rcti rect;
- /* Cannot draw any status text when drawing OpenGL Renders */
- if (G.f & G_FLAG_RENDER_VIEWPORT)
- return;
+ /* Cannot draw any status text when drawing OpenGL Renders */
+ if (G.f & G_FLAG_RENDER_VIEWPORT)
+ return;
- /* Get bounds of region - Necessary to avoid problems with region overlap */
- ED_region_visible_rect(ar, &rect);
+ /* Get bounds of region - Necessary to avoid problems with region overlap */
+ ED_region_visible_rect(ar, &rect);
- /* for now, this should only be used to indicate when we are in stroke editmode */
- if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
- const char *printable = IFACE_("GPencil Stroke Editing");
- float printable_size[2];
+ /* for now, this should only be used to indicate when we are in stroke editmode */
+ if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ const char *printable = IFACE_("GPencil Stroke Editing");
+ float printable_size[2];
- int font_id = BLF_default();
+ int font_id = BLF_default();
- BLF_width_and_height(font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
+ BLF_width_and_height(
+ font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
- int xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
- int yco = (rect.ymax - U.widget_unit);
+ int xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
+ int yco = (rect.ymax - U.widget_unit);
- /* text label */
- UI_FontThemeColor(font_id, TH_TEXT_HI);
+ /* text label */
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
#ifdef WITH_INTERNATIONAL
- BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
#else
- BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
#endif
- /* grease pencil icon... */
- // XXX: is this too intrusive?
- GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- GPU_blend(true);
+ /* grease pencil icon... */
+ // XXX: is this too intrusive?
+ GPU_blend_set_func_separate(
+ GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
- xco -= U.widget_unit;
- yco -= (int)printable_size[1] / 2;
+ xco -= U.widget_unit;
+ yco -= (int)printable_size[1] / 2;
- UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
+ UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
- GPU_blend(false);
- }
+ GPU_blend(false);
+ }
}
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index 8ada5a05618..4724dc068b6 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -21,7 +21,6 @@
* \ingroup edgpencil
*/
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -59,21 +58,21 @@
/* Loops over the gp-frames for a gp-layer, and applies the given callback */
bool ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPDframe *, Scene *))
{
- bGPDframe *gpf;
+ bGPDframe *gpf;
- /* error checker */
- if (gpl == NULL)
- return false;
+ /* error checker */
+ if (gpl == NULL)
+ return false;
- /* do loop */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- /* execute callback */
- if (gpf_cb(gpf, scene))
- return true;
- }
+ /* do loop */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* execute callback */
+ if (gpf_cb(gpf, scene))
+ return true;
+ }
- /* nothing to return */
- return false;
+ /* nothing to return */
+ return false;
}
/* ****************************************** */
@@ -82,24 +81,24 @@ bool ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPD
/* make a listing all the gp-frames in a layer as cfraelems */
void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel)
{
- bGPDframe *gpf;
- CfraElem *ce;
+ bGPDframe *gpf;
+ CfraElem *ce;
- /* error checking */
- if (ELEM(NULL, gpl, elems))
- return;
+ /* error checking */
+ if (ELEM(NULL, gpl, elems))
+ return;
- /* loop through gp-frames, adding */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if ((onlysel == 0) || (gpf->flag & GP_FRAME_SELECT)) {
- ce = MEM_callocN(sizeof(CfraElem), "CfraElem");
+ /* loop through gp-frames, adding */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if ((onlysel == 0) || (gpf->flag & GP_FRAME_SELECT)) {
+ ce = MEM_callocN(sizeof(CfraElem), "CfraElem");
- ce->cfra = (float)gpf->framenum;
- ce->sel = (gpf->flag & GP_FRAME_SELECT) ? 1 : 0;
+ ce->cfra = (float)gpf->framenum;
+ ce->sel = (gpf->flag & GP_FRAME_SELECT) ? 1 : 0;
- BLI_addtail(elems, ce);
- }
- }
+ BLI_addtail(elems, ce);
+ }
+ }
}
/* ***************************************** */
@@ -108,125 +107,128 @@ void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel)
/* check if one of the frames in this layer is selected */
bool ED_gplayer_frame_select_check(bGPDlayer *gpl)
{
- bGPDframe *gpf;
+ bGPDframe *gpf;
- /* error checking */
- if (gpl == NULL)
- return false;
+ /* error checking */
+ if (gpl == NULL)
+ return false;
- /* stop at the first one found */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT)
- return true;
- }
+ /* stop at the first one found */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT)
+ return true;
+ }
- /* not found */
- return false;
+ /* not found */
+ return false;
}
/* helper function - select gp-frame based on SELECT_* mode */
static void gpframe_select(bGPDframe *gpf, short select_mode)
{
- if (gpf == NULL)
- return;
-
- switch (select_mode) {
- case SELECT_ADD:
- gpf->flag |= GP_FRAME_SELECT;
- break;
- case SELECT_SUBTRACT:
- gpf->flag &= ~GP_FRAME_SELECT;
- break;
- case SELECT_INVERT:
- gpf->flag ^= GP_FRAME_SELECT;
- break;
- }
+ if (gpf == NULL)
+ return;
+
+ switch (select_mode) {
+ case SELECT_ADD:
+ gpf->flag |= GP_FRAME_SELECT;
+ break;
+ case SELECT_SUBTRACT:
+ gpf->flag &= ~GP_FRAME_SELECT;
+ break;
+ case SELECT_INVERT:
+ gpf->flag ^= GP_FRAME_SELECT;
+ break;
+ }
}
/* set all/none/invert select (like above, but with SELECT_* modes) */
void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
{
- bGPDframe *gpf;
+ bGPDframe *gpf;
- /* error checking */
- if (gpl == NULL)
- return;
+ /* error checking */
+ if (gpl == NULL)
+ return;
- /* handle according to mode */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- gpframe_select(gpf, select_mode);
- }
+ /* handle according to mode */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ gpframe_select(gpf, select_mode);
+ }
}
/* set all/none/invert select */
void ED_gplayer_frame_select_set(bGPDlayer *gpl, short mode)
{
- /* error checking */
- if (gpl == NULL)
- return;
+ /* error checking */
+ if (gpl == NULL)
+ return;
- /* now call the standard function */
- ED_gpencil_select_frames(gpl, mode);
+ /* now call the standard function */
+ ED_gpencil_select_frames(gpl, mode);
}
/* select the frame in this layer that occurs on this frame (there should only be one at most) */
void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
{
- bGPDframe *gpf;
+ bGPDframe *gpf;
- if (gpl == NULL)
- return;
+ if (gpl == NULL)
+ return;
- gpf = BKE_gpencil_layer_find_frame(gpl, selx);
+ gpf = BKE_gpencil_layer_find_frame(gpl, selx);
- if (gpf) {
- gpframe_select(gpf, select_mode);
- }
+ if (gpf) {
+ gpframe_select(gpf, select_mode);
+ }
}
/* select the frames in this layer that occur within the bounds specified */
void ED_gplayer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode)
{
- bGPDframe *gpf;
+ bGPDframe *gpf;
- if (gpl == NULL)
- return;
+ if (gpl == NULL)
+ return;
- /* only select those frames which are in bounds */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (IN_RANGE(gpf->framenum, min, max))
- gpframe_select(gpf, select_mode);
- }
+ /* only select those frames which are in bounds */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (IN_RANGE(gpf->framenum, min, max))
+ gpframe_select(gpf, select_mode);
+ }
}
/* select the frames in this layer that occur within the lasso/circle region specified */
-void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode)
+void ED_gplayer_frames_select_region(KeyframeEditData *ked,
+ bGPDlayer *gpl,
+ short tool,
+ short select_mode)
{
- bGPDframe *gpf;
-
- if (gpl == NULL)
- return;
-
- /* only select frames which are within the region */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- /* construct a dummy point coordinate to do this testing with */
- float pt[2] = {0};
-
- pt[0] = gpf->framenum;
- pt[1] = ked->channel_y;
-
- /* check the necessary regions */
- if (tool == BEZT_OK_CHANNEL_LASSO) {
- /* Lasso */
- if (keyframe_region_lasso_test(ked->data, pt))
- gpframe_select(gpf, select_mode);
- }
- else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
- /* Circle */
- if (keyframe_region_circle_test(ked->data, pt))
- gpframe_select(gpf, select_mode);
- }
- }
+ bGPDframe *gpf;
+
+ if (gpl == NULL)
+ return;
+
+ /* only select frames which are within the region */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* construct a dummy point coordinate to do this testing with */
+ float pt[2] = {0};
+
+ pt[0] = gpf->framenum;
+ pt[1] = ked->channel_y;
+
+ /* check the necessary regions */
+ if (tool == BEZT_OK_CHANNEL_LASSO) {
+ /* Lasso */
+ if (keyframe_region_lasso_test(ked->data, pt))
+ gpframe_select(gpf, select_mode);
+ }
+ else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
+ /* Circle */
+ if (keyframe_region_circle_test(ked->data, pt))
+ gpframe_select(gpf, select_mode);
+ }
+ }
}
/* ***************************************** */
@@ -235,50 +237,50 @@ void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, shor
/* Delete selected frames */
bool ED_gplayer_frames_delete(bGPDlayer *gpl)
{
- bGPDframe *gpf, *gpfn;
- bool changed = false;
+ bGPDframe *gpf, *gpfn;
+ bool changed = false;
- /* error checking */
- if (gpl == NULL)
- return false;
+ /* error checking */
+ if (gpl == NULL)
+ return false;
- /* check for frames to delete */
- for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
- gpfn = gpf->next;
+ /* check for frames to delete */
+ for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
+ gpfn = gpf->next;
- if (gpf->flag & GP_FRAME_SELECT) {
- BKE_gpencil_layer_delframe(gpl, gpf);
- changed = true;
- }
- }
+ if (gpf->flag & GP_FRAME_SELECT) {
+ BKE_gpencil_layer_delframe(gpl, gpf);
+ changed = true;
+ }
+ }
- return changed;
+ return changed;
}
/* Duplicate selected frames from given gp-layer */
void ED_gplayer_frames_duplicate(bGPDlayer *gpl)
{
- bGPDframe *gpf, *gpfn;
+ bGPDframe *gpf, *gpfn;
- /* error checking */
- if (gpl == NULL)
- return;
+ /* error checking */
+ if (gpl == NULL)
+ return;
- /* duplicate selected frames */
- for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
- gpfn = gpf->next;
+ /* duplicate selected frames */
+ for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
+ gpfn = gpf->next;
- /* duplicate this frame */
- if (gpf->flag & GP_FRAME_SELECT) {
- bGPDframe *gpfd;
+ /* duplicate this frame */
+ if (gpf->flag & GP_FRAME_SELECT) {
+ bGPDframe *gpfd;
- /* duplicate frame, and deselect self */
- gpfd = BKE_gpencil_frame_duplicate(gpf);
- gpf->flag &= ~GP_FRAME_SELECT;
+ /* duplicate frame, and deselect self */
+ gpfd = BKE_gpencil_frame_duplicate(gpf);
+ gpf->flag &= ~GP_FRAME_SELECT;
- BLI_insertlinkafter(&gpl->frames, gpf, gpfd);
- }
- }
+ BLI_insertlinkafter(&gpl->frames, gpf, gpfd);
+ }
+ }
}
/* Set keyframe type for selected frames from given gp-layer
@@ -286,19 +288,18 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl)
*/
void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type)
{
- bGPDframe *gpf;
+ bGPDframe *gpf;
- if (gpl == NULL)
- return;
+ if (gpl == NULL)
+ return;
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT) {
- gpf->key_type = type;
- }
- }
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ gpf->key_type = type;
+ }
+ }
}
-
/* -------------------------------------- */
/* Copy and Paste Tools */
/* - The copy/paste buffer currently stores a set of GP_Layers, with temporary
@@ -311,23 +312,21 @@ void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type)
/* globals for copy/paste data (like for other copy/paste buffers) */
static ListBase gp_anim_copybuf = {NULL, NULL};
-static int gp_anim_copy_firstframe = 999999999;
-static int gp_anim_copy_lastframe = -999999999;
-static int gp_anim_copy_cfra = 0;
-
+static int gp_anim_copy_firstframe = 999999999;
+static int gp_anim_copy_lastframe = -999999999;
+static int gp_anim_copy_cfra = 0;
/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ED_gpencil_anim_copybuf_free(void)
{
- BKE_gpencil_free_layers(&gp_anim_copybuf);
- BLI_listbase_clear(&gp_anim_copybuf);
+ BKE_gpencil_free_layers(&gp_anim_copybuf);
+ BLI_listbase_clear(&gp_anim_copybuf);
- gp_anim_copy_firstframe = 999999999;
- gp_anim_copy_lastframe = -999999999;
- gp_anim_copy_cfra = 0;
+ gp_anim_copy_firstframe = 999999999;
+ gp_anim_copy_lastframe = -999999999;
+ gp_anim_copy_cfra = 0;
}
-
/* This function adds data to the copy/paste buffer, freeing existing data first
* Only the selected GP-layers get their selected keyframes copied.
*
@@ -335,180 +334,177 @@ void ED_gpencil_anim_copybuf_free(void)
*/
bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
{
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- Scene *scene = ac->scene;
-
-
- /* clear buffer first */
- ED_gpencil_anim_copybuf_free();
-
- /* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
-
- /* assume that each of these is a GP layer */
- for (ale = anim_data.first; ale; ale = ale->next) {
- ListBase copied_frames = {NULL, NULL};
- bGPDlayer *gpl = (bGPDlayer *)ale->data;
- bGPDframe *gpf;
-
- /* loop over frames, and copy only selected frames */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- /* if frame is selected, make duplicate it and its strokes */
- if (gpf->flag & GP_FRAME_SELECT) {
- /* make a copy of this frame */
- bGPDframe *new_frame = BKE_gpencil_frame_duplicate(gpf);
- BLI_addtail(&copied_frames, new_frame);
-
- /* extend extents for keyframes encountered */
- if (gpf->framenum < gp_anim_copy_firstframe)
- gp_anim_copy_firstframe = gpf->framenum;
- if (gpf->framenum > gp_anim_copy_lastframe)
- gp_anim_copy_lastframe = gpf->framenum;
- }
- }
-
- /* create a new layer in buffer if there were keyframes here */
- if (BLI_listbase_is_empty(&copied_frames) == false) {
- bGPDlayer *new_layer = MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer");
- BLI_addtail(&gp_anim_copybuf, new_layer);
-
- /* move over copied frames */
- BLI_movelisttolist(&new_layer->frames, &copied_frames);
- BLI_assert(copied_frames.first == NULL);
-
- /* make a copy of the layer's name - for name-based matching later... */
- BLI_strncpy(new_layer->info, gpl->info, sizeof(new_layer->info));
- }
- }
-
- /* in case 'relative' paste method is used */
- gp_anim_copy_cfra = CFRA;
-
- /* clean up */
- ANIM_animdata_freelist(&anim_data);
-
- /* check if anything ended up in the buffer */
- if (ELEM(NULL, gp_anim_copybuf.first, gp_anim_copybuf.last)) {
- BKE_report(ac->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
- return false;
- }
-
- /* report success */
- return true;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ Scene *scene = ac->scene;
+
+ /* clear buffer first */
+ ED_gpencil_anim_copybuf_free();
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* assume that each of these is a GP layer */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ ListBase copied_frames = {NULL, NULL};
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ bGPDframe *gpf;
+
+ /* loop over frames, and copy only selected frames */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* if frame is selected, make duplicate it and its strokes */
+ if (gpf->flag & GP_FRAME_SELECT) {
+ /* make a copy of this frame */
+ bGPDframe *new_frame = BKE_gpencil_frame_duplicate(gpf);
+ BLI_addtail(&copied_frames, new_frame);
+
+ /* extend extents for keyframes encountered */
+ if (gpf->framenum < gp_anim_copy_firstframe)
+ gp_anim_copy_firstframe = gpf->framenum;
+ if (gpf->framenum > gp_anim_copy_lastframe)
+ gp_anim_copy_lastframe = gpf->framenum;
+ }
+ }
+
+ /* create a new layer in buffer if there were keyframes here */
+ if (BLI_listbase_is_empty(&copied_frames) == false) {
+ bGPDlayer *new_layer = MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer");
+ BLI_addtail(&gp_anim_copybuf, new_layer);
+
+ /* move over copied frames */
+ BLI_movelisttolist(&new_layer->frames, &copied_frames);
+ BLI_assert(copied_frames.first == NULL);
+
+ /* make a copy of the layer's name - for name-based matching later... */
+ BLI_strncpy(new_layer->info, gpl->info, sizeof(new_layer->info));
+ }
+ }
+
+ /* in case 'relative' paste method is used */
+ gp_anim_copy_cfra = CFRA;
+
+ /* clean up */
+ ANIM_animdata_freelist(&anim_data);
+
+ /* check if anything ended up in the buffer */
+ if (ELEM(NULL, gp_anim_copybuf.first, gp_anim_copybuf.last)) {
+ BKE_report(ac->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
+ return false;
+ }
+
+ /* report success */
+ return true;
}
-
/* Pastes keyframes from buffer, and reports success */
bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
{
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- Scene *scene = ac->scene;
- bool no_name = false;
- int offset = 0;
-
- /* check if buffer is empty */
- if (BLI_listbase_is_empty(&gp_anim_copybuf)) {
- BKE_report(ac->reports, RPT_ERROR, "No data in buffer to paste");
- return false;
- }
-
- /* check if single channel in buffer (disregard names if so) */
- if (gp_anim_copybuf.first == gp_anim_copybuf.last) {
- no_name = true;
- }
-
- /* methods of offset (eKeyPasteOffset) */
- switch (offset_mode) {
- case KEYFRAME_PASTE_OFFSET_CFRA_START:
- offset = (CFRA - gp_anim_copy_firstframe);
- break;
- case KEYFRAME_PASTE_OFFSET_CFRA_END:
- offset = (CFRA - gp_anim_copy_lastframe);
- break;
- case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
- offset = (CFRA - gp_anim_copy_cfra);
- break;
- case KEYFRAME_PASTE_OFFSET_NONE:
- offset = 0;
- break;
- }
-
-
- /* filter data */
- // TODO: try doing it with selection, then without selection imits
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
-
- /* from selected channels */
- for (ale = anim_data.first; ale; ale = ale->next) {
- bGPDlayer *gpld = (bGPDlayer *)ale->data;
- bGPDlayer *gpls = NULL;
- bGPDframe *gpfs, *gpf;
-
-
- /* find suitable layer from buffer to use to paste from */
- for (gpls = gp_anim_copybuf.first; gpls; gpls = gpls->next) {
- /* check if layer name matches */
- if ((no_name) || STREQ(gpls->info, gpld->info)) {
- break;
- }
- }
-
- /* this situation might occur! */
- if (gpls == NULL)
- continue;
-
- /* add frames from buffer */
- for (gpfs = gpls->frames.first; gpfs; gpfs = gpfs->next) {
- /* temporarily apply offset to buffer-frame while copying */
- gpfs->framenum += offset;
-
- /* get frame to copy data into (if no frame returned, then just ignore) */
- gpf = BKE_gpencil_layer_getframe(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW);
- if (gpf) {
- bGPDstroke *gps, *gpsn;
-
- /* This should be the right frame... as it may be a pre-existing frame,
- * must make sure that only compatible stroke types get copied over
- * - We cannot just add a duplicate frame, as that would cause errors
- * - For now, we don't check if the types will be compatible since we
- * don't have enough info to do so. Instead, we simply just paste,
- * if it works, it will show up.
- */
- for (gps = gpfs->strokes.first; gps; gps = gps->next) {
- /* make a copy of stroke, then of its points array */
- gpsn = MEM_dupallocN(gps);
- gpsn->points = MEM_dupallocN(gps->points);
- if (gps->dvert != NULL) {
- gpsn->dvert = MEM_dupallocN(gps->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps, gpsn);
- }
- /* duplicate triangle information */
- gpsn->triangles = MEM_dupallocN(gps->triangles);
- /* append stroke to frame */
- BLI_addtail(&gpf->strokes, gpsn);
- }
-
- /* if no strokes (i.e. new frame) added, free gpf */
- if (BLI_listbase_is_empty(&gpf->strokes))
- BKE_gpencil_layer_delframe(gpld, gpf);
- }
-
- /* unapply offset from buffer-frame */
- gpfs->framenum -= offset;
- }
- }
-
- /* clean up */
- ANIM_animdata_freelist(&anim_data);
- return true;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ Scene *scene = ac->scene;
+ bool no_name = false;
+ int offset = 0;
+
+ /* check if buffer is empty */
+ if (BLI_listbase_is_empty(&gp_anim_copybuf)) {
+ BKE_report(ac->reports, RPT_ERROR, "No data in buffer to paste");
+ return false;
+ }
+
+ /* check if single channel in buffer (disregard names if so) */
+ if (gp_anim_copybuf.first == gp_anim_copybuf.last) {
+ no_name = true;
+ }
+
+ /* methods of offset (eKeyPasteOffset) */
+ switch (offset_mode) {
+ case KEYFRAME_PASTE_OFFSET_CFRA_START:
+ offset = (CFRA - gp_anim_copy_firstframe);
+ break;
+ case KEYFRAME_PASTE_OFFSET_CFRA_END:
+ offset = (CFRA - gp_anim_copy_lastframe);
+ break;
+ case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
+ offset = (CFRA - gp_anim_copy_cfra);
+ break;
+ case KEYFRAME_PASTE_OFFSET_NONE:
+ offset = 0;
+ break;
+ }
+
+ /* filter data */
+ // TODO: try doing it with selection, then without selection imits
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* from selected channels */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ bGPDlayer *gpld = (bGPDlayer *)ale->data;
+ bGPDlayer *gpls = NULL;
+ bGPDframe *gpfs, *gpf;
+
+ /* find suitable layer from buffer to use to paste from */
+ for (gpls = gp_anim_copybuf.first; gpls; gpls = gpls->next) {
+ /* check if layer name matches */
+ if ((no_name) || STREQ(gpls->info, gpld->info)) {
+ break;
+ }
+ }
+
+ /* this situation might occur! */
+ if (gpls == NULL)
+ continue;
+
+ /* add frames from buffer */
+ for (gpfs = gpls->frames.first; gpfs; gpfs = gpfs->next) {
+ /* temporarily apply offset to buffer-frame while copying */
+ gpfs->framenum += offset;
+
+ /* get frame to copy data into (if no frame returned, then just ignore) */
+ gpf = BKE_gpencil_layer_getframe(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW);
+ if (gpf) {
+ bGPDstroke *gps, *gpsn;
+
+ /* This should be the right frame... as it may be a pre-existing frame,
+ * must make sure that only compatible stroke types get copied over
+ * - We cannot just add a duplicate frame, as that would cause errors
+ * - For now, we don't check if the types will be compatible since we
+ * don't have enough info to do so. Instead, we simply just paste,
+ * if it works, it will show up.
+ */
+ for (gps = gpfs->strokes.first; gps; gps = gps->next) {
+ /* make a copy of stroke, then of its points array */
+ gpsn = MEM_dupallocN(gps);
+ gpsn->points = MEM_dupallocN(gps->points);
+ if (gps->dvert != NULL) {
+ gpsn->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, gpsn);
+ }
+ /* duplicate triangle information */
+ gpsn->triangles = MEM_dupallocN(gps->triangles);
+ /* append stroke to frame */
+ BLI_addtail(&gpf->strokes, gpsn);
+ }
+
+ /* if no strokes (i.e. new frame) added, free gpf */
+ if (BLI_listbase_is_empty(&gpf->strokes))
+ BKE_gpencil_layer_delframe(gpld, gpf);
+ }
+
+ /* unapply offset from buffer-frame */
+ gpfs->framenum -= offset;
+ }
+ }
+
+ /* clean up */
+ ANIM_animdata_freelist(&anim_data);
+ return true;
}
/* -------------------------------------- */
@@ -517,53 +513,54 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
static short snap_gpf_nearest(bGPDframe *UNUSED(gpf), Scene *UNUSED(scene))
{
#if 0 /* note: gpf->framenum is already an int! */
- if (gpf->flag & GP_FRAME_SELECT)
- gpf->framenum = (int)(floor(gpf->framenum + 0.5));
+ if (gpf->flag & GP_FRAME_SELECT)
+ gpf->framenum = (int)(floor(gpf->framenum + 0.5));
#endif
- return 0;
+ return 0;
}
static short snap_gpf_nearestsec(bGPDframe *gpf, Scene *scene)
{
- float secf = (float)FPS;
- if (gpf->flag & GP_FRAME_SELECT)
- gpf->framenum = (int)(floorf(gpf->framenum / secf + 0.5f) * secf);
- return 0;
+ float secf = (float)FPS;
+ if (gpf->flag & GP_FRAME_SELECT)
+ gpf->framenum = (int)(floorf(gpf->framenum / secf + 0.5f) * secf);
+ return 0;
}
static short snap_gpf_cframe(bGPDframe *gpf, Scene *scene)
{
- if (gpf->flag & GP_FRAME_SELECT)
- gpf->framenum = (int)CFRA;
- return 0;
+ if (gpf->flag & GP_FRAME_SELECT)
+ gpf->framenum = (int)CFRA;
+ return 0;
}
static short snap_gpf_nearmarker(bGPDframe *gpf, Scene *scene)
{
- if (gpf->flag & GP_FRAME_SELECT)
- gpf->framenum = (int)ED_markers_find_nearest_marker_time(&scene->markers, (float)gpf->framenum);
- return 0;
+ if (gpf->flag & GP_FRAME_SELECT)
+ gpf->framenum = (int)ED_markers_find_nearest_marker_time(&scene->markers,
+ (float)gpf->framenum);
+ return 0;
}
/* snap selected frames to ... */
void ED_gplayer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode)
{
- switch (mode) {
- case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
- ED_gplayer_frames_looper(gpl, scene, snap_gpf_nearest);
- break;
- case SNAP_KEYS_CURFRAME: /* snap to current frame */
- ED_gplayer_frames_looper(gpl, scene, snap_gpf_cframe);
- break;
- case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
- ED_gplayer_frames_looper(gpl, scene, snap_gpf_nearmarker);
- break;
- case SNAP_KEYS_NEARSEC: /* snap to nearest second */
- ED_gplayer_frames_looper(gpl, scene, snap_gpf_nearestsec);
- break;
- default: /* just in case */
- break;
- }
+ switch (mode) {
+ case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
+ ED_gplayer_frames_looper(gpl, scene, snap_gpf_nearest);
+ break;
+ case SNAP_KEYS_CURFRAME: /* snap to current frame */
+ ED_gplayer_frames_looper(gpl, scene, snap_gpf_cframe);
+ break;
+ case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
+ ED_gplayer_frames_looper(gpl, scene, snap_gpf_nearmarker);
+ break;
+ case SNAP_KEYS_NEARSEC: /* snap to nearest second */
+ ED_gplayer_frames_looper(gpl, scene, snap_gpf_nearestsec);
+ break;
+ default: /* just in case */
+ break;
+ }
}
/* -------------------------------------- */
@@ -571,105 +568,104 @@ void ED_gplayer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode)
static short mirror_gpf_cframe(bGPDframe *gpf, Scene *scene)
{
- int diff;
+ int diff;
- if (gpf->flag & GP_FRAME_SELECT) {
- diff = CFRA - gpf->framenum;
- gpf->framenum = CFRA + diff;
- }
+ if (gpf->flag & GP_FRAME_SELECT) {
+ diff = CFRA - gpf->framenum;
+ gpf->framenum = CFRA + diff;
+ }
- return 0;
+ return 0;
}
static short mirror_gpf_yaxis(bGPDframe *gpf, Scene *UNUSED(scene))
{
- int diff;
+ int diff;
- if (gpf->flag & GP_FRAME_SELECT) {
- diff = -gpf->framenum;
- gpf->framenum = diff;
- }
+ if (gpf->flag & GP_FRAME_SELECT) {
+ diff = -gpf->framenum;
+ gpf->framenum = diff;
+ }
- return 0;
+ return 0;
}
static short mirror_gpf_xaxis(bGPDframe *gpf, Scene *UNUSED(scene))
{
- int diff;
+ int diff;
- /* NOTE: since we can't really do this, we just do the same as for yaxis... */
- if (gpf->flag & GP_FRAME_SELECT) {
- diff = -gpf->framenum;
- gpf->framenum = diff;
- }
+ /* NOTE: since we can't really do this, we just do the same as for yaxis... */
+ if (gpf->flag & GP_FRAME_SELECT) {
+ diff = -gpf->framenum;
+ gpf->framenum = diff;
+ }
- return 0;
+ return 0;
}
static short mirror_gpf_marker(bGPDframe *gpf, Scene *scene)
{
- static TimeMarker *marker;
- static short initialized = 0;
- int diff;
-
- /* In order for this mirror function to work without
- * any extra arguments being added, we use the case
- * of bezt==NULL to denote that we should find the
- * marker to mirror over. The static pointer is safe
- * to use this way, as it will be set to null after
- * each cycle in which this is called.
- */
-
- if (gpf) {
- /* mirroring time */
- if ((gpf->flag & GP_FRAME_SELECT) && (marker)) {
- diff = (marker->frame - gpf->framenum);
- gpf->framenum = (marker->frame + diff);
- }
- }
- else {
- /* initialization time */
- if (initialized) {
- /* reset everything for safety */
- marker = NULL;
- initialized = 0;
- }
- else {
- /* try to find a marker */
- marker = ED_markers_get_first_selected(&scene->markers);
- if (marker) {
- initialized = 1;
- }
- }
- }
-
- return 0;
+ static TimeMarker *marker;
+ static short initialized = 0;
+ int diff;
+
+ /* In order for this mirror function to work without
+ * any extra arguments being added, we use the case
+ * of bezt==NULL to denote that we should find the
+ * marker to mirror over. The static pointer is safe
+ * to use this way, as it will be set to null after
+ * each cycle in which this is called.
+ */
+
+ if (gpf) {
+ /* mirroring time */
+ if ((gpf->flag & GP_FRAME_SELECT) && (marker)) {
+ diff = (marker->frame - gpf->framenum);
+ gpf->framenum = (marker->frame + diff);
+ }
+ }
+ else {
+ /* initialization time */
+ if (initialized) {
+ /* reset everything for safety */
+ marker = NULL;
+ initialized = 0;
+ }
+ else {
+ /* try to find a marker */
+ marker = ED_markers_get_first_selected(&scene->markers);
+ if (marker) {
+ initialized = 1;
+ }
+ }
+ }
+
+ return 0;
}
-
/* mirror selected gp-frames on... */
// TODO: mirror over a specific time
void ED_gplayer_mirror_frames(bGPDlayer *gpl, Scene *scene, short mode)
{
- switch (mode) {
- case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
- ED_gplayer_frames_looper(gpl, scene, mirror_gpf_cframe);
- break;
- case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
- ED_gplayer_frames_looper(gpl, scene, mirror_gpf_yaxis);
- break;
- case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
- ED_gplayer_frames_looper(gpl, scene, mirror_gpf_xaxis);
- break;
- case MIRROR_KEYS_MARKER: /* mirror over marker */
- mirror_gpf_marker(NULL, NULL);
- ED_gplayer_frames_looper(gpl, scene, mirror_gpf_marker);
- mirror_gpf_marker(NULL, NULL);
- break;
- default: /* just in case */
- ED_gplayer_frames_looper(gpl, scene, mirror_gpf_yaxis);
- break;
- }
+ switch (mode) {
+ case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
+ ED_gplayer_frames_looper(gpl, scene, mirror_gpf_cframe);
+ break;
+ case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
+ ED_gplayer_frames_looper(gpl, scene, mirror_gpf_yaxis);
+ break;
+ case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
+ ED_gplayer_frames_looper(gpl, scene, mirror_gpf_xaxis);
+ break;
+ case MIRROR_KEYS_MARKER: /* mirror over marker */
+ mirror_gpf_marker(NULL, NULL);
+ ED_gplayer_frames_looper(gpl, scene, mirror_gpf_marker);
+ mirror_gpf_marker(NULL, NULL);
+ break;
+ default: /* just in case */
+ ED_gplayer_frames_looper(gpl, scene, mirror_gpf_yaxis);
+ break;
+ }
}
/* ***************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c
index de6ecfefb2f..4d62d169bf8 100644
--- a/source/blender/editors/gpencil/gpencil_add_monkey.c
+++ b/source/blender/editors/gpencil/gpencil_add_monkey.c
@@ -42,1386 +42,784 @@
/* Definition of the most important info from a color */
typedef struct ColorTemplate {
- const char *name;
- float line[4];
- float fill[4];
+ const char *name;
+ float line[4];
+ float fill[4];
} ColorTemplate;
/* Add color an ensure duplications (matched by name) */
static int gpencil_monkey_color(
- Main *bmain, Object *ob, const ColorTemplate *pct, bool stroke, bool fill)
+ Main *bmain, Object *ob, const ColorTemplate *pct, bool stroke, bool fill)
{
- short *totcol = give_totcolp(ob);
- Material *ma = NULL;
- for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
- if (STREQ(ma->id.name, pct->name)) {
- return i;
- }
- }
-
- int idx;
-
- /* create a new one */
- ma = BKE_gpencil_object_material_new(bmain, ob, pct->name, &idx);
-
- copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
- copy_v4_v4(ma->gp_style->fill_rgba, pct->fill);
-
- if (!stroke) {
- ma->gp_style->flag &= ~GP_STYLE_STROKE_SHOW;
- }
-
- if (!fill) {
- ma->gp_style->flag &= ~GP_STYLE_FILL_SHOW;
- }
- else {
- ma->gp_style->flag |= GP_STYLE_FILL_SHOW;
- }
-
- return idx;
+ short *totcol = give_totcolp(ob);
+ Material *ma = NULL;
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ if (STREQ(ma->id.name, pct->name)) {
+ return i;
+ }
+ }
+
+ int idx;
+
+ /* create a new one */
+ ma = BKE_gpencil_object_material_new(bmain, ob, pct->name, &idx);
+
+ copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
+ copy_v4_v4(ma->gp_style->fill_rgba, pct->fill);
+
+ if (!stroke) {
+ ma->gp_style->flag &= ~GP_STYLE_STROKE_SHOW;
+ }
+
+ if (!fill) {
+ ma->gp_style->flag &= ~GP_STYLE_FILL_SHOW;
+ }
+ else {
+ ma->gp_style->flag |= GP_STYLE_FILL_SHOW;
+ }
+
+ return idx;
}
/* ***************************************************************** */
/* Monkey Geometry */
static const float data0[270 * GP_PRIM_DATABUF_SIZE] = {
- -0.4911f, 0.0f, -0.1781f, 0.267f, 0.362f,
- -0.5168f, 0.0f, -0.1806f, 0.31f, 0.407f,
- -0.5361f, 0.0f, -0.1817f, 0.38f, 0.439f,
- -0.5618f, 0.0f, -0.1829f, 0.433f, 0.458f,
- -0.5892f, 0.0f, -0.1827f, 0.471f, 0.5f,
- -0.6193f, 0.0f, -0.1814f, 0.496f, 0.516f,
- -0.6499f, 0.0f, -0.1782f, 0.511f, 0.519f,
- -0.6808f, 0.0f, -0.1729f, 0.521f, 0.53f,
- -0.7107f, 0.0f, -0.1651f, 0.527f, 0.533f,
- -0.7404f, 0.0f, -0.1555f, 0.531f, 0.534f,
- -0.7698f, 0.0f, -0.1447f, 0.534f, 0.535f,
- -0.7993f, 0.0f, -0.1332f, 0.535f, 0.535f,
- -0.8289f, 0.0f, -0.1209f, 0.536f, 0.537f,
- -0.8586f, 0.0f, -0.109f, 0.536f, 0.537f,
- -0.8871f, 0.0f, -0.0973f, 0.536f, 0.537f,
- -0.9125f, 0.0f, -0.0838f, 0.535f, 0.535f,
- -0.9353f, 0.0f, -0.0688f, 0.534f, 0.534f,
- -0.9561f, 0.0f, -0.0525f, 0.534f, 0.534f,
- -0.9752f, 0.0f, -0.0346f, 0.533f, 0.534f,
- -0.9944f, 0.0f, -0.016f, 0.533f, 0.534f,
- -1.0148f, 0.0f, 0.0028f, 0.532f, 0.532f,
- -1.0348f, 0.0f, 0.0215f, 0.531f, 0.531f,
- -1.05f, 0.0f, 0.0407f, 0.531f, 0.531f,
- -1.0639f, 0.0f, 0.0613f, 0.532f, 0.532f,
- -1.0752f, 0.0f, 0.0838f, 0.535f, 0.535f,
- -1.0848f, 0.0f, 0.1082f, 0.54f, 0.54f,
- -1.0936f, 0.0f, 0.1346f, 0.542f, 0.542f,
- -1.1024f, 0.0f, 0.1639f, 0.543f, 0.543f,
- -1.1102f, 0.0f, 0.1953f, 0.543f, 0.543f,
- -1.1128f, 0.0f, 0.2277f, 0.546f, 0.546f,
- -1.1091f, 0.0f, 0.2579f, 0.549f, 0.549f,
- -1.1023f, 0.0f, 0.2849f, 0.549f, 0.549f,
- -1.0934f, 0.0f, 0.3086f, 0.549f, 0.549f,
- -1.0831f, 0.0f, 0.3285f, 0.549f, 0.549f,
- -1.0724f, 0.0f, 0.3451f, 0.551f, 0.551f,
- -1.0607f, 0.0f, 0.3594f, 0.553f, 0.553f,
- -1.0474f, 0.0f, 0.3713f, 0.554f, 0.554f,
- -1.031f, 0.0f, 0.3804f, 0.554f, 0.554f,
- -1.0108f, 0.0f, 0.3874f, 0.555f, 0.555f,
- -0.9862f, 0.0f, 0.3922f, 0.556f, 0.556f,
- -0.9568f, 0.0f, 0.3941f, 0.557f, 0.557f,
- -0.9243f, 0.0f, 0.3934f, 0.557f, 0.557f,
- -0.8897f, 0.0f, 0.3861f, 0.557f, 0.557f,
- -0.8556f, 0.0f, 0.3754f, 0.557f, 0.557f,
- -0.8237f, 0.0f, 0.3608f, 0.558f, 0.557f,
- -0.7982f, 0.0f, 0.344f, 0.558f, 0.558f,
- -0.7786f, 0.0f, 0.329f, 0.557f, 0.559f,
- -0.7633f, 0.0f, 0.3183f, 0.556f, 0.559f,
- -0.7498f, 0.0f, 0.3135f, 0.554f, 0.559f,
- -0.7374f, 0.0f, 0.3134f, 0.552f, 0.548f,
- -0.7261f, 0.0f, 0.3179f, 0.551f, 0.546f,
- -0.7146f, 0.0f, 0.3262f, 0.55f, 0.547f,
- -0.703f, 0.0f, 0.3395f, 0.549f, 0.547f,
- -0.692f, 0.0f, 0.3576f, 0.549f, 0.548f,
- -0.6831f, 0.0f, 0.3806f, 0.549f, 0.548f,
- -0.6748f, 0.0f, 0.4052f, 0.55f, 0.549f,
- -0.6648f, 0.0f, 0.4305f, 0.552f, 0.548f,
- -0.6527f, 0.0f, 0.4549f, 0.556f, 0.549f,
- -0.6375f, 0.0f, 0.4783f, 0.563f, 0.549f,
- -0.6195f, 0.0f, 0.5021f, 0.572f, 0.558f,
- -0.5985f, 0.0f, 0.5256f, 0.582f, 0.587f,
- -0.5775f, 0.0f, 0.5488f, 0.591f, 0.595f,
- -0.556f, 0.0f, 0.5715f, 0.597f, 0.598f,
- -0.5339f, 0.0f, 0.593f, 0.602f, 0.603f,
- -0.5119f, 0.0f, 0.613f, 0.605f, 0.606f,
- -0.4905f, 0.0f, 0.6312f, 0.607f, 0.607f,
- -0.4697f, 0.0f, 0.6474f, 0.609f, 0.607f,
- -0.4499f, 0.0f, 0.6613f, 0.612f, 0.611f,
- -0.4306f, 0.0f, 0.6734f, 0.616f, 0.615f,
- -0.4116f, 0.0f, 0.6845f, 0.619f, 0.621f,
- -0.3918f, 0.0f, 0.6954f, 0.623f, 0.623f,
- -0.3709f, 0.0f, 0.7059f, 0.626f, 0.626f,
- -0.3486f, 0.0f, 0.7157f, 0.63f, 0.63f,
- -0.3251f, 0.0f, 0.7249f, 0.637f, 0.632f,
- -0.3006f, 0.0f, 0.7333f, 0.646f, 0.644f,
- -0.2755f, 0.0f, 0.7414f, 0.654f, 0.657f,
- -0.25f, 0.0f, 0.7489f, 0.659f, 0.661f,
- -0.2242f, 0.0f, 0.7562f, 0.664f, 0.664f,
- -0.1979f, 0.0f, 0.7631f, 0.667f, 0.668f,
- -0.171f, 0.0f, 0.7695f, 0.671f, 0.671f,
- -0.1434f, 0.0f, 0.7752f, 0.674f, 0.674f,
- -0.1151f, 0.0f, 0.7801f, 0.677f, 0.678f,
- -0.0861f, 0.0f, 0.7841f, 0.678f, 0.68f,
- -0.0563f, 0.0f, 0.7869f, 0.68f, 0.68f,
- -0.026f, 0.0f, 0.7889f, 0.68f, 0.68f,
- 0.0049f, 0.0f, 0.7899f, 0.681f, 0.681f,
- 0.0362f, 0.0f, 0.7898f, 0.682f, 0.681f,
- 0.0679f, 0.0f, 0.7881f, 0.683f, 0.683f,
- 0.0996f, 0.0f, 0.7853f, 0.685f, 0.683f,
- 0.1313f, 0.0f, 0.7812f, 0.687f, 0.685f,
- 0.1632f, 0.0f, 0.7756f, 0.69f, 0.686f,
- 0.1953f, 0.0f, 0.7687f, 0.693f, 0.694f,
- 0.2277f, 0.0f, 0.7608f, 0.697f, 0.697f,
- 0.2606f, 0.0f, 0.7513f, 0.7f, 0.7f,
- 0.2934f, 0.0f, 0.7404f, 0.704f, 0.704f,
- 0.3258f, 0.0f, 0.7276f, 0.707f, 0.71f,
- 0.357f, 0.0f, 0.7135f, 0.709f, 0.711f,
- 0.387f, 0.0f, 0.6983f, 0.711f, 0.713f,
- 0.4157f, 0.0f, 0.6819f, 0.712f, 0.714f,
- 0.444f, 0.0f, 0.6645f, 0.714f, 0.714f,
- 0.4719f, 0.0f, 0.6459f, 0.715f, 0.715f,
- 0.4994f, 0.0f, 0.6261f, 0.715f, 0.716f,
- 0.526f, 0.0f, 0.6046f, 0.716f, 0.716f,
- 0.552f, 0.0f, 0.5816f, 0.717f, 0.717f,
- 0.577f, 0.0f, 0.5575f, 0.718f, 0.717f,
- 0.6008f, 0.0f, 0.5328f, 0.718f, 0.718f,
- 0.6231f, 0.0f, 0.5077f, 0.718f, 0.718f,
- 0.6423f, 0.0f, 0.4829f, 0.719f, 0.718f,
- 0.658f, 0.0f, 0.4617f, 0.719f, 0.719f,
- 0.6713f, 0.0f, 0.4432f, 0.719f, 0.719f,
- 0.6828f, 0.0f, 0.4266f, 0.719f, 0.719f,
- 0.6928f, 0.0f, 0.4118f, 0.719f, 0.719f,
- 0.7016f, 0.0f, 0.3987f, 0.718f, 0.717f,
- 0.7094f, 0.0f, 0.3871f, 0.717f, 0.717f,
- 0.7165f, 0.0f, 0.3769f, 0.717f, 0.717f,
- 0.7233f, 0.0f, 0.3679f, 0.718f, 0.718f,
- 0.7301f, 0.0f, 0.3598f, 0.717f, 0.719f,
- 0.7373f, 0.0f, 0.3524f, 0.715f, 0.719f,
- 0.7454f, 0.0f, 0.3458f, 0.713f, 0.709f,
- 0.7545f, 0.0f, 0.3398f, 0.718f, 0.704f,
- 0.7651f, 0.0f, 0.3351f, 0.732f, 0.705f,
- 0.777f, 0.0f, 0.3317f, 0.753f, 0.713f,
- 0.7909f, 0.0f, 0.3311f, 0.774f, 0.813f,
- 0.8068f, 0.0f, 0.334f, 0.791f, 0.815f,
- 0.8246f, 0.0f, 0.3398f, 0.802f, 0.815f,
- 0.8438f, 0.0f, 0.3486f, 0.809f, 0.816f,
- 0.8651f, 0.0f, 0.3575f, 0.812f, 0.816f,
- 0.8893f, 0.0f, 0.3665f, 0.814f, 0.816f,
- 0.9166f, 0.0f, 0.374f, 0.814f, 0.817f,
- 0.9459f, 0.0f, 0.3791f, 0.812f, 0.817f,
- 0.9751f, 0.0f, 0.3811f, 0.81f, 0.815f,
- 1.0029f, 0.0f, 0.38f, 0.806f, 0.807f,
- 1.0288f, 0.0f, 0.3754f, 0.8f, 0.801f,
- 1.052f, 0.0f, 0.3673f, 0.794f, 0.8f,
- 1.0722f, 0.0f, 0.3556f, 0.788f, 0.781f,
- 1.0888f, 0.0f, 0.3403f, 0.783f, 0.78f,
- 1.1027f, 0.0f, 0.322f, 0.781f, 0.778f,
- 1.1133f, 0.0f, 0.301f, 0.779f, 0.777f,
- 1.1215f, 0.0f, 0.278f, 0.778f, 0.777f,
- 1.1269f, 0.0f, 0.2534f, 0.777f, 0.777f,
- 1.1296f, 0.0f, 0.2284f, 0.777f, 0.778f,
- 1.1292f, 0.0f, 0.2031f, 0.776f, 0.776f,
- 1.1254f, 0.0f, 0.1778f, 0.775f, 0.776f,
- 1.1178f, 0.0f, 0.153f, 0.774f, 0.774f,
- 1.1076f, 0.0f, 0.1299f, 0.774f, 0.772f,
- 1.0955f, 0.0f, 0.1079f, 0.773f, 0.773f,
- 1.0817f, 0.0f, 0.087f, 0.772f, 0.773f,
- 1.0668f, 0.0f, 0.0677f, 0.771f, 0.772f,
- 1.0508f, 0.0f, 0.0491f, 0.77f, 0.772f,
- 1.0339f, 0.0f, 0.0313f, 0.768f, 0.766f,
- 1.0157f, 0.0f, 0.0144f, 0.767f, 0.765f,
- 0.9969f, 0.0f, -0.0015f, 0.766f, 0.765f,
- 0.9784f, 0.0f, -0.017f, 0.765f, 0.766f,
- 0.96f, 0.0f, -0.0321f, 0.764f, 0.765f,
- 0.9413f, 0.0f, -0.0468f, 0.761f, 0.765f,
- 0.9216f, 0.0f, -0.0611f, 0.756f, 0.761f,
- 0.9009f, 0.0f, -0.0751f, 0.751f, 0.751f,
- 0.8787f, 0.0f, -0.0893f, 0.745f, 0.744f,
- 0.8556f, 0.0f, -0.1027f, 0.739f, 0.738f,
- 0.8312f, 0.0f, -0.1152f, 0.733f, 0.731f,
- 0.8058f, 0.0f, -0.1268f, 0.728f, 0.727f,
- 0.7788f, 0.0f, -0.1372f, 0.723f, 0.723f,
- 0.7505f, 0.0f, -0.1467f, 0.718f, 0.717f,
- 0.7214f, 0.0f, -0.1549f, 0.713f, 0.708f,
- 0.6929f, 0.0f, -0.1617f, 0.709f, 0.706f,
- 0.6652f, 0.0f, -0.1665f, 0.704f, 0.705f,
- 0.6388f, 0.0f, -0.1691f, 0.7f, 0.704f,
- 0.6131f, 0.0f, -0.1701f, 0.695f, 0.698f,
- 0.5883f, 0.0f, -0.1699f, 0.691f, 0.691f,
- 0.5644f, 0.0f, -0.1691f, 0.686f, 0.685f,
- 0.5416f, 0.0f, -0.1683f, 0.681f, 0.683f,
- 0.5195f, 0.0f, -0.168f, 0.676f, 0.676f,
- 0.4975f, 0.0f, -0.1687f, 0.671f, 0.67f,
- 0.4754f, 0.0f, -0.1705f, 0.666f, 0.663f,
- 0.4527f, 0.0f, -0.1741f, 0.663f, 0.66f,
- 0.4293f, 0.0f, -0.1797f, 0.661f, 0.659f,
- 0.4054f, 0.0f, -0.1881f, 0.66f, 0.659f,
- 0.3813f, 0.0f, -0.1992f, 0.659f, 0.657f,
- 0.3585f, 0.0f, -0.212f, 0.658f, 0.659f,
- 0.3368f, 0.0f, -0.2266f, 0.658f, 0.659f,
- 0.3174f, 0.0f, -0.2426f, 0.658f, 0.659f,
- 0.2996f, 0.0f, -0.2594f, 0.657f, 0.657f,
- 0.284f, 0.0f, -0.2768f, 0.656f, 0.658f,
- 0.2702f, 0.0f, -0.2946f, 0.653f, 0.657f,
- 0.2585f, 0.0f, -0.3127f, 0.646f, 0.656f,
- 0.25f, 0.0f, -0.3308f, 0.637f, 0.642f,
- 0.2447f, 0.0f, -0.3489f, 0.628f, 0.609f,
- 0.2418f, 0.0f, -0.3672f, 0.62f, 0.608f,
- 0.2412f, 0.0f, -0.386f, 0.614f, 0.607f,
- 0.2425f, 0.0f, -0.4051f, 0.61f, 0.606f,
- 0.2456f, 0.0f, -0.4246f, 0.608f, 0.604f,
- 0.2509f, 0.0f, -0.4447f, 0.607f, 0.606f,
- 0.2576f, 0.0f, -0.4652f, 0.606f, 0.607f,
- 0.2666f, 0.0f, -0.4867f, 0.605f, 0.607f,
- 0.2766f, 0.0f, -0.5091f, 0.603f, 0.607f,
- 0.2871f, 0.0f, -0.5326f, 0.598f, 0.606f,
- 0.2973f, 0.0f, -0.5569f, 0.591f, 0.602f,
- 0.306f, 0.0f, -0.5826f, 0.583f, 0.585f,
- 0.3131f, 0.0f, -0.61f, 0.574f, 0.576f,
- 0.3197f, 0.0f, -0.6384f, 0.564f, 0.564f,
- 0.326f, 0.0f, -0.6681f, 0.555f, 0.549f,
- 0.3315f, 0.0f, -0.6984f, 0.547f, 0.543f,
- 0.336f, 0.0f, -0.7291f, 0.541f, 0.541f,
- 0.3391f, 0.0f, -0.7593f, 0.536f, 0.538f,
- 0.3399f, 0.0f, -0.7884f, 0.532f, 0.528f,
- 0.3382f, 0.0f, -0.8158f, 0.529f, 0.528f,
- 0.334f, 0.0f, -0.8417f, 0.525f, 0.529f,
- 0.3273f, 0.0f, -0.8657f, 0.521f, 0.528f,
- 0.3185f, 0.0f, -0.8881f, 0.516f, 0.515f,
- 0.3073f, 0.0f, -0.9088f, 0.51f, 0.514f,
- 0.2941f, 0.0f, -0.9278f, 0.505f, 0.507f,
- 0.2786f, 0.0f, -0.9449f, 0.499f, 0.494f,
- 0.261f, 0.0f, -0.96f, 0.495f, 0.49f,
- 0.2413f, 0.0f, -0.9733f, 0.493f, 0.491f,
- 0.2193f, 0.0f, -0.9845f, 0.491f, 0.489f,
- 0.1953f, 0.0f, -0.9935f, 0.491f, 0.491f,
- 0.1693f, 0.0f, -1.0004f, 0.491f, 0.492f,
- 0.1421f, 0.0f, -1.0051f, 0.492f, 0.492f,
- 0.1136f, 0.0f, -1.0072f, 0.492f, 0.492f,
- 0.0842f, 0.0f, -1.0073f, 0.492f, 0.492f,
- 0.0548f, 0.0f, -1.0059f, 0.493f, 0.494f,
- 0.0258f, 0.0f, -1.0037f, 0.493f, 0.494f,
- -0.0027f, 0.0f, -1.0003f, 0.493f, 0.493f,
- -0.0309f, 0.0f, -0.9959f, 0.492f, 0.492f,
- -0.0584f, 0.0f, -0.9904f, 0.491f, 0.492f,
- -0.0858f, 0.0f, -0.9848f, 0.491f, 0.491f,
- -0.1127f, 0.0f, -0.9783f, 0.49f, 0.49f,
- -0.1386f, 0.0f, -0.9703f, 0.49f, 0.49f,
- -0.1649f, 0.0f, -0.9604f, 0.489f, 0.489f,
- -0.191f, 0.0f, -0.9479f, 0.489f, 0.489f,
- -0.2165f, 0.0f, -0.9345f, 0.489f, 0.49f,
- -0.2414f, 0.0f, -0.9205f, 0.489f, 0.489f,
- -0.2654f, 0.0f, -0.9055f, 0.489f, 0.489f,
- -0.2877f, 0.0f, -0.8898f, 0.49f, 0.49f,
- -0.3076f, 0.0f, -0.8723f, 0.49f, 0.489f,
- -0.324f, 0.0f, -0.8532f, 0.491f, 0.489f,
- -0.3367f, 0.0f, -0.8316f, 0.492f, 0.489f,
- -0.3451f, 0.0f, -0.8077f, 0.494f, 0.488f,
- -0.3505f, 0.0f, -0.7829f, 0.497f, 0.49f,
- -0.3531f, 0.0f, -0.7584f, 0.501f, 0.497f,
- -0.3528f, 0.0f, -0.7349f, 0.505f, 0.504f,
- -0.3503f, 0.0f, -0.7115f, 0.51f, 0.51f,
- -0.346f, 0.0f, -0.688f, 0.515f, 0.515f,
- -0.3411f, 0.0f, -0.6643f, 0.52f, 0.522f,
- -0.3361f, 0.0f, -0.6403f, 0.525f, 0.528f,
- -0.3304f, 0.0f, -0.6164f, 0.53f, 0.532f,
- -0.3244f, 0.0f, -0.5925f, 0.535f, 0.535f,
- -0.318f, 0.0f, -0.5687f, 0.539f, 0.54f,
- -0.3124f, 0.0f, -0.5441f, 0.542f, 0.545f,
- -0.3051f, 0.0f, -0.5191f, 0.546f, 0.549f,
- -0.2959f, 0.0f, -0.4917f, 0.548f, 0.549f,
- -0.2882f, 0.0f, -0.4639f, 0.55f, 0.552f,
- -0.2814f, 0.0f, -0.4363f, 0.551f, 0.552f,
- -0.2759f, 0.0f, -0.4084f, 0.552f, 0.553f,
- -0.2707f, 0.0f, -0.3827f, 0.553f, 0.553f,
- -0.2703f, 0.0f, -0.3586f, 0.554f, 0.553f,
- -0.2772f, 0.0f, -0.3375f, 0.554f, 0.554f,
- -0.2871f, 0.0f, -0.3178f, 0.555f, 0.555f,
- -0.2995f, 0.0f, -0.2996f, 0.556f, 0.555f,
- -0.3145f, 0.0f, -0.283f, 0.556f, 0.557f,
- -0.332f, 0.0f, -0.2672f, 0.557f, 0.557f,
- -0.3488f, 0.0f, -0.2531f, 0.558f, 0.558f,
- -0.3639f, 0.0f, -0.2407f, 0.558f, 0.558f,
- -0.3778f, 0.0f, -0.2292f, 0.558f, 0.558f,
- -0.3909f, 0.0f, -0.2191f, 0.559f, 0.559f,
- -0.4032f, 0.0f, -0.2102f, 0.559f, 0.558f,
- -0.4146f, 0.0f, -0.2027f, 0.559f, 0.559f,
- -0.426f, 0.0f, -0.1968f, 0.558f, 0.558f,
- -0.4348f, 0.0f, -0.1931f, 0.558f, 0.558f,
- -0.4479f, 0.0f, -0.1886f, 0.555f, 0.559f,
+ -0.4911f, 0.0f, -0.1781f, 0.267f, 0.362f, -0.5168f, 0.0f, -0.1806f, 0.31f, 0.407f,
+ -0.5361f, 0.0f, -0.1817f, 0.38f, 0.439f, -0.5618f, 0.0f, -0.1829f, 0.433f, 0.458f,
+ -0.5892f, 0.0f, -0.1827f, 0.471f, 0.5f, -0.6193f, 0.0f, -0.1814f, 0.496f, 0.516f,
+ -0.6499f, 0.0f, -0.1782f, 0.511f, 0.519f, -0.6808f, 0.0f, -0.1729f, 0.521f, 0.53f,
+ -0.7107f, 0.0f, -0.1651f, 0.527f, 0.533f, -0.7404f, 0.0f, -0.1555f, 0.531f, 0.534f,
+ -0.7698f, 0.0f, -0.1447f, 0.534f, 0.535f, -0.7993f, 0.0f, -0.1332f, 0.535f, 0.535f,
+ -0.8289f, 0.0f, -0.1209f, 0.536f, 0.537f, -0.8586f, 0.0f, -0.109f, 0.536f, 0.537f,
+ -0.8871f, 0.0f, -0.0973f, 0.536f, 0.537f, -0.9125f, 0.0f, -0.0838f, 0.535f, 0.535f,
+ -0.9353f, 0.0f, -0.0688f, 0.534f, 0.534f, -0.9561f, 0.0f, -0.0525f, 0.534f, 0.534f,
+ -0.9752f, 0.0f, -0.0346f, 0.533f, 0.534f, -0.9944f, 0.0f, -0.016f, 0.533f, 0.534f,
+ -1.0148f, 0.0f, 0.0028f, 0.532f, 0.532f, -1.0348f, 0.0f, 0.0215f, 0.531f, 0.531f,
+ -1.05f, 0.0f, 0.0407f, 0.531f, 0.531f, -1.0639f, 0.0f, 0.0613f, 0.532f, 0.532f,
+ -1.0752f, 0.0f, 0.0838f, 0.535f, 0.535f, -1.0848f, 0.0f, 0.1082f, 0.54f, 0.54f,
+ -1.0936f, 0.0f, 0.1346f, 0.542f, 0.542f, -1.1024f, 0.0f, 0.1639f, 0.543f, 0.543f,
+ -1.1102f, 0.0f, 0.1953f, 0.543f, 0.543f, -1.1128f, 0.0f, 0.2277f, 0.546f, 0.546f,
+ -1.1091f, 0.0f, 0.2579f, 0.549f, 0.549f, -1.1023f, 0.0f, 0.2849f, 0.549f, 0.549f,
+ -1.0934f, 0.0f, 0.3086f, 0.549f, 0.549f, -1.0831f, 0.0f, 0.3285f, 0.549f, 0.549f,
+ -1.0724f, 0.0f, 0.3451f, 0.551f, 0.551f, -1.0607f, 0.0f, 0.3594f, 0.553f, 0.553f,
+ -1.0474f, 0.0f, 0.3713f, 0.554f, 0.554f, -1.031f, 0.0f, 0.3804f, 0.554f, 0.554f,
+ -1.0108f, 0.0f, 0.3874f, 0.555f, 0.555f, -0.9862f, 0.0f, 0.3922f, 0.556f, 0.556f,
+ -0.9568f, 0.0f, 0.3941f, 0.557f, 0.557f, -0.9243f, 0.0f, 0.3934f, 0.557f, 0.557f,
+ -0.8897f, 0.0f, 0.3861f, 0.557f, 0.557f, -0.8556f, 0.0f, 0.3754f, 0.557f, 0.557f,
+ -0.8237f, 0.0f, 0.3608f, 0.558f, 0.557f, -0.7982f, 0.0f, 0.344f, 0.558f, 0.558f,
+ -0.7786f, 0.0f, 0.329f, 0.557f, 0.559f, -0.7633f, 0.0f, 0.3183f, 0.556f, 0.559f,
+ -0.7498f, 0.0f, 0.3135f, 0.554f, 0.559f, -0.7374f, 0.0f, 0.3134f, 0.552f, 0.548f,
+ -0.7261f, 0.0f, 0.3179f, 0.551f, 0.546f, -0.7146f, 0.0f, 0.3262f, 0.55f, 0.547f,
+ -0.703f, 0.0f, 0.3395f, 0.549f, 0.547f, -0.692f, 0.0f, 0.3576f, 0.549f, 0.548f,
+ -0.6831f, 0.0f, 0.3806f, 0.549f, 0.548f, -0.6748f, 0.0f, 0.4052f, 0.55f, 0.549f,
+ -0.6648f, 0.0f, 0.4305f, 0.552f, 0.548f, -0.6527f, 0.0f, 0.4549f, 0.556f, 0.549f,
+ -0.6375f, 0.0f, 0.4783f, 0.563f, 0.549f, -0.6195f, 0.0f, 0.5021f, 0.572f, 0.558f,
+ -0.5985f, 0.0f, 0.5256f, 0.582f, 0.587f, -0.5775f, 0.0f, 0.5488f, 0.591f, 0.595f,
+ -0.556f, 0.0f, 0.5715f, 0.597f, 0.598f, -0.5339f, 0.0f, 0.593f, 0.602f, 0.603f,
+ -0.5119f, 0.0f, 0.613f, 0.605f, 0.606f, -0.4905f, 0.0f, 0.6312f, 0.607f, 0.607f,
+ -0.4697f, 0.0f, 0.6474f, 0.609f, 0.607f, -0.4499f, 0.0f, 0.6613f, 0.612f, 0.611f,
+ -0.4306f, 0.0f, 0.6734f, 0.616f, 0.615f, -0.4116f, 0.0f, 0.6845f, 0.619f, 0.621f,
+ -0.3918f, 0.0f, 0.6954f, 0.623f, 0.623f, -0.3709f, 0.0f, 0.7059f, 0.626f, 0.626f,
+ -0.3486f, 0.0f, 0.7157f, 0.63f, 0.63f, -0.3251f, 0.0f, 0.7249f, 0.637f, 0.632f,
+ -0.3006f, 0.0f, 0.7333f, 0.646f, 0.644f, -0.2755f, 0.0f, 0.7414f, 0.654f, 0.657f,
+ -0.25f, 0.0f, 0.7489f, 0.659f, 0.661f, -0.2242f, 0.0f, 0.7562f, 0.664f, 0.664f,
+ -0.1979f, 0.0f, 0.7631f, 0.667f, 0.668f, -0.171f, 0.0f, 0.7695f, 0.671f, 0.671f,
+ -0.1434f, 0.0f, 0.7752f, 0.674f, 0.674f, -0.1151f, 0.0f, 0.7801f, 0.677f, 0.678f,
+ -0.0861f, 0.0f, 0.7841f, 0.678f, 0.68f, -0.0563f, 0.0f, 0.7869f, 0.68f, 0.68f,
+ -0.026f, 0.0f, 0.7889f, 0.68f, 0.68f, 0.0049f, 0.0f, 0.7899f, 0.681f, 0.681f,
+ 0.0362f, 0.0f, 0.7898f, 0.682f, 0.681f, 0.0679f, 0.0f, 0.7881f, 0.683f, 0.683f,
+ 0.0996f, 0.0f, 0.7853f, 0.685f, 0.683f, 0.1313f, 0.0f, 0.7812f, 0.687f, 0.685f,
+ 0.1632f, 0.0f, 0.7756f, 0.69f, 0.686f, 0.1953f, 0.0f, 0.7687f, 0.693f, 0.694f,
+ 0.2277f, 0.0f, 0.7608f, 0.697f, 0.697f, 0.2606f, 0.0f, 0.7513f, 0.7f, 0.7f,
+ 0.2934f, 0.0f, 0.7404f, 0.704f, 0.704f, 0.3258f, 0.0f, 0.7276f, 0.707f, 0.71f,
+ 0.357f, 0.0f, 0.7135f, 0.709f, 0.711f, 0.387f, 0.0f, 0.6983f, 0.711f, 0.713f,
+ 0.4157f, 0.0f, 0.6819f, 0.712f, 0.714f, 0.444f, 0.0f, 0.6645f, 0.714f, 0.714f,
+ 0.4719f, 0.0f, 0.6459f, 0.715f, 0.715f, 0.4994f, 0.0f, 0.6261f, 0.715f, 0.716f,
+ 0.526f, 0.0f, 0.6046f, 0.716f, 0.716f, 0.552f, 0.0f, 0.5816f, 0.717f, 0.717f,
+ 0.577f, 0.0f, 0.5575f, 0.718f, 0.717f, 0.6008f, 0.0f, 0.5328f, 0.718f, 0.718f,
+ 0.6231f, 0.0f, 0.5077f, 0.718f, 0.718f, 0.6423f, 0.0f, 0.4829f, 0.719f, 0.718f,
+ 0.658f, 0.0f, 0.4617f, 0.719f, 0.719f, 0.6713f, 0.0f, 0.4432f, 0.719f, 0.719f,
+ 0.6828f, 0.0f, 0.4266f, 0.719f, 0.719f, 0.6928f, 0.0f, 0.4118f, 0.719f, 0.719f,
+ 0.7016f, 0.0f, 0.3987f, 0.718f, 0.717f, 0.7094f, 0.0f, 0.3871f, 0.717f, 0.717f,
+ 0.7165f, 0.0f, 0.3769f, 0.717f, 0.717f, 0.7233f, 0.0f, 0.3679f, 0.718f, 0.718f,
+ 0.7301f, 0.0f, 0.3598f, 0.717f, 0.719f, 0.7373f, 0.0f, 0.3524f, 0.715f, 0.719f,
+ 0.7454f, 0.0f, 0.3458f, 0.713f, 0.709f, 0.7545f, 0.0f, 0.3398f, 0.718f, 0.704f,
+ 0.7651f, 0.0f, 0.3351f, 0.732f, 0.705f, 0.777f, 0.0f, 0.3317f, 0.753f, 0.713f,
+ 0.7909f, 0.0f, 0.3311f, 0.774f, 0.813f, 0.8068f, 0.0f, 0.334f, 0.791f, 0.815f,
+ 0.8246f, 0.0f, 0.3398f, 0.802f, 0.815f, 0.8438f, 0.0f, 0.3486f, 0.809f, 0.816f,
+ 0.8651f, 0.0f, 0.3575f, 0.812f, 0.816f, 0.8893f, 0.0f, 0.3665f, 0.814f, 0.816f,
+ 0.9166f, 0.0f, 0.374f, 0.814f, 0.817f, 0.9459f, 0.0f, 0.3791f, 0.812f, 0.817f,
+ 0.9751f, 0.0f, 0.3811f, 0.81f, 0.815f, 1.0029f, 0.0f, 0.38f, 0.806f, 0.807f,
+ 1.0288f, 0.0f, 0.3754f, 0.8f, 0.801f, 1.052f, 0.0f, 0.3673f, 0.794f, 0.8f,
+ 1.0722f, 0.0f, 0.3556f, 0.788f, 0.781f, 1.0888f, 0.0f, 0.3403f, 0.783f, 0.78f,
+ 1.1027f, 0.0f, 0.322f, 0.781f, 0.778f, 1.1133f, 0.0f, 0.301f, 0.779f, 0.777f,
+ 1.1215f, 0.0f, 0.278f, 0.778f, 0.777f, 1.1269f, 0.0f, 0.2534f, 0.777f, 0.777f,
+ 1.1296f, 0.0f, 0.2284f, 0.777f, 0.778f, 1.1292f, 0.0f, 0.2031f, 0.776f, 0.776f,
+ 1.1254f, 0.0f, 0.1778f, 0.775f, 0.776f, 1.1178f, 0.0f, 0.153f, 0.774f, 0.774f,
+ 1.1076f, 0.0f, 0.1299f, 0.774f, 0.772f, 1.0955f, 0.0f, 0.1079f, 0.773f, 0.773f,
+ 1.0817f, 0.0f, 0.087f, 0.772f, 0.773f, 1.0668f, 0.0f, 0.0677f, 0.771f, 0.772f,
+ 1.0508f, 0.0f, 0.0491f, 0.77f, 0.772f, 1.0339f, 0.0f, 0.0313f, 0.768f, 0.766f,
+ 1.0157f, 0.0f, 0.0144f, 0.767f, 0.765f, 0.9969f, 0.0f, -0.0015f, 0.766f, 0.765f,
+ 0.9784f, 0.0f, -0.017f, 0.765f, 0.766f, 0.96f, 0.0f, -0.0321f, 0.764f, 0.765f,
+ 0.9413f, 0.0f, -0.0468f, 0.761f, 0.765f, 0.9216f, 0.0f, -0.0611f, 0.756f, 0.761f,
+ 0.9009f, 0.0f, -0.0751f, 0.751f, 0.751f, 0.8787f, 0.0f, -0.0893f, 0.745f, 0.744f,
+ 0.8556f, 0.0f, -0.1027f, 0.739f, 0.738f, 0.8312f, 0.0f, -0.1152f, 0.733f, 0.731f,
+ 0.8058f, 0.0f, -0.1268f, 0.728f, 0.727f, 0.7788f, 0.0f, -0.1372f, 0.723f, 0.723f,
+ 0.7505f, 0.0f, -0.1467f, 0.718f, 0.717f, 0.7214f, 0.0f, -0.1549f, 0.713f, 0.708f,
+ 0.6929f, 0.0f, -0.1617f, 0.709f, 0.706f, 0.6652f, 0.0f, -0.1665f, 0.704f, 0.705f,
+ 0.6388f, 0.0f, -0.1691f, 0.7f, 0.704f, 0.6131f, 0.0f, -0.1701f, 0.695f, 0.698f,
+ 0.5883f, 0.0f, -0.1699f, 0.691f, 0.691f, 0.5644f, 0.0f, -0.1691f, 0.686f, 0.685f,
+ 0.5416f, 0.0f, -0.1683f, 0.681f, 0.683f, 0.5195f, 0.0f, -0.168f, 0.676f, 0.676f,
+ 0.4975f, 0.0f, -0.1687f, 0.671f, 0.67f, 0.4754f, 0.0f, -0.1705f, 0.666f, 0.663f,
+ 0.4527f, 0.0f, -0.1741f, 0.663f, 0.66f, 0.4293f, 0.0f, -0.1797f, 0.661f, 0.659f,
+ 0.4054f, 0.0f, -0.1881f, 0.66f, 0.659f, 0.3813f, 0.0f, -0.1992f, 0.659f, 0.657f,
+ 0.3585f, 0.0f, -0.212f, 0.658f, 0.659f, 0.3368f, 0.0f, -0.2266f, 0.658f, 0.659f,
+ 0.3174f, 0.0f, -0.2426f, 0.658f, 0.659f, 0.2996f, 0.0f, -0.2594f, 0.657f, 0.657f,
+ 0.284f, 0.0f, -0.2768f, 0.656f, 0.658f, 0.2702f, 0.0f, -0.2946f, 0.653f, 0.657f,
+ 0.2585f, 0.0f, -0.3127f, 0.646f, 0.656f, 0.25f, 0.0f, -0.3308f, 0.637f, 0.642f,
+ 0.2447f, 0.0f, -0.3489f, 0.628f, 0.609f, 0.2418f, 0.0f, -0.3672f, 0.62f, 0.608f,
+ 0.2412f, 0.0f, -0.386f, 0.614f, 0.607f, 0.2425f, 0.0f, -0.4051f, 0.61f, 0.606f,
+ 0.2456f, 0.0f, -0.4246f, 0.608f, 0.604f, 0.2509f, 0.0f, -0.4447f, 0.607f, 0.606f,
+ 0.2576f, 0.0f, -0.4652f, 0.606f, 0.607f, 0.2666f, 0.0f, -0.4867f, 0.605f, 0.607f,
+ 0.2766f, 0.0f, -0.5091f, 0.603f, 0.607f, 0.2871f, 0.0f, -0.5326f, 0.598f, 0.606f,
+ 0.2973f, 0.0f, -0.5569f, 0.591f, 0.602f, 0.306f, 0.0f, -0.5826f, 0.583f, 0.585f,
+ 0.3131f, 0.0f, -0.61f, 0.574f, 0.576f, 0.3197f, 0.0f, -0.6384f, 0.564f, 0.564f,
+ 0.326f, 0.0f, -0.6681f, 0.555f, 0.549f, 0.3315f, 0.0f, -0.6984f, 0.547f, 0.543f,
+ 0.336f, 0.0f, -0.7291f, 0.541f, 0.541f, 0.3391f, 0.0f, -0.7593f, 0.536f, 0.538f,
+ 0.3399f, 0.0f, -0.7884f, 0.532f, 0.528f, 0.3382f, 0.0f, -0.8158f, 0.529f, 0.528f,
+ 0.334f, 0.0f, -0.8417f, 0.525f, 0.529f, 0.3273f, 0.0f, -0.8657f, 0.521f, 0.528f,
+ 0.3185f, 0.0f, -0.8881f, 0.516f, 0.515f, 0.3073f, 0.0f, -0.9088f, 0.51f, 0.514f,
+ 0.2941f, 0.0f, -0.9278f, 0.505f, 0.507f, 0.2786f, 0.0f, -0.9449f, 0.499f, 0.494f,
+ 0.261f, 0.0f, -0.96f, 0.495f, 0.49f, 0.2413f, 0.0f, -0.9733f, 0.493f, 0.491f,
+ 0.2193f, 0.0f, -0.9845f, 0.491f, 0.489f, 0.1953f, 0.0f, -0.9935f, 0.491f, 0.491f,
+ 0.1693f, 0.0f, -1.0004f, 0.491f, 0.492f, 0.1421f, 0.0f, -1.0051f, 0.492f, 0.492f,
+ 0.1136f, 0.0f, -1.0072f, 0.492f, 0.492f, 0.0842f, 0.0f, -1.0073f, 0.492f, 0.492f,
+ 0.0548f, 0.0f, -1.0059f, 0.493f, 0.494f, 0.0258f, 0.0f, -1.0037f, 0.493f, 0.494f,
+ -0.0027f, 0.0f, -1.0003f, 0.493f, 0.493f, -0.0309f, 0.0f, -0.9959f, 0.492f, 0.492f,
+ -0.0584f, 0.0f, -0.9904f, 0.491f, 0.492f, -0.0858f, 0.0f, -0.9848f, 0.491f, 0.491f,
+ -0.1127f, 0.0f, -0.9783f, 0.49f, 0.49f, -0.1386f, 0.0f, -0.9703f, 0.49f, 0.49f,
+ -0.1649f, 0.0f, -0.9604f, 0.489f, 0.489f, -0.191f, 0.0f, -0.9479f, 0.489f, 0.489f,
+ -0.2165f, 0.0f, -0.9345f, 0.489f, 0.49f, -0.2414f, 0.0f, -0.9205f, 0.489f, 0.489f,
+ -0.2654f, 0.0f, -0.9055f, 0.489f, 0.489f, -0.2877f, 0.0f, -0.8898f, 0.49f, 0.49f,
+ -0.3076f, 0.0f, -0.8723f, 0.49f, 0.489f, -0.324f, 0.0f, -0.8532f, 0.491f, 0.489f,
+ -0.3367f, 0.0f, -0.8316f, 0.492f, 0.489f, -0.3451f, 0.0f, -0.8077f, 0.494f, 0.488f,
+ -0.3505f, 0.0f, -0.7829f, 0.497f, 0.49f, -0.3531f, 0.0f, -0.7584f, 0.501f, 0.497f,
+ -0.3528f, 0.0f, -0.7349f, 0.505f, 0.504f, -0.3503f, 0.0f, -0.7115f, 0.51f, 0.51f,
+ -0.346f, 0.0f, -0.688f, 0.515f, 0.515f, -0.3411f, 0.0f, -0.6643f, 0.52f, 0.522f,
+ -0.3361f, 0.0f, -0.6403f, 0.525f, 0.528f, -0.3304f, 0.0f, -0.6164f, 0.53f, 0.532f,
+ -0.3244f, 0.0f, -0.5925f, 0.535f, 0.535f, -0.318f, 0.0f, -0.5687f, 0.539f, 0.54f,
+ -0.3124f, 0.0f, -0.5441f, 0.542f, 0.545f, -0.3051f, 0.0f, -0.5191f, 0.546f, 0.549f,
+ -0.2959f, 0.0f, -0.4917f, 0.548f, 0.549f, -0.2882f, 0.0f, -0.4639f, 0.55f, 0.552f,
+ -0.2814f, 0.0f, -0.4363f, 0.551f, 0.552f, -0.2759f, 0.0f, -0.4084f, 0.552f, 0.553f,
+ -0.2707f, 0.0f, -0.3827f, 0.553f, 0.553f, -0.2703f, 0.0f, -0.3586f, 0.554f, 0.553f,
+ -0.2772f, 0.0f, -0.3375f, 0.554f, 0.554f, -0.2871f, 0.0f, -0.3178f, 0.555f, 0.555f,
+ -0.2995f, 0.0f, -0.2996f, 0.556f, 0.555f, -0.3145f, 0.0f, -0.283f, 0.556f, 0.557f,
+ -0.332f, 0.0f, -0.2672f, 0.557f, 0.557f, -0.3488f, 0.0f, -0.2531f, 0.558f, 0.558f,
+ -0.3639f, 0.0f, -0.2407f, 0.558f, 0.558f, -0.3778f, 0.0f, -0.2292f, 0.558f, 0.558f,
+ -0.3909f, 0.0f, -0.2191f, 0.559f, 0.559f, -0.4032f, 0.0f, -0.2102f, 0.559f, 0.558f,
+ -0.4146f, 0.0f, -0.2027f, 0.559f, 0.559f, -0.426f, 0.0f, -0.1968f, 0.558f, 0.558f,
+ -0.4348f, 0.0f, -0.1931f, 0.558f, 0.558f, -0.4479f, 0.0f, -0.1886f, 0.555f, 0.559f,
};
static const float data1[33 * GP_PRIM_DATABUF_SIZE] = {
- 0.5292f, 0.0f, 0.1742f, 0.1f, 1.0f,
- 0.5291f, 0.0f, 0.1621f, 0.2199f, 1.0f,
- 0.5274f, 0.0f, 0.1386f, 0.4615f, 1.0f,
- 0.5239f, 0.0f, 0.116f, 0.6019f, 1.0f,
- 0.5185f, 0.0f, 0.0945f, 0.6981f, 1.0f,
- 0.5115f, 0.0f, 0.0741f, 0.7689f, 1.0f,
- 0.503f, 0.0f, 0.0548f, 0.8236f, 1.0f,
- 0.4931f, 0.0f, 0.0368f, 0.866f, 1.0f,
- 0.482f, 0.0f, 0.02f, 0.9003f, 1.0f,
- 0.4697f, 0.0f, 0.0046f, 0.9272f, 1.0f,
- 0.4565f, 0.0f, -0.0094f, 0.9485f, 1.0f,
- 0.4424f, 0.0f, -0.0219f, 0.9653f, 1.0f,
- 0.4275f, 0.0f, -0.033f, 0.9781f, 1.0f,
- 0.4121f, 0.0f, -0.0424f, 0.9876f, 1.0f,
- 0.3961f, 0.0f, -0.0501f, 0.9942f, 1.0f,
- 0.3799f, 0.0f, -0.0562f, 0.9983f, 1.0f,
- 0.3634f, 0.0f, -0.0605f, 0.9997f, 1.0f,
- 0.3468f, 0.0f, -0.0629f, 0.999f, 1.0f,
- 0.3303f, 0.0f, -0.0634f, 0.9963f, 1.0f,
- 0.3139f, 0.0f, -0.062f, 0.9912f, 1.0f,
- 0.2979f, 0.0f, -0.0585f, 0.9834f, 1.0f,
- 0.2823f, 0.0f, -0.0529f, 0.9724f, 1.0f,
- 0.2672f, 0.0f, -0.0452f, 0.9576f, 1.0f,
- 0.2529f, 0.0f, -0.0352f, 0.9385f, 1.0f,
- 0.2393f, 0.0f, -0.023f, 0.9143f, 1.0f,
- 0.2267f, 0.0f, -0.0085f, 0.8841f, 1.0f,
- 0.2153f, 0.0f, 0.0085f, 0.8461f, 1.0f,
- 0.205f, 0.0f, 0.0279f, 0.7979f, 1.0f,
- 0.196f, 0.0f, 0.0499f, 0.7359f, 1.0f,
- 0.1886f, 0.0f, 0.0745f, 0.6541f, 1.0f,
- 0.1827f, 0.0f, 0.1017f, 0.5396f, 1.0f,
- 0.1786f, 0.0f, 0.1316f, 0.36f, 1.0f,
- 0.1763f, 0.0f, 0.1643f, 0.1f, 1.0f,
+ 0.5292f, 0.0f, 0.1742f, 0.1f, 1.0f, 0.5291f, 0.0f, 0.1621f, 0.2199f, 1.0f,
+ 0.5274f, 0.0f, 0.1386f, 0.4615f, 1.0f, 0.5239f, 0.0f, 0.116f, 0.6019f, 1.0f,
+ 0.5185f, 0.0f, 0.0945f, 0.6981f, 1.0f, 0.5115f, 0.0f, 0.0741f, 0.7689f, 1.0f,
+ 0.503f, 0.0f, 0.0548f, 0.8236f, 1.0f, 0.4931f, 0.0f, 0.0368f, 0.866f, 1.0f,
+ 0.482f, 0.0f, 0.02f, 0.9003f, 1.0f, 0.4697f, 0.0f, 0.0046f, 0.9272f, 1.0f,
+ 0.4565f, 0.0f, -0.0094f, 0.9485f, 1.0f, 0.4424f, 0.0f, -0.0219f, 0.9653f, 1.0f,
+ 0.4275f, 0.0f, -0.033f, 0.9781f, 1.0f, 0.4121f, 0.0f, -0.0424f, 0.9876f, 1.0f,
+ 0.3961f, 0.0f, -0.0501f, 0.9942f, 1.0f, 0.3799f, 0.0f, -0.0562f, 0.9983f, 1.0f,
+ 0.3634f, 0.0f, -0.0605f, 0.9997f, 1.0f, 0.3468f, 0.0f, -0.0629f, 0.999f, 1.0f,
+ 0.3303f, 0.0f, -0.0634f, 0.9963f, 1.0f, 0.3139f, 0.0f, -0.062f, 0.9912f, 1.0f,
+ 0.2979f, 0.0f, -0.0585f, 0.9834f, 1.0f, 0.2823f, 0.0f, -0.0529f, 0.9724f, 1.0f,
+ 0.2672f, 0.0f, -0.0452f, 0.9576f, 1.0f, 0.2529f, 0.0f, -0.0352f, 0.9385f, 1.0f,
+ 0.2393f, 0.0f, -0.023f, 0.9143f, 1.0f, 0.2267f, 0.0f, -0.0085f, 0.8841f, 1.0f,
+ 0.2153f, 0.0f, 0.0085f, 0.8461f, 1.0f, 0.205f, 0.0f, 0.0279f, 0.7979f, 1.0f,
+ 0.196f, 0.0f, 0.0499f, 0.7359f, 1.0f, 0.1886f, 0.0f, 0.0745f, 0.6541f, 1.0f,
+ 0.1827f, 0.0f, 0.1017f, 0.5396f, 1.0f, 0.1786f, 0.0f, 0.1316f, 0.36f, 1.0f,
+ 0.1763f, 0.0f, 0.1643f, 0.1f, 1.0f,
};
static const float data2[18 * GP_PRIM_DATABUF_SIZE] = {
- -0.0844f, 0.0f, -0.301f, 0.1f, 1.0f,
- -0.0825f, 0.0f, -0.3034f, 0.2199f, 1.0f,
- -0.0751f, 0.0f, -0.3128f, 0.6019f, 1.0f,
- -0.0677f, 0.0f, -0.3216f, 0.7689f, 1.0f,
- -0.06f, 0.0f, -0.3298f, 0.866f, 1.0f,
- -0.0522f, 0.0f, -0.3372f, 0.9272f, 1.0f,
- -0.044f, 0.0f, -0.3437f, 0.9653f, 1.0f,
- -0.0354f, 0.0f, -0.3491f, 0.9876f, 1.0f,
- -0.0264f, 0.0f, -0.3535f, 0.9983f, 1.0f,
- -0.0168f, 0.0f, -0.3566f, 0.999f, 1.0f,
- -0.0065f, 0.0f, -0.3583f, 0.9912f, 1.0f,
- 0.0045f, 0.0f, -0.3585f, 0.9724f, 1.0f,
- 0.0163f, 0.0f, -0.3571f, 0.9385f, 1.0f,
- 0.029f, 0.0f, -0.354f, 0.8841f, 1.0f,
- 0.0427f, 0.0f, -0.3491f, 0.7979f, 1.0f,
- 0.0574f, 0.0f, -0.3421f, 0.6541f, 1.0f,
- 0.0732f, 0.0f, -0.3331f, 0.36f, 1.0f,
- 0.0816f, 0.0f, -0.3278f, 0.1f, 1.0f,
+ -0.0844f, 0.0f, -0.301f, 0.1f, 1.0f, -0.0825f, 0.0f, -0.3034f, 0.2199f, 1.0f,
+ -0.0751f, 0.0f, -0.3128f, 0.6019f, 1.0f, -0.0677f, 0.0f, -0.3216f, 0.7689f, 1.0f,
+ -0.06f, 0.0f, -0.3298f, 0.866f, 1.0f, -0.0522f, 0.0f, -0.3372f, 0.9272f, 1.0f,
+ -0.044f, 0.0f, -0.3437f, 0.9653f, 1.0f, -0.0354f, 0.0f, -0.3491f, 0.9876f, 1.0f,
+ -0.0264f, 0.0f, -0.3535f, 0.9983f, 1.0f, -0.0168f, 0.0f, -0.3566f, 0.999f, 1.0f,
+ -0.0065f, 0.0f, -0.3583f, 0.9912f, 1.0f, 0.0045f, 0.0f, -0.3585f, 0.9724f, 1.0f,
+ 0.0163f, 0.0f, -0.3571f, 0.9385f, 1.0f, 0.029f, 0.0f, -0.354f, 0.8841f, 1.0f,
+ 0.0427f, 0.0f, -0.3491f, 0.7979f, 1.0f, 0.0574f, 0.0f, -0.3421f, 0.6541f, 1.0f,
+ 0.0732f, 0.0f, -0.3331f, 0.36f, 1.0f, 0.0816f, 0.0f, -0.3278f, 0.1f, 1.0f,
};
static const float data3[64 * GP_PRIM_DATABUF_SIZE] = {
- -0.6551f, 0.0f, 0.4448f, 0.1f, 1.0f,
- -0.6353f, 0.0f, 0.4689f, 0.2199f, 1.0f,
- -0.6211f, 0.0f, 0.4845f, 0.36f, 1.0f,
- -0.6033f, 0.0f, 0.5034f, 0.4615f, 1.0f,
- -0.5856f, 0.0f, 0.5211f, 0.5396f, 1.0f,
- -0.5672f, 0.0f, 0.5387f, 0.6019f, 1.0f,
- -0.5485f, 0.0f, 0.5555f, 0.6541f, 1.0f,
- -0.5295f, 0.0f, 0.5718f, 0.6981f, 1.0f,
- -0.5103f, 0.0f, 0.5875f, 0.7359f, 1.0f,
- -0.4909f, 0.0f, 0.6028f, 0.7689f, 1.0f,
- -0.4712f, 0.0f, 0.6174f, 0.7979f, 1.0f,
- -0.4512f, 0.0f, 0.6313f, 0.8236f, 1.0f,
- -0.4307f, 0.0f, 0.6444f, 0.8461f, 1.0f,
- -0.4099f, 0.0f, 0.6568f, 0.866f, 1.0f,
- -0.3884f, 0.0f, 0.6684f, 0.8841f, 1.0f,
- -0.3665f, 0.0f, 0.6793f, 0.9003f, 1.0f,
- -0.3439f, 0.0f, 0.6893f, 0.9143f, 1.0f,
- -0.3207f, 0.0f, 0.6984f, 0.9272f, 1.0f,
- -0.2971f, 0.0f, 0.7069f, 0.9385f, 1.0f,
- -0.2731f, 0.0f, 0.7148f, 0.9485f, 1.0f,
- -0.249f, 0.0f, 0.7222f, 0.9576f, 1.0f,
- -0.2247f, 0.0f, 0.7292f, 0.9653f, 1.0f,
- -0.2003f, 0.0f, 0.7356f, 0.9724f, 1.0f,
- -0.1759f, 0.0f, 0.7416f, 0.9781f, 1.0f,
- -0.1515f, 0.0f, 0.7471f, 0.9834f, 1.0f,
- -0.1272f, 0.0f, 0.7518f, 0.9876f, 1.0f,
- -0.1028f, 0.0f, 0.7556f, 0.9912f, 1.0f,
- -0.0785f, 0.0f, 0.7586f, 0.9942f, 1.0f,
- -0.0543f, 0.0f, 0.7607f, 0.9963f, 1.0f,
- -0.0302f, 0.0f, 0.7621f, 0.9983f, 1.0f,
- -0.0062f, 0.0f, 0.7627f, 0.999f, 1.0f,
- 0.0177f, 0.0f, 0.7625f, 0.9997f, 1.0f,
- 0.0415f, 0.0f, 0.7616f, 0.9997f, 1.0f,
- 0.0652f, 0.0f, 0.7602f, 0.999f, 1.0f,
- 0.0887f, 0.0f, 0.7583f, 0.9983f, 1.0f,
- 0.1122f, 0.0f, 0.7559f, 0.9963f, 1.0f,
- 0.1355f, 0.0f, 0.7529f, 0.9942f, 1.0f,
- 0.1585f, 0.0f, 0.7493f, 0.9912f, 1.0f,
- 0.1814f, 0.0f, 0.7451f, 0.9876f, 1.0f,
- 0.2041f, 0.0f, 0.7404f, 0.9834f, 1.0f,
- 0.2266f, 0.0f, 0.7352f, 0.9781f, 1.0f,
- 0.2488f, 0.0f, 0.729f, 0.9724f, 1.0f,
- 0.2706f, 0.0f, 0.7216f, 0.9653f, 1.0f,
- 0.2921f, 0.0f, 0.7131f, 0.9576f, 1.0f,
- 0.3135f, 0.0f, 0.7041f, 0.9485f, 1.0f,
- 0.3348f, 0.0f, 0.6945f, 0.9385f, 1.0f,
- 0.3559f, 0.0f, 0.6845f, 0.9272f, 1.0f,
- 0.3769f, 0.0f, 0.6739f, 0.9143f, 1.0f,
- 0.3978f, 0.0f, 0.6628f, 0.9003f, 1.0f,
- 0.4185f, 0.0f, 0.651f, 0.8841f, 1.0f,
- 0.439f, 0.0f, 0.6383f, 0.866f, 1.0f,
- 0.4594f, 0.0f, 0.6249f, 0.8461f, 1.0f,
- 0.4795f, 0.0f, 0.6106f, 0.8236f, 1.0f,
- 0.4995f, 0.0f, 0.5956f, 0.7979f, 1.0f,
- 0.5193f, 0.0f, 0.5801f, 0.7689f, 1.0f,
- 0.539f, 0.0f, 0.5642f, 0.7359f, 1.0f,
- 0.5586f, 0.0f, 0.5479f, 0.6981f, 1.0f,
- 0.578f, 0.0f, 0.5312f, 0.6541f, 1.0f,
- 0.597f, 0.0f, 0.5141f, 0.6019f, 1.0f,
- 0.6153f, 0.0f, 0.4966f, 0.5396f, 1.0f,
- 0.6324f, 0.0f, 0.4797f, 0.4615f, 1.0f,
- 0.6498f, 0.0f, 0.462f, 0.36f, 1.0f,
- 0.6638f, 0.0f, 0.4477f, 0.2199f, 1.0f,
- 0.6843f, 0.0f, 0.4263f, 0.1f, 1.0f,
+ -0.6551f, 0.0f, 0.4448f, 0.1f, 1.0f, -0.6353f, 0.0f, 0.4689f, 0.2199f, 1.0f,
+ -0.6211f, 0.0f, 0.4845f, 0.36f, 1.0f, -0.6033f, 0.0f, 0.5034f, 0.4615f, 1.0f,
+ -0.5856f, 0.0f, 0.5211f, 0.5396f, 1.0f, -0.5672f, 0.0f, 0.5387f, 0.6019f, 1.0f,
+ -0.5485f, 0.0f, 0.5555f, 0.6541f, 1.0f, -0.5295f, 0.0f, 0.5718f, 0.6981f, 1.0f,
+ -0.5103f, 0.0f, 0.5875f, 0.7359f, 1.0f, -0.4909f, 0.0f, 0.6028f, 0.7689f, 1.0f,
+ -0.4712f, 0.0f, 0.6174f, 0.7979f, 1.0f, -0.4512f, 0.0f, 0.6313f, 0.8236f, 1.0f,
+ -0.4307f, 0.0f, 0.6444f, 0.8461f, 1.0f, -0.4099f, 0.0f, 0.6568f, 0.866f, 1.0f,
+ -0.3884f, 0.0f, 0.6684f, 0.8841f, 1.0f, -0.3665f, 0.0f, 0.6793f, 0.9003f, 1.0f,
+ -0.3439f, 0.0f, 0.6893f, 0.9143f, 1.0f, -0.3207f, 0.0f, 0.6984f, 0.9272f, 1.0f,
+ -0.2971f, 0.0f, 0.7069f, 0.9385f, 1.0f, -0.2731f, 0.0f, 0.7148f, 0.9485f, 1.0f,
+ -0.249f, 0.0f, 0.7222f, 0.9576f, 1.0f, -0.2247f, 0.0f, 0.7292f, 0.9653f, 1.0f,
+ -0.2003f, 0.0f, 0.7356f, 0.9724f, 1.0f, -0.1759f, 0.0f, 0.7416f, 0.9781f, 1.0f,
+ -0.1515f, 0.0f, 0.7471f, 0.9834f, 1.0f, -0.1272f, 0.0f, 0.7518f, 0.9876f, 1.0f,
+ -0.1028f, 0.0f, 0.7556f, 0.9912f, 1.0f, -0.0785f, 0.0f, 0.7586f, 0.9942f, 1.0f,
+ -0.0543f, 0.0f, 0.7607f, 0.9963f, 1.0f, -0.0302f, 0.0f, 0.7621f, 0.9983f, 1.0f,
+ -0.0062f, 0.0f, 0.7627f, 0.999f, 1.0f, 0.0177f, 0.0f, 0.7625f, 0.9997f, 1.0f,
+ 0.0415f, 0.0f, 0.7616f, 0.9997f, 1.0f, 0.0652f, 0.0f, 0.7602f, 0.999f, 1.0f,
+ 0.0887f, 0.0f, 0.7583f, 0.9983f, 1.0f, 0.1122f, 0.0f, 0.7559f, 0.9963f, 1.0f,
+ 0.1355f, 0.0f, 0.7529f, 0.9942f, 1.0f, 0.1585f, 0.0f, 0.7493f, 0.9912f, 1.0f,
+ 0.1814f, 0.0f, 0.7451f, 0.9876f, 1.0f, 0.2041f, 0.0f, 0.7404f, 0.9834f, 1.0f,
+ 0.2266f, 0.0f, 0.7352f, 0.9781f, 1.0f, 0.2488f, 0.0f, 0.729f, 0.9724f, 1.0f,
+ 0.2706f, 0.0f, 0.7216f, 0.9653f, 1.0f, 0.2921f, 0.0f, 0.7131f, 0.9576f, 1.0f,
+ 0.3135f, 0.0f, 0.7041f, 0.9485f, 1.0f, 0.3348f, 0.0f, 0.6945f, 0.9385f, 1.0f,
+ 0.3559f, 0.0f, 0.6845f, 0.9272f, 1.0f, 0.3769f, 0.0f, 0.6739f, 0.9143f, 1.0f,
+ 0.3978f, 0.0f, 0.6628f, 0.9003f, 1.0f, 0.4185f, 0.0f, 0.651f, 0.8841f, 1.0f,
+ 0.439f, 0.0f, 0.6383f, 0.866f, 1.0f, 0.4594f, 0.0f, 0.6249f, 0.8461f, 1.0f,
+ 0.4795f, 0.0f, 0.6106f, 0.8236f, 1.0f, 0.4995f, 0.0f, 0.5956f, 0.7979f, 1.0f,
+ 0.5193f, 0.0f, 0.5801f, 0.7689f, 1.0f, 0.539f, 0.0f, 0.5642f, 0.7359f, 1.0f,
+ 0.5586f, 0.0f, 0.5479f, 0.6981f, 1.0f, 0.578f, 0.0f, 0.5312f, 0.6541f, 1.0f,
+ 0.597f, 0.0f, 0.5141f, 0.6019f, 1.0f, 0.6153f, 0.0f, 0.4966f, 0.5396f, 1.0f,
+ 0.6324f, 0.0f, 0.4797f, 0.4615f, 1.0f, 0.6498f, 0.0f, 0.462f, 0.36f, 1.0f,
+ 0.6638f, 0.0f, 0.4477f, 0.2199f, 1.0f, 0.6843f, 0.0f, 0.4263f, 0.1f, 1.0f,
};
static const float data4[33 * GP_PRIM_DATABUF_SIZE] = {
- -0.7765f, 0.0f, 0.3255f, 0.1f, 1.0f,
- -0.7908f, 0.0f, 0.3335f, 0.2199f, 1.0f,
- -0.8048f, 0.0f, 0.3402f, 0.4615f, 1.0f,
- -0.8225f, 0.0f, 0.3467f, 0.6019f, 1.0f,
- -0.8426f, 0.0f, 0.3529f, 0.6981f, 1.0f,
- -0.8651f, 0.0f, 0.3587f, 0.7689f, 1.0f,
- -0.8878f, 0.0f, 0.3633f, 0.8236f, 1.0f,
- -0.9105f, 0.0f, 0.367f, 0.866f, 1.0f,
- -0.9323f, 0.0f, 0.3693f, 0.9003f, 1.0f,
- -0.9529f, 0.0f, 0.3701f, 0.9272f, 1.0f,
- -0.972f, 0.0f, 0.3695f, 0.9485f, 1.0f,
- -0.9896f, 0.0f, 0.3675f, 0.9653f, 1.0f,
- -1.0057f, 0.0f, 0.364f, 0.9781f, 1.0f,
- -1.0203f, 0.0f, 0.3592f, 0.9876f, 1.0f,
- -1.0333f, 0.0f, 0.3528f, 0.9942f, 1.0f,
- -1.0447f, 0.0f, 0.3452f, 0.9983f, 1.0f,
- -1.0546f, 0.0f, 0.3362f, 0.9997f, 1.0f,
- -1.0633f, 0.0f, 0.3261f, 0.999f, 1.0f,
- -1.0708f, 0.0f, 0.315f, 0.9963f, 1.0f,
- -1.0767f, 0.0f, 0.3027f, 0.9912f, 1.0f,
- -1.0818f, 0.0f, 0.2894f, 0.9834f, 1.0f,
- -1.0861f, 0.0f, 0.2752f, 0.9724f, 1.0f,
- -1.0897f, 0.0f, 0.2604f, 0.9576f, 1.0f,
- -1.0922f, 0.0f, 0.2446f, 0.9385f, 1.0f,
- -1.0938f, 0.0f, 0.2277f, 0.9143f, 1.0f,
- -1.0944f, 0.0f, 0.2098f, 0.8841f, 1.0f,
- -1.0939f, 0.0f, 0.191f, 0.8461f, 1.0f,
- -1.0924f, 0.0f, 0.1714f, 0.7979f, 1.0f,
- -1.0897f, 0.0f, 0.1511f, 0.7359f, 1.0f,
- -1.0855f, 0.0f, 0.1303f, 0.6541f, 1.0f,
- -1.0798f, 0.0f, 0.1095f, 0.5396f, 1.0f,
- -1.0723f, 0.0f, 0.089f, 0.36f, 1.0f,
- -1.0642f, 0.0f, 0.0702f, 0.1f, 1.0f,
+ -0.7765f, 0.0f, 0.3255f, 0.1f, 1.0f, -0.7908f, 0.0f, 0.3335f, 0.2199f, 1.0f,
+ -0.8048f, 0.0f, 0.3402f, 0.4615f, 1.0f, -0.8225f, 0.0f, 0.3467f, 0.6019f, 1.0f,
+ -0.8426f, 0.0f, 0.3529f, 0.6981f, 1.0f, -0.8651f, 0.0f, 0.3587f, 0.7689f, 1.0f,
+ -0.8878f, 0.0f, 0.3633f, 0.8236f, 1.0f, -0.9105f, 0.0f, 0.367f, 0.866f, 1.0f,
+ -0.9323f, 0.0f, 0.3693f, 0.9003f, 1.0f, -0.9529f, 0.0f, 0.3701f, 0.9272f, 1.0f,
+ -0.972f, 0.0f, 0.3695f, 0.9485f, 1.0f, -0.9896f, 0.0f, 0.3675f, 0.9653f, 1.0f,
+ -1.0057f, 0.0f, 0.364f, 0.9781f, 1.0f, -1.0203f, 0.0f, 0.3592f, 0.9876f, 1.0f,
+ -1.0333f, 0.0f, 0.3528f, 0.9942f, 1.0f, -1.0447f, 0.0f, 0.3452f, 0.9983f, 1.0f,
+ -1.0546f, 0.0f, 0.3362f, 0.9997f, 1.0f, -1.0633f, 0.0f, 0.3261f, 0.999f, 1.0f,
+ -1.0708f, 0.0f, 0.315f, 0.9963f, 1.0f, -1.0767f, 0.0f, 0.3027f, 0.9912f, 1.0f,
+ -1.0818f, 0.0f, 0.2894f, 0.9834f, 1.0f, -1.0861f, 0.0f, 0.2752f, 0.9724f, 1.0f,
+ -1.0897f, 0.0f, 0.2604f, 0.9576f, 1.0f, -1.0922f, 0.0f, 0.2446f, 0.9385f, 1.0f,
+ -1.0938f, 0.0f, 0.2277f, 0.9143f, 1.0f, -1.0944f, 0.0f, 0.2098f, 0.8841f, 1.0f,
+ -1.0939f, 0.0f, 0.191f, 0.8461f, 1.0f, -1.0924f, 0.0f, 0.1714f, 0.7979f, 1.0f,
+ -1.0897f, 0.0f, 0.1511f, 0.7359f, 1.0f, -1.0855f, 0.0f, 0.1303f, 0.6541f, 1.0f,
+ -1.0798f, 0.0f, 0.1095f, 0.5396f, 1.0f, -1.0723f, 0.0f, 0.089f, 0.36f, 1.0f,
+ -1.0642f, 0.0f, 0.0702f, 0.1f, 1.0f,
};
static const float data5[64 * GP_PRIM_DATABUF_SIZE] = {
- 0.8135f, 0.0f, 0.3341f, 0.1f, 1.0f,
- 0.8191f, 0.0f, 0.3376f, 0.2199f, 1.0f,
- 0.8246f, 0.0f, 0.3408f, 0.36f, 1.0f,
- 0.8304f, 0.0f, 0.3438f, 0.4615f, 1.0f,
- 0.8368f, 0.0f, 0.3465f, 0.5396f, 1.0f,
- 0.843f, 0.0f, 0.3491f, 0.6019f, 1.0f,
- 0.8494f, 0.0f, 0.3515f, 0.6541f, 1.0f,
- 0.8558f, 0.0f, 0.3536f, 0.6981f, 1.0f,
- 0.8623f, 0.0f, 0.3557f, 0.7359f, 1.0f,
- 0.8688f, 0.0f, 0.3575f, 0.7689f, 1.0f,
- 0.8752f, 0.0f, 0.3593f, 0.7979f, 1.0f,
- 0.8813f, 0.0f, 0.3609f, 0.8236f, 1.0f,
- 0.8872f, 0.0f, 0.3625f, 0.8461f, 1.0f,
- 0.8929f, 0.0f, 0.364f, 0.866f, 1.0f,
- 0.8984f, 0.0f, 0.3653f, 0.8841f, 1.0f,
- 0.9039f, 0.0f, 0.3665f, 0.9003f, 1.0f,
- 0.9093f, 0.0f, 0.3675f, 0.9143f, 1.0f,
- 0.9146f, 0.0f, 0.3684f, 0.9272f, 1.0f,
- 0.9199f, 0.0f, 0.3692f, 0.9385f, 1.0f,
- 0.9253f, 0.0f, 0.3698f, 0.9485f, 1.0f,
- 0.9305f, 0.0f, 0.3703f, 0.9576f, 1.0f,
- 0.9358f, 0.0f, 0.3706f, 0.9653f, 1.0f,
- 0.941f, 0.0f, 0.3709f, 0.9724f, 1.0f,
- 0.9462f, 0.0f, 0.371f, 0.9781f, 1.0f,
- 0.9514f, 0.0f, 0.371f, 0.9834f, 1.0f,
- 0.9566f, 0.0f, 0.3708f, 0.9876f, 1.0f,
- 0.9617f, 0.0f, 0.3706f, 0.9912f, 1.0f,
- 0.9668f, 0.0f, 0.3702f, 0.9942f, 1.0f,
- 0.9718f, 0.0f, 0.3697f, 0.9963f, 1.0f,
- 0.9768f, 0.0f, 0.3692f, 0.9983f, 1.0f,
- 0.9818f, 0.0f, 0.3685f, 0.999f, 1.0f,
- 0.9867f, 0.0f, 0.3677f, 0.9997f, 1.0f,
- 0.9916f, 0.0f, 0.3667f, 0.9997f, 1.0f,
- 0.9964f, 0.0f, 0.3657f, 0.999f, 1.0f,
- 1.0012f, 0.0f, 0.3646f, 0.9983f, 1.0f,
- 1.006f, 0.0f, 0.3634f, 0.9963f, 1.0f,
- 1.0107f, 0.0f, 0.3621f, 0.9942f, 1.0f,
- 1.0154f, 0.0f, 0.3607f, 0.9912f, 1.0f,
- 1.02f, 0.0f, 0.3593f, 0.9876f, 1.0f,
- 1.0245f, 0.0f, 0.3577f, 0.9834f, 1.0f,
- 1.029f, 0.0f, 0.3561f, 0.9781f, 1.0f,
- 1.0335f, 0.0f, 0.3543f, 0.9724f, 1.0f,
- 1.0379f, 0.0f, 0.3525f, 0.9653f, 1.0f,
- 1.0422f, 0.0f, 0.3507f, 0.9576f, 1.0f,
- 1.0465f, 0.0f, 0.3487f, 0.9485f, 1.0f,
- 1.0507f, 0.0f, 0.3468f, 0.9385f, 1.0f,
- 1.0549f, 0.0f, 0.3447f, 0.9272f, 1.0f,
- 1.0591f, 0.0f, 0.3427f, 0.9143f, 1.0f,
- 1.0633f, 0.0f, 0.3404f, 0.9003f, 1.0f,
- 1.0675f, 0.0f, 0.338f, 0.8841f, 1.0f,
- 1.0717f, 0.0f, 0.3351f, 0.866f, 1.0f,
- 1.0761f, 0.0f, 0.3318f, 0.8461f, 1.0f,
- 1.0805f, 0.0f, 0.3279f, 0.8236f, 1.0f,
- 1.0849f, 0.0f, 0.3235f, 0.7979f, 1.0f,
- 1.0893f, 0.0f, 0.3186f, 0.7689f, 1.0f,
- 1.0936f, 0.0f, 0.3134f, 0.7359f, 1.0f,
- 1.0979f, 0.0f, 0.3076f, 0.6981f, 1.0f,
- 1.102f, 0.0f, 0.3017f, 0.6541f, 1.0f,
- 1.106f, 0.0f, 0.2953f, 0.6019f, 1.0f,
- 1.1097f, 0.0f, 0.289f, 0.5396f, 1.0f,
- 1.1132f, 0.0f, 0.2826f, 0.4615f, 1.0f,
- 1.1164f, 0.0f, 0.2766f, 0.36f, 1.0f,
- 1.1193f, 0.0f, 0.2708f, 0.2199f, 1.0f,
- 1.1221f, 0.0f, 0.2652f, 0.1f, 1.0f,
+ 0.8135f, 0.0f, 0.3341f, 0.1f, 1.0f, 0.8191f, 0.0f, 0.3376f, 0.2199f, 1.0f,
+ 0.8246f, 0.0f, 0.3408f, 0.36f, 1.0f, 0.8304f, 0.0f, 0.3438f, 0.4615f, 1.0f,
+ 0.8368f, 0.0f, 0.3465f, 0.5396f, 1.0f, 0.843f, 0.0f, 0.3491f, 0.6019f, 1.0f,
+ 0.8494f, 0.0f, 0.3515f, 0.6541f, 1.0f, 0.8558f, 0.0f, 0.3536f, 0.6981f, 1.0f,
+ 0.8623f, 0.0f, 0.3557f, 0.7359f, 1.0f, 0.8688f, 0.0f, 0.3575f, 0.7689f, 1.0f,
+ 0.8752f, 0.0f, 0.3593f, 0.7979f, 1.0f, 0.8813f, 0.0f, 0.3609f, 0.8236f, 1.0f,
+ 0.8872f, 0.0f, 0.3625f, 0.8461f, 1.0f, 0.8929f, 0.0f, 0.364f, 0.866f, 1.0f,
+ 0.8984f, 0.0f, 0.3653f, 0.8841f, 1.0f, 0.9039f, 0.0f, 0.3665f, 0.9003f, 1.0f,
+ 0.9093f, 0.0f, 0.3675f, 0.9143f, 1.0f, 0.9146f, 0.0f, 0.3684f, 0.9272f, 1.0f,
+ 0.9199f, 0.0f, 0.3692f, 0.9385f, 1.0f, 0.9253f, 0.0f, 0.3698f, 0.9485f, 1.0f,
+ 0.9305f, 0.0f, 0.3703f, 0.9576f, 1.0f, 0.9358f, 0.0f, 0.3706f, 0.9653f, 1.0f,
+ 0.941f, 0.0f, 0.3709f, 0.9724f, 1.0f, 0.9462f, 0.0f, 0.371f, 0.9781f, 1.0f,
+ 0.9514f, 0.0f, 0.371f, 0.9834f, 1.0f, 0.9566f, 0.0f, 0.3708f, 0.9876f, 1.0f,
+ 0.9617f, 0.0f, 0.3706f, 0.9912f, 1.0f, 0.9668f, 0.0f, 0.3702f, 0.9942f, 1.0f,
+ 0.9718f, 0.0f, 0.3697f, 0.9963f, 1.0f, 0.9768f, 0.0f, 0.3692f, 0.9983f, 1.0f,
+ 0.9818f, 0.0f, 0.3685f, 0.999f, 1.0f, 0.9867f, 0.0f, 0.3677f, 0.9997f, 1.0f,
+ 0.9916f, 0.0f, 0.3667f, 0.9997f, 1.0f, 0.9964f, 0.0f, 0.3657f, 0.999f, 1.0f,
+ 1.0012f, 0.0f, 0.3646f, 0.9983f, 1.0f, 1.006f, 0.0f, 0.3634f, 0.9963f, 1.0f,
+ 1.0107f, 0.0f, 0.3621f, 0.9942f, 1.0f, 1.0154f, 0.0f, 0.3607f, 0.9912f, 1.0f,
+ 1.02f, 0.0f, 0.3593f, 0.9876f, 1.0f, 1.0245f, 0.0f, 0.3577f, 0.9834f, 1.0f,
+ 1.029f, 0.0f, 0.3561f, 0.9781f, 1.0f, 1.0335f, 0.0f, 0.3543f, 0.9724f, 1.0f,
+ 1.0379f, 0.0f, 0.3525f, 0.9653f, 1.0f, 1.0422f, 0.0f, 0.3507f, 0.9576f, 1.0f,
+ 1.0465f, 0.0f, 0.3487f, 0.9485f, 1.0f, 1.0507f, 0.0f, 0.3468f, 0.9385f, 1.0f,
+ 1.0549f, 0.0f, 0.3447f, 0.9272f, 1.0f, 1.0591f, 0.0f, 0.3427f, 0.9143f, 1.0f,
+ 1.0633f, 0.0f, 0.3404f, 0.9003f, 1.0f, 1.0675f, 0.0f, 0.338f, 0.8841f, 1.0f,
+ 1.0717f, 0.0f, 0.3351f, 0.866f, 1.0f, 1.0761f, 0.0f, 0.3318f, 0.8461f, 1.0f,
+ 1.0805f, 0.0f, 0.3279f, 0.8236f, 1.0f, 1.0849f, 0.0f, 0.3235f, 0.7979f, 1.0f,
+ 1.0893f, 0.0f, 0.3186f, 0.7689f, 1.0f, 1.0936f, 0.0f, 0.3134f, 0.7359f, 1.0f,
+ 1.0979f, 0.0f, 0.3076f, 0.6981f, 1.0f, 1.102f, 0.0f, 0.3017f, 0.6541f, 1.0f,
+ 1.106f, 0.0f, 0.2953f, 0.6019f, 1.0f, 1.1097f, 0.0f, 0.289f, 0.5396f, 1.0f,
+ 1.1132f, 0.0f, 0.2826f, 0.4615f, 1.0f, 1.1164f, 0.0f, 0.2766f, 0.36f, 1.0f,
+ 1.1193f, 0.0f, 0.2708f, 0.2199f, 1.0f, 1.1221f, 0.0f, 0.2652f, 0.1f, 1.0f,
};
static const float data6[33 * GP_PRIM_DATABUF_SIZE] = {
- -0.2677f, 0.0f, -0.3496f, 0.1f, 1.0f,
- -0.2658f, 0.0f, -0.3919f, 0.2199f, 1.0f,
- -0.2657f, 0.0f, -0.4295f, 0.4615f, 1.0f,
- -0.2691f, 0.0f, -0.4621f, 0.6019f, 1.0f,
- -0.275f, 0.0f, -0.4949f, 0.6981f, 1.0f,
- -0.2828f, 0.0f, -0.527f, 0.7689f, 1.0f,
- -0.2911f, 0.0f, -0.5578f, 0.8236f, 1.0f,
- -0.2971f, 0.0f, -0.5884f, 0.866f, 1.0f,
- -0.303f, 0.0f, -0.6181f, 0.9003f, 1.0f,
- -0.3089f, 0.0f, -0.6467f, 0.9272f, 1.0f,
- -0.3148f, 0.0f, -0.6738f, 0.9485f, 1.0f,
- -0.3196f, 0.0f, -0.7f, 0.9653f, 1.0f,
- -0.323f, 0.0f, -0.7253f, 0.9781f, 1.0f,
- -0.3234f, 0.0f, -0.7496f, 0.9876f, 1.0f,
- -0.3219f, 0.0f, -0.7728f, 0.9942f, 1.0f,
- -0.3184f, 0.0f, -0.7949f, 0.9983f, 1.0f,
- -0.3103f, 0.0f, -0.8138f, 0.9997f, 1.0f,
- -0.3004f, 0.0f, -0.8307f, 0.999f, 1.0f,
- -0.2892f, 0.0f, -0.8464f, 0.9963f, 1.0f,
- -0.2766f, 0.0f, -0.8611f, 0.9912f, 1.0f,
- -0.2618f, 0.0f, -0.8735f, 0.9834f, 1.0f,
- -0.2469f, 0.0f, -0.8853f, 0.9724f, 1.0f,
- -0.2315f, 0.0f, -0.8964f, 0.9576f, 1.0f,
- -0.2158f, 0.0f, -0.9068f, 0.9385f, 1.0f,
- -0.1997f, 0.0f, -0.9167f, 0.9143f, 1.0f,
- -0.1833f, 0.0f, -0.9262f, 0.8841f, 1.0f,
- -0.1663f, 0.0f, -0.9355f, 0.8461f, 1.0f,
- -0.1481f, 0.0f, -0.9445f, 0.7979f, 1.0f,
- -0.1282f, 0.0f, -0.9534f, 0.7359f, 1.0f,
- -0.1077f, 0.0f, -0.9625f, 0.6541f, 1.0f,
- -0.0854f, 0.0f, -0.9718f, 0.5396f, 1.0f,
- -0.0616f, 0.0f, -0.9813f, 0.36f, 1.0f,
- -0.0248f, 0.0f, -0.992f, 0.1f, 1.0f,
+ -0.2677f, 0.0f, -0.3496f, 0.1f, 1.0f, -0.2658f, 0.0f, -0.3919f, 0.2199f, 1.0f,
+ -0.2657f, 0.0f, -0.4295f, 0.4615f, 1.0f, -0.2691f, 0.0f, -0.4621f, 0.6019f, 1.0f,
+ -0.275f, 0.0f, -0.4949f, 0.6981f, 1.0f, -0.2828f, 0.0f, -0.527f, 0.7689f, 1.0f,
+ -0.2911f, 0.0f, -0.5578f, 0.8236f, 1.0f, -0.2971f, 0.0f, -0.5884f, 0.866f, 1.0f,
+ -0.303f, 0.0f, -0.6181f, 0.9003f, 1.0f, -0.3089f, 0.0f, -0.6467f, 0.9272f, 1.0f,
+ -0.3148f, 0.0f, -0.6738f, 0.9485f, 1.0f, -0.3196f, 0.0f, -0.7f, 0.9653f, 1.0f,
+ -0.323f, 0.0f, -0.7253f, 0.9781f, 1.0f, -0.3234f, 0.0f, -0.7496f, 0.9876f, 1.0f,
+ -0.3219f, 0.0f, -0.7728f, 0.9942f, 1.0f, -0.3184f, 0.0f, -0.7949f, 0.9983f, 1.0f,
+ -0.3103f, 0.0f, -0.8138f, 0.9997f, 1.0f, -0.3004f, 0.0f, -0.8307f, 0.999f, 1.0f,
+ -0.2892f, 0.0f, -0.8464f, 0.9963f, 1.0f, -0.2766f, 0.0f, -0.8611f, 0.9912f, 1.0f,
+ -0.2618f, 0.0f, -0.8735f, 0.9834f, 1.0f, -0.2469f, 0.0f, -0.8853f, 0.9724f, 1.0f,
+ -0.2315f, 0.0f, -0.8964f, 0.9576f, 1.0f, -0.2158f, 0.0f, -0.9068f, 0.9385f, 1.0f,
+ -0.1997f, 0.0f, -0.9167f, 0.9143f, 1.0f, -0.1833f, 0.0f, -0.9262f, 0.8841f, 1.0f,
+ -0.1663f, 0.0f, -0.9355f, 0.8461f, 1.0f, -0.1481f, 0.0f, -0.9445f, 0.7979f, 1.0f,
+ -0.1282f, 0.0f, -0.9534f, 0.7359f, 1.0f, -0.1077f, 0.0f, -0.9625f, 0.6541f, 1.0f,
+ -0.0854f, 0.0f, -0.9718f, 0.5396f, 1.0f, -0.0616f, 0.0f, -0.9813f, 0.36f, 1.0f,
+ -0.0248f, 0.0f, -0.992f, 0.1f, 1.0f,
};
static const float data7[18 * GP_PRIM_DATABUF_SIZE] = {
- -0.0618f, 0.0f, -0.1922f, 0.1f, 1.0f,
- -0.0703f, 0.0f, -0.2021f, 0.2199f, 1.0f,
- -0.0758f, 0.0f, -0.2103f, 0.6019f, 1.0f,
- -0.0803f, 0.0f, -0.2206f, 0.7689f, 1.0f,
- -0.083f, 0.0f, -0.2307f, 0.866f, 1.0f,
- -0.0851f, 0.0f, -0.2405f, 0.9272f, 1.0f,
- -0.0865f, 0.0f, -0.2499f, 0.9653f, 1.0f,
- -0.0872f, 0.0f, -0.2588f, 0.9876f, 1.0f,
- -0.0869f, 0.0f, -0.2673f, 0.9983f, 1.0f,
- -0.0858f, 0.0f, -0.2754f, 0.999f, 1.0f,
- -0.0831f, 0.0f, -0.2829f, 0.9912f, 1.0f,
- -0.0791f, 0.0f, -0.2898f, 0.9724f, 1.0f,
- -0.074f, 0.0f, -0.2966f, 0.9385f, 1.0f,
- -0.0674f, 0.0f, -0.303f, 0.8841f, 1.0f,
- -0.0591f, 0.0f, -0.3084f, 0.7979f, 1.0f,
- -0.0465f, 0.0f, -0.3134f, 0.6541f, 1.0f,
- -0.0331f, 0.0f, -0.3165f, 0.36f, 1.0f,
- -0.015f, 0.0f, -0.318f, 0.1f, 1.0f,
+ -0.0618f, 0.0f, -0.1922f, 0.1f, 1.0f, -0.0703f, 0.0f, -0.2021f, 0.2199f, 1.0f,
+ -0.0758f, 0.0f, -0.2103f, 0.6019f, 1.0f, -0.0803f, 0.0f, -0.2206f, 0.7689f, 1.0f,
+ -0.083f, 0.0f, -0.2307f, 0.866f, 1.0f, -0.0851f, 0.0f, -0.2405f, 0.9272f, 1.0f,
+ -0.0865f, 0.0f, -0.2499f, 0.9653f, 1.0f, -0.0872f, 0.0f, -0.2588f, 0.9876f, 1.0f,
+ -0.0869f, 0.0f, -0.2673f, 0.9983f, 1.0f, -0.0858f, 0.0f, -0.2754f, 0.999f, 1.0f,
+ -0.0831f, 0.0f, -0.2829f, 0.9912f, 1.0f, -0.0791f, 0.0f, -0.2898f, 0.9724f, 1.0f,
+ -0.074f, 0.0f, -0.2966f, 0.9385f, 1.0f, -0.0674f, 0.0f, -0.303f, 0.8841f, 1.0f,
+ -0.0591f, 0.0f, -0.3084f, 0.7979f, 1.0f, -0.0465f, 0.0f, -0.3134f, 0.6541f, 1.0f,
+ -0.0331f, 0.0f, -0.3165f, 0.36f, 1.0f, -0.015f, 0.0f, -0.318f, 0.1f, 1.0f,
};
static const float data8[49 * GP_PRIM_DATABUF_SIZE] = {
- 0.5311f, 0.0f, 0.1661f, 1.0f, 1.0f,
- 0.5307f, 0.0f, 0.1794f, 1.0f, 1.0f,
- 0.5277f, 0.0f, 0.2057f, 1.0f, 1.0f,
- 0.5218f, 0.0f, 0.2314f, 1.0f, 1.0f,
- 0.513f, 0.0f, 0.256f, 1.0f, 1.0f,
- 0.5014f, 0.0f, 0.279f, 1.0f, 1.0f,
- 0.4874f, 0.0f, 0.3001f, 1.0f, 1.0f,
- 0.4711f, 0.0f, 0.3189f, 1.0f, 1.0f,
- 0.4529f, 0.0f, 0.3351f, 1.0f, 1.0f,
- 0.4329f, 0.0f, 0.3483f, 1.0f, 1.0f,
- 0.4117f, 0.0f, 0.3585f, 1.0f, 1.0f,
- 0.3894f, 0.0f, 0.3654f, 1.0f, 1.0f,
- 0.3666f, 0.0f, 0.3689f, 1.0f, 1.0f,
- 0.3435f, 0.0f, 0.3689f, 1.0f, 1.0f,
- 0.3207f, 0.0f, 0.3654f, 1.0f, 1.0f,
- 0.2985f, 0.0f, 0.3585f, 1.0f, 1.0f,
- 0.2772f, 0.0f, 0.3483f, 1.0f, 1.0f,
- 0.2573f, 0.0f, 0.3351f, 1.0f, 1.0f,
- 0.239f, 0.0f, 0.3189f, 1.0f, 1.0f,
- 0.2227f, 0.0f, 0.3001f, 1.0f, 1.0f,
- 0.2087f, 0.0f, 0.279f, 1.0f, 1.0f,
- 0.1972f, 0.0f, 0.256f, 1.0f, 1.0f,
- 0.1884f, 0.0f, 0.2314f, 1.0f, 1.0f,
- 0.1824f, 0.0f, 0.2057f, 1.0f, 1.0f,
- 0.1794f, 0.0f, 0.1794f, 1.0f, 1.0f,
- 0.1794f, 0.0f, 0.1528f, 1.0f, 1.0f,
- 0.1824f, 0.0f, 0.1264f, 1.0f, 1.0f,
- 0.1884f, 0.0f, 0.1007f, 1.0f, 1.0f,
- 0.1972f, 0.0f, 0.0762f, 1.0f, 1.0f,
- 0.2087f, 0.0f, 0.0531f, 1.0f, 1.0f,
- 0.2227f, 0.0f, 0.032f, 1.0f, 1.0f,
- 0.239f, 0.0f, 0.0132f, 1.0f, 1.0f,
- 0.2573f, 0.0f, -0.0029f, 1.0f, 1.0f,
- 0.2772f, 0.0f, -0.0162f, 1.0f, 1.0f,
- 0.2985f, 0.0f, -0.0264f, 1.0f, 1.0f,
- 0.3207f, 0.0f, -0.0333f, 1.0f, 1.0f,
- 0.3435f, 0.0f, -0.0368f, 1.0f, 1.0f,
- 0.3666f, 0.0f, -0.0368f, 1.0f, 1.0f,
- 0.3894f, 0.0f, -0.0333f, 1.0f, 1.0f,
- 0.4117f, 0.0f, -0.0264f, 1.0f, 1.0f,
- 0.4329f, 0.0f, -0.0162f, 1.0f, 1.0f,
- 0.4529f, 0.0f, -0.0029f, 1.0f, 1.0f,
- 0.4711f, 0.0f, 0.0132f, 1.0f, 1.0f,
- 0.4874f, 0.0f, 0.032f, 1.0f, 1.0f,
- 0.5014f, 0.0f, 0.0531f, 1.0f, 1.0f,
- 0.513f, 0.0f, 0.0762f, 1.0f, 1.0f,
- 0.5218f, 0.0f, 0.1007f, 1.0f, 1.0f,
- 0.5277f, 0.0f, 0.1264f, 1.0f, 1.0f,
- 0.5307f, 0.0f, 0.1528f, 1.0f, 1.0f,
+ 0.5311f, 0.0f, 0.1661f, 1.0f, 1.0f, 0.5307f, 0.0f, 0.1794f, 1.0f, 1.0f,
+ 0.5277f, 0.0f, 0.2057f, 1.0f, 1.0f, 0.5218f, 0.0f, 0.2314f, 1.0f, 1.0f,
+ 0.513f, 0.0f, 0.256f, 1.0f, 1.0f, 0.5014f, 0.0f, 0.279f, 1.0f, 1.0f,
+ 0.4874f, 0.0f, 0.3001f, 1.0f, 1.0f, 0.4711f, 0.0f, 0.3189f, 1.0f, 1.0f,
+ 0.4529f, 0.0f, 0.3351f, 1.0f, 1.0f, 0.4329f, 0.0f, 0.3483f, 1.0f, 1.0f,
+ 0.4117f, 0.0f, 0.3585f, 1.0f, 1.0f, 0.3894f, 0.0f, 0.3654f, 1.0f, 1.0f,
+ 0.3666f, 0.0f, 0.3689f, 1.0f, 1.0f, 0.3435f, 0.0f, 0.3689f, 1.0f, 1.0f,
+ 0.3207f, 0.0f, 0.3654f, 1.0f, 1.0f, 0.2985f, 0.0f, 0.3585f, 1.0f, 1.0f,
+ 0.2772f, 0.0f, 0.3483f, 1.0f, 1.0f, 0.2573f, 0.0f, 0.3351f, 1.0f, 1.0f,
+ 0.239f, 0.0f, 0.3189f, 1.0f, 1.0f, 0.2227f, 0.0f, 0.3001f, 1.0f, 1.0f,
+ 0.2087f, 0.0f, 0.279f, 1.0f, 1.0f, 0.1972f, 0.0f, 0.256f, 1.0f, 1.0f,
+ 0.1884f, 0.0f, 0.2314f, 1.0f, 1.0f, 0.1824f, 0.0f, 0.2057f, 1.0f, 1.0f,
+ 0.1794f, 0.0f, 0.1794f, 1.0f, 1.0f, 0.1794f, 0.0f, 0.1528f, 1.0f, 1.0f,
+ 0.1824f, 0.0f, 0.1264f, 1.0f, 1.0f, 0.1884f, 0.0f, 0.1007f, 1.0f, 1.0f,
+ 0.1972f, 0.0f, 0.0762f, 1.0f, 1.0f, 0.2087f, 0.0f, 0.0531f, 1.0f, 1.0f,
+ 0.2227f, 0.0f, 0.032f, 1.0f, 1.0f, 0.239f, 0.0f, 0.0132f, 1.0f, 1.0f,
+ 0.2573f, 0.0f, -0.0029f, 1.0f, 1.0f, 0.2772f, 0.0f, -0.0162f, 1.0f, 1.0f,
+ 0.2985f, 0.0f, -0.0264f, 1.0f, 1.0f, 0.3207f, 0.0f, -0.0333f, 1.0f, 1.0f,
+ 0.3435f, 0.0f, -0.0368f, 1.0f, 1.0f, 0.3666f, 0.0f, -0.0368f, 1.0f, 1.0f,
+ 0.3894f, 0.0f, -0.0333f, 1.0f, 1.0f, 0.4117f, 0.0f, -0.0264f, 1.0f, 1.0f,
+ 0.4329f, 0.0f, -0.0162f, 1.0f, 1.0f, 0.4529f, 0.0f, -0.0029f, 1.0f, 1.0f,
+ 0.4711f, 0.0f, 0.0132f, 1.0f, 1.0f, 0.4874f, 0.0f, 0.032f, 1.0f, 1.0f,
+ 0.5014f, 0.0f, 0.0531f, 1.0f, 1.0f, 0.513f, 0.0f, 0.0762f, 1.0f, 1.0f,
+ 0.5218f, 0.0f, 0.1007f, 1.0f, 1.0f, 0.5277f, 0.0f, 0.1264f, 1.0f, 1.0f,
+ 0.5307f, 0.0f, 0.1528f, 1.0f, 1.0f,
};
static const float data9[33 * GP_PRIM_DATABUF_SIZE] = {
- -0.5271f, 0.0f, 0.1742f, 0.1f, 1.0f,
- -0.527f, 0.0f, 0.1621f, 0.2199f, 1.0f,
- -0.5253f, 0.0f, 0.1386f, 0.4615f, 1.0f,
- -0.5217f, 0.0f, 0.116f, 0.6019f, 1.0f,
- -0.5164f, 0.0f, 0.0945f, 0.6981f, 1.0f,
- -0.5094f, 0.0f, 0.0741f, 0.7689f, 1.0f,
- -0.5009f, 0.0f, 0.0548f, 0.8236f, 1.0f,
- -0.491f, 0.0f, 0.0368f, 0.866f, 1.0f,
- -0.4799f, 0.0f, 0.02f, 0.9003f, 1.0f,
- -0.4676f, 0.0f, 0.0046f, 0.9272f, 1.0f,
- -0.4544f, 0.0f, -0.0094f, 0.9485f, 1.0f,
- -0.4402f, 0.0f, -0.0219f, 0.9653f, 1.0f,
- -0.4254f, 0.0f, -0.033f, 0.9781f, 1.0f,
- -0.4099f, 0.0f, -0.0424f, 0.9876f, 1.0f,
- -0.394f, 0.0f, -0.0501f, 0.9942f, 1.0f,
- -0.3777f, 0.0f, -0.0562f, 0.9983f, 1.0f,
- -0.3612f, 0.0f, -0.0605f, 0.9997f, 1.0f,
- -0.3447f, 0.0f, -0.0629f, 0.999f, 1.0f,
- -0.3281f, 0.0f, -0.0634f, 0.9963f, 1.0f,
- -0.3118f, 0.0f, -0.062f, 0.9912f, 1.0f,
- -0.2957f, 0.0f, -0.0585f, 0.9834f, 1.0f,
- -0.2801f, 0.0f, -0.0529f, 0.9724f, 1.0f,
- -0.2651f, 0.0f, -0.0452f, 0.9576f, 1.0f,
- -0.2507f, 0.0f, -0.0352f, 0.9385f, 1.0f,
- -0.2372f, 0.0f, -0.023f, 0.9143f, 1.0f,
- -0.2246f, 0.0f, -0.0085f, 0.8841f, 1.0f,
- -0.2131f, 0.0f, 0.0085f, 0.8461f, 1.0f,
- -0.2028f, 0.0f, 0.0279f, 0.7979f, 1.0f,
- -0.1939f, 0.0f, 0.0499f, 0.7359f, 1.0f,
- -0.1864f, 0.0f, 0.0745f, 0.6541f, 1.0f,
- -0.1806f, 0.0f, 0.1017f, 0.5396f, 1.0f,
- -0.1765f, 0.0f, 0.1316f, 0.36f, 1.0f,
- -0.1742f, 0.0f, 0.1643f, 0.1f, 1.0f,
+ -0.5271f, 0.0f, 0.1742f, 0.1f, 1.0f, -0.527f, 0.0f, 0.1621f, 0.2199f, 1.0f,
+ -0.5253f, 0.0f, 0.1386f, 0.4615f, 1.0f, -0.5217f, 0.0f, 0.116f, 0.6019f, 1.0f,
+ -0.5164f, 0.0f, 0.0945f, 0.6981f, 1.0f, -0.5094f, 0.0f, 0.0741f, 0.7689f, 1.0f,
+ -0.5009f, 0.0f, 0.0548f, 0.8236f, 1.0f, -0.491f, 0.0f, 0.0368f, 0.866f, 1.0f,
+ -0.4799f, 0.0f, 0.02f, 0.9003f, 1.0f, -0.4676f, 0.0f, 0.0046f, 0.9272f, 1.0f,
+ -0.4544f, 0.0f, -0.0094f, 0.9485f, 1.0f, -0.4402f, 0.0f, -0.0219f, 0.9653f, 1.0f,
+ -0.4254f, 0.0f, -0.033f, 0.9781f, 1.0f, -0.4099f, 0.0f, -0.0424f, 0.9876f, 1.0f,
+ -0.394f, 0.0f, -0.0501f, 0.9942f, 1.0f, -0.3777f, 0.0f, -0.0562f, 0.9983f, 1.0f,
+ -0.3612f, 0.0f, -0.0605f, 0.9997f, 1.0f, -0.3447f, 0.0f, -0.0629f, 0.999f, 1.0f,
+ -0.3281f, 0.0f, -0.0634f, 0.9963f, 1.0f, -0.3118f, 0.0f, -0.062f, 0.9912f, 1.0f,
+ -0.2957f, 0.0f, -0.0585f, 0.9834f, 1.0f, -0.2801f, 0.0f, -0.0529f, 0.9724f, 1.0f,
+ -0.2651f, 0.0f, -0.0452f, 0.9576f, 1.0f, -0.2507f, 0.0f, -0.0352f, 0.9385f, 1.0f,
+ -0.2372f, 0.0f, -0.023f, 0.9143f, 1.0f, -0.2246f, 0.0f, -0.0085f, 0.8841f, 1.0f,
+ -0.2131f, 0.0f, 0.0085f, 0.8461f, 1.0f, -0.2028f, 0.0f, 0.0279f, 0.7979f, 1.0f,
+ -0.1939f, 0.0f, 0.0499f, 0.7359f, 1.0f, -0.1864f, 0.0f, 0.0745f, 0.6541f, 1.0f,
+ -0.1806f, 0.0f, 0.1017f, 0.5396f, 1.0f, -0.1765f, 0.0f, 0.1316f, 0.36f, 1.0f,
+ -0.1742f, 0.0f, 0.1643f, 0.1f, 1.0f,
};
static const float data10[49 * GP_PRIM_DATABUF_SIZE] = {
- -0.174f, 0.0f, 0.1661f, 1.0f, 1.0f,
- -0.1744f, 0.0f, 0.1794f, 1.0f, 1.0f,
- -0.1774f, 0.0f, 0.2057f, 1.0f, 1.0f,
- -0.1833f, 0.0f, 0.2314f, 1.0f, 1.0f,
- -0.1922f, 0.0f, 0.256f, 1.0f, 1.0f,
- -0.2037f, 0.0f, 0.279f, 1.0f, 1.0f,
- -0.2177f, 0.0f, 0.3001f, 1.0f, 1.0f,
- -0.234f, 0.0f, 0.3189f, 1.0f, 1.0f,
- -0.2522f, 0.0f, 0.3351f, 1.0f, 1.0f,
- -0.2722f, 0.0f, 0.3483f, 1.0f, 1.0f,
- -0.2935f, 0.0f, 0.3585f, 1.0f, 1.0f,
- -0.3157f, 0.0f, 0.3654f, 1.0f, 1.0f,
- -0.3385f, 0.0f, 0.3689f, 1.0f, 1.0f,
- -0.3616f, 0.0f, 0.3689f, 1.0f, 1.0f,
- -0.3844f, 0.0f, 0.3654f, 1.0f, 1.0f,
- -0.4066f, 0.0f, 0.3585f, 1.0f, 1.0f,
- -0.4279f, 0.0f, 0.3483f, 1.0f, 1.0f,
- -0.4479f, 0.0f, 0.3351f, 1.0f, 1.0f,
- -0.4661f, 0.0f, 0.3189f, 1.0f, 1.0f,
- -0.4824f, 0.0f, 0.3001f, 1.0f, 1.0f,
- -0.4964f, 0.0f, 0.279f, 1.0f, 1.0f,
- -0.508f, 0.0f, 0.256f, 1.0f, 1.0f,
- -0.5168f, 0.0f, 0.2314f, 1.0f, 1.0f,
- -0.5227f, 0.0f, 0.2057f, 1.0f, 1.0f,
- -0.5257f, 0.0f, 0.1794f, 1.0f, 1.0f,
- -0.5257f, 0.0f, 0.1528f, 1.0f, 1.0f,
- -0.5227f, 0.0f, 0.1264f, 1.0f, 1.0f,
- -0.5168f, 0.0f, 0.1007f, 1.0f, 1.0f,
- -0.508f, 0.0f, 0.0762f, 1.0f, 1.0f,
- -0.4964f, 0.0f, 0.0531f, 1.0f, 1.0f,
- -0.4824f, 0.0f, 0.032f, 1.0f, 1.0f,
- -0.4661f, 0.0f, 0.0132f, 1.0f, 1.0f,
- -0.4479f, 0.0f, -0.0029f, 1.0f, 1.0f,
- -0.4279f, 0.0f, -0.0162f, 1.0f, 1.0f,
- -0.4066f, 0.0f, -0.0264f, 1.0f, 1.0f,
- -0.3844f, 0.0f, -0.0333f, 1.0f, 1.0f,
- -0.3616f, 0.0f, -0.0368f, 1.0f, 1.0f,
- -0.3385f, 0.0f, -0.0368f, 1.0f, 1.0f,
- -0.3157f, 0.0f, -0.0333f, 1.0f, 1.0f,
- -0.2935f, 0.0f, -0.0264f, 1.0f, 1.0f,
- -0.2722f, 0.0f, -0.0162f, 1.0f, 1.0f,
- -0.2522f, 0.0f, -0.0029f, 1.0f, 1.0f,
- -0.234f, 0.0f, 0.0132f, 1.0f, 1.0f,
- -0.2177f, 0.0f, 0.032f, 1.0f, 1.0f,
- -0.2037f, 0.0f, 0.0531f, 1.0f, 1.0f,
- -0.1922f, 0.0f, 0.0762f, 1.0f, 1.0f,
- -0.1833f, 0.0f, 0.1007f, 1.0f, 1.0f,
- -0.1774f, 0.0f, 0.1264f, 1.0f, 1.0f,
- -0.1744f, 0.0f, 0.1528f, 1.0f, 1.0f,
+ -0.174f, 0.0f, 0.1661f, 1.0f, 1.0f, -0.1744f, 0.0f, 0.1794f, 1.0f, 1.0f,
+ -0.1774f, 0.0f, 0.2057f, 1.0f, 1.0f, -0.1833f, 0.0f, 0.2314f, 1.0f, 1.0f,
+ -0.1922f, 0.0f, 0.256f, 1.0f, 1.0f, -0.2037f, 0.0f, 0.279f, 1.0f, 1.0f,
+ -0.2177f, 0.0f, 0.3001f, 1.0f, 1.0f, -0.234f, 0.0f, 0.3189f, 1.0f, 1.0f,
+ -0.2522f, 0.0f, 0.3351f, 1.0f, 1.0f, -0.2722f, 0.0f, 0.3483f, 1.0f, 1.0f,
+ -0.2935f, 0.0f, 0.3585f, 1.0f, 1.0f, -0.3157f, 0.0f, 0.3654f, 1.0f, 1.0f,
+ -0.3385f, 0.0f, 0.3689f, 1.0f, 1.0f, -0.3616f, 0.0f, 0.3689f, 1.0f, 1.0f,
+ -0.3844f, 0.0f, 0.3654f, 1.0f, 1.0f, -0.4066f, 0.0f, 0.3585f, 1.0f, 1.0f,
+ -0.4279f, 0.0f, 0.3483f, 1.0f, 1.0f, -0.4479f, 0.0f, 0.3351f, 1.0f, 1.0f,
+ -0.4661f, 0.0f, 0.3189f, 1.0f, 1.0f, -0.4824f, 0.0f, 0.3001f, 1.0f, 1.0f,
+ -0.4964f, 0.0f, 0.279f, 1.0f, 1.0f, -0.508f, 0.0f, 0.256f, 1.0f, 1.0f,
+ -0.5168f, 0.0f, 0.2314f, 1.0f, 1.0f, -0.5227f, 0.0f, 0.2057f, 1.0f, 1.0f,
+ -0.5257f, 0.0f, 0.1794f, 1.0f, 1.0f, -0.5257f, 0.0f, 0.1528f, 1.0f, 1.0f,
+ -0.5227f, 0.0f, 0.1264f, 1.0f, 1.0f, -0.5168f, 0.0f, 0.1007f, 1.0f, 1.0f,
+ -0.508f, 0.0f, 0.0762f, 1.0f, 1.0f, -0.4964f, 0.0f, 0.0531f, 1.0f, 1.0f,
+ -0.4824f, 0.0f, 0.032f, 1.0f, 1.0f, -0.4661f, 0.0f, 0.0132f, 1.0f, 1.0f,
+ -0.4479f, 0.0f, -0.0029f, 1.0f, 1.0f, -0.4279f, 0.0f, -0.0162f, 1.0f, 1.0f,
+ -0.4066f, 0.0f, -0.0264f, 1.0f, 1.0f, -0.3844f, 0.0f, -0.0333f, 1.0f, 1.0f,
+ -0.3616f, 0.0f, -0.0368f, 1.0f, 1.0f, -0.3385f, 0.0f, -0.0368f, 1.0f, 1.0f,
+ -0.3157f, 0.0f, -0.0333f, 1.0f, 1.0f, -0.2935f, 0.0f, -0.0264f, 1.0f, 1.0f,
+ -0.2722f, 0.0f, -0.0162f, 1.0f, 1.0f, -0.2522f, 0.0f, -0.0029f, 1.0f, 1.0f,
+ -0.234f, 0.0f, 0.0132f, 1.0f, 1.0f, -0.2177f, 0.0f, 0.032f, 1.0f, 1.0f,
+ -0.2037f, 0.0f, 0.0531f, 1.0f, 1.0f, -0.1922f, 0.0f, 0.0762f, 1.0f, 1.0f,
+ -0.1833f, 0.0f, 0.1007f, 1.0f, 1.0f, -0.1774f, 0.0f, 0.1264f, 1.0f, 1.0f,
+ -0.1744f, 0.0f, 0.1528f, 1.0f, 1.0f,
};
static const float data11[18 * GP_PRIM_DATABUF_SIZE] = {
- 0.963f, 0.0f, 0.1753f, 0.1f, 1.0f,
- 0.9555f, 0.0f, 0.1761f, 0.2199f, 1.0f,
- 0.9367f, 0.0f, 0.1758f, 0.6019f, 1.0f,
- 0.9202f, 0.0f, 0.1741f, 0.7689f, 1.0f,
- 0.9036f, 0.0f, 0.1714f, 0.866f, 1.0f,
- 0.8885f, 0.0f, 0.1668f, 0.9272f, 1.0f,
- 0.8746f, 0.0f, 0.1607f, 0.9653f, 1.0f,
- 0.8621f, 0.0f, 0.1531f, 0.9876f, 1.0f,
- 0.8503f, 0.0f, 0.1447f, 0.9983f, 1.0f,
- 0.8389f, 0.0f, 0.1352f, 0.999f, 1.0f,
- 0.8279f, 0.0f, 0.1244f, 0.9912f, 1.0f,
- 0.8174f, 0.0f, 0.1125f, 0.9724f, 1.0f,
- 0.8079f, 0.0f, 0.099f, 0.9385f, 1.0f,
- 0.7999f, 0.0f, 0.0839f, 0.8841f, 1.0f,
- 0.7935f, 0.0f, 0.0669f, 0.7979f, 1.0f,
- 0.7892f, 0.0f, 0.0488f, 0.6541f, 1.0f,
- 0.787f, 0.0f, 0.0305f, 0.36f, 1.0f,
- 0.7847f, 0.0f, 0.0139f, 0.1f, 1.0f,
+ 0.963f, 0.0f, 0.1753f, 0.1f, 1.0f, 0.9555f, 0.0f, 0.1761f, 0.2199f, 1.0f,
+ 0.9367f, 0.0f, 0.1758f, 0.6019f, 1.0f, 0.9202f, 0.0f, 0.1741f, 0.7689f, 1.0f,
+ 0.9036f, 0.0f, 0.1714f, 0.866f, 1.0f, 0.8885f, 0.0f, 0.1668f, 0.9272f, 1.0f,
+ 0.8746f, 0.0f, 0.1607f, 0.9653f, 1.0f, 0.8621f, 0.0f, 0.1531f, 0.9876f, 1.0f,
+ 0.8503f, 0.0f, 0.1447f, 0.9983f, 1.0f, 0.8389f, 0.0f, 0.1352f, 0.999f, 1.0f,
+ 0.8279f, 0.0f, 0.1244f, 0.9912f, 1.0f, 0.8174f, 0.0f, 0.1125f, 0.9724f, 1.0f,
+ 0.8079f, 0.0f, 0.099f, 0.9385f, 1.0f, 0.7999f, 0.0f, 0.0839f, 0.8841f, 1.0f,
+ 0.7935f, 0.0f, 0.0669f, 0.7979f, 1.0f, 0.7892f, 0.0f, 0.0488f, 0.6541f, 1.0f,
+ 0.787f, 0.0f, 0.0305f, 0.36f, 1.0f, 0.7847f, 0.0f, 0.0139f, 0.1f, 1.0f,
};
static const float data12[18 * GP_PRIM_DATABUF_SIZE] = {
- -1.0227f, 0.0f, 0.1753f, 0.1f, 1.0f,
- -1.0153f, 0.0f, 0.1761f, 0.2199f, 1.0f,
- -0.9964f, 0.0f, 0.1758f, 0.6019f, 1.0f,
- -0.9799f, 0.0f, 0.1741f, 0.7689f, 1.0f,
- -0.9634f, 0.0f, 0.1714f, 0.866f, 1.0f,
- -0.9483f, 0.0f, 0.1668f, 0.9272f, 1.0f,
- -0.9344f, 0.0f, 0.1607f, 0.9653f, 1.0f,
- -0.9219f, 0.0f, 0.1531f, 0.9876f, 1.0f,
- -0.9101f, 0.0f, 0.1447f, 0.9983f, 1.0f,
- -0.8986f, 0.0f, 0.1352f, 0.999f, 1.0f,
- -0.8876f, 0.0f, 0.1244f, 0.9912f, 1.0f,
- -0.8772f, 0.0f, 0.1125f, 0.9724f, 1.0f,
- -0.8677f, 0.0f, 0.099f, 0.9385f, 1.0f,
- -0.8597f, 0.0f, 0.0839f, 0.8841f, 1.0f,
- -0.8533f, 0.0f, 0.0669f, 0.7979f, 1.0f,
- -0.849f, 0.0f, 0.0488f, 0.6541f, 1.0f,
- -0.8467f, 0.0f, 0.0305f, 0.36f, 1.0f,
- -0.8444f, 0.0f, 0.0139f, 0.1f, 1.0f,
+ -1.0227f, 0.0f, 0.1753f, 0.1f, 1.0f, -1.0153f, 0.0f, 0.1761f, 0.2199f, 1.0f,
+ -0.9964f, 0.0f, 0.1758f, 0.6019f, 1.0f, -0.9799f, 0.0f, 0.1741f, 0.7689f, 1.0f,
+ -0.9634f, 0.0f, 0.1714f, 0.866f, 1.0f, -0.9483f, 0.0f, 0.1668f, 0.9272f, 1.0f,
+ -0.9344f, 0.0f, 0.1607f, 0.9653f, 1.0f, -0.9219f, 0.0f, 0.1531f, 0.9876f, 1.0f,
+ -0.9101f, 0.0f, 0.1447f, 0.9983f, 1.0f, -0.8986f, 0.0f, 0.1352f, 0.999f, 1.0f,
+ -0.8876f, 0.0f, 0.1244f, 0.9912f, 1.0f, -0.8772f, 0.0f, 0.1125f, 0.9724f, 1.0f,
+ -0.8677f, 0.0f, 0.099f, 0.9385f, 1.0f, -0.8597f, 0.0f, 0.0839f, 0.8841f, 1.0f,
+ -0.8533f, 0.0f, 0.0669f, 0.7979f, 1.0f, -0.849f, 0.0f, 0.0488f, 0.6541f, 1.0f,
+ -0.8467f, 0.0f, 0.0305f, 0.36f, 1.0f, -0.8444f, 0.0f, 0.0139f, 0.1f, 1.0f,
};
static const float data13[33 * GP_PRIM_DATABUF_SIZE] = {
- -0.6794f, 0.0f, 0.3908f, 0.1f, 1.0f,
- -0.6711f, 0.0f, 0.4112f, 0.2199f, 1.0f,
- -0.6513f, 0.0f, 0.4509f, 0.4615f, 1.0f,
- -0.6276f, 0.0f, 0.489f, 0.6019f, 1.0f,
- -0.6001f, 0.0f, 0.5253f, 0.6981f, 1.0f,
- -0.5692f, 0.0f, 0.5598f, 0.7689f, 1.0f,
- -0.535f, 0.0f, 0.5924f, 0.8236f, 1.0f,
- -0.4979f, 0.0f, 0.6228f, 0.866f, 1.0f,
- -0.4579f, 0.0f, 0.651f, 0.9003f, 1.0f,
- -0.4155f, 0.0f, 0.677f, 0.9272f, 1.0f,
- -0.3707f, 0.0f, 0.7005f, 0.9485f, 1.0f,
- -0.3239f, 0.0f, 0.7215f, 0.9653f, 1.0f,
- -0.2753f, 0.0f, 0.7399f, 0.9781f, 1.0f,
- -0.2251f, 0.0f, 0.7555f, 0.9876f, 1.0f,
- -0.1736f, 0.0f, 0.7683f, 0.9942f, 1.0f,
- -0.121f, 0.0f, 0.778f, 0.9983f, 1.0f,
- -0.0675f, 0.0f, 0.7847f, 0.9997f, 1.0f,
- -0.0134f, 0.0f, 0.7882f, 0.999f, 1.0f,
- 0.0411f, 0.0f, 0.7884f, 0.9963f, 1.0f,
- 0.0957f, 0.0f, 0.7851f, 0.9912f, 1.0f,
- 0.1503f, 0.0f, 0.7783f, 0.9834f, 1.0f,
- 0.2045f, 0.0f, 0.7678f, 0.9724f, 1.0f,
- 0.2581f, 0.0f, 0.7536f, 0.9576f, 1.0f,
- 0.311f, 0.0f, 0.7355f, 0.9385f, 1.0f,
- 0.3628f, 0.0f, 0.7134f, 0.9143f, 1.0f,
- 0.4133f, 0.0f, 0.6873f, 0.8841f, 1.0f,
- 0.4622f, 0.0f, 0.6569f, 0.8461f, 1.0f,
- 0.5095f, 0.0f, 0.6221f, 0.7979f, 1.0f,
- 0.5547f, 0.0f, 0.583f, 0.7359f, 1.0f,
- 0.5977f, 0.0f, 0.5393f, 0.6541f, 1.0f,
- 0.6382f, 0.0f, 0.4909f, 0.5396f, 1.0f,
- 0.676f, 0.0f, 0.4377f, 0.36f, 1.0f,
- 0.7109f, 0.0f, 0.3797f, 0.1f, 1.0f,
+ -0.6794f, 0.0f, 0.3908f, 0.1f, 1.0f, -0.6711f, 0.0f, 0.4112f, 0.2199f, 1.0f,
+ -0.6513f, 0.0f, 0.4509f, 0.4615f, 1.0f, -0.6276f, 0.0f, 0.489f, 0.6019f, 1.0f,
+ -0.6001f, 0.0f, 0.5253f, 0.6981f, 1.0f, -0.5692f, 0.0f, 0.5598f, 0.7689f, 1.0f,
+ -0.535f, 0.0f, 0.5924f, 0.8236f, 1.0f, -0.4979f, 0.0f, 0.6228f, 0.866f, 1.0f,
+ -0.4579f, 0.0f, 0.651f, 0.9003f, 1.0f, -0.4155f, 0.0f, 0.677f, 0.9272f, 1.0f,
+ -0.3707f, 0.0f, 0.7005f, 0.9485f, 1.0f, -0.3239f, 0.0f, 0.7215f, 0.9653f, 1.0f,
+ -0.2753f, 0.0f, 0.7399f, 0.9781f, 1.0f, -0.2251f, 0.0f, 0.7555f, 0.9876f, 1.0f,
+ -0.1736f, 0.0f, 0.7683f, 0.9942f, 1.0f, -0.121f, 0.0f, 0.778f, 0.9983f, 1.0f,
+ -0.0675f, 0.0f, 0.7847f, 0.9997f, 1.0f, -0.0134f, 0.0f, 0.7882f, 0.999f, 1.0f,
+ 0.0411f, 0.0f, 0.7884f, 0.9963f, 1.0f, 0.0957f, 0.0f, 0.7851f, 0.9912f, 1.0f,
+ 0.1503f, 0.0f, 0.7783f, 0.9834f, 1.0f, 0.2045f, 0.0f, 0.7678f, 0.9724f, 1.0f,
+ 0.2581f, 0.0f, 0.7536f, 0.9576f, 1.0f, 0.311f, 0.0f, 0.7355f, 0.9385f, 1.0f,
+ 0.3628f, 0.0f, 0.7134f, 0.9143f, 1.0f, 0.4133f, 0.0f, 0.6873f, 0.8841f, 1.0f,
+ 0.4622f, 0.0f, 0.6569f, 0.8461f, 1.0f, 0.5095f, 0.0f, 0.6221f, 0.7979f, 1.0f,
+ 0.5547f, 0.0f, 0.583f, 0.7359f, 1.0f, 0.5977f, 0.0f, 0.5393f, 0.6541f, 1.0f,
+ 0.6382f, 0.0f, 0.4909f, 0.5396f, 1.0f, 0.676f, 0.0f, 0.4377f, 0.36f, 1.0f,
+ 0.7109f, 0.0f, 0.3797f, 0.1f, 1.0f,
};
static const float data14[33 * GP_PRIM_DATABUF_SIZE] = {
- -0.7544f, 0.0f, 0.1799f, 0.1f, 1.0f,
- -0.7495f, 0.0f, 0.162f, 0.2199f, 1.0f,
- -0.7392f, 0.0f, 0.1283f, 0.4615f, 1.0f,
- -0.7281f, 0.0f, 0.0975f, 0.6019f, 1.0f,
- -0.7161f, 0.0f, 0.0693f, 0.6981f, 1.0f,
- -0.7033f, 0.0f, 0.0435f, 0.7689f, 1.0f,
- -0.6898f, 0.0f, 0.02f, 0.8236f, 1.0f,
- -0.6757f, 0.0f, -0.0014f, 0.866f, 1.0f,
- -0.6609f, 0.0f, -0.0208f, 0.9003f, 1.0f,
- -0.6455f, 0.0f, -0.0386f, 0.9272f, 1.0f,
- -0.6297f, 0.0f, -0.0547f, 0.9485f, 1.0f,
- -0.6133f, 0.0f, -0.0695f, 0.9653f, 1.0f,
- -0.5966f, 0.0f, -0.083f, 0.9781f, 1.0f,
- -0.5795f, 0.0f, -0.0955f, 0.9876f, 1.0f,
- -0.5621f, 0.0f, -0.1071f, 0.9942f, 1.0f,
- -0.5444f, 0.0f, -0.118f, 0.9983f, 1.0f,
- -0.5265f, 0.0f, -0.1284f, 0.9997f, 1.0f,
- -0.5084f, 0.0f, -0.1384f, 0.999f, 1.0f,
- -0.4902f, 0.0f, -0.1483f, 0.9963f, 1.0f,
- -0.4719f, 0.0f, -0.1582f, 0.9912f, 1.0f,
- -0.4537f, 0.0f, -0.1682f, 0.9834f, 1.0f,
- -0.4355f, 0.0f, -0.1787f, 0.9724f, 1.0f,
- -0.4173f, 0.0f, -0.1896f, 0.9576f, 1.0f,
- -0.3993f, 0.0f, -0.2013f, 0.9385f, 1.0f,
- -0.3815f, 0.0f, -0.2138f, 0.9143f, 1.0f,
- -0.364f, 0.0f, -0.2274f, 0.8841f, 1.0f,
- -0.3467f, 0.0f, -0.2422f, 0.8461f, 1.0f,
- -0.3298f, 0.0f, -0.2584f, 0.7979f, 1.0f,
- -0.3133f, 0.0f, -0.2762f, 0.7359f, 1.0f,
- -0.2972f, 0.0f, -0.2958f, 0.6541f, 1.0f,
- -0.2816f, 0.0f, -0.3173f, 0.5396f, 1.0f,
- -0.2665f, 0.0f, -0.3409f, 0.36f, 1.0f,
- -0.2521f, 0.0f, -0.3668f, 0.1f, 1.0f,
+ -0.7544f, 0.0f, 0.1799f, 0.1f, 1.0f, -0.7495f, 0.0f, 0.162f, 0.2199f, 1.0f,
+ -0.7392f, 0.0f, 0.1283f, 0.4615f, 1.0f, -0.7281f, 0.0f, 0.0975f, 0.6019f, 1.0f,
+ -0.7161f, 0.0f, 0.0693f, 0.6981f, 1.0f, -0.7033f, 0.0f, 0.0435f, 0.7689f, 1.0f,
+ -0.6898f, 0.0f, 0.02f, 0.8236f, 1.0f, -0.6757f, 0.0f, -0.0014f, 0.866f, 1.0f,
+ -0.6609f, 0.0f, -0.0208f, 0.9003f, 1.0f, -0.6455f, 0.0f, -0.0386f, 0.9272f, 1.0f,
+ -0.6297f, 0.0f, -0.0547f, 0.9485f, 1.0f, -0.6133f, 0.0f, -0.0695f, 0.9653f, 1.0f,
+ -0.5966f, 0.0f, -0.083f, 0.9781f, 1.0f, -0.5795f, 0.0f, -0.0955f, 0.9876f, 1.0f,
+ -0.5621f, 0.0f, -0.1071f, 0.9942f, 1.0f, -0.5444f, 0.0f, -0.118f, 0.9983f, 1.0f,
+ -0.5265f, 0.0f, -0.1284f, 0.9997f, 1.0f, -0.5084f, 0.0f, -0.1384f, 0.999f, 1.0f,
+ -0.4902f, 0.0f, -0.1483f, 0.9963f, 1.0f, -0.4719f, 0.0f, -0.1582f, 0.9912f, 1.0f,
+ -0.4537f, 0.0f, -0.1682f, 0.9834f, 1.0f, -0.4355f, 0.0f, -0.1787f, 0.9724f, 1.0f,
+ -0.4173f, 0.0f, -0.1896f, 0.9576f, 1.0f, -0.3993f, 0.0f, -0.2013f, 0.9385f, 1.0f,
+ -0.3815f, 0.0f, -0.2138f, 0.9143f, 1.0f, -0.364f, 0.0f, -0.2274f, 0.8841f, 1.0f,
+ -0.3467f, 0.0f, -0.2422f, 0.8461f, 1.0f, -0.3298f, 0.0f, -0.2584f, 0.7979f, 1.0f,
+ -0.3133f, 0.0f, -0.2762f, 0.7359f, 1.0f, -0.2972f, 0.0f, -0.2958f, 0.6541f, 1.0f,
+ -0.2816f, 0.0f, -0.3173f, 0.5396f, 1.0f, -0.2665f, 0.0f, -0.3409f, 0.36f, 1.0f,
+ -0.2521f, 0.0f, -0.3668f, 0.1f, 1.0f,
};
static const float data15[65 * GP_PRIM_DATABUF_SIZE] = {
- -0.2854f, 0.0f, -0.4528f, 0.1f, 1.0f,
- -0.2866f, 0.0f, -0.4623f, 0.1288f, 1.0f,
- -0.2899f, 0.0f, -0.4814f, 0.2962f, 1.0f,
- -0.2943f, 0.0f, -0.5008f, 0.4147f, 1.0f,
- -0.2995f, 0.0f, -0.5203f, 0.5028f, 1.0f,
- -0.3054f, 0.0f, -0.54f, 0.5723f, 1.0f,
- -0.3117f, 0.0f, -0.5598f, 0.6291f, 1.0f,
- -0.3182f, 0.0f, -0.5797f, 0.6768f, 1.0f,
- -0.3249f, 0.0f, -0.5996f, 0.7177f, 1.0f,
- -0.3314f, 0.0f, -0.6196f, 0.753f, 1.0f,
- -0.3376f, 0.0f, -0.6395f, 0.7838f, 1.0f,
- -0.3432f, 0.0f, -0.6594f, 0.8109f, 1.0f,
- -0.3482f, 0.0f, -0.6792f, 0.8349f, 1.0f,
- -0.3523f, 0.0f, -0.6989f, 0.8564f, 1.0f,
- -0.3552f, 0.0f, -0.7185f, 0.8756f, 1.0f,
- -0.3569f, 0.0f, -0.7379f, 0.8922f, 1.0f,
- -0.357f, 0.0f, -0.7571f, 0.9074f, 1.0f,
- -0.3555f, 0.0f, -0.7761f, 0.9211f, 1.0f,
- -0.3522f, 0.0f, -0.7948f, 0.9329f, 1.0f,
- -0.3467f, 0.0f, -0.8132f, 0.944f, 1.0f,
- -0.339f, 0.0f, -0.8313f, 0.9531f, 1.0f,
- -0.3289f, 0.0f, -0.849f, 0.9617f, 1.0f,
- -0.316f, 0.0f, -0.8663f, 0.9688f, 1.0f,
- -0.3004f, 0.0f, -0.8831f, 0.9755f, 1.0f,
- -0.2817f, 0.0f, -0.8996f, 0.9808f, 1.0f,
- -0.2598f, 0.0f, -0.9155f, 0.9858f, 1.0f,
- -0.2344f, 0.0f, -0.9309f, 0.9894f, 1.0f,
- -0.2051f, 0.0f, -0.9457f, 0.993f, 1.0f,
- -0.1716f, 0.0f, -0.9599f, 0.9952f, 1.0f,
- -0.1341f, 0.0f, -0.9733f, 0.9973f, 1.0f,
- -0.0928f, 0.0f, -0.9857f, 0.9987f, 1.0f,
- -0.05f, 0.0f, -0.9962f, 0.9993f, 1.0f,
- -0.0087f, 0.0f, -1.0041f, 1.0f, 1.0f,
- 0.0287f, 0.0f, -1.0087f, 0.9993f, 1.0f,
- 0.062f, 0.0f, -1.0104f, 0.9987f, 1.0f,
- 0.0924f, 0.0f, -1.0102f, 0.9973f, 1.0f,
- 0.1205f, 0.0f, -1.0086f, 0.9952f, 1.0f,
- 0.1465f, 0.0f, -1.0057f, 0.993f, 1.0f,
- 0.1706f, 0.0f, -1.0017f, 0.9894f, 1.0f,
- 0.1928f, 0.0f, -0.9964f, 0.9858f, 1.0f,
- 0.2132f, 0.0f, -0.99f, 0.9808f, 1.0f,
- 0.2318f, 0.0f, -0.9824f, 0.9755f, 1.0f,
- 0.2487f, 0.0f, -0.9738f, 0.9688f, 1.0f,
- 0.2641f, 0.0f, -0.9641f, 0.9617f, 1.0f,
- 0.2778f, 0.0f, -0.9533f, 0.9531f, 1.0f,
- 0.2901f, 0.0f, -0.9415f, 0.944f, 1.0f,
- 0.3009f, 0.0f, -0.9287f, 0.9329f, 1.0f,
- 0.3103f, 0.0f, -0.9148f, 0.9211f, 1.0f,
- 0.3183f, 0.0f, -0.8999f, 0.9074f, 1.0f,
- 0.325f, 0.0f, -0.8841f, 0.8922f, 1.0f,
- 0.3304f, 0.0f, -0.8672f, 0.8756f, 1.0f,
- 0.3345f, 0.0f, -0.8493f, 0.8564f, 1.0f,
- 0.3374f, 0.0f, -0.8305f, 0.8349f, 1.0f,
- 0.3391f, 0.0f, -0.8107f, 0.8109f, 1.0f,
- 0.3397f, 0.0f, -0.7899f, 0.7838f, 1.0f,
- 0.3392f, 0.0f, -0.7682f, 0.753f, 1.0f,
- 0.3377f, 0.0f, -0.7456f, 0.7177f, 1.0f,
- 0.3352f, 0.0f, -0.7221f, 0.6768f, 1.0f,
- 0.3317f, 0.0f, -0.6976f, 0.6291f, 1.0f,
- 0.3273f, 0.0f, -0.6722f, 0.5723f, 1.0f,
- 0.322f, 0.0f, -0.646f, 0.5028f, 1.0f,
- 0.316f, 0.0f, -0.6188f, 0.4147f, 1.0f,
- 0.3091f, 0.0f, -0.5908f, 0.2962f, 1.0f,
- 0.3015f, 0.0f, -0.5619f, 0.1288f, 1.0f,
- 0.2974f, 0.0f, -0.5472f, 0.1f, 1.0f,
+ -0.2854f, 0.0f, -0.4528f, 0.1f, 1.0f, -0.2866f, 0.0f, -0.4623f, 0.1288f, 1.0f,
+ -0.2899f, 0.0f, -0.4814f, 0.2962f, 1.0f, -0.2943f, 0.0f, -0.5008f, 0.4147f, 1.0f,
+ -0.2995f, 0.0f, -0.5203f, 0.5028f, 1.0f, -0.3054f, 0.0f, -0.54f, 0.5723f, 1.0f,
+ -0.3117f, 0.0f, -0.5598f, 0.6291f, 1.0f, -0.3182f, 0.0f, -0.5797f, 0.6768f, 1.0f,
+ -0.3249f, 0.0f, -0.5996f, 0.7177f, 1.0f, -0.3314f, 0.0f, -0.6196f, 0.753f, 1.0f,
+ -0.3376f, 0.0f, -0.6395f, 0.7838f, 1.0f, -0.3432f, 0.0f, -0.6594f, 0.8109f, 1.0f,
+ -0.3482f, 0.0f, -0.6792f, 0.8349f, 1.0f, -0.3523f, 0.0f, -0.6989f, 0.8564f, 1.0f,
+ -0.3552f, 0.0f, -0.7185f, 0.8756f, 1.0f, -0.3569f, 0.0f, -0.7379f, 0.8922f, 1.0f,
+ -0.357f, 0.0f, -0.7571f, 0.9074f, 1.0f, -0.3555f, 0.0f, -0.7761f, 0.9211f, 1.0f,
+ -0.3522f, 0.0f, -0.7948f, 0.9329f, 1.0f, -0.3467f, 0.0f, -0.8132f, 0.944f, 1.0f,
+ -0.339f, 0.0f, -0.8313f, 0.9531f, 1.0f, -0.3289f, 0.0f, -0.849f, 0.9617f, 1.0f,
+ -0.316f, 0.0f, -0.8663f, 0.9688f, 1.0f, -0.3004f, 0.0f, -0.8831f, 0.9755f, 1.0f,
+ -0.2817f, 0.0f, -0.8996f, 0.9808f, 1.0f, -0.2598f, 0.0f, -0.9155f, 0.9858f, 1.0f,
+ -0.2344f, 0.0f, -0.9309f, 0.9894f, 1.0f, -0.2051f, 0.0f, -0.9457f, 0.993f, 1.0f,
+ -0.1716f, 0.0f, -0.9599f, 0.9952f, 1.0f, -0.1341f, 0.0f, -0.9733f, 0.9973f, 1.0f,
+ -0.0928f, 0.0f, -0.9857f, 0.9987f, 1.0f, -0.05f, 0.0f, -0.9962f, 0.9993f, 1.0f,
+ -0.0087f, 0.0f, -1.0041f, 1.0f, 1.0f, 0.0287f, 0.0f, -1.0087f, 0.9993f, 1.0f,
+ 0.062f, 0.0f, -1.0104f, 0.9987f, 1.0f, 0.0924f, 0.0f, -1.0102f, 0.9973f, 1.0f,
+ 0.1205f, 0.0f, -1.0086f, 0.9952f, 1.0f, 0.1465f, 0.0f, -1.0057f, 0.993f, 1.0f,
+ 0.1706f, 0.0f, -1.0017f, 0.9894f, 1.0f, 0.1928f, 0.0f, -0.9964f, 0.9858f, 1.0f,
+ 0.2132f, 0.0f, -0.99f, 0.9808f, 1.0f, 0.2318f, 0.0f, -0.9824f, 0.9755f, 1.0f,
+ 0.2487f, 0.0f, -0.9738f, 0.9688f, 1.0f, 0.2641f, 0.0f, -0.9641f, 0.9617f, 1.0f,
+ 0.2778f, 0.0f, -0.9533f, 0.9531f, 1.0f, 0.2901f, 0.0f, -0.9415f, 0.944f, 1.0f,
+ 0.3009f, 0.0f, -0.9287f, 0.9329f, 1.0f, 0.3103f, 0.0f, -0.9148f, 0.9211f, 1.0f,
+ 0.3183f, 0.0f, -0.8999f, 0.9074f, 1.0f, 0.325f, 0.0f, -0.8841f, 0.8922f, 1.0f,
+ 0.3304f, 0.0f, -0.8672f, 0.8756f, 1.0f, 0.3345f, 0.0f, -0.8493f, 0.8564f, 1.0f,
+ 0.3374f, 0.0f, -0.8305f, 0.8349f, 1.0f, 0.3391f, 0.0f, -0.8107f, 0.8109f, 1.0f,
+ 0.3397f, 0.0f, -0.7899f, 0.7838f, 1.0f, 0.3392f, 0.0f, -0.7682f, 0.753f, 1.0f,
+ 0.3377f, 0.0f, -0.7456f, 0.7177f, 1.0f, 0.3352f, 0.0f, -0.7221f, 0.6768f, 1.0f,
+ 0.3317f, 0.0f, -0.6976f, 0.6291f, 1.0f, 0.3273f, 0.0f, -0.6722f, 0.5723f, 1.0f,
+ 0.322f, 0.0f, -0.646f, 0.5028f, 1.0f, 0.316f, 0.0f, -0.6188f, 0.4147f, 1.0f,
+ 0.3091f, 0.0f, -0.5908f, 0.2962f, 1.0f, 0.3015f, 0.0f, -0.5619f, 0.1288f, 1.0f,
+ 0.2974f, 0.0f, -0.5472f, 0.1f, 1.0f,
};
static const float data16[34 * GP_PRIM_DATABUF_SIZE] = {
- -0.4408f, 0.0f, 0.5073f, 0.1f, 1.0f,
- -0.4312f, 0.0f, 0.5132f, 0.1288f, 1.0f,
- -0.3945f, 0.0f, 0.5319f, 0.4147f, 1.0f,
- -0.3605f, 0.0f, 0.5438f, 0.5723f, 1.0f,
- -0.3288f, 0.0f, 0.5496f, 0.6768f, 1.0f,
- -0.2992f, 0.0f, 0.5501f, 0.753f, 1.0f,
- -0.2712f, 0.0f, 0.546f, 0.8109f, 1.0f,
- -0.2446f, 0.0f, 0.5381f, 0.8564f, 1.0f,
- -0.2191f, 0.0f, 0.5272f, 0.8922f, 1.0f,
- -0.1943f, 0.0f, 0.5139f, 0.9211f, 1.0f,
- -0.1699f, 0.0f, 0.4992f, 0.944f, 1.0f,
- -0.1456f, 0.0f, 0.4837f, 0.9617f, 1.0f,
- -0.1211f, 0.0f, 0.4682f, 0.9755f, 1.0f,
- -0.096f, 0.0f, 0.4535f, 0.9858f, 1.0f,
- -0.07f, 0.0f, 0.4404f, 0.993f, 1.0f,
- -0.0428f, 0.0f, 0.4301f, 0.9973f, 1.0f,
- -0.016f, 0.0f, 0.4235f, 0.9993f, 1.0f,
- 0.0076f, 0.0f, 0.4216f, 0.9993f, 1.0f,
- 0.0283f, 0.0f, 0.4237f, 0.9973f, 1.0f,
- 0.0477f, 0.0f, 0.4291f, 0.993f, 1.0f,
- 0.067f, 0.0f, 0.4369f, 0.9858f, 1.0f,
- 0.0866f, 0.0f, 0.4465f, 0.9755f, 1.0f,
- 0.1068f, 0.0f, 0.4576f, 0.9617f, 1.0f,
- 0.1278f, 0.0f, 0.4695f, 0.944f, 1.0f,
- 0.1498f, 0.0f, 0.4819f, 0.9211f, 1.0f,
- 0.173f, 0.0f, 0.4941f, 0.8922f, 1.0f,
- 0.1977f, 0.0f, 0.5056f, 0.8564f, 1.0f,
- 0.2241f, 0.0f, 0.5159f, 0.8109f, 1.0f,
- 0.2523f, 0.0f, 0.5244f, 0.753f, 1.0f,
- 0.2825f, 0.0f, 0.5307f, 0.6768f, 1.0f,
- 0.315f, 0.0f, 0.5342f, 0.5723f, 1.0f,
- 0.3499f, 0.0f, 0.5345f, 0.4147f, 1.0f,
- 0.3875f, 0.0f, 0.5311f, 0.1288f, 1.0f,
- 0.3973f, 0.0f, 0.5295f, 0.1f, 1.0f,
+ -0.4408f, 0.0f, 0.5073f, 0.1f, 1.0f, -0.4312f, 0.0f, 0.5132f, 0.1288f, 1.0f,
+ -0.3945f, 0.0f, 0.5319f, 0.4147f, 1.0f, -0.3605f, 0.0f, 0.5438f, 0.5723f, 1.0f,
+ -0.3288f, 0.0f, 0.5496f, 0.6768f, 1.0f, -0.2992f, 0.0f, 0.5501f, 0.753f, 1.0f,
+ -0.2712f, 0.0f, 0.546f, 0.8109f, 1.0f, -0.2446f, 0.0f, 0.5381f, 0.8564f, 1.0f,
+ -0.2191f, 0.0f, 0.5272f, 0.8922f, 1.0f, -0.1943f, 0.0f, 0.5139f, 0.9211f, 1.0f,
+ -0.1699f, 0.0f, 0.4992f, 0.944f, 1.0f, -0.1456f, 0.0f, 0.4837f, 0.9617f, 1.0f,
+ -0.1211f, 0.0f, 0.4682f, 0.9755f, 1.0f, -0.096f, 0.0f, 0.4535f, 0.9858f, 1.0f,
+ -0.07f, 0.0f, 0.4404f, 0.993f, 1.0f, -0.0428f, 0.0f, 0.4301f, 0.9973f, 1.0f,
+ -0.016f, 0.0f, 0.4235f, 0.9993f, 1.0f, 0.0076f, 0.0f, 0.4216f, 0.9993f, 1.0f,
+ 0.0283f, 0.0f, 0.4237f, 0.9973f, 1.0f, 0.0477f, 0.0f, 0.4291f, 0.993f, 1.0f,
+ 0.067f, 0.0f, 0.4369f, 0.9858f, 1.0f, 0.0866f, 0.0f, 0.4465f, 0.9755f, 1.0f,
+ 0.1068f, 0.0f, 0.4576f, 0.9617f, 1.0f, 0.1278f, 0.0f, 0.4695f, 0.944f, 1.0f,
+ 0.1498f, 0.0f, 0.4819f, 0.9211f, 1.0f, 0.173f, 0.0f, 0.4941f, 0.8922f, 1.0f,
+ 0.1977f, 0.0f, 0.5056f, 0.8564f, 1.0f, 0.2241f, 0.0f, 0.5159f, 0.8109f, 1.0f,
+ 0.2523f, 0.0f, 0.5244f, 0.753f, 1.0f, 0.2825f, 0.0f, 0.5307f, 0.6768f, 1.0f,
+ 0.315f, 0.0f, 0.5342f, 0.5723f, 1.0f, 0.3499f, 0.0f, 0.5345f, 0.4147f, 1.0f,
+ 0.3875f, 0.0f, 0.5311f, 0.1288f, 1.0f, 0.3973f, 0.0f, 0.5295f, 0.1f, 1.0f,
};
static const float data17[33 * GP_PRIM_DATABUF_SIZE] = {
- 0.724f, 0.0f, 0.1799f, 0.1f, 1.0f,
- 0.7192f, 0.0f, 0.162f, 0.2199f, 1.0f,
- 0.7089f, 0.0f, 0.1283f, 0.4615f, 1.0f,
- 0.6977f, 0.0f, 0.0975f, 0.6019f, 1.0f,
- 0.6858f, 0.0f, 0.0693f, 0.6981f, 1.0f,
- 0.673f, 0.0f, 0.0435f, 0.7689f, 1.0f,
- 0.6595f, 0.0f, 0.02f, 0.8236f, 1.0f,
- 0.6453f, 0.0f, -0.0014f, 0.866f, 1.0f,
- 0.6306f, 0.0f, -0.0208f, 0.9003f, 1.0f,
- 0.6152f, 0.0f, -0.0386f, 0.9272f, 1.0f,
- 0.5994f, 0.0f, -0.0547f, 0.9485f, 1.0f,
- 0.583f, 0.0f, -0.0695f, 0.9653f, 1.0f,
- 0.5663f, 0.0f, -0.083f, 0.9781f, 1.0f,
- 0.5492f, 0.0f, -0.0955f, 0.9876f, 1.0f,
- 0.5317f, 0.0f, -0.1071f, 0.9942f, 1.0f,
- 0.514f, 0.0f, -0.118f, 0.9983f, 1.0f,
- 0.4961f, 0.0f, -0.1284f, 0.9997f, 1.0f,
- 0.4781f, 0.0f, -0.1384f, 0.999f, 1.0f,
- 0.4599f, 0.0f, -0.1483f, 0.9963f, 1.0f,
- 0.4416f, 0.0f, -0.1582f, 0.9912f, 1.0f,
- 0.4234f, 0.0f, -0.1682f, 0.9834f, 1.0f,
- 0.4051f, 0.0f, -0.1787f, 0.9724f, 1.0f,
- 0.387f, 0.0f, -0.1896f, 0.9576f, 1.0f,
- 0.369f, 0.0f, -0.2013f, 0.9385f, 1.0f,
- 0.3512f, 0.0f, -0.2138f, 0.9143f, 1.0f,
- 0.3337f, 0.0f, -0.2274f, 0.8841f, 1.0f,
- 0.3164f, 0.0f, -0.2422f, 0.8461f, 1.0f,
- 0.2995f, 0.0f, -0.2584f, 0.7979f, 1.0f,
- 0.2829f, 0.0f, -0.2762f, 0.7359f, 1.0f,
- 0.2669f, 0.0f, -0.2958f, 0.6541f, 1.0f,
- 0.2513f, 0.0f, -0.3173f, 0.5396f, 1.0f,
- 0.2362f, 0.0f, -0.3409f, 0.36f, 1.0f,
- 0.2218f, 0.0f, -0.3668f, 0.1f, 1.0f,
+ 0.724f, 0.0f, 0.1799f, 0.1f, 1.0f, 0.7192f, 0.0f, 0.162f, 0.2199f, 1.0f,
+ 0.7089f, 0.0f, 0.1283f, 0.4615f, 1.0f, 0.6977f, 0.0f, 0.0975f, 0.6019f, 1.0f,
+ 0.6858f, 0.0f, 0.0693f, 0.6981f, 1.0f, 0.673f, 0.0f, 0.0435f, 0.7689f, 1.0f,
+ 0.6595f, 0.0f, 0.02f, 0.8236f, 1.0f, 0.6453f, 0.0f, -0.0014f, 0.866f, 1.0f,
+ 0.6306f, 0.0f, -0.0208f, 0.9003f, 1.0f, 0.6152f, 0.0f, -0.0386f, 0.9272f, 1.0f,
+ 0.5994f, 0.0f, -0.0547f, 0.9485f, 1.0f, 0.583f, 0.0f, -0.0695f, 0.9653f, 1.0f,
+ 0.5663f, 0.0f, -0.083f, 0.9781f, 1.0f, 0.5492f, 0.0f, -0.0955f, 0.9876f, 1.0f,
+ 0.5317f, 0.0f, -0.1071f, 0.9942f, 1.0f, 0.514f, 0.0f, -0.118f, 0.9983f, 1.0f,
+ 0.4961f, 0.0f, -0.1284f, 0.9997f, 1.0f, 0.4781f, 0.0f, -0.1384f, 0.999f, 1.0f,
+ 0.4599f, 0.0f, -0.1483f, 0.9963f, 1.0f, 0.4416f, 0.0f, -0.1582f, 0.9912f, 1.0f,
+ 0.4234f, 0.0f, -0.1682f, 0.9834f, 1.0f, 0.4051f, 0.0f, -0.1787f, 0.9724f, 1.0f,
+ 0.387f, 0.0f, -0.1896f, 0.9576f, 1.0f, 0.369f, 0.0f, -0.2013f, 0.9385f, 1.0f,
+ 0.3512f, 0.0f, -0.2138f, 0.9143f, 1.0f, 0.3337f, 0.0f, -0.2274f, 0.8841f, 1.0f,
+ 0.3164f, 0.0f, -0.2422f, 0.8461f, 1.0f, 0.2995f, 0.0f, -0.2584f, 0.7979f, 1.0f,
+ 0.2829f, 0.0f, -0.2762f, 0.7359f, 1.0f, 0.2669f, 0.0f, -0.2958f, 0.6541f, 1.0f,
+ 0.2513f, 0.0f, -0.3173f, 0.5396f, 1.0f, 0.2362f, 0.0f, -0.3409f, 0.36f, 1.0f,
+ 0.2218f, 0.0f, -0.3668f, 0.1f, 1.0f,
};
static const float data18[33 * GP_PRIM_DATABUF_SIZE] = {
- -0.1119f, 0.0f, -0.7868f, 0.1f, 1.0f,
- -0.1087f, 0.0f, -0.7905f, 0.2199f, 1.0f,
- -0.1022f, 0.0f, -0.7974f, 0.4615f, 1.0f,
- -0.0955f, 0.0f, -0.8038f, 0.6019f, 1.0f,
- -0.0886f, 0.0f, -0.8097f, 0.6981f, 1.0f,
- -0.0816f, 0.0f, -0.8152f, 0.7689f, 1.0f,
- -0.0744f, 0.0f, -0.8201f, 0.8236f, 1.0f,
- -0.0671f, 0.0f, -0.8246f, 0.866f, 1.0f,
- -0.0597f, 0.0f, -0.8286f, 0.9003f, 1.0f,
- -0.0522f, 0.0f, -0.8321f, 0.9272f, 1.0f,
- -0.0446f, 0.0f, -0.8351f, 0.9485f, 1.0f,
- -0.0369f, 0.0f, -0.8376f, 0.9653f, 1.0f,
- -0.0292f, 0.0f, -0.8397f, 0.9781f, 1.0f,
- -0.0214f, 0.0f, -0.8413f, 0.9876f, 1.0f,
- -0.0136f, 0.0f, -0.8424f, 0.9942f, 1.0f,
- -0.0057f, 0.0f, -0.843f, 0.9983f, 1.0f,
- 0.0022f, 0.0f, -0.8431f, 0.9997f, 1.0f,
- 0.01f, 0.0f, -0.8428f, 0.999f, 1.0f,
- 0.0178f, 0.0f, -0.8419f, 0.9963f, 1.0f,
- 0.0257f, 0.0f, -0.8407f, 0.9912f, 1.0f,
- 0.0334f, 0.0f, -0.8389f, 0.9834f, 1.0f,
- 0.0411f, 0.0f, -0.8366f, 0.9724f, 1.0f,
- 0.0488f, 0.0f, -0.8339f, 0.9576f, 1.0f,
- 0.0564f, 0.0f, -0.8308f, 0.9385f, 1.0f,
- 0.0638f, 0.0f, -0.8271f, 0.9143f, 1.0f,
- 0.0712f, 0.0f, -0.823f, 0.8841f, 1.0f,
- 0.0785f, 0.0f, -0.8184f, 0.8461f, 1.0f,
- 0.0856f, 0.0f, -0.8134f, 0.7979f, 1.0f,
- 0.0925f, 0.0f, -0.8079f, 0.7359f, 1.0f,
- 0.0994f, 0.0f, -0.8019f, 0.6541f, 1.0f,
- 0.106f, 0.0f, -0.7954f, 0.5396f, 1.0f,
- 0.1125f, 0.0f, -0.7885f, 0.36f, 1.0f,
- 0.1187f, 0.0f, -0.7812f, 0.1f, 1.0f,
+ -0.1119f, 0.0f, -0.7868f, 0.1f, 1.0f, -0.1087f, 0.0f, -0.7905f, 0.2199f, 1.0f,
+ -0.1022f, 0.0f, -0.7974f, 0.4615f, 1.0f, -0.0955f, 0.0f, -0.8038f, 0.6019f, 1.0f,
+ -0.0886f, 0.0f, -0.8097f, 0.6981f, 1.0f, -0.0816f, 0.0f, -0.8152f, 0.7689f, 1.0f,
+ -0.0744f, 0.0f, -0.8201f, 0.8236f, 1.0f, -0.0671f, 0.0f, -0.8246f, 0.866f, 1.0f,
+ -0.0597f, 0.0f, -0.8286f, 0.9003f, 1.0f, -0.0522f, 0.0f, -0.8321f, 0.9272f, 1.0f,
+ -0.0446f, 0.0f, -0.8351f, 0.9485f, 1.0f, -0.0369f, 0.0f, -0.8376f, 0.9653f, 1.0f,
+ -0.0292f, 0.0f, -0.8397f, 0.9781f, 1.0f, -0.0214f, 0.0f, -0.8413f, 0.9876f, 1.0f,
+ -0.0136f, 0.0f, -0.8424f, 0.9942f, 1.0f, -0.0057f, 0.0f, -0.843f, 0.9983f, 1.0f,
+ 0.0022f, 0.0f, -0.8431f, 0.9997f, 1.0f, 0.01f, 0.0f, -0.8428f, 0.999f, 1.0f,
+ 0.0178f, 0.0f, -0.8419f, 0.9963f, 1.0f, 0.0257f, 0.0f, -0.8407f, 0.9912f, 1.0f,
+ 0.0334f, 0.0f, -0.8389f, 0.9834f, 1.0f, 0.0411f, 0.0f, -0.8366f, 0.9724f, 1.0f,
+ 0.0488f, 0.0f, -0.8339f, 0.9576f, 1.0f, 0.0564f, 0.0f, -0.8308f, 0.9385f, 1.0f,
+ 0.0638f, 0.0f, -0.8271f, 0.9143f, 1.0f, 0.0712f, 0.0f, -0.823f, 0.8841f, 1.0f,
+ 0.0785f, 0.0f, -0.8184f, 0.8461f, 1.0f, 0.0856f, 0.0f, -0.8134f, 0.7979f, 1.0f,
+ 0.0925f, 0.0f, -0.8079f, 0.7359f, 1.0f, 0.0994f, 0.0f, -0.8019f, 0.6541f, 1.0f,
+ 0.106f, 0.0f, -0.7954f, 0.5396f, 1.0f, 0.1125f, 0.0f, -0.7885f, 0.36f, 1.0f,
+ 0.1187f, 0.0f, -0.7812f, 0.1f, 1.0f,
};
static const float data19[34 * GP_PRIM_DATABUF_SIZE] = {
- -0.1119f, 0.0f, -0.2655f, 0.1f, 1.0f,
- -0.1101f, 0.0f, -0.2605f, 0.1288f, 1.0f,
- -0.1032f, 0.0f, -0.2424f, 0.4147f, 1.0f,
- -0.0965f, 0.0f, -0.2276f, 0.5723f, 1.0f,
- -0.0901f, 0.0f, -0.2158f, 0.6768f, 1.0f,
- -0.0837f, 0.0f, -0.2069f, 0.753f, 1.0f,
- -0.0775f, 0.0f, -0.2006f, 0.8109f, 1.0f,
- -0.0712f, 0.0f, -0.1967f, 0.8564f, 1.0f,
- -0.065f, 0.0f, -0.1949f, 0.8922f, 1.0f,
- -0.0587f, 0.0f, -0.195f, 0.9211f, 1.0f,
- -0.0522f, 0.0f, -0.1968f, 0.944f, 1.0f,
- -0.0455f, 0.0f, -0.2001f, 0.9617f, 1.0f,
- -0.0386f, 0.0f, -0.2046f, 0.9755f, 1.0f,
- -0.0315f, 0.0f, -0.21f, 0.9858f, 1.0f,
- -0.0239f, 0.0f, -0.2163f, 0.993f, 1.0f,
- -0.016f, 0.0f, -0.223f, 0.9973f, 1.0f,
- -0.0075f, 0.0f, -0.2301f, 0.9993f, 1.0f,
- -0.0002f, 0.0f, -0.2342f, 0.9993f, 1.0f,
- 0.0054f, 0.0f, -0.234f, 0.9973f, 1.0f,
- 0.0106f, 0.0f, -0.2324f, 0.993f, 1.0f,
- 0.0155f, 0.0f, -0.2297f, 0.9858f, 1.0f,
- 0.0202f, 0.0f, -0.2261f, 0.9755f, 1.0f,
- 0.0249f, 0.0f, -0.2219f, 0.9617f, 1.0f,
- 0.0296f, 0.0f, -0.2174f, 0.944f, 1.0f,
- 0.0344f, 0.0f, -0.2128f, 0.9211f, 1.0f,
- 0.0394f, 0.0f, -0.2084f, 0.8922f, 1.0f,
- 0.0448f, 0.0f, -0.2044f, 0.8564f, 1.0f,
- 0.0506f, 0.0f, -0.2012f, 0.8109f, 1.0f,
- 0.057f, 0.0f, -0.1988f, 0.753f, 1.0f,
- 0.064f, 0.0f, -0.1977f, 0.6768f, 1.0f,
- 0.0717f, 0.0f, -0.198f, 0.5723f, 1.0f,
- 0.0804f, 0.0f, -0.2001f, 0.4147f, 1.0f,
- 0.0899f, 0.0f, -0.2042f, 0.1288f, 1.0f,
- 0.0925f, 0.0f, -0.2055f, 0.1f, 1.0f,
+ -0.1119f, 0.0f, -0.2655f, 0.1f, 1.0f, -0.1101f, 0.0f, -0.2605f, 0.1288f, 1.0f,
+ -0.1032f, 0.0f, -0.2424f, 0.4147f, 1.0f, -0.0965f, 0.0f, -0.2276f, 0.5723f, 1.0f,
+ -0.0901f, 0.0f, -0.2158f, 0.6768f, 1.0f, -0.0837f, 0.0f, -0.2069f, 0.753f, 1.0f,
+ -0.0775f, 0.0f, -0.2006f, 0.8109f, 1.0f, -0.0712f, 0.0f, -0.1967f, 0.8564f, 1.0f,
+ -0.065f, 0.0f, -0.1949f, 0.8922f, 1.0f, -0.0587f, 0.0f, -0.195f, 0.9211f, 1.0f,
+ -0.0522f, 0.0f, -0.1968f, 0.944f, 1.0f, -0.0455f, 0.0f, -0.2001f, 0.9617f, 1.0f,
+ -0.0386f, 0.0f, -0.2046f, 0.9755f, 1.0f, -0.0315f, 0.0f, -0.21f, 0.9858f, 1.0f,
+ -0.0239f, 0.0f, -0.2163f, 0.993f, 1.0f, -0.016f, 0.0f, -0.223f, 0.9973f, 1.0f,
+ -0.0075f, 0.0f, -0.2301f, 0.9993f, 1.0f, -0.0002f, 0.0f, -0.2342f, 0.9993f, 1.0f,
+ 0.0054f, 0.0f, -0.234f, 0.9973f, 1.0f, 0.0106f, 0.0f, -0.2324f, 0.993f, 1.0f,
+ 0.0155f, 0.0f, -0.2297f, 0.9858f, 1.0f, 0.0202f, 0.0f, -0.2261f, 0.9755f, 1.0f,
+ 0.0249f, 0.0f, -0.2219f, 0.9617f, 1.0f, 0.0296f, 0.0f, -0.2174f, 0.944f, 1.0f,
+ 0.0344f, 0.0f, -0.2128f, 0.9211f, 1.0f, 0.0394f, 0.0f, -0.2084f, 0.8922f, 1.0f,
+ 0.0448f, 0.0f, -0.2044f, 0.8564f, 1.0f, 0.0506f, 0.0f, -0.2012f, 0.8109f, 1.0f,
+ 0.057f, 0.0f, -0.1988f, 0.753f, 1.0f, 0.064f, 0.0f, -0.1977f, 0.6768f, 1.0f,
+ 0.0717f, 0.0f, -0.198f, 0.5723f, 1.0f, 0.0804f, 0.0f, -0.2001f, 0.4147f, 1.0f,
+ 0.0899f, 0.0f, -0.2042f, 0.1288f, 1.0f, 0.0925f, 0.0f, -0.2055f, 0.1f, 1.0f,
};
static const float data20[33 * GP_PRIM_DATABUF_SIZE] = {
- 0.7993f, 0.0f, 0.3242f, 0.1f, 1.0f,
- 0.8169f, 0.0f, 0.3354f, 0.2199f, 1.0f,
- 0.8512f, 0.0f, 0.3542f, 0.4615f, 1.0f,
- 0.884f, 0.0f, 0.3686f, 0.6019f, 1.0f,
- 0.9153f, 0.0f, 0.3787f, 0.6981f, 1.0f,
- 0.945f, 0.0f, 0.3848f, 0.7689f, 1.0f,
- 0.9729f, 0.0f, 0.3871f, 0.8236f, 1.0f,
- 0.9989f, 0.0f, 0.3857f, 0.866f, 1.0f,
- 1.0229f, 0.0f, 0.3811f, 0.9003f, 1.0f,
- 1.0447f, 0.0f, 0.3732f, 0.9272f, 1.0f,
- 1.0643f, 0.0f, 0.3624f, 0.9485f, 1.0f,
- 1.0814f, 0.0f, 0.349f, 0.9653f, 1.0f,
- 1.096f, 0.0f, 0.333f, 0.9781f, 1.0f,
- 1.108f, 0.0f, 0.3147f, 0.9876f, 1.0f,
- 1.1172f, 0.0f, 0.2944f, 0.9942f, 1.0f,
- 1.1235f, 0.0f, 0.2723f, 0.9983f, 1.0f,
- 1.1267f, 0.0f, 0.2485f, 0.9997f, 1.0f,
- 1.1269f, 0.0f, 0.2233f, 0.999f, 1.0f,
- 1.1237f, 0.0f, 0.197f, 0.9963f, 1.0f,
- 1.1172f, 0.0f, 0.1697f, 0.9912f, 1.0f,
- 1.1071f, 0.0f, 0.1417f, 0.9834f, 1.0f,
- 1.0934f, 0.0f, 0.1131f, 0.9724f, 1.0f,
- 1.0759f, 0.0f, 0.0842f, 0.9576f, 1.0f,
- 1.0545f, 0.0f, 0.0553f, 0.9385f, 1.0f,
- 1.0291f, 0.0f, 0.0265f, 0.9143f, 1.0f,
- 0.9995f, 0.0f, -0.0019f, 0.8841f, 1.0f,
- 0.9657f, 0.0f, -0.0298f, 0.8461f, 1.0f,
- 0.9275f, 0.0f, -0.0569f, 0.7979f, 1.0f,
- 0.8847f, 0.0f, -0.0829f, 0.7359f, 1.0f,
- 0.8373f, 0.0f, -0.1077f, 0.6541f, 1.0f,
- 0.7852f, 0.0f, -0.1311f, 0.5396f, 1.0f,
- 0.7281f, 0.0f, -0.1528f, 0.36f, 1.0f,
- 0.6661f, 0.0f, -0.1725f, 0.1f, 1.0f,
+ 0.7993f, 0.0f, 0.3242f, 0.1f, 1.0f, 0.8169f, 0.0f, 0.3354f, 0.2199f, 1.0f,
+ 0.8512f, 0.0f, 0.3542f, 0.4615f, 1.0f, 0.884f, 0.0f, 0.3686f, 0.6019f, 1.0f,
+ 0.9153f, 0.0f, 0.3787f, 0.6981f, 1.0f, 0.945f, 0.0f, 0.3848f, 0.7689f, 1.0f,
+ 0.9729f, 0.0f, 0.3871f, 0.8236f, 1.0f, 0.9989f, 0.0f, 0.3857f, 0.866f, 1.0f,
+ 1.0229f, 0.0f, 0.3811f, 0.9003f, 1.0f, 1.0447f, 0.0f, 0.3732f, 0.9272f, 1.0f,
+ 1.0643f, 0.0f, 0.3624f, 0.9485f, 1.0f, 1.0814f, 0.0f, 0.349f, 0.9653f, 1.0f,
+ 1.096f, 0.0f, 0.333f, 0.9781f, 1.0f, 1.108f, 0.0f, 0.3147f, 0.9876f, 1.0f,
+ 1.1172f, 0.0f, 0.2944f, 0.9942f, 1.0f, 1.1235f, 0.0f, 0.2723f, 0.9983f, 1.0f,
+ 1.1267f, 0.0f, 0.2485f, 0.9997f, 1.0f, 1.1269f, 0.0f, 0.2233f, 0.999f, 1.0f,
+ 1.1237f, 0.0f, 0.197f, 0.9963f, 1.0f, 1.1172f, 0.0f, 0.1697f, 0.9912f, 1.0f,
+ 1.1071f, 0.0f, 0.1417f, 0.9834f, 1.0f, 1.0934f, 0.0f, 0.1131f, 0.9724f, 1.0f,
+ 1.0759f, 0.0f, 0.0842f, 0.9576f, 1.0f, 1.0545f, 0.0f, 0.0553f, 0.9385f, 1.0f,
+ 1.0291f, 0.0f, 0.0265f, 0.9143f, 1.0f, 0.9995f, 0.0f, -0.0019f, 0.8841f, 1.0f,
+ 0.9657f, 0.0f, -0.0298f, 0.8461f, 1.0f, 0.9275f, 0.0f, -0.0569f, 0.7979f, 1.0f,
+ 0.8847f, 0.0f, -0.0829f, 0.7359f, 1.0f, 0.8373f, 0.0f, -0.1077f, 0.6541f, 1.0f,
+ 0.7852f, 0.0f, -0.1311f, 0.5396f, 1.0f, 0.7281f, 0.0f, -0.1528f, 0.36f, 1.0f,
+ 0.6661f, 0.0f, -0.1725f, 0.1f, 1.0f,
};
static const float data21[64 * GP_PRIM_DATABUF_SIZE] = {
- -0.7428f, 0.0f, 0.2977f, 0.1f, 1.0f,
- -0.7608f, 0.0f, 0.3138f, 0.2199f, 1.0f,
- -0.7786f, 0.0f, 0.3284f, 0.36f, 1.0f,
- -0.7962f, 0.0f, 0.3414f, 0.4615f, 1.0f,
- -0.8135f, 0.0f, 0.3531f, 0.5396f, 1.0f,
- -0.8306f, 0.0f, 0.3633f, 0.6019f, 1.0f,
- -0.8473f, 0.0f, 0.3722f, 0.6541f, 1.0f,
- -0.8637f, 0.0f, 0.3798f, 0.6981f, 1.0f,
- -0.8798f, 0.0f, 0.386f, 0.7359f, 1.0f,
- -0.8956f, 0.0f, 0.3911f, 0.7689f, 1.0f,
- -0.9109f, 0.0f, 0.3949f, 0.7979f, 1.0f,
- -0.9259f, 0.0f, 0.3975f, 0.8236f, 1.0f,
- -0.9405f, 0.0f, 0.3989f, 0.8461f, 1.0f,
- -0.9546f, 0.0f, 0.3993f, 0.866f, 1.0f,
- -0.9682f, 0.0f, 0.3986f, 0.8841f, 1.0f,
- -0.9814f, 0.0f, 0.3969f, 0.9003f, 1.0f,
- -0.994f, 0.0f, 0.3941f, 0.9143f, 1.0f,
- -1.0062f, 0.0f, 0.3904f, 0.9272f, 1.0f,
- -1.0178f, 0.0f, 0.3858f, 0.9385f, 1.0f,
- -1.0288f, 0.0f, 0.3803f, 0.9485f, 1.0f,
- -1.0393f, 0.0f, 0.3739f, 0.9576f, 1.0f,
- -1.0492f, 0.0f, 0.3668f, 0.9653f, 1.0f,
- -1.0584f, 0.0f, 0.3588f, 0.9724f, 1.0f,
- -1.067f, 0.0f, 0.3501f, 0.9781f, 1.0f,
- -1.075f, 0.0f, 0.3407f, 0.9834f, 1.0f,
- -1.0822f, 0.0f, 0.3307f, 0.9876f, 1.0f,
- -1.0888f, 0.0f, 0.32f, 0.9912f, 1.0f,
- -1.0946f, 0.0f, 0.3087f, 0.9942f, 1.0f,
- -1.0997f, 0.0f, 0.2969f, 0.9963f, 1.0f,
- -1.104f, 0.0f, 0.2845f, 0.9983f, 1.0f,
- -1.1075f, 0.0f, 0.2717f, 0.999f, 1.0f,
- -1.1103f, 0.0f, 0.2584f, 0.9997f, 1.0f,
- -1.1122f, 0.0f, 0.2447f, 0.9997f, 1.0f,
- -1.1132f, 0.0f, 0.2306f, 0.999f, 1.0f,
- -1.1134f, 0.0f, 0.2162f, 0.9983f, 1.0f,
- -1.1128f, 0.0f, 0.2015f, 0.9963f, 1.0f,
- -1.1112f, 0.0f, 0.1865f, 0.9942f, 1.0f,
- -1.1086f, 0.0f, 0.1713f, 0.9912f, 1.0f,
- -1.1052f, 0.0f, 0.1559f, 0.9876f, 1.0f,
- -1.1007f, 0.0f, 0.1404f, 0.9834f, 1.0f,
- -1.0953f, 0.0f, 0.1247f, 0.9781f, 1.0f,
- -1.0889f, 0.0f, 0.109f, 0.9724f, 1.0f,
- -1.0814f, 0.0f, 0.0932f, 0.9653f, 1.0f,
- -1.0729f, 0.0f, 0.0774f, 0.9576f, 1.0f,
- -1.0633f, 0.0f, 0.0617f, 0.9485f, 1.0f,
- -1.0527f, 0.0f, 0.046f, 0.9385f, 1.0f,
- -1.0409f, 0.0f, 0.0304f, 0.9272f, 1.0f,
- -1.028f, 0.0f, 0.015f, 0.9143f, 1.0f,
- -1.0139f, 0.0f, -0.0003f, 0.9003f, 1.0f,
- -0.9987f, 0.0f, -0.0154f, 0.8841f, 1.0f,
- -0.9823f, 0.0f, -0.0302f, 0.866f, 1.0f,
- -0.9646f, 0.0f, -0.0447f, 0.8461f, 1.0f,
- -0.9458f, 0.0f, -0.0589f, 0.8236f, 1.0f,
- -0.9257f, 0.0f, -0.0727f, 0.7979f, 1.0f,
- -0.9043f, 0.0f, -0.0862f, 0.7689f, 1.0f,
- -0.8816f, 0.0f, -0.0992f, 0.7359f, 1.0f,
- -0.8576f, 0.0f, -0.1117f, 0.6981f, 1.0f,
- -0.8323f, 0.0f, -0.1237f, 0.6541f, 1.0f,
- -0.8056f, 0.0f, -0.1352f, 0.6019f, 1.0f,
- -0.7775f, 0.0f, -0.1461f, 0.5396f, 1.0f,
- -0.7481f, 0.0f, -0.1564f, 0.4615f, 1.0f,
- -0.7172f, 0.0f, -0.166f, 0.36f, 1.0f,
- -0.6849f, 0.0f, -0.175f, 0.2199f, 1.0f,
- -0.6512f, 0.0f, -0.1832f, 0.1f, 1.0f,
+ -0.7428f, 0.0f, 0.2977f, 0.1f, 1.0f, -0.7608f, 0.0f, 0.3138f, 0.2199f, 1.0f,
+ -0.7786f, 0.0f, 0.3284f, 0.36f, 1.0f, -0.7962f, 0.0f, 0.3414f, 0.4615f, 1.0f,
+ -0.8135f, 0.0f, 0.3531f, 0.5396f, 1.0f, -0.8306f, 0.0f, 0.3633f, 0.6019f, 1.0f,
+ -0.8473f, 0.0f, 0.3722f, 0.6541f, 1.0f, -0.8637f, 0.0f, 0.3798f, 0.6981f, 1.0f,
+ -0.8798f, 0.0f, 0.386f, 0.7359f, 1.0f, -0.8956f, 0.0f, 0.3911f, 0.7689f, 1.0f,
+ -0.9109f, 0.0f, 0.3949f, 0.7979f, 1.0f, -0.9259f, 0.0f, 0.3975f, 0.8236f, 1.0f,
+ -0.9405f, 0.0f, 0.3989f, 0.8461f, 1.0f, -0.9546f, 0.0f, 0.3993f, 0.866f, 1.0f,
+ -0.9682f, 0.0f, 0.3986f, 0.8841f, 1.0f, -0.9814f, 0.0f, 0.3969f, 0.9003f, 1.0f,
+ -0.994f, 0.0f, 0.3941f, 0.9143f, 1.0f, -1.0062f, 0.0f, 0.3904f, 0.9272f, 1.0f,
+ -1.0178f, 0.0f, 0.3858f, 0.9385f, 1.0f, -1.0288f, 0.0f, 0.3803f, 0.9485f, 1.0f,
+ -1.0393f, 0.0f, 0.3739f, 0.9576f, 1.0f, -1.0492f, 0.0f, 0.3668f, 0.9653f, 1.0f,
+ -1.0584f, 0.0f, 0.3588f, 0.9724f, 1.0f, -1.067f, 0.0f, 0.3501f, 0.9781f, 1.0f,
+ -1.075f, 0.0f, 0.3407f, 0.9834f, 1.0f, -1.0822f, 0.0f, 0.3307f, 0.9876f, 1.0f,
+ -1.0888f, 0.0f, 0.32f, 0.9912f, 1.0f, -1.0946f, 0.0f, 0.3087f, 0.9942f, 1.0f,
+ -1.0997f, 0.0f, 0.2969f, 0.9963f, 1.0f, -1.104f, 0.0f, 0.2845f, 0.9983f, 1.0f,
+ -1.1075f, 0.0f, 0.2717f, 0.999f, 1.0f, -1.1103f, 0.0f, 0.2584f, 0.9997f, 1.0f,
+ -1.1122f, 0.0f, 0.2447f, 0.9997f, 1.0f, -1.1132f, 0.0f, 0.2306f, 0.999f, 1.0f,
+ -1.1134f, 0.0f, 0.2162f, 0.9983f, 1.0f, -1.1128f, 0.0f, 0.2015f, 0.9963f, 1.0f,
+ -1.1112f, 0.0f, 0.1865f, 0.9942f, 1.0f, -1.1086f, 0.0f, 0.1713f, 0.9912f, 1.0f,
+ -1.1052f, 0.0f, 0.1559f, 0.9876f, 1.0f, -1.1007f, 0.0f, 0.1404f, 0.9834f, 1.0f,
+ -1.0953f, 0.0f, 0.1247f, 0.9781f, 1.0f, -1.0889f, 0.0f, 0.109f, 0.9724f, 1.0f,
+ -1.0814f, 0.0f, 0.0932f, 0.9653f, 1.0f, -1.0729f, 0.0f, 0.0774f, 0.9576f, 1.0f,
+ -1.0633f, 0.0f, 0.0617f, 0.9485f, 1.0f, -1.0527f, 0.0f, 0.046f, 0.9385f, 1.0f,
+ -1.0409f, 0.0f, 0.0304f, 0.9272f, 1.0f, -1.028f, 0.0f, 0.015f, 0.9143f, 1.0f,
+ -1.0139f, 0.0f, -0.0003f, 0.9003f, 1.0f, -0.9987f, 0.0f, -0.0154f, 0.8841f, 1.0f,
+ -0.9823f, 0.0f, -0.0302f, 0.866f, 1.0f, -0.9646f, 0.0f, -0.0447f, 0.8461f, 1.0f,
+ -0.9458f, 0.0f, -0.0589f, 0.8236f, 1.0f, -0.9257f, 0.0f, -0.0727f, 0.7979f, 1.0f,
+ -0.9043f, 0.0f, -0.0862f, 0.7689f, 1.0f, -0.8816f, 0.0f, -0.0992f, 0.7359f, 1.0f,
+ -0.8576f, 0.0f, -0.1117f, 0.6981f, 1.0f, -0.8323f, 0.0f, -0.1237f, 0.6541f, 1.0f,
+ -0.8056f, 0.0f, -0.1352f, 0.6019f, 1.0f, -0.7775f, 0.0f, -0.1461f, 0.5396f, 1.0f,
+ -0.7481f, 0.0f, -0.1564f, 0.4615f, 1.0f, -0.7172f, 0.0f, -0.166f, 0.36f, 1.0f,
+ -0.6849f, 0.0f, -0.175f, 0.2199f, 1.0f, -0.6512f, 0.0f, -0.1832f, 0.1f, 1.0f,
};
static const float data22[26 * GP_PRIM_DATABUF_SIZE] = {
- 0.2721f, 0.0f, 0.2084f, 1.0f, 1.0f,
- 0.2721f, 0.0f, 0.2112f, 1.0f, 1.0f,
- 0.2739f, 0.0f, 0.2223f, 1.0f, 1.0f,
- 0.2778f, 0.0f, 0.2324f, 1.0f, 1.0f,
- 0.2836f, 0.0f, 0.2409f, 1.0f, 1.0f,
- 0.291f, 0.0f, 0.2471f, 1.0f, 1.0f,
- 0.2994f, 0.0f, 0.2507f, 1.0f, 1.0f,
- 0.3082f, 0.0f, 0.2515f, 1.0f, 1.0f,
- 0.3169f, 0.0f, 0.2493f, 1.0f, 1.0f,
- 0.3248f, 0.0f, 0.2443f, 1.0f, 1.0f,
- 0.3315f, 0.0f, 0.2369f, 1.0f, 1.0f,
- 0.3364f, 0.0f, 0.2275f, 1.0f, 1.0f,
- 0.3392f, 0.0f, 0.2168f, 1.0f, 1.0f,
- 0.3398f, 0.0f, 0.2056f, 1.0f, 1.0f,
- 0.3381f, 0.0f, 0.1945f, 1.0f, 1.0f,
- 0.3342f, 0.0f, 0.1844f, 1.0f, 1.0f,
- 0.3283f, 0.0f, 0.176f, 1.0f, 1.0f,
- 0.321f, 0.0f, 0.1697f, 1.0f, 1.0f,
- 0.3126f, 0.0f, 0.1661f, 1.0f, 1.0f,
- 0.3038f, 0.0f, 0.1653f, 1.0f, 1.0f,
- 0.2951f, 0.0f, 0.1675f, 1.0f, 1.0f,
- 0.2871f, 0.0f, 0.1725f, 1.0f, 1.0f,
- 0.2805f, 0.0f, 0.1799f, 1.0f, 1.0f,
- 0.2756f, 0.0f, 0.1893f, 1.0f, 1.0f,
- 0.2727f, 0.0f, 0.2f, 1.0f, 1.0f,
- 0.2721f, 0.0f, 0.2056f, 1.0f, 1.0f,
+ 0.2721f, 0.0f, 0.2084f, 1.0f, 1.0f, 0.2721f, 0.0f, 0.2112f, 1.0f, 1.0f,
+ 0.2739f, 0.0f, 0.2223f, 1.0f, 1.0f, 0.2778f, 0.0f, 0.2324f, 1.0f, 1.0f,
+ 0.2836f, 0.0f, 0.2409f, 1.0f, 1.0f, 0.291f, 0.0f, 0.2471f, 1.0f, 1.0f,
+ 0.2994f, 0.0f, 0.2507f, 1.0f, 1.0f, 0.3082f, 0.0f, 0.2515f, 1.0f, 1.0f,
+ 0.3169f, 0.0f, 0.2493f, 1.0f, 1.0f, 0.3248f, 0.0f, 0.2443f, 1.0f, 1.0f,
+ 0.3315f, 0.0f, 0.2369f, 1.0f, 1.0f, 0.3364f, 0.0f, 0.2275f, 1.0f, 1.0f,
+ 0.3392f, 0.0f, 0.2168f, 1.0f, 1.0f, 0.3398f, 0.0f, 0.2056f, 1.0f, 1.0f,
+ 0.3381f, 0.0f, 0.1945f, 1.0f, 1.0f, 0.3342f, 0.0f, 0.1844f, 1.0f, 1.0f,
+ 0.3283f, 0.0f, 0.176f, 1.0f, 1.0f, 0.321f, 0.0f, 0.1697f, 1.0f, 1.0f,
+ 0.3126f, 0.0f, 0.1661f, 1.0f, 1.0f, 0.3038f, 0.0f, 0.1653f, 1.0f, 1.0f,
+ 0.2951f, 0.0f, 0.1675f, 1.0f, 1.0f, 0.2871f, 0.0f, 0.1725f, 1.0f, 1.0f,
+ 0.2805f, 0.0f, 0.1799f, 1.0f, 1.0f, 0.2756f, 0.0f, 0.1893f, 1.0f, 1.0f,
+ 0.2727f, 0.0f, 0.2f, 1.0f, 1.0f, 0.2721f, 0.0f, 0.2056f, 1.0f, 1.0f,
};
static const float data23[26 * GP_PRIM_DATABUF_SIZE] = {
- -0.3545f, 0.0f, 0.2084f, 1.0f, 1.0f,
- -0.3544f, 0.0f, 0.2112f, 1.0f, 1.0f,
- -0.3527f, 0.0f, 0.2223f, 1.0f, 1.0f,
- -0.3488f, 0.0f, 0.2324f, 1.0f, 1.0f,
- -0.343f, 0.0f, 0.2409f, 1.0f, 1.0f,
- -0.3356f, 0.0f, 0.2471f, 1.0f, 1.0f,
- -0.3272f, 0.0f, 0.2507f, 1.0f, 1.0f,
- -0.3184f, 0.0f, 0.2515f, 1.0f, 1.0f,
- -0.3097f, 0.0f, 0.2493f, 1.0f, 1.0f,
- -0.3018f, 0.0f, 0.2443f, 1.0f, 1.0f,
- -0.2951f, 0.0f, 0.2369f, 1.0f, 1.0f,
- -0.2902f, 0.0f, 0.2275f, 1.0f, 1.0f,
- -0.2874f, 0.0f, 0.2168f, 1.0f, 1.0f,
- -0.2868f, 0.0f, 0.2056f, 1.0f, 1.0f,
- -0.2885f, 0.0f, 0.1945f, 1.0f, 1.0f,
- -0.2924f, 0.0f, 0.1844f, 1.0f, 1.0f,
- -0.2983f, 0.0f, 0.176f, 1.0f, 1.0f,
- -0.3056f, 0.0f, 0.1697f, 1.0f, 1.0f,
- -0.314f, 0.0f, 0.1661f, 1.0f, 1.0f,
- -0.3228f, 0.0f, 0.1653f, 1.0f, 1.0f,
- -0.3315f, 0.0f, 0.1675f, 1.0f, 1.0f,
- -0.3394f, 0.0f, 0.1725f, 1.0f, 1.0f,
- -0.3461f, 0.0f, 0.1799f, 1.0f, 1.0f,
- -0.351f, 0.0f, 0.1893f, 1.0f, 1.0f,
- -0.3539f, 0.0f, 0.2f, 1.0f, 1.0f,
- -0.3544f, 0.0f, 0.2056f, 1.0f, 1.0f,
+ -0.3545f, 0.0f, 0.2084f, 1.0f, 1.0f, -0.3544f, 0.0f, 0.2112f, 1.0f, 1.0f,
+ -0.3527f, 0.0f, 0.2223f, 1.0f, 1.0f, -0.3488f, 0.0f, 0.2324f, 1.0f, 1.0f,
+ -0.343f, 0.0f, 0.2409f, 1.0f, 1.0f, -0.3356f, 0.0f, 0.2471f, 1.0f, 1.0f,
+ -0.3272f, 0.0f, 0.2507f, 1.0f, 1.0f, -0.3184f, 0.0f, 0.2515f, 1.0f, 1.0f,
+ -0.3097f, 0.0f, 0.2493f, 1.0f, 1.0f, -0.3018f, 0.0f, 0.2443f, 1.0f, 1.0f,
+ -0.2951f, 0.0f, 0.2369f, 1.0f, 1.0f, -0.2902f, 0.0f, 0.2275f, 1.0f, 1.0f,
+ -0.2874f, 0.0f, 0.2168f, 1.0f, 1.0f, -0.2868f, 0.0f, 0.2056f, 1.0f, 1.0f,
+ -0.2885f, 0.0f, 0.1945f, 1.0f, 1.0f, -0.2924f, 0.0f, 0.1844f, 1.0f, 1.0f,
+ -0.2983f, 0.0f, 0.176f, 1.0f, 1.0f, -0.3056f, 0.0f, 0.1697f, 1.0f, 1.0f,
+ -0.314f, 0.0f, 0.1661f, 1.0f, 1.0f, -0.3228f, 0.0f, 0.1653f, 1.0f, 1.0f,
+ -0.3315f, 0.0f, 0.1675f, 1.0f, 1.0f, -0.3394f, 0.0f, 0.1725f, 1.0f, 1.0f,
+ -0.3461f, 0.0f, 0.1799f, 1.0f, 1.0f, -0.351f, 0.0f, 0.1893f, 1.0f, 1.0f,
+ -0.3539f, 0.0f, 0.2f, 1.0f, 1.0f, -0.3544f, 0.0f, 0.2056f, 1.0f, 1.0f,
};
static const float data24[33 * GP_PRIM_DATABUF_SIZE] = {
- 0.1904f, 0.0f, 0.0983f, 0.1f, 1.0f,
- 0.1997f, 0.0f, 0.0774f, 0.2199f, 1.0f,
- 0.2234f, 0.0f, 0.0407f, 0.4615f, 1.0f,
- 0.2477f, 0.0f, 0.0158f, 0.6019f, 1.0f,
- 0.2767f, 0.0f, -0.0047f, 0.6981f, 1.0f,
- 0.3061f, 0.0f, -0.0179f, 0.7689f, 1.0f,
- 0.3346f, 0.0f, -0.0247f, 0.8236f, 1.0f,
- 0.362f, 0.0f, -0.0262f, 0.866f, 1.0f,
- 0.3881f, 0.0f, -0.0231f, 0.9003f, 1.0f,
- 0.4128f, 0.0f, -0.0159f, 0.9272f, 1.0f,
- 0.436f, 0.0f, -0.0049f, 0.9485f, 1.0f,
- 0.4577f, 0.0f, 0.0099f, 0.9653f, 1.0f,
- 0.4778f, 0.0f, 0.0289f, 0.9781f, 1.0f,
- 0.4959f, 0.0f, 0.0524f, 0.9876f, 1.0f,
- 0.5114f, 0.0f, 0.0806f, 0.9942f, 1.0f,
- 0.5229f, 0.0f, 0.1134f, 0.9983f, 1.0f,
- 0.5291f, 0.0f, 0.1498f, 0.9997f, 1.0f,
- 0.5289f, 0.0f, 0.1884f, 0.999f, 1.0f,
- 0.5219f, 0.0f, 0.2267f, 0.9963f, 1.0f,
- 0.5087f, 0.0f, 0.2616f, 0.9912f, 1.0f,
- 0.4907f, 0.0f, 0.2916f, 0.9834f, 1.0f,
- 0.4697f, 0.0f, 0.3159f, 0.9724f, 1.0f,
- 0.4465f, 0.0f, 0.3349f, 0.9576f, 1.0f,
- 0.422f, 0.0f, 0.3489f, 0.9385f, 1.0f,
- 0.3964f, 0.0f, 0.3582f, 0.9143f, 1.0f,
- 0.3705f, 0.0f, 0.3628f, 0.8841f, 1.0f,
- 0.3436f, 0.0f, 0.363f, 0.8461f, 1.0f,
- 0.3166f, 0.0f, 0.3586f, 0.7979f, 1.0f,
- 0.2897f, 0.0f, 0.3491f, 0.7359f, 1.0f,
- 0.2635f, 0.0f, 0.3344f, 0.6541f, 1.0f,
- 0.2382f, 0.0f, 0.3137f, 0.5396f, 1.0f,
- 0.2162f, 0.0f, 0.2882f, 0.36f, 1.0f,
- 0.1949f, 0.0f, 0.2516f, 0.1f, 1.0f,
+ 0.1904f, 0.0f, 0.0983f, 0.1f, 1.0f, 0.1997f, 0.0f, 0.0774f, 0.2199f, 1.0f,
+ 0.2234f, 0.0f, 0.0407f, 0.4615f, 1.0f, 0.2477f, 0.0f, 0.0158f, 0.6019f, 1.0f,
+ 0.2767f, 0.0f, -0.0047f, 0.6981f, 1.0f, 0.3061f, 0.0f, -0.0179f, 0.7689f, 1.0f,
+ 0.3346f, 0.0f, -0.0247f, 0.8236f, 1.0f, 0.362f, 0.0f, -0.0262f, 0.866f, 1.0f,
+ 0.3881f, 0.0f, -0.0231f, 0.9003f, 1.0f, 0.4128f, 0.0f, -0.0159f, 0.9272f, 1.0f,
+ 0.436f, 0.0f, -0.0049f, 0.9485f, 1.0f, 0.4577f, 0.0f, 0.0099f, 0.9653f, 1.0f,
+ 0.4778f, 0.0f, 0.0289f, 0.9781f, 1.0f, 0.4959f, 0.0f, 0.0524f, 0.9876f, 1.0f,
+ 0.5114f, 0.0f, 0.0806f, 0.9942f, 1.0f, 0.5229f, 0.0f, 0.1134f, 0.9983f, 1.0f,
+ 0.5291f, 0.0f, 0.1498f, 0.9997f, 1.0f, 0.5289f, 0.0f, 0.1884f, 0.999f, 1.0f,
+ 0.5219f, 0.0f, 0.2267f, 0.9963f, 1.0f, 0.5087f, 0.0f, 0.2616f, 0.9912f, 1.0f,
+ 0.4907f, 0.0f, 0.2916f, 0.9834f, 1.0f, 0.4697f, 0.0f, 0.3159f, 0.9724f, 1.0f,
+ 0.4465f, 0.0f, 0.3349f, 0.9576f, 1.0f, 0.422f, 0.0f, 0.3489f, 0.9385f, 1.0f,
+ 0.3964f, 0.0f, 0.3582f, 0.9143f, 1.0f, 0.3705f, 0.0f, 0.3628f, 0.8841f, 1.0f,
+ 0.3436f, 0.0f, 0.363f, 0.8461f, 1.0f, 0.3166f, 0.0f, 0.3586f, 0.7979f, 1.0f,
+ 0.2897f, 0.0f, 0.3491f, 0.7359f, 1.0f, 0.2635f, 0.0f, 0.3344f, 0.6541f, 1.0f,
+ 0.2382f, 0.0f, 0.3137f, 0.5396f, 1.0f, 0.2162f, 0.0f, 0.2882f, 0.36f, 1.0f,
+ 0.1949f, 0.0f, 0.2516f, 0.1f, 1.0f,
};
static const float data25[18 * GP_PRIM_DATABUF_SIZE] = {
- -1.0361f, 0.0f, 0.1745f, 0.1f, 1.0f,
- -1.0319f, 0.0f, 0.177f, 0.2199f, 1.0f,
- -1.0153f, 0.0f, 0.1852f, 0.6019f, 1.0f,
- -0.999f, 0.0f, 0.1907f, 0.7689f, 1.0f,
- -0.983f, 0.0f, 0.1936f, 0.866f, 1.0f,
- -0.9673f, 0.0f, 0.1941f, 0.9272f, 1.0f,
- -0.9522f, 0.0f, 0.1923f, 0.9653f, 1.0f,
- -0.9376f, 0.0f, 0.1885f, 0.9876f, 1.0f,
- -0.9236f, 0.0f, 0.1827f, 0.9983f, 1.0f,
- -0.9103f, 0.0f, 0.1752f, 0.999f, 1.0f,
- -0.8978f, 0.0f, 0.1662f, 0.9912f, 1.0f,
- -0.8862f, 0.0f, 0.1558f, 0.9724f, 1.0f,
- -0.8756f, 0.0f, 0.1441f, 0.9385f, 1.0f,
- -0.866f, 0.0f, 0.1314f, 0.8841f, 1.0f,
- -0.8575f, 0.0f, 0.1179f, 0.7979f, 1.0f,
- -0.8501f, 0.0f, 0.1036f, 0.6541f, 1.0f,
- -0.8441f, 0.0f, 0.0889f, 0.36f, 1.0f,
- -0.8416f, 0.0f, 0.0813f, 0.1f, 1.0f,
+ -1.0361f, 0.0f, 0.1745f, 0.1f, 1.0f, -1.0319f, 0.0f, 0.177f, 0.2199f, 1.0f,
+ -1.0153f, 0.0f, 0.1852f, 0.6019f, 1.0f, -0.999f, 0.0f, 0.1907f, 0.7689f, 1.0f,
+ -0.983f, 0.0f, 0.1936f, 0.866f, 1.0f, -0.9673f, 0.0f, 0.1941f, 0.9272f, 1.0f,
+ -0.9522f, 0.0f, 0.1923f, 0.9653f, 1.0f, -0.9376f, 0.0f, 0.1885f, 0.9876f, 1.0f,
+ -0.9236f, 0.0f, 0.1827f, 0.9983f, 1.0f, -0.9103f, 0.0f, 0.1752f, 0.999f, 1.0f,
+ -0.8978f, 0.0f, 0.1662f, 0.9912f, 1.0f, -0.8862f, 0.0f, 0.1558f, 0.9724f, 1.0f,
+ -0.8756f, 0.0f, 0.1441f, 0.9385f, 1.0f, -0.866f, 0.0f, 0.1314f, 0.8841f, 1.0f,
+ -0.8575f, 0.0f, 0.1179f, 0.7979f, 1.0f, -0.8501f, 0.0f, 0.1036f, 0.6541f, 1.0f,
+ -0.8441f, 0.0f, 0.0889f, 0.36f, 1.0f, -0.8416f, 0.0f, 0.0813f, 0.1f, 1.0f,
};
static const float data26[18 * GP_PRIM_DATABUF_SIZE] = {
- 0.9747f, 0.0f, 0.1745f, 0.1f, 1.0f,
- 0.9706f, 0.0f, 0.177f, 0.2199f, 1.0f,
- 0.954f, 0.0f, 0.1852f, 0.6019f, 1.0f,
- 0.9377f, 0.0f, 0.1907f, 0.7689f, 1.0f,
- 0.9216f, 0.0f, 0.1936f, 0.866f, 1.0f,
- 0.906f, 0.0f, 0.1941f, 0.9272f, 1.0f,
- 0.8908f, 0.0f, 0.1923f, 0.9653f, 1.0f,
- 0.8762f, 0.0f, 0.1885f, 0.9876f, 1.0f,
- 0.8622f, 0.0f, 0.1827f, 0.9983f, 1.0f,
- 0.849f, 0.0f, 0.1752f, 0.999f, 1.0f,
- 0.8365f, 0.0f, 0.1662f, 0.9912f, 1.0f,
- 0.8249f, 0.0f, 0.1558f, 0.9724f, 1.0f,
- 0.8143f, 0.0f, 0.1441f, 0.9385f, 1.0f,
- 0.8046f, 0.0f, 0.1314f, 0.8841f, 1.0f,
- 0.7961f, 0.0f, 0.1179f, 0.7979f, 1.0f,
- 0.7888f, 0.0f, 0.1036f, 0.6541f, 1.0f,
- 0.7828f, 0.0f, 0.0889f, 0.36f, 1.0f,
- 0.7802f, 0.0f, 0.0813f, 0.1f, 1.0f,
+ 0.9747f, 0.0f, 0.1745f, 0.1f, 1.0f, 0.9706f, 0.0f, 0.177f, 0.2199f, 1.0f,
+ 0.954f, 0.0f, 0.1852f, 0.6019f, 1.0f, 0.9377f, 0.0f, 0.1907f, 0.7689f, 1.0f,
+ 0.9216f, 0.0f, 0.1936f, 0.866f, 1.0f, 0.906f, 0.0f, 0.1941f, 0.9272f, 1.0f,
+ 0.8908f, 0.0f, 0.1923f, 0.9653f, 1.0f, 0.8762f, 0.0f, 0.1885f, 0.9876f, 1.0f,
+ 0.8622f, 0.0f, 0.1827f, 0.9983f, 1.0f, 0.849f, 0.0f, 0.1752f, 0.999f, 1.0f,
+ 0.8365f, 0.0f, 0.1662f, 0.9912f, 1.0f, 0.8249f, 0.0f, 0.1558f, 0.9724f, 1.0f,
+ 0.8143f, 0.0f, 0.1441f, 0.9385f, 1.0f, 0.8046f, 0.0f, 0.1314f, 0.8841f, 1.0f,
+ 0.7961f, 0.0f, 0.1179f, 0.7979f, 1.0f, 0.7888f, 0.0f, 0.1036f, 0.6541f, 1.0f,
+ 0.7828f, 0.0f, 0.0889f, 0.36f, 1.0f, 0.7802f, 0.0f, 0.0813f, 0.1f, 1.0f,
};
static const float data27[33 * GP_PRIM_DATABUF_SIZE] = {
- -0.186f, 0.0f, 0.0983f, 0.1f, 1.0f,
- -0.1954f, 0.0f, 0.0774f, 0.2199f, 1.0f,
- -0.2191f, 0.0f, 0.0407f, 0.4615f, 1.0f,
- -0.2434f, 0.0f, 0.0158f, 0.6019f, 1.0f,
- -0.2723f, 0.0f, -0.0047f, 0.6981f, 1.0f,
- -0.3017f, 0.0f, -0.0179f, 0.7689f, 1.0f,
- -0.3302f, 0.0f, -0.0247f, 0.8236f, 1.0f,
- -0.3576f, 0.0f, -0.0262f, 0.866f, 1.0f,
- -0.3837f, 0.0f, -0.0231f, 0.9003f, 1.0f,
- -0.4085f, 0.0f, -0.0159f, 0.9272f, 1.0f,
- -0.4317f, 0.0f, -0.0049f, 0.9485f, 1.0f,
- -0.4533f, 0.0f, 0.0099f, 0.9653f, 1.0f,
- -0.4734f, 0.0f, 0.0289f, 0.9781f, 1.0f,
- -0.4916f, 0.0f, 0.0524f, 0.9876f, 1.0f,
- -0.507f, 0.0f, 0.0806f, 0.9942f, 1.0f,
- -0.5185f, 0.0f, 0.1134f, 0.9983f, 1.0f,
- -0.5247f, 0.0f, 0.1498f, 0.9997f, 1.0f,
- -0.5246f, 0.0f, 0.1884f, 0.999f, 1.0f,
- -0.5175f, 0.0f, 0.2267f, 0.9963f, 1.0f,
- -0.5043f, 0.0f, 0.2616f, 0.9912f, 1.0f,
- -0.4864f, 0.0f, 0.2916f, 0.9834f, 1.0f,
- -0.4653f, 0.0f, 0.3159f, 0.9724f, 1.0f,
- -0.4422f, 0.0f, 0.3349f, 0.9576f, 1.0f,
- -0.4177f, 0.0f, 0.3489f, 0.9385f, 1.0f,
- -0.3921f, 0.0f, 0.3582f, 0.9143f, 1.0f,
- -0.3661f, 0.0f, 0.3628f, 0.8841f, 1.0f,
- -0.3392f, 0.0f, 0.363f, 0.8461f, 1.0f,
- -0.3123f, 0.0f, 0.3586f, 0.7979f, 1.0f,
- -0.2853f, 0.0f, 0.3491f, 0.7359f, 1.0f,
- -0.2591f, 0.0f, 0.3344f, 0.6541f, 1.0f,
- -0.2339f, 0.0f, 0.3137f, 0.5396f, 1.0f,
- -0.2118f, 0.0f, 0.2882f, 0.36f, 1.0f,
- -0.1906f, 0.0f, 0.2516f, 0.1f, 1.0f,
+ -0.186f, 0.0f, 0.0983f, 0.1f, 1.0f, -0.1954f, 0.0f, 0.0774f, 0.2199f, 1.0f,
+ -0.2191f, 0.0f, 0.0407f, 0.4615f, 1.0f, -0.2434f, 0.0f, 0.0158f, 0.6019f, 1.0f,
+ -0.2723f, 0.0f, -0.0047f, 0.6981f, 1.0f, -0.3017f, 0.0f, -0.0179f, 0.7689f, 1.0f,
+ -0.3302f, 0.0f, -0.0247f, 0.8236f, 1.0f, -0.3576f, 0.0f, -0.0262f, 0.866f, 1.0f,
+ -0.3837f, 0.0f, -0.0231f, 0.9003f, 1.0f, -0.4085f, 0.0f, -0.0159f, 0.9272f, 1.0f,
+ -0.4317f, 0.0f, -0.0049f, 0.9485f, 1.0f, -0.4533f, 0.0f, 0.0099f, 0.9653f, 1.0f,
+ -0.4734f, 0.0f, 0.0289f, 0.9781f, 1.0f, -0.4916f, 0.0f, 0.0524f, 0.9876f, 1.0f,
+ -0.507f, 0.0f, 0.0806f, 0.9942f, 1.0f, -0.5185f, 0.0f, 0.1134f, 0.9983f, 1.0f,
+ -0.5247f, 0.0f, 0.1498f, 0.9997f, 1.0f, -0.5246f, 0.0f, 0.1884f, 0.999f, 1.0f,
+ -0.5175f, 0.0f, 0.2267f, 0.9963f, 1.0f, -0.5043f, 0.0f, 0.2616f, 0.9912f, 1.0f,
+ -0.4864f, 0.0f, 0.2916f, 0.9834f, 1.0f, -0.4653f, 0.0f, 0.3159f, 0.9724f, 1.0f,
+ -0.4422f, 0.0f, 0.3349f, 0.9576f, 1.0f, -0.4177f, 0.0f, 0.3489f, 0.9385f, 1.0f,
+ -0.3921f, 0.0f, 0.3582f, 0.9143f, 1.0f, -0.3661f, 0.0f, 0.3628f, 0.8841f, 1.0f,
+ -0.3392f, 0.0f, 0.363f, 0.8461f, 1.0f, -0.3123f, 0.0f, 0.3586f, 0.7979f, 1.0f,
+ -0.2853f, 0.0f, 0.3491f, 0.7359f, 1.0f, -0.2591f, 0.0f, 0.3344f, 0.6541f, 1.0f,
+ -0.2339f, 0.0f, 0.3137f, 0.5396f, 1.0f, -0.2118f, 0.0f, 0.2882f, 0.36f, 1.0f,
+ -0.1906f, 0.0f, 0.2516f, 0.1f, 1.0f,
};
-
/* ***************************************************************** */
/* Monkey Color Data */
static const ColorTemplate gp_monkey_pct_black = {
- "Black",
- {0.0f, 0.0f, 0.0f, 1.0f},
- {0.0f, 0.0f, 0.0f, 0.0f},
+ "Black",
+ {0.0f, 0.0f, 0.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
};
static const ColorTemplate gp_monkey_pct_skin = {
- "Skin",
- {0.733f, 0.569f, 0.361f, 1.0f},
- {0.745f, 0.502f, 0.278f, 1.0f},
+ "Skin",
+ {0.733f, 0.569f, 0.361f, 1.0f},
+ {0.745f, 0.502f, 0.278f, 1.0f},
};
static const ColorTemplate gp_monkey_pct_skin_light = {
- "Skin_Light",
- {0.914f, 0.827f, 0.635f, 1.0f},
- {0.913f, 0.828f, 0.637f, 0.0f},
+ "Skin_Light",
+ {0.914f, 0.827f, 0.635f, 1.0f},
+ {0.913f, 0.828f, 0.637f, 0.0f},
};
static const ColorTemplate gp_monkey_pct_skin_shadow = {
- "Skin_Shadow",
- {0.322f, 0.29f, 0.224f, 0.5f},
- {0.32f, 0.29f, 0.223f, 0.3f},
+ "Skin_Shadow",
+ {0.322f, 0.29f, 0.224f, 0.5f},
+ {0.32f, 0.29f, 0.223f, 0.3f},
};
static const ColorTemplate gp_monkey_pct_eyes = {
- "Eyes",
- {0.553f, 0.39f, 0.266f, 0.0f},
- {0.847f, 0.723f, 0.599f, 1.0f},
+ "Eyes",
+ {0.553f, 0.39f, 0.266f, 0.0f},
+ {0.847f, 0.723f, 0.599f, 1.0f},
};
static const ColorTemplate gp_monkey_pct_pupils = {
- "Pupils",
- {0.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 1.0f},
+ "Pupils",
+ {0.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 0.0f, 1.0f},
};
/* ***************************************************************** */
@@ -1430,122 +828,121 @@ static const ColorTemplate gp_monkey_pct_pupils = {
/* add a 2D Suzanne (original model created by Matias Mendiola) */
void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4])
{
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
- bGPdata *gpd = (bGPdata *)ob->data;
- bGPDstroke *gps;
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDstroke *gps;
- /* create colors */
- int color_Black = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_black, true, false);
- int color_Skin = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin, false, true);
- int color_Skin_Light = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin_light, true, false);
- int color_Skin_Shadow = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin_shadow, true, false);
- int color_Eyes = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_eyes, false, true);
- int color_Pupils = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_pupils, false, true);
+ /* create colors */
+ int color_Black = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_black, true, false);
+ int color_Skin = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin, false, true);
+ int color_Skin_Light = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin_light, true, false);
+ int color_Skin_Shadow = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin_shadow, true, false);
+ int color_Eyes = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_eyes, false, true);
+ int color_Pupils = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_pupils, false, true);
- /* set first color as active */
- ob->actcol = color_Black + 1;
+ /* set first color as active */
+ ob->actcol = color_Black + 1;
- /* layers */
- /* NOTE: For now, we just add new layers, to make it easier to separate out old/new instances */
- bGPDlayer *Fills = BKE_gpencil_layer_addnew(gpd, "Fills", false);
- bGPDlayer *Lines = BKE_gpencil_layer_addnew(gpd, "Lines", true);
+ /* layers */
+ /* NOTE: For now, we just add new layers, to make it easier to separate out old/new instances */
+ bGPDlayer *Fills = BKE_gpencil_layer_addnew(gpd, "Fills", false);
+ bGPDlayer *Lines = BKE_gpencil_layer_addnew(gpd, "Lines", true);
- /* frames */
- /* NOTE: No need to check for existing, as this will take care of it for us */
- bGPDframe *frameFills = BKE_gpencil_frame_addnew(Fills, cfra_eval);
- bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, cfra_eval);
+ /* frames */
+ /* NOTE: No need to check for existing, as this will take care of it for us */
+ bGPDframe *frameFills = BKE_gpencil_frame_addnew(Fills, cfra_eval);
+ bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, cfra_eval);
- /* generate strokes */
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin, 270, 75);
- BKE_gpencil_stroke_add_points(gps, data0, 270, mat);
+ /* generate strokes */
+ gps = BKE_gpencil_add_stroke(frameFills, color_Skin, 270, 75);
+ BKE_gpencil_stroke_add_points(gps, data0, 270, mat);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 33, 60);
- BKE_gpencil_stroke_add_points(gps, data1, 33, mat);
+ gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 33, 60);
+ BKE_gpencil_stroke_add_points(gps, data1, 33, mat);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 18, 60);
- BKE_gpencil_stroke_add_points(gps, data2, 18, mat);
+ gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 18, 60);
+ BKE_gpencil_stroke_add_points(gps, data2, 18, mat);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 64, 60);
- BKE_gpencil_stroke_add_points(gps, data3, 64, mat);
+ gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 64, 60);
+ BKE_gpencil_stroke_add_points(gps, data3, 64, mat);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 33, 60);
- BKE_gpencil_stroke_add_points(gps, data4, 33, mat);
+ gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 33, 60);
+ BKE_gpencil_stroke_add_points(gps, data4, 33, mat);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 64, 60);
- BKE_gpencil_stroke_add_points(gps, data5, 64, mat);
+ gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 64, 60);
+ BKE_gpencil_stroke_add_points(gps, data5, 64, mat);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 33, 60);
- BKE_gpencil_stroke_add_points(gps, data6, 33, mat);
+ gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 33, 60);
+ BKE_gpencil_stroke_add_points(gps, data6, 33, mat);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 18, 40);
- BKE_gpencil_stroke_add_points(gps, data7, 18, mat);
+ gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 18, 40);
+ BKE_gpencil_stroke_add_points(gps, data7, 18, mat);
- gps = BKE_gpencil_add_stroke(frameFills, color_Eyes, 49, 60);
- BKE_gpencil_stroke_add_points(gps, data8, 49, mat);
+ gps = BKE_gpencil_add_stroke(frameFills, color_Eyes, 49, 60);
+ BKE_gpencil_stroke_add_points(gps, data8, 49, mat);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 33, 60);
- BKE_gpencil_stroke_add_points(gps, data9, 33, mat);
+ gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 33, 60);
+ BKE_gpencil_stroke_add_points(gps, data9, 33, mat);
- gps = BKE_gpencil_add_stroke(frameFills, color_Eyes, 49, 60);
- BKE_gpencil_stroke_add_points(gps, data10, 49, mat);
+ gps = BKE_gpencil_add_stroke(frameFills, color_Eyes, 49, 60);
+ BKE_gpencil_stroke_add_points(gps, data10, 49, mat);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 18, 40);
- BKE_gpencil_stroke_add_points(gps, data11, 18, mat);
+ gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 18, 40);
+ BKE_gpencil_stroke_add_points(gps, data11, 18, mat);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 18, 40);
- BKE_gpencil_stroke_add_points(gps, data12, 18, mat);
+ gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 18, 40);
+ BKE_gpencil_stroke_add_points(gps, data12, 18, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
- BKE_gpencil_stroke_add_points(gps, data13, 33, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
+ BKE_gpencil_stroke_add_points(gps, data13, 33, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
- BKE_gpencil_stroke_add_points(gps, data14, 33, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
+ BKE_gpencil_stroke_add_points(gps, data14, 33, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 65, 60);
- BKE_gpencil_stroke_add_points(gps, data15, 65, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 65, 60);
+ BKE_gpencil_stroke_add_points(gps, data15, 65, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 34, 60);
- BKE_gpencil_stroke_add_points(gps, data16, 34, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 34, 60);
+ BKE_gpencil_stroke_add_points(gps, data16, 34, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
- BKE_gpencil_stroke_add_points(gps, data17, 33, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
+ BKE_gpencil_stroke_add_points(gps, data17, 33, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 40);
- BKE_gpencil_stroke_add_points(gps, data18, 33, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 40);
+ BKE_gpencil_stroke_add_points(gps, data18, 33, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 34, 40);
- BKE_gpencil_stroke_add_points(gps, data19, 34, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 34, 40);
+ BKE_gpencil_stroke_add_points(gps, data19, 34, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
- BKE_gpencil_stroke_add_points(gps, data20, 33, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
+ BKE_gpencil_stroke_add_points(gps, data20, 33, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 64, 60);
- BKE_gpencil_stroke_add_points(gps, data21, 64, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 64, 60);
+ BKE_gpencil_stroke_add_points(gps, data21, 64, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 26, 60);
- BKE_gpencil_stroke_add_points(gps, data22, 26, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 26, 60);
+ BKE_gpencil_stroke_add_points(gps, data22, 26, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 26, 60);
- BKE_gpencil_stroke_add_points(gps, data23, 26, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 26, 60);
+ BKE_gpencil_stroke_add_points(gps, data23, 26, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
- BKE_gpencil_stroke_add_points(gps, data24, 33, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
+ BKE_gpencil_stroke_add_points(gps, data24, 33, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 18, 40);
- BKE_gpencil_stroke_add_points(gps, data25, 18, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 18, 40);
+ BKE_gpencil_stroke_add_points(gps, data25, 18, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 18, 40);
- BKE_gpencil_stroke_add_points(gps, data26, 18, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 18, 40);
+ BKE_gpencil_stroke_add_points(gps, data26, 18, mat);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
- BKE_gpencil_stroke_add_points(gps, data27, 33, mat);
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
+ BKE_gpencil_stroke_add_points(gps, data27, 33, mat);
- /* update depsgraph */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ /* update depsgraph */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
}
-
/* ***************************************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c
index 1107819a09a..d6e068926dd 100644
--- a/source/blender/editors/gpencil/gpencil_add_stroke.c
+++ b/source/blender/editors/gpencil/gpencil_add_stroke.c
@@ -42,170 +42,169 @@
/* Definition of the most important info from a color */
typedef struct ColorTemplate {
- const char *name;
- float line[4];
- float fill[4];
+ const char *name;
+ float line[4];
+ float fill[4];
} ColorTemplate;
/* Add color an ensure duplications (matched by name) */
-static int gp_stroke_material(
- Main *bmain, Object *ob, const ColorTemplate *pct, const bool fill)
+static int gp_stroke_material(Main *bmain, Object *ob, const ColorTemplate *pct, const bool fill)
{
- short *totcol = give_totcolp(ob);
- Material *ma = NULL;
- for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
- if (STREQ(ma->id.name, pct->name)) {
- return i;
- }
- }
+ short *totcol = give_totcolp(ob);
+ Material *ma = NULL;
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ if (STREQ(ma->id.name, pct->name)) {
+ return i;
+ }
+ }
- int idx;
+ int idx;
- /* create a new one */
- ma = BKE_gpencil_object_material_new(bmain, ob, pct->name, &idx);
+ /* create a new one */
+ ma = BKE_gpencil_object_material_new(bmain, ob, pct->name, &idx);
- copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
- copy_v4_v4(ma->gp_style->fill_rgba, pct->fill);
+ copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
+ copy_v4_v4(ma->gp_style->fill_rgba, pct->fill);
- if (fill) {
- ma->gp_style->flag |= GP_STYLE_FILL_SHOW;
- }
+ if (fill) {
+ ma->gp_style->flag |= GP_STYLE_FILL_SHOW;
+ }
- return idx;
+ return idx;
}
/* ***************************************************************** */
/* Stroke Geometry */
static const float data0[175 * GP_PRIM_DATABUF_SIZE] = {
- -1.281f, 0.0f, -0.315f, 0.038f, 1.0f, -1.269f, 0.0f, -0.302f, 0.069f, 1.0f,
- -1.261f, 0.0f, -0.293f, 0.089f, 1.0f, -1.251f, 0.0f, -0.282f, 0.112f, 1.0f,
- -1.241f, 0.0f, -0.271f, 0.134f, 1.0f, -1.23f, 0.0f, -0.259f, 0.155f, 1.0f,
- -1.219f, 0.0f, -0.247f, 0.175f, 1.0f, -1.208f, 0.0f, -0.234f, 0.194f, 1.0f,
- -1.196f, 0.0f, -0.221f, 0.211f, 1.0f, -1.184f, 0.0f, -0.208f, 0.227f, 1.0f,
- -1.172f, 0.0f, -0.194f, 0.242f, 1.0f, -1.159f, 0.0f, -0.18f, 0.256f, 1.0f,
- -1.147f, 0.0f, -0.165f, 0.268f, 1.0f, -1.134f, 0.0f, -0.151f, 0.28f, 1.0f,
- -1.121f, 0.0f, -0.136f, 0.29f, 1.0f, -1.108f, 0.0f, -0.121f, 0.299f, 1.0f,
- -1.094f, 0.0f, -0.106f, 0.307f, 1.0f, -1.08f, 0.0f, -0.091f, 0.315f, 1.0f,
- -1.066f, 0.0f, -0.076f, 0.322f, 1.0f, -1.052f, 0.0f, -0.061f, 0.329f, 1.0f,
- -1.037f, 0.0f, -0.047f, 0.335f, 1.0f, -1.022f, 0.0f, -0.032f, 0.341f, 1.0f,
- -1.007f, 0.0f, -0.017f, 0.346f, 1.0f, -0.991f, 0.0f, -0.003f, 0.351f, 1.0f,
- -0.975f, 0.0f, 0.012f, 0.355f, 1.0f, -0.959f, 0.0f, 0.027f, 0.36f, 1.0f,
- -0.942f, 0.0f, 0.041f, 0.364f, 1.0f, -0.926f, 0.0f, 0.056f, 0.368f, 1.0f,
- -0.909f, 0.0f, 0.071f, 0.371f, 1.0f, -0.893f, 0.0f, 0.086f, 0.373f, 1.0f,
- -0.876f, 0.0f, 0.1f, 0.376f, 1.0f, -0.859f, 0.0f, 0.115f, 0.377f, 1.0f,
- -0.842f, 0.0f, 0.129f, 0.378f, 1.0f, -0.824f, 0.0f, 0.144f, 0.379f, 1.0f,
- -0.807f, 0.0f, 0.158f, 0.379f, 1.0f, -0.79f, 0.0f, 0.172f, 0.379f, 1.0f,
- -0.773f, 0.0f, 0.186f, 0.38f, 1.0f, -0.755f, 0.0f, 0.199f, 0.38f, 1.0f,
- -0.738f, 0.0f, 0.212f, 0.381f, 1.0f, -0.721f, 0.0f, 0.224f, 0.382f, 1.0f,
- -0.703f, 0.0f, 0.236f, 0.384f, 1.0f, -0.686f, 0.0f, 0.248f, 0.386f, 1.0f,
- -0.67f, 0.0f, 0.26f, 0.388f, 1.0f, -0.653f, 0.0f, 0.27f, 0.39f, 1.0f,
- -0.637f, 0.0f, 0.28f, 0.393f, 1.0f, -0.621f, 0.0f, 0.29f, 0.396f, 1.0f,
- -0.605f, 0.0f, 0.298f, 0.399f, 1.0f, -0.589f, 0.0f, 0.306f, 0.403f, 1.0f,
- -0.574f, 0.0f, 0.313f, 0.407f, 1.0f, -0.559f, 0.0f, 0.319f, 0.411f, 1.0f,
- -0.544f, 0.0f, 0.325f, 0.415f, 1.0f, -0.53f, 0.0f, 0.331f, 0.42f, 1.0f,
- -0.516f, 0.0f, 0.336f, 0.425f, 1.0f, -0.503f, 0.0f, 0.34f, 0.431f, 1.0f,
- -0.489f, 0.0f, 0.344f, 0.437f, 1.0f, -0.477f, 0.0f, 0.347f, 0.443f, 1.0f,
- -0.464f, 0.0f, 0.35f, 0.45f, 1.0f, -0.452f, 0.0f, 0.352f, 0.457f, 1.0f,
- -0.44f, 0.0f, 0.354f, 0.464f, 1.0f, -0.429f, 0.0f, 0.355f, 0.471f, 1.0f,
- -0.418f, 0.0f, 0.355f, 0.479f, 1.0f, -0.407f, 0.0f, 0.355f, 0.487f, 1.0f,
- -0.397f, 0.0f, 0.354f, 0.495f, 1.0f, -0.387f, 0.0f, 0.353f, 0.503f, 1.0f,
- -0.378f, 0.0f, 0.351f, 0.512f, 1.0f, -0.368f, 0.0f, 0.348f, 0.52f, 1.0f,
- -0.36f, 0.0f, 0.344f, 0.528f, 1.0f, -0.351f, 0.0f, 0.34f, 0.537f, 1.0f,
- -0.344f, 0.0f, 0.336f, 0.545f, 1.0f, -0.336f, 0.0f, 0.33f, 0.553f, 1.0f,
- -0.329f, 0.0f, 0.324f, 0.562f, 1.0f, -0.322f, 0.0f, 0.318f, 0.57f, 1.0f,
- -0.316f, 0.0f, 0.31f, 0.579f, 1.0f, -0.311f, 0.0f, 0.303f, 0.588f, 1.0f,
- -0.306f, 0.0f, 0.294f, 0.597f, 1.0f, -0.301f, 0.0f, 0.285f, 0.606f, 1.0f,
- -0.297f, 0.0f, 0.275f, 0.615f, 1.0f, -0.293f, 0.0f, 0.264f, 0.625f, 1.0f,
- -0.29f, 0.0f, 0.253f, 0.635f, 1.0f, -0.288f, 0.0f, 0.241f, 0.644f, 1.0f,
- -0.286f, 0.0f, 0.229f, 0.654f, 1.0f, -0.285f, 0.0f, 0.216f, 0.664f, 1.0f,
- -0.284f, 0.0f, 0.202f, 0.675f, 1.0f, -0.283f, 0.0f, 0.188f, 0.685f, 1.0f,
- -0.283f, 0.0f, 0.173f, 0.696f, 1.0f, -0.284f, 0.0f, 0.158f, 0.707f, 1.0f,
- -0.285f, 0.0f, 0.142f, 0.718f, 1.0f, -0.286f, 0.0f, 0.125f, 0.729f, 1.0f,
- -0.288f, 0.0f, 0.108f, 0.74f, 1.0f, -0.29f, 0.0f, 0.091f, 0.751f, 1.0f,
- -0.293f, 0.0f, 0.073f, 0.761f, 1.0f, -0.295f, 0.0f, 0.054f, 0.772f, 1.0f,
- -0.298f, 0.0f, 0.035f, 0.782f, 1.0f, -0.302f, 0.0f, 0.016f, 0.793f, 1.0f,
- -0.305f, 0.0f, -0.004f, 0.804f, 1.0f, -0.309f, 0.0f, -0.024f, 0.815f, 1.0f,
- -0.313f, 0.0f, -0.044f, 0.828f, 1.0f, -0.317f, 0.0f, -0.065f, 0.843f, 1.0f,
- -0.321f, 0.0f, -0.085f, 0.86f, 1.0f, -0.326f, 0.0f, -0.106f, 0.879f, 1.0f,
- -0.33f, 0.0f, -0.127f, 0.897f, 1.0f, -0.335f, 0.0f, -0.148f, 0.915f, 1.0f,
- -0.339f, 0.0f, -0.168f, 0.932f, 1.0f, -0.344f, 0.0f, -0.189f, 0.947f, 1.0f,
- -0.348f, 0.0f, -0.21f, 0.962f, 1.0f, -0.353f, 0.0f, -0.23f, 0.974f, 1.0f,
- -0.357f, 0.0f, -0.25f, 0.985f, 1.0f, -0.361f, 0.0f, -0.27f, 0.995f, 1.0f,
- -0.365f, 0.0f, -0.29f, 1.004f, 1.0f, -0.369f, 0.0f, -0.309f, 1.011f, 1.0f,
- -0.372f, 0.0f, -0.328f, 1.018f, 1.0f, -0.375f, 0.0f, -0.347f, 1.024f, 1.0f,
- -0.377f, 0.0f, -0.365f, 1.029f, 1.0f, -0.379f, 0.0f, -0.383f, 1.033f, 1.0f,
- -0.38f, 0.0f, -0.4f, 1.036f, 1.0f, -0.38f, 0.0f, -0.417f, 1.037f, 1.0f,
- -0.38f, 0.0f, -0.434f, 1.037f, 1.0f, -0.379f, 0.0f, -0.449f, 1.035f, 1.0f,
- -0.377f, 0.0f, -0.464f, 1.032f, 1.0f, -0.374f, 0.0f, -0.478f, 1.029f, 1.0f,
- -0.371f, 0.0f, -0.491f, 1.026f, 1.0f, -0.366f, 0.0f, -0.503f, 1.023f, 1.0f,
- -0.361f, 0.0f, -0.513f, 1.021f, 1.0f, -0.354f, 0.0f, -0.523f, 1.019f, 1.0f,
- -0.347f, 0.0f, -0.531f, 1.017f, 1.0f, -0.339f, 0.0f, -0.538f, 1.016f, 1.0f,
- -0.33f, 0.0f, -0.543f, 1.016f, 1.0f, -0.32f, 0.0f, -0.547f, 1.016f, 1.0f,
- -0.31f, 0.0f, -0.549f, 1.016f, 1.0f, -0.298f, 0.0f, -0.55f, 1.017f, 1.0f,
- -0.286f, 0.0f, -0.55f, 1.017f, 1.0f, -0.274f, 0.0f, -0.548f, 1.018f, 1.0f,
- -0.261f, 0.0f, -0.544f, 1.017f, 1.0f, -0.247f, 0.0f, -0.539f, 1.017f, 1.0f,
- -0.232f, 0.0f, -0.533f, 1.016f, 1.0f, -0.218f, 0.0f, -0.525f, 1.015f, 1.0f,
- -0.202f, 0.0f, -0.515f, 1.013f, 1.0f, -0.186f, 0.0f, -0.503f, 1.009f, 1.0f,
- -0.169f, 0.0f, -0.49f, 1.005f, 1.0f, -0.151f, 0.0f, -0.475f, 0.998f, 1.0f,
- -0.132f, 0.0f, -0.458f, 0.99f, 1.0f, -0.112f, 0.0f, -0.44f, 0.98f, 1.0f,
- -0.091f, 0.0f, -0.42f, 0.968f, 1.0f, -0.069f, 0.0f, -0.398f, 0.955f, 1.0f,
- -0.045f, 0.0f, -0.375f, 0.939f, 1.0f, -0.021f, 0.0f, -0.35f, 0.923f, 1.0f,
- 0.005f, 0.0f, -0.324f, 0.908f, 1.0f, 0.031f, 0.0f, -0.297f, 0.895f, 1.0f,
- 0.06f, 0.0f, -0.268f, 0.882f, 1.0f, 0.089f, 0.0f, -0.238f, 0.87f, 1.0f,
- 0.12f, 0.0f, -0.207f, 0.858f, 1.0f, 0.153f, 0.0f, -0.175f, 0.844f, 1.0f,
- 0.187f, 0.0f, -0.14f, 0.828f, 1.0f, 0.224f, 0.0f, -0.104f, 0.81f, 1.0f,
- 0.262f, 0.0f, -0.067f, 0.79f, 1.0f, 0.302f, 0.0f, -0.027f, 0.769f, 1.0f,
- 0.344f, 0.0f, 0.014f, 0.747f, 1.0f, 0.388f, 0.0f, 0.056f, 0.724f, 1.0f,
- 0.434f, 0.0f, 0.1f, 0.7f, 1.0f, 0.483f, 0.0f, 0.145f, 0.676f, 1.0f,
- 0.533f, 0.0f, 0.191f, 0.651f, 1.0f, 0.585f, 0.0f, 0.238f, 0.625f, 1.0f,
- 0.637f, 0.0f, 0.284f, 0.599f, 1.0f, 0.69f, 0.0f, 0.33f, 0.573f, 1.0f,
- 0.746f, 0.0f, 0.376f, 0.546f, 1.0f, 0.802f, 0.0f, 0.421f, 0.516f, 1.0f,
- 0.859f, 0.0f, 0.464f, 0.483f, 1.0f, 0.915f, 0.0f, 0.506f, 0.446f, 1.0f,
- 0.97f, 0.0f, 0.545f, 0.407f, 1.0f, 1.023f, 0.0f, 0.581f, 0.365f, 1.0f,
- 1.075f, 0.0f, 0.614f, 0.322f, 1.0f, 1.122f, 0.0f, 0.643f, 0.28f, 1.0f,
- 1.169f, 0.0f, 0.671f, 0.236f, 1.0f, 1.207f, 0.0f, 0.693f, 0.202f, 1.0f,
- 1.264f, 0.0f, 0.725f, 0.155f, 1.0f,
+ -1.281f, 0.0f, -0.315f, 0.038f, 1.0f, -1.269f, 0.0f, -0.302f, 0.069f, 1.0f,
+ -1.261f, 0.0f, -0.293f, 0.089f, 1.0f, -1.251f, 0.0f, -0.282f, 0.112f, 1.0f,
+ -1.241f, 0.0f, -0.271f, 0.134f, 1.0f, -1.23f, 0.0f, -0.259f, 0.155f, 1.0f,
+ -1.219f, 0.0f, -0.247f, 0.175f, 1.0f, -1.208f, 0.0f, -0.234f, 0.194f, 1.0f,
+ -1.196f, 0.0f, -0.221f, 0.211f, 1.0f, -1.184f, 0.0f, -0.208f, 0.227f, 1.0f,
+ -1.172f, 0.0f, -0.194f, 0.242f, 1.0f, -1.159f, 0.0f, -0.18f, 0.256f, 1.0f,
+ -1.147f, 0.0f, -0.165f, 0.268f, 1.0f, -1.134f, 0.0f, -0.151f, 0.28f, 1.0f,
+ -1.121f, 0.0f, -0.136f, 0.29f, 1.0f, -1.108f, 0.0f, -0.121f, 0.299f, 1.0f,
+ -1.094f, 0.0f, -0.106f, 0.307f, 1.0f, -1.08f, 0.0f, -0.091f, 0.315f, 1.0f,
+ -1.066f, 0.0f, -0.076f, 0.322f, 1.0f, -1.052f, 0.0f, -0.061f, 0.329f, 1.0f,
+ -1.037f, 0.0f, -0.047f, 0.335f, 1.0f, -1.022f, 0.0f, -0.032f, 0.341f, 1.0f,
+ -1.007f, 0.0f, -0.017f, 0.346f, 1.0f, -0.991f, 0.0f, -0.003f, 0.351f, 1.0f,
+ -0.975f, 0.0f, 0.012f, 0.355f, 1.0f, -0.959f, 0.0f, 0.027f, 0.36f, 1.0f,
+ -0.942f, 0.0f, 0.041f, 0.364f, 1.0f, -0.926f, 0.0f, 0.056f, 0.368f, 1.0f,
+ -0.909f, 0.0f, 0.071f, 0.371f, 1.0f, -0.893f, 0.0f, 0.086f, 0.373f, 1.0f,
+ -0.876f, 0.0f, 0.1f, 0.376f, 1.0f, -0.859f, 0.0f, 0.115f, 0.377f, 1.0f,
+ -0.842f, 0.0f, 0.129f, 0.378f, 1.0f, -0.824f, 0.0f, 0.144f, 0.379f, 1.0f,
+ -0.807f, 0.0f, 0.158f, 0.379f, 1.0f, -0.79f, 0.0f, 0.172f, 0.379f, 1.0f,
+ -0.773f, 0.0f, 0.186f, 0.38f, 1.0f, -0.755f, 0.0f, 0.199f, 0.38f, 1.0f,
+ -0.738f, 0.0f, 0.212f, 0.381f, 1.0f, -0.721f, 0.0f, 0.224f, 0.382f, 1.0f,
+ -0.703f, 0.0f, 0.236f, 0.384f, 1.0f, -0.686f, 0.0f, 0.248f, 0.386f, 1.0f,
+ -0.67f, 0.0f, 0.26f, 0.388f, 1.0f, -0.653f, 0.0f, 0.27f, 0.39f, 1.0f,
+ -0.637f, 0.0f, 0.28f, 0.393f, 1.0f, -0.621f, 0.0f, 0.29f, 0.396f, 1.0f,
+ -0.605f, 0.0f, 0.298f, 0.399f, 1.0f, -0.589f, 0.0f, 0.306f, 0.403f, 1.0f,
+ -0.574f, 0.0f, 0.313f, 0.407f, 1.0f, -0.559f, 0.0f, 0.319f, 0.411f, 1.0f,
+ -0.544f, 0.0f, 0.325f, 0.415f, 1.0f, -0.53f, 0.0f, 0.331f, 0.42f, 1.0f,
+ -0.516f, 0.0f, 0.336f, 0.425f, 1.0f, -0.503f, 0.0f, 0.34f, 0.431f, 1.0f,
+ -0.489f, 0.0f, 0.344f, 0.437f, 1.0f, -0.477f, 0.0f, 0.347f, 0.443f, 1.0f,
+ -0.464f, 0.0f, 0.35f, 0.45f, 1.0f, -0.452f, 0.0f, 0.352f, 0.457f, 1.0f,
+ -0.44f, 0.0f, 0.354f, 0.464f, 1.0f, -0.429f, 0.0f, 0.355f, 0.471f, 1.0f,
+ -0.418f, 0.0f, 0.355f, 0.479f, 1.0f, -0.407f, 0.0f, 0.355f, 0.487f, 1.0f,
+ -0.397f, 0.0f, 0.354f, 0.495f, 1.0f, -0.387f, 0.0f, 0.353f, 0.503f, 1.0f,
+ -0.378f, 0.0f, 0.351f, 0.512f, 1.0f, -0.368f, 0.0f, 0.348f, 0.52f, 1.0f,
+ -0.36f, 0.0f, 0.344f, 0.528f, 1.0f, -0.351f, 0.0f, 0.34f, 0.537f, 1.0f,
+ -0.344f, 0.0f, 0.336f, 0.545f, 1.0f, -0.336f, 0.0f, 0.33f, 0.553f, 1.0f,
+ -0.329f, 0.0f, 0.324f, 0.562f, 1.0f, -0.322f, 0.0f, 0.318f, 0.57f, 1.0f,
+ -0.316f, 0.0f, 0.31f, 0.579f, 1.0f, -0.311f, 0.0f, 0.303f, 0.588f, 1.0f,
+ -0.306f, 0.0f, 0.294f, 0.597f, 1.0f, -0.301f, 0.0f, 0.285f, 0.606f, 1.0f,
+ -0.297f, 0.0f, 0.275f, 0.615f, 1.0f, -0.293f, 0.0f, 0.264f, 0.625f, 1.0f,
+ -0.29f, 0.0f, 0.253f, 0.635f, 1.0f, -0.288f, 0.0f, 0.241f, 0.644f, 1.0f,
+ -0.286f, 0.0f, 0.229f, 0.654f, 1.0f, -0.285f, 0.0f, 0.216f, 0.664f, 1.0f,
+ -0.284f, 0.0f, 0.202f, 0.675f, 1.0f, -0.283f, 0.0f, 0.188f, 0.685f, 1.0f,
+ -0.283f, 0.0f, 0.173f, 0.696f, 1.0f, -0.284f, 0.0f, 0.158f, 0.707f, 1.0f,
+ -0.285f, 0.0f, 0.142f, 0.718f, 1.0f, -0.286f, 0.0f, 0.125f, 0.729f, 1.0f,
+ -0.288f, 0.0f, 0.108f, 0.74f, 1.0f, -0.29f, 0.0f, 0.091f, 0.751f, 1.0f,
+ -0.293f, 0.0f, 0.073f, 0.761f, 1.0f, -0.295f, 0.0f, 0.054f, 0.772f, 1.0f,
+ -0.298f, 0.0f, 0.035f, 0.782f, 1.0f, -0.302f, 0.0f, 0.016f, 0.793f, 1.0f,
+ -0.305f, 0.0f, -0.004f, 0.804f, 1.0f, -0.309f, 0.0f, -0.024f, 0.815f, 1.0f,
+ -0.313f, 0.0f, -0.044f, 0.828f, 1.0f, -0.317f, 0.0f, -0.065f, 0.843f, 1.0f,
+ -0.321f, 0.0f, -0.085f, 0.86f, 1.0f, -0.326f, 0.0f, -0.106f, 0.879f, 1.0f,
+ -0.33f, 0.0f, -0.127f, 0.897f, 1.0f, -0.335f, 0.0f, -0.148f, 0.915f, 1.0f,
+ -0.339f, 0.0f, -0.168f, 0.932f, 1.0f, -0.344f, 0.0f, -0.189f, 0.947f, 1.0f,
+ -0.348f, 0.0f, -0.21f, 0.962f, 1.0f, -0.353f, 0.0f, -0.23f, 0.974f, 1.0f,
+ -0.357f, 0.0f, -0.25f, 0.985f, 1.0f, -0.361f, 0.0f, -0.27f, 0.995f, 1.0f,
+ -0.365f, 0.0f, -0.29f, 1.004f, 1.0f, -0.369f, 0.0f, -0.309f, 1.011f, 1.0f,
+ -0.372f, 0.0f, -0.328f, 1.018f, 1.0f, -0.375f, 0.0f, -0.347f, 1.024f, 1.0f,
+ -0.377f, 0.0f, -0.365f, 1.029f, 1.0f, -0.379f, 0.0f, -0.383f, 1.033f, 1.0f,
+ -0.38f, 0.0f, -0.4f, 1.036f, 1.0f, -0.38f, 0.0f, -0.417f, 1.037f, 1.0f,
+ -0.38f, 0.0f, -0.434f, 1.037f, 1.0f, -0.379f, 0.0f, -0.449f, 1.035f, 1.0f,
+ -0.377f, 0.0f, -0.464f, 1.032f, 1.0f, -0.374f, 0.0f, -0.478f, 1.029f, 1.0f,
+ -0.371f, 0.0f, -0.491f, 1.026f, 1.0f, -0.366f, 0.0f, -0.503f, 1.023f, 1.0f,
+ -0.361f, 0.0f, -0.513f, 1.021f, 1.0f, -0.354f, 0.0f, -0.523f, 1.019f, 1.0f,
+ -0.347f, 0.0f, -0.531f, 1.017f, 1.0f, -0.339f, 0.0f, -0.538f, 1.016f, 1.0f,
+ -0.33f, 0.0f, -0.543f, 1.016f, 1.0f, -0.32f, 0.0f, -0.547f, 1.016f, 1.0f,
+ -0.31f, 0.0f, -0.549f, 1.016f, 1.0f, -0.298f, 0.0f, -0.55f, 1.017f, 1.0f,
+ -0.286f, 0.0f, -0.55f, 1.017f, 1.0f, -0.274f, 0.0f, -0.548f, 1.018f, 1.0f,
+ -0.261f, 0.0f, -0.544f, 1.017f, 1.0f, -0.247f, 0.0f, -0.539f, 1.017f, 1.0f,
+ -0.232f, 0.0f, -0.533f, 1.016f, 1.0f, -0.218f, 0.0f, -0.525f, 1.015f, 1.0f,
+ -0.202f, 0.0f, -0.515f, 1.013f, 1.0f, -0.186f, 0.0f, -0.503f, 1.009f, 1.0f,
+ -0.169f, 0.0f, -0.49f, 1.005f, 1.0f, -0.151f, 0.0f, -0.475f, 0.998f, 1.0f,
+ -0.132f, 0.0f, -0.458f, 0.99f, 1.0f, -0.112f, 0.0f, -0.44f, 0.98f, 1.0f,
+ -0.091f, 0.0f, -0.42f, 0.968f, 1.0f, -0.069f, 0.0f, -0.398f, 0.955f, 1.0f,
+ -0.045f, 0.0f, -0.375f, 0.939f, 1.0f, -0.021f, 0.0f, -0.35f, 0.923f, 1.0f,
+ 0.005f, 0.0f, -0.324f, 0.908f, 1.0f, 0.031f, 0.0f, -0.297f, 0.895f, 1.0f,
+ 0.06f, 0.0f, -0.268f, 0.882f, 1.0f, 0.089f, 0.0f, -0.238f, 0.87f, 1.0f,
+ 0.12f, 0.0f, -0.207f, 0.858f, 1.0f, 0.153f, 0.0f, -0.175f, 0.844f, 1.0f,
+ 0.187f, 0.0f, -0.14f, 0.828f, 1.0f, 0.224f, 0.0f, -0.104f, 0.81f, 1.0f,
+ 0.262f, 0.0f, -0.067f, 0.79f, 1.0f, 0.302f, 0.0f, -0.027f, 0.769f, 1.0f,
+ 0.344f, 0.0f, 0.014f, 0.747f, 1.0f, 0.388f, 0.0f, 0.056f, 0.724f, 1.0f,
+ 0.434f, 0.0f, 0.1f, 0.7f, 1.0f, 0.483f, 0.0f, 0.145f, 0.676f, 1.0f,
+ 0.533f, 0.0f, 0.191f, 0.651f, 1.0f, 0.585f, 0.0f, 0.238f, 0.625f, 1.0f,
+ 0.637f, 0.0f, 0.284f, 0.599f, 1.0f, 0.69f, 0.0f, 0.33f, 0.573f, 1.0f,
+ 0.746f, 0.0f, 0.376f, 0.546f, 1.0f, 0.802f, 0.0f, 0.421f, 0.516f, 1.0f,
+ 0.859f, 0.0f, 0.464f, 0.483f, 1.0f, 0.915f, 0.0f, 0.506f, 0.446f, 1.0f,
+ 0.97f, 0.0f, 0.545f, 0.407f, 1.0f, 1.023f, 0.0f, 0.581f, 0.365f, 1.0f,
+ 1.075f, 0.0f, 0.614f, 0.322f, 1.0f, 1.122f, 0.0f, 0.643f, 0.28f, 1.0f,
+ 1.169f, 0.0f, 0.671f, 0.236f, 1.0f, 1.207f, 0.0f, 0.693f, 0.202f, 1.0f,
+ 1.264f, 0.0f, 0.725f, 0.155f, 1.0f,
};
/* ***************************************************************** */
/* Color Data */
static const ColorTemplate gp_stroke_material_black = {
- "Black",
- {0.0f, 0.0f, 0.0f, 1.0f},
- {0.0f, 0.0f, 0.0f, 0.0f},
+ "Black",
+ {0.0f, 0.0f, 0.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
};
static const ColorTemplate gp_stroke_material_white = {
- "White",
- {1.0f, 1.0f, 1.0f, 1.0f},
- {0.0f, 0.0f, 0.0f, 0.0f},
+ "White",
+ {1.0f, 1.0f, 1.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
};
static const ColorTemplate gp_stroke_material_red = {
- "Red",
- {1.0f, 0.0f, 0.0f, 1.0f},
- {0.0f, 0.0f, 0.0f, 0.0f},
+ "Red",
+ {1.0f, 0.0f, 0.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
};
static const ColorTemplate gp_stroke_material_green = {
- "Green",
- {0.0f, 1.0f, 0.0f, 1.0f},
- {0.0f, 0.0f, 0.0f, 0.0f},
+ "Green",
+ {0.0f, 1.0f, 0.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
};
static const ColorTemplate gp_stroke_material_blue = {
- "Blue",
- {0.0f, 0.0f, 1.0f, 1.0f},
- {0.0f, 0.0f, 0.0f, 0.0f},
+ "Blue",
+ {0.0f, 0.0f, 1.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
};
static const ColorTemplate gp_stroke_material_grey = {
- "Grey",
- {0.358f, 0.358f, 0.358f, 1.0f},
- {0.5f, 0.5f, 0.5f, 1.0f},
+ "Grey",
+ {0.358f, 0.358f, 0.358f, 1.0f},
+ {0.5f, 0.5f, 0.5f, 1.0f},
};
/* ***************************************************************** */
@@ -214,37 +213,37 @@ static const ColorTemplate gp_stroke_material_grey = {
/* add a Simple stroke with colors (original design created by Daniel M. Lara and Matias Mendiola) */
void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4])
{
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
- bGPdata *gpd = (bGPdata *)ob->data;
- bGPDstroke *gps;
-
- /* create colors */
- int color_black = gp_stroke_material(bmain, ob, &gp_stroke_material_black, false);
- gp_stroke_material(bmain, ob, &gp_stroke_material_white, false);
- gp_stroke_material(bmain, ob, &gp_stroke_material_red, false);
- gp_stroke_material(bmain, ob, &gp_stroke_material_green, false);
- gp_stroke_material(bmain, ob, &gp_stroke_material_blue, false);
- gp_stroke_material(bmain, ob, &gp_stroke_material_grey, true);
-
- /* set first color as active and in brushes */
- ob->actcol = color_black + 1;
-
- /* layers */
- bGPDlayer *colors = BKE_gpencil_layer_addnew(gpd, "Colors", false);
- bGPDlayer *lines = BKE_gpencil_layer_addnew(gpd, "Lines", true);
-
- /* frames */
- bGPDframe *frame_color = BKE_gpencil_frame_addnew(colors, cfra_eval);
- bGPDframe *frame_lines = BKE_gpencil_frame_addnew(lines, cfra_eval);
- UNUSED_VARS(frame_color);
-
- /* generate stroke */
- gps = BKE_gpencil_add_stroke(frame_lines, color_black, 175, 75);
- BKE_gpencil_stroke_add_points(gps, data0, 175, mat);
-
- /* update depsgraph */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDstroke *gps;
+
+ /* create colors */
+ int color_black = gp_stroke_material(bmain, ob, &gp_stroke_material_black, false);
+ gp_stroke_material(bmain, ob, &gp_stroke_material_white, false);
+ gp_stroke_material(bmain, ob, &gp_stroke_material_red, false);
+ gp_stroke_material(bmain, ob, &gp_stroke_material_green, false);
+ gp_stroke_material(bmain, ob, &gp_stroke_material_blue, false);
+ gp_stroke_material(bmain, ob, &gp_stroke_material_grey, true);
+
+ /* set first color as active and in brushes */
+ ob->actcol = color_black + 1;
+
+ /* layers */
+ bGPDlayer *colors = BKE_gpencil_layer_addnew(gpd, "Colors", false);
+ bGPDlayer *lines = BKE_gpencil_layer_addnew(gpd, "Lines", true);
+
+ /* frames */
+ bGPDframe *frame_color = BKE_gpencil_frame_addnew(colors, cfra_eval);
+ bGPDframe *frame_lines = BKE_gpencil_frame_addnew(lines, cfra_eval);
+ UNUSED_VARS(frame_color);
+
+ /* generate stroke */
+ gps = BKE_gpencil_add_stroke(frame_lines, color_black, 175, 75);
+ BKE_gpencil_stroke_add_points(gps, data0, 175, mat);
+
+ /* update depsgraph */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
}
diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c
index 8fff6b207ba..d99a630a45c 100644
--- a/source/blender/editors/gpencil/gpencil_armature.c
+++ b/source/blender/editors/gpencil/gpencil_armature.c
@@ -22,7 +22,6 @@
* \ingroup edgpencil
*/
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -69,609 +68,625 @@
#include "gpencil_intern.h"
enum {
- GP_ARMATURE_NAME = 0,
- GP_ARMATURE_AUTO = 1,
+ GP_ARMATURE_NAME = 0,
+ GP_ARMATURE_AUTO = 1,
};
#define DEFAULT_RATIO 0.10f
#define DEFAULT_DECAY 0.8f
-static int gpencil_bone_looper(
- Object *ob, Bone *bone, void *data,
- int(*bone_func)(Object *, Bone *, void *))
+static int gpencil_bone_looper(Object *ob,
+ Bone *bone,
+ void *data,
+ int (*bone_func)(Object *, Bone *, void *))
{
- /* We want to apply the function bone_func to every bone
- * in an armature -- feed bone_looper the first bone and
- * a pointer to the bone_func and watch it go!. The int count
- * can be useful for counting bones with a certain property
- * (e.g. skinnable)
- */
- int count = 0;
-
- if (bone) {
- /* only do bone_func if the bone is non null */
- count += bone_func(ob, bone, data);
-
- /* try to execute bone_func for the first child */
- count += gpencil_bone_looper(ob, bone->childbase.first, data, bone_func);
-
- /* try to execute bone_func for the next bone at this
- * depth of the recursion.
- */
- count += gpencil_bone_looper(ob, bone->next, data, bone_func);
- }
-
- return count;
+ /* We want to apply the function bone_func to every bone
+ * in an armature -- feed bone_looper the first bone and
+ * a pointer to the bone_func and watch it go!. The int count
+ * can be useful for counting bones with a certain property
+ * (e.g. skinnable)
+ */
+ int count = 0;
+
+ if (bone) {
+ /* only do bone_func if the bone is non null */
+ count += bone_func(ob, bone, data);
+
+ /* try to execute bone_func for the first child */
+ count += gpencil_bone_looper(ob, bone->childbase.first, data, bone_func);
+
+ /* try to execute bone_func for the next bone at this
+ * depth of the recursion.
+ */
+ count += gpencil_bone_looper(ob, bone->next, data, bone_func);
+ }
+
+ return count;
}
static int gpencil_bone_skinnable_cb(Object *UNUSED(ob), Bone *bone, void *datap)
{
- /* Bones that are deforming
- * are regarded to be "skinnable" and are eligible for
- * auto-skinning.
- *
- * This function performs 2 functions:
- *
- * a) It returns 1 if the bone is skinnable.
- * If we loop over all bones with this
- * function, we can count the number of
- * skinnable bones.
- * b) If the pointer data is non null,
- * it is treated like a handle to a
- * bone pointer -- the bone pointer
- * is set to point at this bone, and
- * the pointer the handle points to
- * is incremented to point to the
- * next member of an array of pointers
- * to bones. This way we can loop using
- * this function to construct an array of
- * pointers to bones that point to all
- * skinnable bones.
- */
- Bone ***hbone;
- int a, segments;
- struct { Object *armob; void *list; int heat;} *data = datap;
-
- if (!(bone->flag & BONE_HIDDEN_P)) {
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (data->heat && data->armob->pose &&
- BKE_pose_channel_find_name(data->armob->pose, bone->name))
- {
- segments = bone->segments;
- }
- else {
- segments = 1;
- }
-
- if (data->list != NULL) {
- hbone = (Bone ***)&data->list;
-
- for (a = 0; a < segments; a++) {
- **hbone = bone;
- (*hbone)++;
- }
- }
- return segments;
- }
- }
- return 0;
+ /* Bones that are deforming
+ * are regarded to be "skinnable" and are eligible for
+ * auto-skinning.
+ *
+ * This function performs 2 functions:
+ *
+ * a) It returns 1 if the bone is skinnable.
+ * If we loop over all bones with this
+ * function, we can count the number of
+ * skinnable bones.
+ * b) If the pointer data is non null,
+ * it is treated like a handle to a
+ * bone pointer -- the bone pointer
+ * is set to point at this bone, and
+ * the pointer the handle points to
+ * is incremented to point to the
+ * next member of an array of pointers
+ * to bones. This way we can loop using
+ * this function to construct an array of
+ * pointers to bones that point to all
+ * skinnable bones.
+ */
+ Bone ***hbone;
+ int a, segments;
+ struct {
+ Object *armob;
+ void *list;
+ int heat;
+ } *data = datap;
+
+ if (!(bone->flag & BONE_HIDDEN_P)) {
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (data->heat && data->armob->pose &&
+ BKE_pose_channel_find_name(data->armob->pose, bone->name)) {
+ segments = bone->segments;
+ }
+ else {
+ segments = 1;
+ }
+
+ if (data->list != NULL) {
+ hbone = (Bone ***)&data->list;
+
+ for (a = 0; a < segments; a++) {
+ **hbone = bone;
+ (*hbone)++;
+ }
+ }
+ return segments;
+ }
+ }
+ return 0;
}
static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
{
- /* This group creates a vertex group to ob that has the
- * same name as bone (provided the bone is skinnable).
- * If such a vertex group already exist the routine exits.
- */
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (!defgroup_find_name(ob, bone->name)) {
- BKE_object_defgroup_add_name(ob, bone->name);
- return 1;
- }
- }
- return 0;
+ /* This group creates a vertex group to ob that has the
+ * same name as bone (provided the bone is skinnable).
+ * If such a vertex group already exist the routine exits.
+ */
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (!defgroup_find_name(ob, bone->name)) {
+ BKE_object_defgroup_add_name(ob, bone->name);
+ return 1;
+ }
+ }
+ return 0;
}
static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
{
- /* Bones that are deforming
- * are regarded to be "skinnable" and are eligible for
- * auto-skinning.
- *
- * This function performs 2 functions:
- *
- * a) If the bone is skinnable, it creates
- * a vertex group for ob that has
- * the name of the skinnable bone
- * (if one doesn't exist already).
- * b) If the pointer data is non null,
- * it is treated like a handle to a
- * bDeformGroup pointer -- the
- * bDeformGroup pointer is set to point
- * to the deform group with the bone's
- * name, and the pointer the handle
- * points to is incremented to point to the
- * next member of an array of pointers
- * to bDeformGroups. This way we can loop using
- * this function to construct an array of
- * pointers to bDeformGroups, all with names
- * of skinnable bones.
- */
- bDeformGroup ***hgroup, *defgroup = NULL;
- int a, segments;
- struct { Object *armob; void *list; int heat; } *data = datap;
- bArmature *arm = data->armob->data;
-
- if (!(bone->flag & BONE_HIDDEN_P)) {
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (data->heat && data->armob->pose &&
- BKE_pose_channel_find_name(data->armob->pose, bone->name))
- {
- segments = bone->segments;
- }
- else {
- segments = 1;
- }
-
- if (arm->layer & bone->layer) {
- if (!(defgroup = defgroup_find_name(ob, bone->name))) {
- defgroup = BKE_object_defgroup_add_name(ob, bone->name);
- }
- else if (defgroup->flag & DG_LOCK_WEIGHT) {
- /* In case vgroup already exists and is locked, do not modify it here. See T43814. */
- defgroup = NULL;
- }
- }
-
- if (data->list != NULL) {
- hgroup = (bDeformGroup ***)&data->list;
-
- for (a = 0; a < segments; a++) {
- **hgroup = defgroup;
- (*hgroup)++;
- }
- }
- return segments;
- }
- }
- return 0;
+ /* Bones that are deforming
+ * are regarded to be "skinnable" and are eligible for
+ * auto-skinning.
+ *
+ * This function performs 2 functions:
+ *
+ * a) If the bone is skinnable, it creates
+ * a vertex group for ob that has
+ * the name of the skinnable bone
+ * (if one doesn't exist already).
+ * b) If the pointer data is non null,
+ * it is treated like a handle to a
+ * bDeformGroup pointer -- the
+ * bDeformGroup pointer is set to point
+ * to the deform group with the bone's
+ * name, and the pointer the handle
+ * points to is incremented to point to the
+ * next member of an array of pointers
+ * to bDeformGroups. This way we can loop using
+ * this function to construct an array of
+ * pointers to bDeformGroups, all with names
+ * of skinnable bones.
+ */
+ bDeformGroup ***hgroup, *defgroup = NULL;
+ int a, segments;
+ struct {
+ Object *armob;
+ void *list;
+ int heat;
+ } *data = datap;
+ bArmature *arm = data->armob->data;
+
+ if (!(bone->flag & BONE_HIDDEN_P)) {
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (data->heat && data->armob->pose &&
+ BKE_pose_channel_find_name(data->armob->pose, bone->name)) {
+ segments = bone->segments;
+ }
+ else {
+ segments = 1;
+ }
+
+ if (arm->layer & bone->layer) {
+ if (!(defgroup = defgroup_find_name(ob, bone->name))) {
+ defgroup = BKE_object_defgroup_add_name(ob, bone->name);
+ }
+ else if (defgroup->flag & DG_LOCK_WEIGHT) {
+ /* In case vgroup already exists and is locked, do not modify it here. See T43814. */
+ defgroup = NULL;
+ }
+ }
+
+ if (data->list != NULL) {
+ hgroup = (bDeformGroup ***)&data->list;
+
+ for (a = 0; a < segments; a++) {
+ **hgroup = defgroup;
+ (*hgroup)++;
+ }
+ }
+ return segments;
+ }
+ }
+ return 0;
}
/* get weight value depending of distance and decay value */
static float get_weight(float dist, float decay_rad, float dif_rad)
{
- float weight = 1.0f;
- if (dist < decay_rad) {
- weight = 1.0f;
- }
- else {
- weight = interpf(0.0f, 0.9f, (dist - decay_rad) / dif_rad);
- }
-
- return weight;
+ float weight = 1.0f;
+ if (dist < decay_rad) {
+ weight = 1.0f;
+ }
+ else {
+ weight = interpf(0.0f, 0.9f, (dist - decay_rad) / dif_rad);
+ }
+
+ return weight;
}
/* This functions implements the automatic computation of vertex group weights */
static void gpencil_add_verts_to_dgroups(
- const bContext *C, Object *ob, Object *ob_arm, const float ratio, const float decay)
+ const bContext *C, Object *ob, Object *ob_arm, const float ratio, const float decay)
{
- bArmature *arm = ob_arm->data;
- Bone **bonelist, *bone;
- bDeformGroup **dgrouplist;
- bPoseChannel *pchan;
- bGPdata *gpd = (bGPdata *)ob->data;
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
-
- Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL;
- float(*root)[3], (*tip)[3], (*verts)[3];
- float *radsqr;
- int *selected;
- float weight;
- int numbones, i, j, segments = 0;
- struct { Object *armob; void *list; int heat; } looper_data;
-
- looper_data.armob = ob_arm;
- looper_data.heat = true;
- looper_data.list = NULL;
-
- /* count the number of skinnable bones */
- numbones = gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, gpencil_bone_skinnable_cb);
-
- if (numbones == 0)
- return;
-
- /* create an array of pointer to bones that are skinnable
- * and fill it with all of the skinnable bones */
- bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist");
- looper_data.list = bonelist;
- gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, gpencil_bone_skinnable_cb);
-
- /* create an array of pointers to the deform groups that
- * correspond to the skinnable bones (creating them
- * as necessary. */
- dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist");
-
- looper_data.list = dgrouplist;
- gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb);
-
- /* create an array of root and tip positions transformed into
- * global coords */
- root = MEM_callocN(numbones * sizeof(float) * 3, "root");
- tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
- selected = MEM_callocN(numbones * sizeof(int), "selected");
- radsqr = MEM_callocN(numbones * sizeof(float), "radsqr");
-
- for (j = 0; j < numbones; j++) {
- bone = bonelist[j];
-
- /* handle bbone */
- if (segments == 0) {
- segments = 1;
- bbone = NULL;
-
- if ((ob_arm->pose) &&
- (pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name)))
- {
- if (bone->segments > 1) {
- segments = bone->segments;
- BKE_pchan_bbone_spline_setup(pchan, true, false, bbone_array);
- bbone = bbone_array;
- }
- }
- }
-
- segments--;
-
- /* compute root and tip */
- if (bbone) {
- mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
- if ((segments + 1) < bone->segments) {
- mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
- }
- else {
- copy_v3_v3(tip[j], bone->arm_tail);
- }
- }
- else {
- copy_v3_v3(root[j], bone->arm_head);
- copy_v3_v3(tip[j], bone->arm_tail);
- }
-
- mul_m4_v3(ob_arm->obmat, root[j]);
- mul_m4_v3(ob_arm->obmat, tip[j]);
-
- selected[j] = 1;
-
- /* calculate radius squared */
- radsqr[j] = len_squared_v3v3(root[j], tip[j]) * ratio;
- }
-
- /* loop all strokes */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- bGPDframe *init_gpf = gpl->actframe;
- bGPDspoint *pt = NULL;
-
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) ||
- ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit)))
- {
-
- if (gpf == NULL)
- continue;
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- BKE_gpencil_dvert_ensure(gps);
-
- /* create verts array */
- verts = MEM_callocN(gps->totpoints * sizeof(*verts), __func__);
-
- /* transform stroke points to global space */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- copy_v3_v3(verts[i], &pt->x);
- mul_m4_v3(ob->obmat, verts[i]);
- }
-
- /* loop groups and assign weight */
- for (j = 0; j < numbones; j++) {
- int def_nr = BLI_findindex(&ob->defbase, dgrouplist[j]);
- if (def_nr < 0) {
- continue;
- }
-
- float decay_rad = radsqr[j] - (radsqr[j] * decay);
- float dif_rad = radsqr[j] - decay_rad;
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- MDeformVert *dvert = &gps->dvert[i];
- float dist = dist_squared_to_line_segment_v3(verts[i], root[j], tip[j]);
- if (dist > radsqr[j]) {
- /* if not in cylinder, check if inside extreme spheres */
- weight = 0.0f;
- dist = len_squared_v3v3(root[j], verts[i]);
- if (dist < radsqr[j]) {
- weight = get_weight(dist, decay_rad, dif_rad);
- }
- else {
- dist = len_squared_v3v3(tip[j], verts[i]);
- if (dist < radsqr[j]) {
- weight = get_weight(dist, decay_rad, dif_rad);
- }
- }
- }
- else {
- /* inside bone cylinder */
- weight = get_weight(dist, decay_rad, dif_rad);
- }
-
- /* assign weight */
- MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
- if (dw) {
- dw->weight = weight;
- }
- }
- }
- MEM_SAFE_FREE(verts);
- }
- }
-
- /* if not multiedit, exit loop*/
- if (!is_multiedit) {
- break;
- }
- }
- }
-
- /* free the memory allocated */
- MEM_SAFE_FREE(bonelist);
- MEM_SAFE_FREE(dgrouplist);
- MEM_SAFE_FREE(root);
- MEM_SAFE_FREE(tip);
- MEM_SAFE_FREE(radsqr);
- MEM_SAFE_FREE(selected);
+ bArmature *arm = ob_arm->data;
+ Bone **bonelist, *bone;
+ bDeformGroup **dgrouplist;
+ bPoseChannel *pchan;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
+ Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL;
+ float(*root)[3], (*tip)[3], (*verts)[3];
+ float *radsqr;
+ int *selected;
+ float weight;
+ int numbones, i, j, segments = 0;
+ struct {
+ Object *armob;
+ void *list;
+ int heat;
+ } looper_data;
+
+ looper_data.armob = ob_arm;
+ looper_data.heat = true;
+ looper_data.list = NULL;
+
+ /* count the number of skinnable bones */
+ numbones = gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, gpencil_bone_skinnable_cb);
+
+ if (numbones == 0)
+ return;
+
+ /* create an array of pointer to bones that are skinnable
+ * and fill it with all of the skinnable bones */
+ bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist");
+ looper_data.list = bonelist;
+ gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, gpencil_bone_skinnable_cb);
+
+ /* create an array of pointers to the deform groups that
+ * correspond to the skinnable bones (creating them
+ * as necessary. */
+ dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist");
+
+ looper_data.list = dgrouplist;
+ gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb);
+
+ /* create an array of root and tip positions transformed into
+ * global coords */
+ root = MEM_callocN(numbones * sizeof(float) * 3, "root");
+ tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
+ selected = MEM_callocN(numbones * sizeof(int), "selected");
+ radsqr = MEM_callocN(numbones * sizeof(float), "radsqr");
+
+ for (j = 0; j < numbones; j++) {
+ bone = bonelist[j];
+
+ /* handle bbone */
+ if (segments == 0) {
+ segments = 1;
+ bbone = NULL;
+
+ if ((ob_arm->pose) && (pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name))) {
+ if (bone->segments > 1) {
+ segments = bone->segments;
+ BKE_pchan_bbone_spline_setup(pchan, true, false, bbone_array);
+ bbone = bbone_array;
+ }
+ }
+ }
+
+ segments--;
+
+ /* compute root and tip */
+ if (bbone) {
+ mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
+ if ((segments + 1) < bone->segments) {
+ mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
+ }
+ else {
+ copy_v3_v3(tip[j], bone->arm_tail);
+ }
+ }
+ else {
+ copy_v3_v3(root[j], bone->arm_head);
+ copy_v3_v3(tip[j], bone->arm_tail);
+ }
+
+ mul_m4_v3(ob_arm->obmat, root[j]);
+ mul_m4_v3(ob_arm->obmat, tip[j]);
+
+ selected[j] = 1;
+
+ /* calculate radius squared */
+ radsqr[j] = len_squared_v3v3(root[j], tip[j]) * ratio;
+ }
+
+ /* loop all strokes */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *init_gpf = gpl->actframe;
+ bGPDspoint *pt = NULL;
+
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ BKE_gpencil_dvert_ensure(gps);
+
+ /* create verts array */
+ verts = MEM_callocN(gps->totpoints * sizeof(*verts), __func__);
+
+ /* transform stroke points to global space */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ copy_v3_v3(verts[i], &pt->x);
+ mul_m4_v3(ob->obmat, verts[i]);
+ }
+
+ /* loop groups and assign weight */
+ for (j = 0; j < numbones; j++) {
+ int def_nr = BLI_findindex(&ob->defbase, dgrouplist[j]);
+ if (def_nr < 0) {
+ continue;
+ }
+
+ float decay_rad = radsqr[j] - (radsqr[j] * decay);
+ float dif_rad = radsqr[j] - decay_rad;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ float dist = dist_squared_to_line_segment_v3(verts[i], root[j], tip[j]);
+ if (dist > radsqr[j]) {
+ /* if not in cylinder, check if inside extreme spheres */
+ weight = 0.0f;
+ dist = len_squared_v3v3(root[j], verts[i]);
+ if (dist < radsqr[j]) {
+ weight = get_weight(dist, decay_rad, dif_rad);
+ }
+ else {
+ dist = len_squared_v3v3(tip[j], verts[i]);
+ if (dist < radsqr[j]) {
+ weight = get_weight(dist, decay_rad, dif_rad);
+ }
+ }
+ }
+ else {
+ /* inside bone cylinder */
+ weight = get_weight(dist, decay_rad, dif_rad);
+ }
+
+ /* assign weight */
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = weight;
+ }
+ }
+ }
+ MEM_SAFE_FREE(verts);
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+
+ /* free the memory allocated */
+ MEM_SAFE_FREE(bonelist);
+ MEM_SAFE_FREE(dgrouplist);
+ MEM_SAFE_FREE(root);
+ MEM_SAFE_FREE(tip);
+ MEM_SAFE_FREE(radsqr);
+ MEM_SAFE_FREE(selected);
}
-static void gpencil_object_vgroup_calc_from_armature(
- const bContext *C,
- Object *ob, Object *ob_arm,
- const int mode, const float ratio, const float decay)
+static void gpencil_object_vgroup_calc_from_armature(const bContext *C,
+ Object *ob,
+ Object *ob_arm,
+ const int mode,
+ const float ratio,
+ const float decay)
{
- /* Lets try to create some vertex groups
- * based on the bones of the parent armature.
- */
- bArmature *arm = ob_arm->data;
-
- /* always create groups */
- const int defbase_tot = BLI_listbase_count(&ob->defbase);
- int defbase_add;
- /* Traverse the bone list, trying to create empty vertex
- * groups corresponding to the bone.
- */
- defbase_add = gpencil_bone_looper(
- ob, arm->bonebase.first, NULL,
- vgroup_add_unique_bone_cb);
-
- if (defbase_add) {
- /* its possible there are DWeight's outside the range of the current
- * objects deform groups, in this case the new groups wont be empty */
- ED_vgroup_data_clamp_range(ob->data, defbase_tot);
- }
-
- if (mode == GP_ARMATURE_AUTO) {
- /* Traverse the bone list, trying to fill vertex groups
- * with the corresponding vertice weights for which the
- * bone is closest.
- */
- gpencil_add_verts_to_dgroups(
- C, ob, ob_arm,
- ratio, decay);
- }
+ /* Lets try to create some vertex groups
+ * based on the bones of the parent armature.
+ */
+ bArmature *arm = ob_arm->data;
+
+ /* always create groups */
+ const int defbase_tot = BLI_listbase_count(&ob->defbase);
+ int defbase_add;
+ /* Traverse the bone list, trying to create empty vertex
+ * groups corresponding to the bone.
+ */
+ defbase_add = gpencil_bone_looper(ob, arm->bonebase.first, NULL, vgroup_add_unique_bone_cb);
+
+ if (defbase_add) {
+ /* its possible there are DWeight's outside the range of the current
+ * objects deform groups, in this case the new groups wont be empty */
+ ED_vgroup_data_clamp_range(ob->data, defbase_tot);
+ }
+
+ if (mode == GP_ARMATURE_AUTO) {
+ /* Traverse the bone list, trying to fill vertex groups
+ * with the corresponding vertice weights for which the
+ * bone is closest.
+ */
+ gpencil_add_verts_to_dgroups(C, ob, ob_arm, ratio, decay);
+ }
}
bool ED_gpencil_add_armature_weights(
- const bContext *C, ReportList *reports,
- Object *ob, Object *ob_arm, int mode)
+ const bContext *C, ReportList *reports, Object *ob, Object *ob_arm, int mode)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
-
- if (ob == NULL) {
- return false;
- }
-
- /* if no armature modifier, add a new one */
- GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob, eGpencilModifierType_Armature);
- if (md == NULL) {
- md = ED_object_gpencil_modifier_add(
- reports, bmain, scene,
- ob, "Armature", eGpencilModifierType_Armature);
- if (md == NULL) {
- BKE_report(reports, RPT_ERROR,
- "Unable to add a new Armature modifier to object");
- return false;
- }
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- }
-
- /* verify armature */
- ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
- if (mmd->object == NULL) {
- mmd->object = ob_arm;
- }
- else {
- if (ob_arm != mmd->object) {
- BKE_report(reports, RPT_ERROR,
- "The existing Armature modifier is already using a different Armature object");
- return false;
- }
- }
-
- /* add weights */
- gpencil_object_vgroup_calc_from_armature(C, ob, ob_arm, mode, DEFAULT_RATIO, DEFAULT_DECAY);
-
- return true;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ if (ob == NULL) {
+ return false;
+ }
+
+ /* if no armature modifier, add a new one */
+ GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob, eGpencilModifierType_Armature);
+ if (md == NULL) {
+ md = ED_object_gpencil_modifier_add(
+ reports, bmain, scene, ob, "Armature", eGpencilModifierType_Armature);
+ if (md == NULL) {
+ BKE_report(reports, RPT_ERROR, "Unable to add a new Armature modifier to object");
+ return false;
+ }
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+
+ /* verify armature */
+ ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
+ if (mmd->object == NULL) {
+ mmd->object = ob_arm;
+ }
+ else {
+ if (ob_arm != mmd->object) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "The existing Armature modifier is already using a different Armature object");
+ return false;
+ }
+ }
+
+ /* add weights */
+ gpencil_object_vgroup_calc_from_armature(C, ob, ob_arm, mode, DEFAULT_RATIO, DEFAULT_DECAY);
+
+ return true;
}
/* ***************** Generate armature weights ************************** */
static bool gpencil_generate_weights_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- if (ob == NULL) {
- return false;
- }
+ if (ob == NULL) {
+ return false;
+ }
- if (ob->type != OB_GPENCIL) {
- return false;
- }
+ if (ob->type != OB_GPENCIL) {
+ return false;
+ }
- ViewLayer *view_layer = CTX_data_view_layer(C);
- bGPdata *gpd = (bGPdata *)ob->data;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
- if (BLI_listbase_count(&gpd->layers) == 0) {
- return false;
- }
+ if (BLI_listbase_count(&gpd->layers) == 0) {
+ return false;
+ }
- /* need some armature in the view layer */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if (base->object->type == OB_ARMATURE) {
- return true;
- }
- }
+ /* need some armature in the view layer */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object->type == OB_ARMATURE) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
static int gpencil_generate_weights_exec(bContext *C, wmOperator *op)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = CTX_data_active_object(C);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- bGPdata *gpd = (bGPdata *)ob->data;
- Object *ob_arm = NULL;
-
- const int mode = RNA_enum_get(op->ptr, "mode");
- const float ratio = RNA_float_get(op->ptr, "ratio");
- const float decay = RNA_float_get(op->ptr, "decay");
-
- /* sanity checks */
- if (ELEM(NULL, ob, gpd))
- return OPERATOR_CANCELLED;
-
- /* get armature */
- const int arm_idx = RNA_enum_get(op->ptr, "armature");
- if (arm_idx > 0) {
- Base *base = BLI_findlink(&view_layer->object_bases, arm_idx - 1);
- ob_arm = base->object;
- }
- else {
- /* get armature from modifier */
- GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob_eval, eGpencilModifierType_Armature);
- if (md == NULL) {
- BKE_report(op->reports, RPT_ERROR,
- "The grease pencil object need an Armature modifier");
- return OPERATOR_CANCELLED;
- }
-
- ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
- if (mmd->object == NULL) {
- BKE_report(op->reports, RPT_ERROR,
- "Armature modifier is not valid or wrong defined");
- return OPERATOR_CANCELLED;
- }
-
- ob_arm = mmd->object;
- }
-
- if (ob_arm == NULL) {
- BKE_report(op->reports, RPT_ERROR,
- "No Armature object in the view layer");
- return OPERATOR_CANCELLED;
- }
-
- gpencil_object_vgroup_calc_from_armature(C, ob, ob_arm, mode, ratio, decay);
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = CTX_data_active_object(C);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ Object *ob_arm = NULL;
+
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ const float ratio = RNA_float_get(op->ptr, "ratio");
+ const float decay = RNA_float_get(op->ptr, "decay");
+
+ /* sanity checks */
+ if (ELEM(NULL, ob, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* get armature */
+ const int arm_idx = RNA_enum_get(op->ptr, "armature");
+ if (arm_idx > 0) {
+ Base *base = BLI_findlink(&view_layer->object_bases, arm_idx - 1);
+ ob_arm = base->object;
+ }
+ else {
+ /* get armature from modifier */
+ GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob_eval,
+ eGpencilModifierType_Armature);
+ if (md == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "The grease pencil object need an Armature modifier");
+ return OPERATOR_CANCELLED;
+ }
+
+ ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
+ if (mmd->object == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Armature modifier is not valid or wrong defined");
+ return OPERATOR_CANCELLED;
+ }
+
+ ob_arm = mmd->object;
+ }
+
+ if (ob_arm == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Armature object in the view layer");
+ return OPERATOR_CANCELLED;
+ }
+
+ gpencil_object_vgroup_calc_from_armature(C, ob, ob_arm, mode, ratio, decay);
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
/* Dynamically populate an enum of Armatures */
-static const EnumPropertyItem *gpencil_armatures_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+static const EnumPropertyItem *gpencil_armatures_enum_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- EnumPropertyItem *item = NULL, item_tmp = { 0 };
- int totitem = 0;
- int i = 0;
-
- if (C == NULL) {
- return DummyRNA_DEFAULT_items;
- }
-
- /* add default */
- item_tmp.identifier = "DEFAULT";
- item_tmp.name = "Default";
- item_tmp.value = 0;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- i++;
-
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- Object *ob = base->object;
- if (ob->type == OB_ARMATURE) {
- item_tmp.identifier = item_tmp.name = ob->id.name + 2;
- item_tmp.value = i;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
- i++;
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+
+ if (C == NULL) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* add default */
+ item_tmp.identifier = "DEFAULT";
+ item_tmp.name = "Default";
+ item_tmp.value = 0;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ i++;
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ if (ob->type == OB_ARMATURE) {
+ item_tmp.identifier = item_tmp.name = ob->id.name + 2;
+ item_tmp.value = i;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+ i++;
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
}
void GPENCIL_OT_generate_weights(wmOperatorType *ot)
{
- static const EnumPropertyItem mode_type[] = {
- {GP_ARMATURE_NAME, "NAME", 0, "Empty Groups", ""},
- {GP_ARMATURE_AUTO, "AUTO", 0, "Automatic Weights", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Generate Automatic Weights";
- ot->idname = "GPENCIL_OT_generate_weights";
- ot->description = "Generate automatic weights for armatures (requires armature modifier)";
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* callbacks */
- ot->exec = gpencil_generate_weights_exec;
- ot->poll = gpencil_generate_weights_poll;
-
- ot->prop = RNA_def_enum(ot->srna, "mode", mode_type, 0, "Mode", "");
-
- prop = RNA_def_enum(ot->srna, "armature", DummyRNA_DEFAULT_items, 0, "Armature", "Armature to use");
- RNA_def_enum_funcs(prop, gpencil_armatures_enum_itemf);
-
- RNA_def_float(
- ot->srna, "ratio", DEFAULT_RATIO, 0.0f, 2.0f, "Ratio",
- "Ratio between bone length and influence radius", 0.001f, 1.0f);
-
- RNA_def_float(
- ot->srna, "decay", DEFAULT_DECAY, 0.0f, 1.0f, "Decay",
- "Factor to reduce influence depending of distance to bone axis", 0.0f, 1.0f);
+ static const EnumPropertyItem mode_type[] = {
+ {GP_ARMATURE_NAME, "NAME", 0, "Empty Groups", ""},
+ {GP_ARMATURE_AUTO, "AUTO", 0, "Automatic Weights", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Generate Automatic Weights";
+ ot->idname = "GPENCIL_OT_generate_weights";
+ ot->description = "Generate automatic weights for armatures (requires armature modifier)";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gpencil_generate_weights_exec;
+ ot->poll = gpencil_generate_weights_poll;
+
+ ot->prop = RNA_def_enum(ot->srna, "mode", mode_type, 0, "Mode", "");
+
+ prop = RNA_def_enum(
+ ot->srna, "armature", DummyRNA_DEFAULT_items, 0, "Armature", "Armature to use");
+ RNA_def_enum_funcs(prop, gpencil_armatures_enum_itemf);
+
+ RNA_def_float(ot->srna,
+ "ratio",
+ DEFAULT_RATIO,
+ 0.0f,
+ 2.0f,
+ "Ratio",
+ "Ratio between bone length and influence radius",
+ 0.001f,
+ 1.0f);
+
+ RNA_def_float(ot->srna,
+ "decay",
+ DEFAULT_DECAY,
+ 0.0f,
+ 1.0f,
+ "Decay",
+ "Factor to reduce influence depending of distance to bone axis",
+ 0.0f,
+ 1.0f);
}
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 8f64ec1c868..ef0ebd06d07 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -22,7 +22,6 @@
* \ingroup edgpencil
*/
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -86,145 +85,133 @@
/* Context for brush operators */
typedef struct tGP_BrushEditData {
- /* Current editor/region/etc. */
- /* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */
- Depsgraph *depsgraph;
- Scene *scene;
- Object *object;
-
- ScrArea *sa;
- ARegion *ar;
-
- /* Current GPencil datablock */
- bGPdata *gpd;
+ /* Current editor/region/etc. */
+ /* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */
+ Depsgraph *depsgraph;
+ Scene *scene;
+ Object *object;
- /* Brush Settings */
- GP_Sculpt_Settings *settings;
- GP_Sculpt_Data *gp_brush;
- GP_Sculpt_Data *gp_brush_old;
+ ScrArea *sa;
+ ARegion *ar;
- eGP_Sculpt_Types brush_type;
- eGP_Sculpt_Types brush_type_old;
- eGP_Sculpt_Flag flag;
+ /* Current GPencil datablock */
+ bGPdata *gpd;
- /* Space Conversion Data */
- GP_SpaceConversion gsc;
+ /* Brush Settings */
+ GP_Sculpt_Settings *settings;
+ GP_Sculpt_Data *gp_brush;
+ GP_Sculpt_Data *gp_brush_old;
+ eGP_Sculpt_Types brush_type;
+ eGP_Sculpt_Types brush_type_old;
+ eGP_Sculpt_Flag flag;
- /* Is the brush currently painting? */
- bool is_painting;
- bool is_weight_mode;
+ /* Space Conversion Data */
+ GP_SpaceConversion gsc;
- /* Start of new sculpt stroke */
- bool first;
+ /* Is the brush currently painting? */
+ bool is_painting;
+ bool is_weight_mode;
- /* Is multiframe editing enabled, and are we using falloff for that? */
- bool is_multiframe;
- bool use_multiframe_falloff;
+ /* Start of new sculpt stroke */
+ bool first;
- /* Current frame */
- int cfra;
+ /* Is multiframe editing enabled, and are we using falloff for that? */
+ bool is_multiframe;
+ bool use_multiframe_falloff;
+ /* Current frame */
+ int cfra;
- /* Brush Runtime Data: */
- /* - position and pressure
- * - the *_prev variants are the previous values
- */
- float mval[2], mval_prev[2];
- float pressure, pressure_prev;
+ /* Brush Runtime Data: */
+ /* - position and pressure
+ * - the *_prev variants are the previous values
+ */
+ float mval[2], mval_prev[2];
+ float pressure, pressure_prev;
- /* - effect vector (e.g. 2D/3D translation for grab brush) */
- float dvec[3];
+ /* - effect vector (e.g. 2D/3D translation for grab brush) */
+ float dvec[3];
- /* - multiframe falloff factor */
- float mf_falloff;
+ /* - multiframe falloff factor */
+ float mf_falloff;
- /* active vertex group */
- int vrgroup;
+ /* active vertex group */
+ int vrgroup;
+ /* brush geometry (bounding box) */
+ rcti brush_rect;
- /* brush geometry (bounding box) */
- rcti brush_rect;
+ /* Custom data for certain brushes */
+ /* - map from bGPDstroke's to structs containing custom data about those strokes */
+ GHash *stroke_customdata;
+ /* - general customdata */
+ void *customdata;
- /* Custom data for certain brushes */
- /* - map from bGPDstroke's to structs containing custom data about those strokes */
- GHash *stroke_customdata;
- /* - general customdata */
- void *customdata;
+ /* Timer for in-place accumulation of brush effect */
+ wmTimer *timer;
+ bool timerTick; /* is this event from a timer */
-
- /* Timer for in-place accumulation of brush effect */
- wmTimer *timer;
- bool timerTick; /* is this event from a timer */
-
- RNG *rng;
+ RNG *rng;
} tGP_BrushEditData;
-
/* Callback for performing some brush operation on a single point */
typedef bool (*GP_BrushApplyCb)(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2]);
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2]);
/* ************************************************ */
/* Utility Functions */
/* apply lock axis reset */
-static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso, bGPDspoint *pt, const float save_pt[3])
+static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso,
+ bGPDspoint *pt,
+ const float save_pt[3])
{
- if (gso->sa->spacetype != SPACE_VIEW3D) {
- return;
- }
-
- const ToolSettings *ts = gso->scene->toolsettings;
- const View3DCursor *cursor = &gso->scene->cursor;
- const int axis = ts->gp_sculpt.lock_axis;
-
- /* lock axis control */
- switch (axis) {
- case GP_LOCKAXIS_X:
- {
- pt->x = save_pt[0];
- break;
- }
- case GP_LOCKAXIS_Y:
- {
- pt->y = save_pt[1];
- break;
- }
- case GP_LOCKAXIS_Z:
- {
- pt->z = save_pt[2];
- break;
- }
- case GP_LOCKAXIS_CURSOR:
- {
- /* compute a plane with cursor normal and position of the point
- before do the sculpt */
- const float scale[3] = { 1.0f, 1.0f, 1.0f };
- float plane_normal[3] = { 0.0f, 0.0f, 1.0f };
- float plane[4];
- float mat[4][4];
- float r_close[3];
-
- loc_eul_size_to_mat4(mat,
- cursor->location,
- cursor->rotation_euler,
- scale);
-
- mul_mat3_m4_v3(mat, plane_normal);
- plane_from_point_normal_v3(plane, save_pt, plane_normal);
-
- /* find closest point to the plane with the new position */
- closest_to_plane_v3(r_close, plane, &pt->x);
- copy_v3_v3(&pt->x, r_close);
- break;
- }
- default:
- {
- break;
- }
- }
+ if (gso->sa->spacetype != SPACE_VIEW3D) {
+ return;
+ }
+
+ const ToolSettings *ts = gso->scene->toolsettings;
+ const View3DCursor *cursor = &gso->scene->cursor;
+ const int axis = ts->gp_sculpt.lock_axis;
+
+ /* lock axis control */
+ switch (axis) {
+ case GP_LOCKAXIS_X: {
+ pt->x = save_pt[0];
+ break;
+ }
+ case GP_LOCKAXIS_Y: {
+ pt->y = save_pt[1];
+ break;
+ }
+ case GP_LOCKAXIS_Z: {
+ pt->z = save_pt[2];
+ break;
+ }
+ case GP_LOCKAXIS_CURSOR: {
+ /* compute a plane with cursor normal and position of the point
+ before do the sculpt */
+ const float scale[3] = {1.0f, 1.0f, 1.0f};
+ float plane_normal[3] = {0.0f, 0.0f, 1.0f};
+ float plane[4];
+ float mat[4][4];
+ float r_close[3];
+
+ loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, scale);
+
+ mul_mat3_m4_v3(mat, plane_normal);
+ plane_from_point_normal_v3(plane, save_pt, plane_normal);
+
+ /* find closest point to the plane with the new position */
+ closest_to_plane_v3(r_close, plane, &pt->x);
+ copy_v3_v3(&pt->x, r_close);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
}
/* Context ---------------------------------------- */
@@ -232,22 +219,22 @@ static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso, bGPDspoint *pt, c
/* Get the sculpting settings */
static GP_Sculpt_Settings *gpsculpt_get_settings(Scene *scene)
{
- return &scene->toolsettings->gp_sculpt;
+ return &scene->toolsettings->gp_sculpt;
}
/* Get the active brush */
static GP_Sculpt_Data *gpsculpt_get_brush(Scene *scene, bool is_weight_mode)
{
- GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
- GP_Sculpt_Data *gp_brush = NULL;
- if (is_weight_mode) {
- gp_brush = &gset->brush[gset->weighttype];
- }
- else {
- gp_brush = &gset->brush[gset->brushtype];
- }
-
- return gp_brush;
+ GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
+ GP_Sculpt_Data *gp_brush = NULL;
+ if (is_weight_mode) {
+ gp_brush = &gset->brush[gset->weighttype];
+ }
+ else {
+ gp_brush = &gset->brush[gset->brushtype];
+ }
+
+ return gp_brush;
}
/* Brush Operations ------------------------------- */
@@ -255,56 +242,56 @@ static GP_Sculpt_Data *gpsculpt_get_brush(Scene *scene, bool is_weight_mode)
/* Invert behavior of brush? */
static bool gp_brush_invert_check(tGP_BrushEditData *gso)
{
- /* The basic setting is the brush's setting (from the panel) */
- bool invert = ((gso->gp_brush->flag & GP_SCULPT_FLAG_INVERT) != 0);
-
- /* During runtime, the user can hold down the Ctrl key to invert the basic behavior */
- if (gso->flag & GP_SCULPT_FLAG_INVERT) {
- invert ^= true;
- }
-
- /* set temporary status */
- if (invert) {
- gso->gp_brush->flag |= GP_SCULPT_FLAG_TMP_INVERT;
- }
- else {
- gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
- }
-
- return invert;
+ /* The basic setting is the brush's setting (from the panel) */
+ bool invert = ((gso->gp_brush->flag & GP_SCULPT_FLAG_INVERT) != 0);
+
+ /* During runtime, the user can hold down the Ctrl key to invert the basic behavior */
+ if (gso->flag & GP_SCULPT_FLAG_INVERT) {
+ invert ^= true;
+ }
+
+ /* set temporary status */
+ if (invert) {
+ gso->gp_brush->flag |= GP_SCULPT_FLAG_TMP_INVERT;
+ }
+ else {
+ gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
+ }
+
+ return invert;
}
/* Compute strength of effect */
static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, const int co[2])
{
- GP_Sculpt_Data *gp_brush = gso->gp_brush;
+ GP_Sculpt_Data *gp_brush = gso->gp_brush;
- /* basic strength factor from brush settings */
- float influence = gp_brush->strength;
+ /* basic strength factor from brush settings */
+ float influence = gp_brush->strength;
- /* use pressure? */
- if (gp_brush->flag & GP_SCULPT_FLAG_USE_PRESSURE) {
- influence *= gso->pressure;
- }
+ /* use pressure? */
+ if (gp_brush->flag & GP_SCULPT_FLAG_USE_PRESSURE) {
+ influence *= gso->pressure;
+ }
- /* distance fading */
- if (gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
- int mval_i[2];
- round_v2i_v2fl(mval_i, gso->mval);
- float distance = (float)len_v2v2_int(mval_i, co);
- float fac;
+ /* distance fading */
+ if (gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, gso->mval);
+ float distance = (float)len_v2v2_int(mval_i, co);
+ float fac;
- CLAMP(distance, 0.0f, (float)radius);
- fac = 1.0f - (distance / (float)radius);
+ CLAMP(distance, 0.0f, (float)radius);
+ fac = 1.0f - (distance / (float)radius);
- influence *= fac;
- }
+ influence *= fac;
+ }
- /* apply multiframe falloff */
- influence *= gso->mf_falloff;
+ /* apply multiframe falloff */
+ influence *= gso->mf_falloff;
- /* return influence */
- return influence;
+ /* return influence */
+ return influence;
}
/* ************************************************ */
@@ -318,38 +305,34 @@ static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, c
/* A simple (but slower + inaccurate) smooth-brush implementation to test the algorithm for stroke smoothing */
static bool gp_brush_smooth_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- // GP_Sculpt_Data *gp_brush = gso->brush;
- float inf = gp_brush_influence_calc(gso, radius, co);
- /* need one flag enabled by default */
- if ((gso->settings->flag &
- (GP_SCULPT_SETT_FLAG_APPLY_POSITION |
- GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
- GP_SCULPT_SETT_FLAG_APPLY_THICKNESS |
- GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0)
- {
- gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
- }
-
- /* perform smoothing */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
- BKE_gpencil_smooth_stroke(gps, pt_index, inf);
- }
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
- BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
- }
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
- BKE_gpencil_smooth_stroke_thickness(gps, pt_index, inf);
- }
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
- BKE_gpencil_smooth_stroke_uv(gps, pt_index, inf);
- }
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- return true;
+ // GP_Sculpt_Data *gp_brush = gso->brush;
+ float inf = gp_brush_influence_calc(gso, radius, co);
+ /* need one flag enabled by default */
+ if ((gso->settings->flag &
+ (GP_SCULPT_SETT_FLAG_APPLY_POSITION | GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
+ GP_SCULPT_SETT_FLAG_APPLY_THICKNESS | GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0) {
+ gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
+ }
+
+ /* perform smoothing */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
+ BKE_gpencil_smooth_stroke(gps, pt_index, inf);
+ }
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
+ BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
+ }
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
+ BKE_gpencil_smooth_stroke_thickness(gps, pt_index, inf);
+ }
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
+ BKE_gpencil_smooth_stroke_uv(gps, pt_index, inf);
+ }
+
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ return true;
}
/* ----------------------------------------------- */
@@ -357,77 +340,73 @@ static bool gp_brush_smooth_apply(
/* Make lines thicker or thinner by the specified amounts */
static bool gp_brush_thickness_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + pt_index;
- float inf;
-
- /* Compute strength of effect
- * - We divide the strength by 10, so that users can set "sane" values.
- * Otherwise, good default values are in the range of 0.093
- */
- inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
-
- /* apply */
- // XXX: this is much too strong, and it should probably do some smoothing with the surrounding stuff
- if (gp_brush_invert_check(gso)) {
- /* make line thinner - reduce stroke pressure */
- pt->pressure -= inf;
- }
- else {
- /* make line thicker - increase stroke pressure */
- pt->pressure += inf;
- }
-
- /* Pressure should stay within [0.0, 1.0]
- * However, it is nice for volumetric strokes to be able to exceed
- * the upper end of this range. Therefore, we don't actually clamp
- * down on the upper end.
- */
- if (pt->pressure < 0.0f)
- pt->pressure = 0.0f;
-
- return true;
+ bGPDspoint *pt = gps->points + pt_index;
+ float inf;
+
+ /* Compute strength of effect
+ * - We divide the strength by 10, so that users can set "sane" values.
+ * Otherwise, good default values are in the range of 0.093
+ */
+ inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
+
+ /* apply */
+ // XXX: this is much too strong, and it should probably do some smoothing with the surrounding stuff
+ if (gp_brush_invert_check(gso)) {
+ /* make line thinner - reduce stroke pressure */
+ pt->pressure -= inf;
+ }
+ else {
+ /* make line thicker - increase stroke pressure */
+ pt->pressure += inf;
+ }
+
+ /* Pressure should stay within [0.0, 1.0]
+ * However, it is nice for volumetric strokes to be able to exceed
+ * the upper end of this range. Therefore, we don't actually clamp
+ * down on the upper end.
+ */
+ if (pt->pressure < 0.0f)
+ pt->pressure = 0.0f;
+
+ return true;
}
-
/* ----------------------------------------------- */
/* Color Strength Brush */
/* Make color more or less transparent by the specified amounts */
static bool gp_brush_strength_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + pt_index;
- float inf;
-
- /* Compute strength of effect
- * - We divide the strength, so that users can set "sane" values.
- * Otherwise, good default values are in the range of 0.093
- */
- inf = gp_brush_influence_calc(gso, radius, co) / 20.0f;
-
- /* apply */
- if (gp_brush_invert_check(gso)) {
- /* make line more transparent - reduce alpha factor */
- pt->strength -= inf;
- }
- else {
- /* make line more opaque - increase stroke strength */
- pt->strength += inf;
- }
- /* smooth the strength */
- BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
-
- /* Strength should stay within [0.0, 1.0] */
- CLAMP(pt->strength, 0.0f, 1.0f);
-
- return true;
+ bGPDspoint *pt = gps->points + pt_index;
+ float inf;
+
+ /* Compute strength of effect
+ * - We divide the strength, so that users can set "sane" values.
+ * Otherwise, good default values are in the range of 0.093
+ */
+ inf = gp_brush_influence_calc(gso, radius, co) / 20.0f;
+
+ /* apply */
+ if (gp_brush_invert_check(gso)) {
+ /* make line more transparent - reduce alpha factor */
+ pt->strength -= inf;
+ }
+ else {
+ /* make line more opaque - increase stroke strength */
+ pt->strength += inf;
+ }
+ /* smooth the strength */
+ BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
+
+ /* Strength should stay within [0.0, 1.0] */
+ CLAMP(pt->strength, 0.0f, 1.0f);
+
+ return true;
}
-
/* ----------------------------------------------- */
/* Grab Brush */
@@ -438,145 +417,145 @@ static bool gp_brush_strength_apply(
* the brush region.
*/
typedef struct tGPSB_Grab_StrokeData {
- /* array of indices to corresponding points in the stroke */
- int *points;
- /* array of influence weights for each of the included points */
- float *weights;
-
- /* capacity of the arrays */
- int capacity;
- /* actual number of items currently stored */
- int size;
+ /* array of indices to corresponding points in the stroke */
+ int *points;
+ /* array of influence weights for each of the included points */
+ float *weights;
+
+ /* capacity of the arrays */
+ int capacity;
+ /* actual number of items currently stored */
+ int size;
} tGPSB_Grab_StrokeData;
/* initialise custom data for handling this stroke */
static void gp_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps)
{
- tGPSB_Grab_StrokeData *data = NULL;
+ tGPSB_Grab_StrokeData *data = NULL;
- BLI_assert(gps->totpoints > 0);
+ BLI_assert(gps->totpoints > 0);
- /* Check if there are buffers already (from a prior run) */
- if (BLI_ghash_haskey(gso->stroke_customdata, gps)) {
- /* Ensure that the caches are empty
- * - Since we reuse these between different strokes, we don't
- * want the previous invocation's data polluting the arrays
- */
- data = BLI_ghash_lookup(gso->stroke_customdata, gps);
- BLI_assert(data != NULL);
+ /* Check if there are buffers already (from a prior run) */
+ if (BLI_ghash_haskey(gso->stroke_customdata, gps)) {
+ /* Ensure that the caches are empty
+ * - Since we reuse these between different strokes, we don't
+ * want the previous invocation's data polluting the arrays
+ */
+ data = BLI_ghash_lookup(gso->stroke_customdata, gps);
+ BLI_assert(data != NULL);
- data->size = 0; /* minimum requirement - so that we can repopulate again */
+ data->size = 0; /* minimum requirement - so that we can repopulate again */
- memset(data->points, 0, sizeof(int) * data->capacity);
- memset(data->weights, 0, sizeof(float) * data->capacity);
- }
- else {
- /* Create new instance */
- data = MEM_callocN(sizeof(tGPSB_Grab_StrokeData), "GP Stroke Grab Data");
+ memset(data->points, 0, sizeof(int) * data->capacity);
+ memset(data->weights, 0, sizeof(float) * data->capacity);
+ }
+ else {
+ /* Create new instance */
+ data = MEM_callocN(sizeof(tGPSB_Grab_StrokeData), "GP Stroke Grab Data");
- data->capacity = gps->totpoints;
- data->size = 0;
+ data->capacity = gps->totpoints;
+ data->size = 0;
- data->points = MEM_callocN(sizeof(int) * data->capacity, "GP Stroke Grab Indices");
- data->weights = MEM_callocN(sizeof(float) * data->capacity, "GP Stroke Grab Weights");
+ data->points = MEM_callocN(sizeof(int) * data->capacity, "GP Stroke Grab Indices");
+ data->weights = MEM_callocN(sizeof(float) * data->capacity, "GP Stroke Grab Weights");
- /* hook up to the cache */
- BLI_ghash_insert(gso->stroke_customdata, gps, data);
- }
+ /* hook up to the cache */
+ BLI_ghash_insert(gso->stroke_customdata, gps, data);
+ }
}
/* store references to stroke points in the initial stage */
static bool gp_brush_grab_store_points(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
- float inf = gp_brush_influence_calc(gso, radius, co);
+ tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
+ float inf = gp_brush_influence_calc(gso, radius, co);
- BLI_assert(data != NULL);
- BLI_assert(data->size < data->capacity);
+ BLI_assert(data != NULL);
+ BLI_assert(data->size < data->capacity);
- /* insert this point into the set of affected points */
- data->points[data->size] = pt_index;
- data->weights[data->size] = inf;
- data->size++;
+ /* insert this point into the set of affected points */
+ data->points[data->size] = pt_index;
+ data->weights[data->size] = inf;
+ data->size++;
- /* done */
- return true;
+ /* done */
+ return true;
}
/* Compute effect vector for grab brush */
static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
{
- /* Convert mouse-movements to movement vector */
- // TODO: incorporate pressure into this?
- // XXX: screen-space strokes in 3D space will suffer!
- if (gso->sa->spacetype == SPACE_VIEW3D) {
- RegionView3D *rv3d = gso->ar->regiondata;
- float *rvec = gso->scene->cursor.location;
- float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
-
- float mval_f[2];
-
- /* convert from 2D screenspace to 3D... */
- mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
- mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
-
- ED_view3d_win_to_delta(gso->ar, mval_f, gso->dvec, zfac);
- }
- else {
- /* 2D - just copy */
- // XXX: view2d?
- gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
- gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
- gso->dvec[2] = 0.0f; /* unused */
- }
+ /* Convert mouse-movements to movement vector */
+ // TODO: incorporate pressure into this?
+ // XXX: screen-space strokes in 3D space will suffer!
+ if (gso->sa->spacetype == SPACE_VIEW3D) {
+ RegionView3D *rv3d = gso->ar->regiondata;
+ float *rvec = gso->scene->cursor.location;
+ float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
+
+ float mval_f[2];
+
+ /* convert from 2D screenspace to 3D... */
+ mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+
+ ED_view3d_win_to_delta(gso->ar, mval_f, gso->dvec, zfac);
+ }
+ else {
+ /* 2D - just copy */
+ // XXX: view2d?
+ gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+ gso->dvec[2] = 0.0f; /* unused */
+ }
}
/* Apply grab transform to all relevant points of the affected strokes */
-static void gp_brush_grab_apply_cached(
- tGP_BrushEditData *gso, bGPDstroke *gps, float diff_mat[4][4])
+static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso,
+ bGPDstroke *gps,
+ float diff_mat[4][4])
{
- tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
- int i;
-
- /* Apply dvec to all of the stored points */
- for (i = 0; i < data->size; i++) {
- bGPDspoint *pt = &gps->points[data->points[i]];
- float delta[3] = {0.0f};
-
- /* adjust the amount of displacement to apply */
- mul_v3_v3fl(delta, gso->dvec, data->weights[i]);
-
- float fpt[3];
- float save_pt[3];
- copy_v3_v3(save_pt, &pt->x);
- /* apply transformation */
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- /* apply */
- add_v3_v3v3(&pt->x, fpt, delta);
- /* undo transformation to the init parent position */
- float inverse_diff_mat[4][4];
- invert_m4_m4(inverse_diff_mat, diff_mat);
- mul_m4_v3(inverse_diff_mat, &pt->x);
-
- /* compute lock axis */
- gpsculpt_compute_lock_axis(gso, pt, save_pt);
- }
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
+ int i;
+
+ /* Apply dvec to all of the stored points */
+ for (i = 0; i < data->size; i++) {
+ bGPDspoint *pt = &gps->points[data->points[i]];
+ float delta[3] = {0.0f};
+
+ /* adjust the amount of displacement to apply */
+ mul_v3_v3fl(delta, gso->dvec, data->weights[i]);
+
+ float fpt[3];
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
+ /* apply transformation */
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* apply */
+ add_v3_v3v3(&pt->x, fpt, delta);
+ /* undo transformation to the init parent position */
+ float inverse_diff_mat[4][4];
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+ mul_m4_v3(inverse_diff_mat, &pt->x);
+
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
+ }
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
}
/* free customdata used for handling this stroke */
static void gp_brush_grab_stroke_free(void *ptr)
{
- tGPSB_Grab_StrokeData *data = (tGPSB_Grab_StrokeData *)ptr;
+ tGPSB_Grab_StrokeData *data = (tGPSB_Grab_StrokeData *)ptr;
- /* free arrays */
- MEM_freeN(data->points);
- MEM_freeN(data->weights);
+ /* free arrays */
+ MEM_freeN(data->points);
+ MEM_freeN(data->weights);
- /* ... and this item itself, since it was also allocated */
- MEM_freeN(data);
+ /* ... and this item itself, since it was also allocated */
+ MEM_freeN(data);
}
/* ----------------------------------------------- */
@@ -584,29 +563,28 @@ static void gp_brush_grab_stroke_free(void *ptr)
/* NOTE: Depends on gp_brush_grab_calc_dvec() */
static bool gp_brush_push_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + pt_index;
- float save_pt[3];
- copy_v3_v3(save_pt, &pt->x);
+ bGPDspoint *pt = gps->points + pt_index;
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
- float inf = gp_brush_influence_calc(gso, radius, co);
- float delta[3] = {0.0f};
+ float inf = gp_brush_influence_calc(gso, radius, co);
+ float delta[3] = {0.0f};
- /* adjust the amount of displacement to apply */
- mul_v3_v3fl(delta, gso->dvec, inf);
+ /* adjust the amount of displacement to apply */
+ mul_v3_v3fl(delta, gso->dvec, inf);
- /* apply */
- add_v3_v3(&pt->x, delta);
+ /* apply */
+ add_v3_v3(&pt->x, delta);
- /* compute lock axis */
- gpsculpt_compute_lock_axis(gso, pt, save_pt);
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- /* done */
- return true;
+ /* done */
+ return true;
}
/* ----------------------------------------------- */
@@ -615,84 +593,83 @@ static bool gp_brush_push_apply(
/* Compute reference midpoint for the brush - this is what we'll be moving towards */
static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
{
- if (gso->sa->spacetype == SPACE_VIEW3D) {
- /* Convert mouse position to 3D space
- * See: gpencil_paint.c :: gp_stroke_convertcoords()
- */
- RegionView3D *rv3d = gso->ar->regiondata;
- const float *rvec = gso->scene->cursor.location;
- float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
-
- float mval_f[2];
- copy_v2_v2(mval_f, gso->mval);
- float mval_prj[2];
- float dvec[3];
-
-
- if (ED_view3d_project_float_global(gso->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- sub_v2_v2v2(mval_f, mval_prj, mval_f);
- ED_view3d_win_to_delta(gso->ar, mval_f, dvec, zfac);
- sub_v3_v3v3(gso->dvec, rvec, dvec);
- }
- else {
- zero_v3(gso->dvec);
- }
- }
- else {
- /* Just 2D coordinates */
- // XXX: fix View2D offsets later
- gso->dvec[0] = (float)gso->mval[0];
- gso->dvec[1] = (float)gso->mval[1];
- gso->dvec[2] = 0.0f;
- }
+ if (gso->sa->spacetype == SPACE_VIEW3D) {
+ /* Convert mouse position to 3D space
+ * See: gpencil_paint.c :: gp_stroke_convertcoords()
+ */
+ RegionView3D *rv3d = gso->ar->regiondata;
+ const float *rvec = gso->scene->cursor.location;
+ float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
+
+ float mval_f[2];
+ copy_v2_v2(mval_f, gso->mval);
+ float mval_prj[2];
+ float dvec[3];
+
+ if (ED_view3d_project_float_global(gso->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
+ V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval_f);
+ ED_view3d_win_to_delta(gso->ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(gso->dvec, rvec, dvec);
+ }
+ else {
+ zero_v3(gso->dvec);
+ }
+ }
+ else {
+ /* Just 2D coordinates */
+ // XXX: fix View2D offsets later
+ gso->dvec[0] = (float)gso->mval[0];
+ gso->dvec[1] = (float)gso->mval[1];
+ gso->dvec[2] = 0.0f;
+ }
}
/* Shrink distance between midpoint and this point... */
static bool gp_brush_pinch_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + pt_index;
- float fac, inf;
- float vec[3];
- float save_pt[3];
- copy_v3_v3(save_pt, &pt->x);
-
- /* Scale down standard influence value to get it more manageable...
- * - No damping = Unmanageable at > 0.5 strength
- * - Div 10 = Not enough effect
- * - Div 5 = Happy medium... (by trial and error)
- */
- inf = gp_brush_influence_calc(gso, radius, co) / 5.0f;
-
- /* 1) Make this point relative to the cursor/midpoint (dvec) */
- sub_v3_v3v3(vec, &pt->x, gso->dvec);
-
- /* 2) Shrink the distance by pulling the point towards the midpoint
- * (0.0 = at midpoint, 1 = at edge of brush region)
- * OR
- * Increase the distance (if inverting the brush action!)
- */
- if (gp_brush_invert_check(gso)) {
- /* Inflate (inverse) */
- fac = 1.0f + (inf * inf); /* squared to temper the effect... */
- }
- else {
- /* Shrink (default) */
- fac = 1.0f - (inf * inf); /* squared to temper the effect... */
- }
- mul_v3_fl(vec, fac);
-
- /* 3) Translate back to original space, with the shrinkage applied */
- add_v3_v3v3(&pt->x, gso->dvec, vec);
-
- /* compute lock axis */
- gpsculpt_compute_lock_axis(gso, pt, save_pt);
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* done */
- return true;
+ bGPDspoint *pt = gps->points + pt_index;
+ float fac, inf;
+ float vec[3];
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
+
+ /* Scale down standard influence value to get it more manageable...
+ * - No damping = Unmanageable at > 0.5 strength
+ * - Div 10 = Not enough effect
+ * - Div 5 = Happy medium... (by trial and error)
+ */
+ inf = gp_brush_influence_calc(gso, radius, co) / 5.0f;
+
+ /* 1) Make this point relative to the cursor/midpoint (dvec) */
+ sub_v3_v3v3(vec, &pt->x, gso->dvec);
+
+ /* 2) Shrink the distance by pulling the point towards the midpoint
+ * (0.0 = at midpoint, 1 = at edge of brush region)
+ * OR
+ * Increase the distance (if inverting the brush action!)
+ */
+ if (gp_brush_invert_check(gso)) {
+ /* Inflate (inverse) */
+ fac = 1.0f + (inf * inf); /* squared to temper the effect... */
+ }
+ else {
+ /* Shrink (default) */
+ fac = 1.0f - (inf * inf); /* squared to temper the effect... */
+ }
+ mul_v3_fl(vec, fac);
+
+ /* 3) Translate back to original space, with the shrinkage applied */
+ add_v3_v3v3(&pt->x, gso->dvec, vec);
+
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
+
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* done */
+ return true;
}
/* ----------------------------------------------- */
@@ -703,268 +680,259 @@ static bool gp_brush_pinch_apply(
*/
static bool gp_brush_twist_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + pt_index;
- float angle, inf;
- float save_pt[3];
- copy_v3_v3(save_pt, &pt->x);
-
- /* Angle to rotate by */
- inf = gp_brush_influence_calc(gso, radius, co);
- angle = DEG2RADF(1.0f) * inf;
-
- if (gp_brush_invert_check(gso)) {
- /* invert angle that we rotate by */
- angle *= -1;
- }
-
- /* Rotate in 2D or 3D space? */
- if (gps->flag & GP_STROKE_3DSPACE) {
- /* Perform rotation in 3D space... */
- RegionView3D *rv3d = gso->ar->regiondata;
- float rmat[3][3];
- float axis[3];
- float vec[3];
-
- /* Compute rotation matrix - rotate around view vector by angle */
- negate_v3_v3(axis, rv3d->persinv[2]);
- normalize_v3(axis);
-
- axis_angle_normalized_to_mat3(rmat, axis, angle);
-
- /* Rotate point (no matrix-space transforms needed, as GP points are in world space) */
- sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center
- * (center is stored in dvec) */
- mul_m3_v3(rmat, vec);
- add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */
-
- /* compute lock axis */
- gpsculpt_compute_lock_axis(gso, pt, save_pt);
- }
- else {
- const float axis[3] = {0.0f, 0.0f, 1.0f};
- float vec[3] = {0.0f};
- float rmat[3][3];
-
- /* Express position of point relative to cursor, ready to rotate */
- // XXX: There is still some offset here, but it's close to working as expected...
- vec[0] = (float)(co[0] - gso->mval[0]);
- vec[1] = (float)(co[1] - gso->mval[1]);
-
- /* rotate point */
- axis_angle_normalized_to_mat3(rmat, axis, angle);
- mul_m3_v3(rmat, vec);
-
- /* Convert back to screen-coordinates */
- vec[0] += (float)gso->mval[0];
- vec[1] += (float)gso->mval[1];
-
- /* Map from screen-coordinates to final coordinate space */
- if (gps->flag & GP_STROKE_2DSPACE) {
- View2D *v2d = gso->gsc.v2d;
- UI_view2d_region_to_view(v2d, vec[0], vec[1], &pt->x, &pt->y);
- }
- else {
- // XXX
- copy_v2_v2(&pt->x, vec);
- }
- }
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* done */
- return true;
+ bGPDspoint *pt = gps->points + pt_index;
+ float angle, inf;
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
+
+ /* Angle to rotate by */
+ inf = gp_brush_influence_calc(gso, radius, co);
+ angle = DEG2RADF(1.0f) * inf;
+
+ if (gp_brush_invert_check(gso)) {
+ /* invert angle that we rotate by */
+ angle *= -1;
+ }
+
+ /* Rotate in 2D or 3D space? */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* Perform rotation in 3D space... */
+ RegionView3D *rv3d = gso->ar->regiondata;
+ float rmat[3][3];
+ float axis[3];
+ float vec[3];
+
+ /* Compute rotation matrix - rotate around view vector by angle */
+ negate_v3_v3(axis, rv3d->persinv[2]);
+ normalize_v3(axis);
+
+ axis_angle_normalized_to_mat3(rmat, axis, angle);
+
+ /* Rotate point (no matrix-space transforms needed, as GP points are in world space) */
+ sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center
+ * (center is stored in dvec) */
+ mul_m3_v3(rmat, vec);
+ add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */
+
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
+ }
+ else {
+ const float axis[3] = {0.0f, 0.0f, 1.0f};
+ float vec[3] = {0.0f};
+ float rmat[3][3];
+
+ /* Express position of point relative to cursor, ready to rotate */
+ // XXX: There is still some offset here, but it's close to working as expected...
+ vec[0] = (float)(co[0] - gso->mval[0]);
+ vec[1] = (float)(co[1] - gso->mval[1]);
+
+ /* rotate point */
+ axis_angle_normalized_to_mat3(rmat, axis, angle);
+ mul_m3_v3(rmat, vec);
+
+ /* Convert back to screen-coordinates */
+ vec[0] += (float)gso->mval[0];
+ vec[1] += (float)gso->mval[1];
+
+ /* Map from screen-coordinates to final coordinate space */
+ if (gps->flag & GP_STROKE_2DSPACE) {
+ View2D *v2d = gso->gsc.v2d;
+ UI_view2d_region_to_view(v2d, vec[0], vec[1], &pt->x, &pt->y);
+ }
+ else {
+ // XXX
+ copy_v2_v2(&pt->x, vec);
+ }
+ }
+
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* done */
+ return true;
}
-
/* ----------------------------------------------- */
/* Randomize Brush */
/* Apply some random jitter to the point */
static bool gp_brush_randomize_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + pt_index;
- float save_pt[3];
- copy_v3_v3(save_pt, &pt->x);
-
- /* Amount of jitter to apply depends on the distance of the point to the cursor,
- * as well as the strength of the brush
- */
- const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f;
- const float fac = BLI_rng_get_float(gso->rng) * inf;
- /* need one flag enabled by default */
- if ((gso->settings->flag &
- (GP_SCULPT_SETT_FLAG_APPLY_POSITION |
- GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
- GP_SCULPT_SETT_FLAG_APPLY_THICKNESS |
- GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0)
- {
- gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
- }
-
- /* apply random to position */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
- /* Jitter is applied perpendicular to the mouse movement vector
- * - We compute all effects in screenspace (since it's easier)
- * and then project these to get the points/distances in
- * view-space as needed.
- */
- float mvec[2], svec[2];
-
- /* mouse movement in ints -> floats */
- mvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
- mvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
-
- /* rotate mvec by 90 degrees... */
- svec[0] = -mvec[1];
- svec[1] = mvec[0];
-
- /* scale the displacement by the random displacement, and apply */
- if (BLI_rng_get_float(gso->rng) > 0.5f) {
- mul_v2_fl(svec, -fac);
- }
- else {
- mul_v2_fl(svec, fac);
- }
-
- //printf("%f %f (%f), nco = {%f %f}, co = %d %d\n", svec[0], svec[1], fac, nco[0], nco[1], co[0], co[1]);
-
- /* convert to dataspace */
- if (gps->flag & GP_STROKE_3DSPACE) {
- /* 3D: Project to 3D space */
- if (gso->sa->spacetype == SPACE_VIEW3D) {
- bool flip;
- RegionView3D *rv3d = gso->ar->regiondata;
- float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
- if (flip == false) {
- float dvec[3];
- ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac);
- add_v3_v3(&pt->x, dvec);
- /* compute lock axis */
- gpsculpt_compute_lock_axis(gso, pt, save_pt);
- }
- }
- else {
- /* ERROR */
- BLI_assert(!"3D stroke being sculpted in non-3D view");
- }
- }
- else {
- /* 2D: As-is */
- // XXX: v2d scaling/offset?
- float nco[2];
- nco[0] = (float)co[0] + svec[0];
- nco[1] = (float)co[1] + svec[1];
-
- copy_v2_v2(&pt->x, nco);
- }
- }
- /* apply random to strength */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
- if (BLI_rng_get_float(gso->rng) > 0.5f) {
- pt->strength += fac;
- }
- else {
- pt->strength -= fac;
- }
- CLAMP_MIN(pt->strength, 0.0f);
- CLAMP_MAX(pt->strength, 1.0f);
- }
- /* apply random to thickness (use pressure) */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
- if (BLI_rng_get_float(gso->rng) > 0.5f) {
- pt->pressure += fac;
- }
- else {
- pt->pressure -= fac;
- }
- /* only limit lower value */
- CLAMP_MIN(pt->pressure, 0.0f);
- }
- /* apply random to UV (use pressure) */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
- if (BLI_rng_get_float(gso->rng) > 0.5f) {
- pt->uv_rot += fac;
- }
- else {
- pt->uv_rot -= fac;
- }
- CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
- }
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* done */
- return true;
+ bGPDspoint *pt = gps->points + pt_index;
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
+
+ /* Amount of jitter to apply depends on the distance of the point to the cursor,
+ * as well as the strength of the brush
+ */
+ const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f;
+ const float fac = BLI_rng_get_float(gso->rng) * inf;
+ /* need one flag enabled by default */
+ if ((gso->settings->flag &
+ (GP_SCULPT_SETT_FLAG_APPLY_POSITION | GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
+ GP_SCULPT_SETT_FLAG_APPLY_THICKNESS | GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0) {
+ gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
+ }
+
+ /* apply random to position */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
+ /* Jitter is applied perpendicular to the mouse movement vector
+ * - We compute all effects in screenspace (since it's easier)
+ * and then project these to get the points/distances in
+ * view-space as needed.
+ */
+ float mvec[2], svec[2];
+
+ /* mouse movement in ints -> floats */
+ mvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ mvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+
+ /* rotate mvec by 90 degrees... */
+ svec[0] = -mvec[1];
+ svec[1] = mvec[0];
+
+ /* scale the displacement by the random displacement, and apply */
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
+ mul_v2_fl(svec, -fac);
+ }
+ else {
+ mul_v2_fl(svec, fac);
+ }
+
+ //printf("%f %f (%f), nco = {%f %f}, co = %d %d\n", svec[0], svec[1], fac, nco[0], nco[1], co[0], co[1]);
+
+ /* convert to dataspace */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* 3D: Project to 3D space */
+ if (gso->sa->spacetype == SPACE_VIEW3D) {
+ bool flip;
+ RegionView3D *rv3d = gso->ar->regiondata;
+ float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
+ if (flip == false) {
+ float dvec[3];
+ ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac);
+ add_v3_v3(&pt->x, dvec);
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
+ }
+ }
+ else {
+ /* ERROR */
+ BLI_assert(!"3D stroke being sculpted in non-3D view");
+ }
+ }
+ else {
+ /* 2D: As-is */
+ // XXX: v2d scaling/offset?
+ float nco[2];
+ nco[0] = (float)co[0] + svec[0];
+ nco[1] = (float)co[1] + svec[1];
+
+ copy_v2_v2(&pt->x, nco);
+ }
+ }
+ /* apply random to strength */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
+ pt->strength += fac;
+ }
+ else {
+ pt->strength -= fac;
+ }
+ CLAMP_MIN(pt->strength, 0.0f);
+ CLAMP_MAX(pt->strength, 1.0f);
+ }
+ /* apply random to thickness (use pressure) */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
+ pt->pressure += fac;
+ }
+ else {
+ pt->pressure -= fac;
+ }
+ /* only limit lower value */
+ CLAMP_MIN(pt->pressure, 0.0f);
+ }
+ /* apply random to UV (use pressure) */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
+ pt->uv_rot += fac;
+ }
+ else {
+ pt->uv_rot -= fac;
+ }
+ CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
+ }
+
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* done */
+ return true;
}
/* Weight Paint Brush */
/* Change weight paint for vertex groups */
static bool gp_brush_weight_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- /* create dvert */
- BKE_gpencil_dvert_ensure(gps);
-
- bGPDspoint *pt = gps->points + pt_index;
- MDeformVert *dvert = gps->dvert + pt_index;
- float inf;
-
- /* Compute strength of effect
- * - We divide the strength by 10, so that users can set "sane" values.
- * Otherwise, good default values are in the range of 0.093
- */
- inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
-
- /* need a vertex group */
- if (gso->vrgroup == -1) {
- if (gso->object) {
- BKE_object_defgroup_add(gso->object);
- gso->vrgroup = 0;
- }
- }
- else {
- bDeformGroup *defgroup = BLI_findlink(&gso->object->defbase, gso->vrgroup);
- if (defgroup->flag & DG_LOCK_WEIGHT) {
- return false;
- }
- }
- /* get current weight */
- MDeformWeight *dw = defvert_verify_index(dvert, gso->vrgroup);
- float curweight = dw ? dw->weight : 0.0f;
-
- if (gp_brush_invert_check(gso)) {
- /* reduce weight */
- curweight -= inf;
- }
- else {
- /* increase weight */
- curweight += inf;
- }
-
- /* verify target weight */
- CLAMP_MAX(curweight, gso->gp_brush->weight);
-
- CLAMP(curweight, 0.0f, 1.0f);
- if (dw) {
- dw->weight = curweight;
- }
-
- /* weight should stay within [0.0, 1.0] */
- if (pt->pressure < 0.0f)
- pt->pressure = 0.0f;
-
- return true;
+ /* create dvert */
+ BKE_gpencil_dvert_ensure(gps);
+
+ bGPDspoint *pt = gps->points + pt_index;
+ MDeformVert *dvert = gps->dvert + pt_index;
+ float inf;
+
+ /* Compute strength of effect
+ * - We divide the strength by 10, so that users can set "sane" values.
+ * Otherwise, good default values are in the range of 0.093
+ */
+ inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
+
+ /* need a vertex group */
+ if (gso->vrgroup == -1) {
+ if (gso->object) {
+ BKE_object_defgroup_add(gso->object);
+ gso->vrgroup = 0;
+ }
+ }
+ else {
+ bDeformGroup *defgroup = BLI_findlink(&gso->object->defbase, gso->vrgroup);
+ if (defgroup->flag & DG_LOCK_WEIGHT) {
+ return false;
+ }
+ }
+ /* get current weight */
+ MDeformWeight *dw = defvert_verify_index(dvert, gso->vrgroup);
+ float curweight = dw ? dw->weight : 0.0f;
+
+ if (gp_brush_invert_check(gso)) {
+ /* reduce weight */
+ curweight -= inf;
+ }
+ else {
+ /* increase weight */
+ curweight += inf;
+ }
+
+ /* verify target weight */
+ CLAMP_MAX(curweight, gso->gp_brush->weight);
+
+ CLAMP(curweight, 0.0f, 1.0f);
+ if (dw) {
+ dw->weight = curweight;
+ }
+
+ /* weight should stay within [0.0, 1.0] */
+ if (pt->pressure < 0.0f)
+ pt->pressure = 0.0f;
+
+ return true;
}
-
-
/* ************************************************ */
/* Non Callback-Based Brushes */
@@ -980,217 +948,218 @@ static bool gp_brush_weight_apply(
/* Custom state data for clone brush */
typedef struct tGPSB_CloneBrushData {
- /* midpoint of the strokes on the clipboard */
- float buffer_midpoint[3];
+ /* midpoint of the strokes on the clipboard */
+ float buffer_midpoint[3];
- /* number of strokes in the paste buffer (and/or to be created each time) */
- size_t totitems;
+ /* number of strokes in the paste buffer (and/or to be created each time) */
+ size_t totitems;
- /* for "stamp" mode, the currently pasted brushes */
- bGPDstroke **new_strokes;
+ /* for "stamp" mode, the currently pasted brushes */
+ bGPDstroke **new_strokes;
- /* mapping from colors referenced per stroke, to the new colours in the "pasted" strokes */
- GHash *new_colors;
+ /* mapping from colors referenced per stroke, to the new colours in the "pasted" strokes */
+ GHash *new_colors;
} tGPSB_CloneBrushData;
/* Initialise "clone" brush data */
static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso)
{
- tGPSB_CloneBrushData *data;
- bGPDstroke *gps;
-
- /* init custom data */
- gso->customdata = data = MEM_callocN(sizeof(tGPSB_CloneBrushData), "CloneBrushData");
-
- /* compute midpoint of strokes on clipboard */
- for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- const float dfac = 1.0f / ((float)gps->totpoints);
- float mid[3] = {0.0f};
-
- bGPDspoint *pt;
- int i;
-
- /* compute midpoint of this stroke */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- float co[3];
-
- mul_v3_v3fl(co, &pt->x, dfac);
- add_v3_v3(mid, co);
- }
-
- /* combine this stroke's data with the main data */
- add_v3_v3(data->buffer_midpoint, mid);
- data->totitems++;
- }
- }
-
- /* Divide the midpoint by the number of strokes, to finish averaging it */
- if (data->totitems > 1) {
- mul_v3_fl(data->buffer_midpoint, 1.0f / (float)data->totitems);
- }
-
- /* Create a buffer for storing the current strokes */
- if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
- data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems, "cloned strokes ptr array");
- }
-
- /* Init colormap for mapping between the pasted stroke's source color (names)
- * and the final colours that will be used here instead.
- */
- data->new_colors = gp_copybuf_validate_colormap(C);
+ tGPSB_CloneBrushData *data;
+ bGPDstroke *gps;
+
+ /* init custom data */
+ gso->customdata = data = MEM_callocN(sizeof(tGPSB_CloneBrushData), "CloneBrushData");
+
+ /* compute midpoint of strokes on clipboard */
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ const float dfac = 1.0f / ((float)gps->totpoints);
+ float mid[3] = {0.0f};
+
+ bGPDspoint *pt;
+ int i;
+
+ /* compute midpoint of this stroke */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float co[3];
+
+ mul_v3_v3fl(co, &pt->x, dfac);
+ add_v3_v3(mid, co);
+ }
+
+ /* combine this stroke's data with the main data */
+ add_v3_v3(data->buffer_midpoint, mid);
+ data->totitems++;
+ }
+ }
+
+ /* Divide the midpoint by the number of strokes, to finish averaging it */
+ if (data->totitems > 1) {
+ mul_v3_fl(data->buffer_midpoint, 1.0f / (float)data->totitems);
+ }
+
+ /* Create a buffer for storing the current strokes */
+ if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
+ data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems,
+ "cloned strokes ptr array");
+ }
+
+ /* Init colormap for mapping between the pasted stroke's source color (names)
+ * and the final colours that will be used here instead.
+ */
+ data->new_colors = gp_copybuf_validate_colormap(C);
}
/* Free custom data used for "clone" brush */
static void gp_brush_clone_free(tGP_BrushEditData *gso)
{
- tGPSB_CloneBrushData *data = gso->customdata;
-
- /* free strokes array */
- if (data->new_strokes) {
- MEM_freeN(data->new_strokes);
- data->new_strokes = NULL;
- }
-
- /* free copybuf colormap */
- if (data->new_colors) {
- BLI_ghash_free(data->new_colors, NULL, NULL);
- data->new_colors = NULL;
- }
-
- /* free the customdata itself */
- MEM_freeN(data);
- gso->customdata = NULL;
+ tGPSB_CloneBrushData *data = gso->customdata;
+
+ /* free strokes array */
+ if (data->new_strokes) {
+ MEM_freeN(data->new_strokes);
+ data->new_strokes = NULL;
+ }
+
+ /* free copybuf colormap */
+ if (data->new_colors) {
+ BLI_ghash_free(data->new_colors, NULL, NULL);
+ data->new_colors = NULL;
+ }
+
+ /* free the customdata itself */
+ MEM_freeN(data);
+ gso->customdata = NULL;
}
/* Create new copies of the strokes on the clipboard */
static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
{
- tGPSB_CloneBrushData *data = gso->customdata;
-
- Object *ob = CTX_data_active_object(C);
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
-
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
- bGPDstroke *gps;
-
- float delta[3];
- size_t strokes_added = 0;
-
- /* Compute amount to offset the points by */
- /* NOTE: This assumes that screenspace strokes are NOT used in the 3D view... */
-
- gp_brush_calc_midpoint(gso); /* this puts the cursor location into gso->dvec */
- sub_v3_v3v3(delta, gso->dvec, data->buffer_midpoint);
-
- /* Copy each stroke into the layer */
- for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- bGPDstroke *new_stroke;
- bGPDspoint *pt;
- int i;
-
- /* Make a new stroke */
- new_stroke = MEM_dupallocN(gps);
-
- new_stroke->points = MEM_dupallocN(gps->points);
- if (gps->dvert != NULL) {
- new_stroke->dvert = MEM_dupallocN(gps->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps, new_stroke);
- }
- new_stroke->triangles = MEM_dupallocN(gps->triangles);
-
- new_stroke->next = new_stroke->prev = NULL;
- BLI_addtail(&gpf->strokes, new_stroke);
-
- /* Fix color references */
- Material *ma = BLI_ghash_lookup(data->new_colors, &new_stroke->mat_nr);
- gps->mat_nr = BKE_gpencil_object_material_get_index(ob, ma);
- if (!ma || gps->mat_nr) {
- gps->mat_nr = 0;
- }
- /* Adjust all the stroke's points, so that the strokes
- * get pasted relative to where the cursor is now
- */
- for (i = 0, pt = new_stroke->points; i < new_stroke->totpoints; i++, pt++) {
- /* assume that the delta can just be applied, and then everything works */
- add_v3_v3(&pt->x, delta);
- }
-
- /* Store ref for later */
- if ((data->new_strokes) && (strokes_added < data->totitems)) {
- data->new_strokes[strokes_added] = new_stroke;
- strokes_added++;
- }
- }
- }
+ tGPSB_CloneBrushData *data = gso->customdata;
+
+ Object *ob = CTX_data_active_object(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
+ bGPDstroke *gps;
+
+ float delta[3];
+ size_t strokes_added = 0;
+
+ /* Compute amount to offset the points by */
+ /* NOTE: This assumes that screenspace strokes are NOT used in the 3D view... */
+
+ gp_brush_calc_midpoint(gso); /* this puts the cursor location into gso->dvec */
+ sub_v3_v3v3(delta, gso->dvec, data->buffer_midpoint);
+
+ /* Copy each stroke into the layer */
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ bGPDstroke *new_stroke;
+ bGPDspoint *pt;
+ int i;
+
+ /* Make a new stroke */
+ new_stroke = MEM_dupallocN(gps);
+
+ new_stroke->points = MEM_dupallocN(gps->points);
+ if (gps->dvert != NULL) {
+ new_stroke->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, new_stroke);
+ }
+ new_stroke->triangles = MEM_dupallocN(gps->triangles);
+
+ new_stroke->next = new_stroke->prev = NULL;
+ BLI_addtail(&gpf->strokes, new_stroke);
+
+ /* Fix color references */
+ Material *ma = BLI_ghash_lookup(data->new_colors, &new_stroke->mat_nr);
+ gps->mat_nr = BKE_gpencil_object_material_get_index(ob, ma);
+ if (!ma || gps->mat_nr) {
+ gps->mat_nr = 0;
+ }
+ /* Adjust all the stroke's points, so that the strokes
+ * get pasted relative to where the cursor is now
+ */
+ for (i = 0, pt = new_stroke->points; i < new_stroke->totpoints; i++, pt++) {
+ /* assume that the delta can just be applied, and then everything works */
+ add_v3_v3(&pt->x, delta);
+ }
+
+ /* Store ref for later */
+ if ((data->new_strokes) && (strokes_added < data->totitems)) {
+ data->new_strokes[strokes_added] = new_stroke;
+ strokes_added++;
+ }
+ }
+ }
}
/* Move newly-added strokes around - "Stamp" mode of the Clone brush */
static void gp_brush_clone_adjust(tGP_BrushEditData *gso)
{
- tGPSB_CloneBrushData *data = gso->customdata;
- size_t snum;
-
- /* Compute the amount of movement to apply (overwrites dvec) */
- gp_brush_grab_calc_dvec(gso);
-
- /* For each of the stored strokes, apply the offset to each point */
- /* NOTE: Again this assumes that in the 3D view, we only have 3d space and not screenspace strokes... */
- for (snum = 0; snum < data->totitems; snum++) {
- bGPDstroke *gps = data->new_strokes[snum];
- bGPDspoint *pt;
- int i;
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (gso->gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
- /* "Smudge" Effect when falloff is enabled */
- float delta[3] = {0.0f};
- int sco[2] = {0};
- float influence;
-
- /* compute influence on point */
- gp_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]);
- influence = gp_brush_influence_calc(gso, gso->gp_brush->size, sco);
-
- /* adjust the amount of displacement to apply */
- mul_v3_v3fl(delta, gso->dvec, influence);
-
- /* apply */
- add_v3_v3(&pt->x, delta);
- }
- else {
- /* Just apply the offset - All points move perfectly in sync with the cursor */
- add_v3_v3(&pt->x, gso->dvec);
- }
- }
- }
+ tGPSB_CloneBrushData *data = gso->customdata;
+ size_t snum;
+
+ /* Compute the amount of movement to apply (overwrites dvec) */
+ gp_brush_grab_calc_dvec(gso);
+
+ /* For each of the stored strokes, apply the offset to each point */
+ /* NOTE: Again this assumes that in the 3D view, we only have 3d space and not screenspace strokes... */
+ for (snum = 0; snum < data->totitems; snum++) {
+ bGPDstroke *gps = data->new_strokes[snum];
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (gso->gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
+ /* "Smudge" Effect when falloff is enabled */
+ float delta[3] = {0.0f};
+ int sco[2] = {0};
+ float influence;
+
+ /* compute influence on point */
+ gp_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]);
+ influence = gp_brush_influence_calc(gso, gso->gp_brush->size, sco);
+
+ /* adjust the amount of displacement to apply */
+ mul_v3_v3fl(delta, gso->dvec, influence);
+
+ /* apply */
+ add_v3_v3(&pt->x, delta);
+ }
+ else {
+ /* Just apply the offset - All points move perfectly in sync with the cursor */
+ add_v3_v3(&pt->x, gso->dvec);
+ }
+ }
+ }
}
/* Entrypoint for applying "clone" brush */
static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso)
{
- /* Which "mode" are we operating in? */
- if (gso->first) {
- /* Create initial clones */
- gp_brush_clone_add(C, gso);
- }
- else {
- /* Stamp or Continuous Mode */
- if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
- /* Stamp - Proceed to translate the newly added strokes */
- gp_brush_clone_adjust(gso);
- }
- else {
- /* Continuous - Just keep pasting everytime we move */
- /* TODO: The spacing of repeat should be controlled using a "stepsize" or similar property? */
- gp_brush_clone_add(C, gso);
- }
- }
-
- return true;
+ /* Which "mode" are we operating in? */
+ if (gso->first) {
+ /* Create initial clones */
+ gp_brush_clone_add(C, gso);
+ }
+ else {
+ /* Stamp or Continuous Mode */
+ if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
+ /* Stamp - Proceed to translate the newly added strokes */
+ gp_brush_clone_adjust(gso);
+ }
+ else {
+ /* Continuous - Just keep pasting everytime we move */
+ /* TODO: The spacing of repeat should be controlled using a "stepsize" or similar property? */
+ gp_brush_clone_add(C, gso);
+ }
+ }
+
+ return true;
}
/* ************************************************ */
@@ -1198,18 +1167,19 @@ static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso)
static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
{
- const char *brush_name = NULL;
- char str[UI_MAX_DRAW_STR] = "";
+ const char *brush_name = NULL;
+ char str[UI_MAX_DRAW_STR] = "";
- RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name);
+ RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name);
- BLI_snprintf(str, sizeof(str),
- IFACE_("GPencil Sculpt: %s Stroke | LMB to paint | RMB/Escape to Exit"
- " | Ctrl to Invert Action | Wheel Up/Down for Size "
- " | Shift-Wheel Up/Down for Strength"),
- (brush_name) ? brush_name : "<?>");
+ BLI_snprintf(str,
+ sizeof(str),
+ IFACE_("GPencil Sculpt: %s Stroke | LMB to paint | RMB/Escape to Exit"
+ " | Ctrl to Invert Action | Wheel Up/Down for Size "
+ " | Shift-Wheel Up/Down for Strength"),
+ (brush_name) ? brush_name : "<?>");
- ED_workspace_status_text(C, str);
+ ED_workspace_status_text(C, str);
}
/* ************************************************ */
@@ -1219,586 +1189,576 @@ static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
- const bool is_weight_mode = ob->mode == OB_MODE_WEIGHT_GPENCIL;
- /* set the brush using the tool */
+ const bool is_weight_mode = ob->mode == OB_MODE_WEIGHT_GPENCIL;
+ /* set the brush using the tool */
#if 0
- GP_Sculpt_Settings *gset = &ts->gp_sculpt;
- eGP_Sculpt_Types mode = is_weight_mode ? gset->weighttype : gset->brushtype;
+ GP_Sculpt_Settings *gset = &ts->gp_sculpt;
+ eGP_Sculpt_Types mode = is_weight_mode ? gset->weighttype : gset->brushtype;
#endif
- tGP_BrushEditData *gso;
-
- /* setup operator data */
- gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData");
- op->customdata = gso;
-
- gso->depsgraph = CTX_data_depsgraph(C);
- /* store state */
- gso->settings = gpsculpt_get_settings(scene);
- gso->gp_brush = gpsculpt_get_brush(scene, is_weight_mode);
- gso->is_weight_mode = is_weight_mode;
-
- if (is_weight_mode) {
- gso->brush_type = gso->settings->weighttype;
- }
- else {
- gso->brush_type = gso->settings->brushtype;
- }
-
- /* Random generator, only init once. */
- uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
- rng_seed ^= POINTER_AS_UINT(gso);
- gso->rng = BLI_rng_new(rng_seed);
-
- gso->is_painting = false;
- gso->first = true;
-
- gso->gpd = ED_gpencil_data_get_active(C);
- gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */
-
- /* some brushes cannot use pressure for radius */
- if (ELEM(gso->brush_type, GP_SCULPT_TYPE_GRAB, GP_SCULPT_TYPE_CLONE)) {
- gso->gp_brush->flag &= ~GP_SCULPT_FLAG_PRESSURE_RADIUS;
- }
-
- gso->scene = scene;
- gso->object = ob;
- if (ob) {
- gso->vrgroup = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
- gso->vrgroup = -1;
- }
- }
- else {
- gso->vrgroup = - 1;
- }
-
- gso->sa = CTX_wm_area(C);
- gso->ar = CTX_wm_region(C);
-
- /* multiframe settings */
- gso->is_multiframe = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
- gso->use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
-
- /* Init multi-edit falloff curve data before doing anything,
- * so we won't have to do it again later. */
- if (gso->is_multiframe) {
- curvemapping_initialize(ts->gp_sculpt.cur_falloff);
- }
-
- /* initialise custom data for brushes */
- switch (gso->brush_type) {
- case GP_SCULPT_TYPE_CLONE:
- {
- bGPDstroke *gps;
- bool found = false;
-
- /* check that there are some usable strokes in the buffer */
- for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- found = true;
- break;
- }
- }
-
- if (found == false) {
- /* STOP HERE! Nothing to paste! */
- BKE_report(op->reports, RPT_ERROR,
- "Copy some strokes to the clipboard before using the Clone brush to paste copies of them");
-
- MEM_freeN(gso);
- op->customdata = NULL;
- return false;
- }
- else {
- /* initialise customdata */
- gp_brush_clone_init(C, gso);
- }
- break;
- }
-
- case GP_SCULPT_TYPE_GRAB:
- {
- /* initialise the cache needed for this brush */
- gso->stroke_customdata = BLI_ghash_ptr_new("GP Grab Brush - Strokes Hash");
- break;
- }
-
- /* Others - No customdata needed */
- default:
- break;
- }
-
-
- /* setup space conversions */
- gp_point_conversion_init(C, &gso->gsc);
-
- /* update header */
- gpsculpt_brush_header_set(C, gso);
-
- /* setup cursor drawing */
- //WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
- if (gso->sa->spacetype != SPACE_VIEW3D) {
- ED_gpencil_toggle_brush_cursor(C, true, NULL);
- }
- return true;
+ tGP_BrushEditData *gso;
+
+ /* setup operator data */
+ gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData");
+ op->customdata = gso;
+
+ gso->depsgraph = CTX_data_depsgraph(C);
+ /* store state */
+ gso->settings = gpsculpt_get_settings(scene);
+ gso->gp_brush = gpsculpt_get_brush(scene, is_weight_mode);
+ gso->is_weight_mode = is_weight_mode;
+
+ if (is_weight_mode) {
+ gso->brush_type = gso->settings->weighttype;
+ }
+ else {
+ gso->brush_type = gso->settings->brushtype;
+ }
+
+ /* Random generator, only init once. */
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= POINTER_AS_UINT(gso);
+ gso->rng = BLI_rng_new(rng_seed);
+
+ gso->is_painting = false;
+ gso->first = true;
+
+ gso->gpd = ED_gpencil_data_get_active(C);
+ gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */
+
+ /* some brushes cannot use pressure for radius */
+ if (ELEM(gso->brush_type, GP_SCULPT_TYPE_GRAB, GP_SCULPT_TYPE_CLONE)) {
+ gso->gp_brush->flag &= ~GP_SCULPT_FLAG_PRESSURE_RADIUS;
+ }
+
+ gso->scene = scene;
+ gso->object = ob;
+ if (ob) {
+ gso->vrgroup = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
+ gso->vrgroup = -1;
+ }
+ }
+ else {
+ gso->vrgroup = -1;
+ }
+
+ gso->sa = CTX_wm_area(C);
+ gso->ar = CTX_wm_region(C);
+
+ /* multiframe settings */
+ gso->is_multiframe = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
+ gso->use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
+
+ /* Init multi-edit falloff curve data before doing anything,
+ * so we won't have to do it again later. */
+ if (gso->is_multiframe) {
+ curvemapping_initialize(ts->gp_sculpt.cur_falloff);
+ }
+
+ /* initialise custom data for brushes */
+ switch (gso->brush_type) {
+ case GP_SCULPT_TYPE_CLONE: {
+ bGPDstroke *gps;
+ bool found = false;
+
+ /* check that there are some usable strokes in the buffer */
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ /* STOP HERE! Nothing to paste! */
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Copy some strokes to the clipboard before using the Clone brush to paste "
+ "copies of them");
+
+ MEM_freeN(gso);
+ op->customdata = NULL;
+ return false;
+ }
+ else {
+ /* initialise customdata */
+ gp_brush_clone_init(C, gso);
+ }
+ break;
+ }
+
+ case GP_SCULPT_TYPE_GRAB: {
+ /* initialise the cache needed for this brush */
+ gso->stroke_customdata = BLI_ghash_ptr_new("GP Grab Brush - Strokes Hash");
+ break;
+ }
+
+ /* Others - No customdata needed */
+ default:
+ break;
+ }
+
+ /* setup space conversions */
+ gp_point_conversion_init(C, &gso->gsc);
+
+ /* update header */
+ gpsculpt_brush_header_set(C, gso);
+
+ /* setup cursor drawing */
+ //WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ if (gso->sa->spacetype != SPACE_VIEW3D) {
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ }
+ return true;
}
static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
{
- tGP_BrushEditData *gso = op->customdata;
- wmWindow *win = CTX_wm_window(C);
-
- /* free brush-specific data */
- switch (gso->brush_type) {
- case GP_SCULPT_TYPE_GRAB:
- {
- /* Free per-stroke customdata
- * - Keys don't need to be freed, as those are the strokes
- * - Values assigned to those keys do, as they are custom structs
- */
- BLI_ghash_free(gso->stroke_customdata, NULL, gp_brush_grab_stroke_free);
- break;
- }
-
- case GP_SCULPT_TYPE_CLONE:
- {
- /* Free customdata */
- gp_brush_clone_free(gso);
- break;
- }
-
- default:
- break;
- }
-
- /* unregister timer (only used for realtime) */
- if (gso->timer) {
- WM_event_remove_timer(CTX_wm_manager(C), win, gso->timer);
- }
-
- if (gso->rng != NULL) {
- BLI_rng_free(gso->rng);
- }
-
- /* disable cursor and headerprints */
- ED_workspace_status_text(C, NULL);
- WM_cursor_modal_restore(win);
- if (gso->sa->spacetype != SPACE_VIEW3D) {
- ED_gpencil_toggle_brush_cursor(C, false, NULL);
- }
-
- /* disable temp invert flag */
- gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
-
- /* free operator data */
- MEM_freeN(gso);
- op->customdata = NULL;
+ tGP_BrushEditData *gso = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+
+ /* free brush-specific data */
+ switch (gso->brush_type) {
+ case GP_SCULPT_TYPE_GRAB: {
+ /* Free per-stroke customdata
+ * - Keys don't need to be freed, as those are the strokes
+ * - Values assigned to those keys do, as they are custom structs
+ */
+ BLI_ghash_free(gso->stroke_customdata, NULL, gp_brush_grab_stroke_free);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_CLONE: {
+ /* Free customdata */
+ gp_brush_clone_free(gso);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ /* unregister timer (only used for realtime) */
+ if (gso->timer) {
+ WM_event_remove_timer(CTX_wm_manager(C), win, gso->timer);
+ }
+
+ if (gso->rng != NULL) {
+ BLI_rng_free(gso->rng);
+ }
+
+ /* disable cursor and headerprints */
+ ED_workspace_status_text(C, NULL);
+ WM_cursor_modal_restore(win);
+ if (gso->sa->spacetype != SPACE_VIEW3D) {
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ }
+
+ /* disable temp invert flag */
+ gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
+
+ /* free operator data */
+ MEM_freeN(gso);
+ op->customdata = NULL;
}
/* poll callback for stroke sculpting operator(s) */
static bool gpsculpt_brush_poll(bContext *C)
{
- /* NOTE: this is a bit slower, but is the most accurate... */
- return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
+ /* NOTE: this is a bit slower, but is the most accurate... */
+ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
}
/* Init Sculpt Stroke ---------------------------------- */
static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
{
- bGPdata *gpd = gso->gpd;
-
- bGPDlayer *gpl;
- int cfra_eval = (int)DEG_get_ctime(gso->depsgraph);
-
- /* only try to add a new frame if this is the first stroke, or the frame has changed */
- if ((gpd == NULL) || (cfra_eval == gso->cfra))
- return;
-
- /* go through each layer, and ensure that we've got a valid frame to use */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- bGPDframe *gpf = gpl->actframe;
-
- /* Make a new frame to work on if the layer's frame and the current scene frame don't match up
- * - This is useful when animating as it saves that "uh-oh" moment when you realize you've
- * spent too much time editing the wrong frame...
- */
- // XXX: should this be allowed when framelock is enabled?
- if (gpf->framenum != cfra_eval) {
- BKE_gpencil_frame_addcopy(gpl, cfra_eval);
- }
- }
- }
-
- /* save off new current frame, so that next update works fine */
- gso->cfra = cfra_eval;
+ bGPdata *gpd = gso->gpd;
+
+ bGPDlayer *gpl;
+ int cfra_eval = (int)DEG_get_ctime(gso->depsgraph);
+
+ /* only try to add a new frame if this is the first stroke, or the frame has changed */
+ if ((gpd == NULL) || (cfra_eval == gso->cfra))
+ return;
+
+ /* go through each layer, and ensure that we've got a valid frame to use */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *gpf = gpl->actframe;
+
+ /* Make a new frame to work on if the layer's frame and the current scene frame don't match up
+ * - This is useful when animating as it saves that "uh-oh" moment when you realize you've
+ * spent too much time editing the wrong frame...
+ */
+ // XXX: should this be allowed when framelock is enabled?
+ if (gpf->framenum != cfra_eval) {
+ BKE_gpencil_frame_addcopy(gpl, cfra_eval);
+ }
+ }
+ }
+
+ /* save off new current frame, so that next update works fine */
+ gso->cfra = cfra_eval;
}
/* Apply ----------------------------------------------- */
/* Apply brush operation to points in this stroke */
-static bool gpsculpt_brush_do_stroke(
- tGP_BrushEditData *gso, bGPDstroke *gps,
- float diff_mat[4][4], GP_BrushApplyCb apply)
+static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
+ bGPDstroke *gps,
+ float diff_mat[4][4],
+ GP_BrushApplyCb apply)
{
- GP_SpaceConversion *gsc = &gso->gsc;
- rcti *rect = &gso->brush_rect;
- GP_Sculpt_Data *gp_brush = gso->gp_brush;
- const int radius = (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ? gso->gp_brush->size * gso->pressure : gso->gp_brush->size;
-
- bGPDspoint *pt1, *pt2;
- int pc1[2] = {0};
- int pc2[2] = {0};
- int i;
- bool include_last = false;
- bool changed = false;
-
- if (gps->totpoints == 1) {
- bGPDspoint pt_temp;
- gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
- gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
-
- /* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
- /* only check if point is inside */
- int mval_i[2];
- round_v2i_v2fl(mval_i, gso->mval);
- if (len_v2v2_int(mval_i, pc1) <= radius) {
- /* apply operation to this point */
- changed = apply(gso, gps, 0, radius, pc1);
- }
- }
- }
- else {
- /* Loop over the points in the stroke, checking for intersections
- * - an intersection means that we touched the stroke
- */
- for (i = 0; (i + 1) < gps->totpoints; i++) {
- /* Get points to work with */
- pt1 = gps->points + i;
- pt2 = gps->points + i + 1;
-
- /* Skip if neither one is selected (and we are only allowed to edit/consider selected points) */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
- if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) {
- include_last = false;
- continue;
- }
- }
- bGPDspoint npt;
- gp_point_to_parent_space(pt1, diff_mat, &npt);
- gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
-
- gp_point_to_parent_space(pt2, diff_mat, &npt);
- gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
-
- /* Check that point segment of the boundbox of the selection stroke */
- if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
- ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1])))
- {
- /* Check if point segment of stroke had anything to do with
- * brush region (either within stroke painted, or on its lines)
- * - this assumes that linewidth is irrelevant
- */
- if (gp_stroke_inside_circle(gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
- /* Apply operation to these points */
- bool ok = false;
-
- /* To each point individually... */
- ok = apply(gso, gps, i, radius, pc1);
-
- /* Only do the second point if this is the last segment,
- * and it is unlikely that the point will get handled
- * otherwise.
- *
- * NOTE: There is a small risk here that the second point wasn't really
- * actually in-range. In that case, it only got in because
- * the line linking the points was!
- */
- if (i + 1 == gps->totpoints - 1) {
- ok |= apply(gso, gps, i + 1, radius, pc2);
- include_last = false;
- }
- else {
- include_last = true;
- }
-
- changed |= ok;
- }
- else if (include_last) {
- /* This case is for cases where for whatever reason the second vert (1st here) doesn't get included
- * because the whole edge isn't in bounds, but it would've qualified since it did with the
- * previous step (but wasn't added then, to avoid double-ups)
- */
- changed |= apply(gso, gps, i, radius, pc1);
- include_last = false;
- }
- }
- }
- }
-
- return changed;
+ GP_SpaceConversion *gsc = &gso->gsc;
+ rcti *rect = &gso->brush_rect;
+ GP_Sculpt_Data *gp_brush = gso->gp_brush;
+ const int radius = (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
+ gso->gp_brush->size * gso->pressure :
+ gso->gp_brush->size;
+
+ bGPDspoint *pt1, *pt2;
+ int pc1[2] = {0};
+ int pc2[2] = {0};
+ int i;
+ bool include_last = false;
+ bool changed = false;
+
+ if (gps->totpoints == 1) {
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, gso->mval);
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ /* apply operation to this point */
+ changed = apply(gso, gps, 0, radius, pc1);
+ }
+ }
+ }
+ else {
+ /* Loop over the points in the stroke, checking for intersections
+ * - an intersection means that we touched the stroke
+ */
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+ /* Get points to work with */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ /* Skip if neither one is selected (and we are only allowed to edit/consider selected points) */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
+ if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) {
+ include_last = false;
+ continue;
+ }
+ }
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
+
+ /* Check that point segment of the boundbox of the selection stroke */
+ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
+ /* Check if point segment of stroke had anything to do with
+ * brush region (either within stroke painted, or on its lines)
+ * - this assumes that linewidth is irrelevant
+ */
+ if (gp_stroke_inside_circle(
+ gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ /* Apply operation to these points */
+ bool ok = false;
+
+ /* To each point individually... */
+ ok = apply(gso, gps, i, radius, pc1);
+
+ /* Only do the second point if this is the last segment,
+ * and it is unlikely that the point will get handled
+ * otherwise.
+ *
+ * NOTE: There is a small risk here that the second point wasn't really
+ * actually in-range. In that case, it only got in because
+ * the line linking the points was!
+ */
+ if (i + 1 == gps->totpoints - 1) {
+ ok |= apply(gso, gps, i + 1, radius, pc2);
+ include_last = false;
+ }
+ else {
+ include_last = true;
+ }
+
+ changed |= ok;
+ }
+ else if (include_last) {
+ /* This case is for cases where for whatever reason the second vert (1st here) doesn't get included
+ * because the whole edge isn't in bounds, but it would've qualified since it did with the
+ * previous step (but wasn't added then, to avoid double-ups)
+ */
+ changed |= apply(gso, gps, i, radius, pc1);
+ include_last = false;
+ }
+ }
+ }
+ }
+
+ return changed;
}
/* Apply sculpt brushes to strokes in the given frame */
static bool gpsculpt_brush_do_frame(
- bContext *C, tGP_BrushEditData *gso,
- bGPDlayer *gpl, bGPDframe *gpf,
- float diff_mat[4][4])
+ bContext *C, tGP_BrushEditData *gso, bGPDlayer *gpl, bGPDframe *gpf, float diff_mat[4][4])
{
- bool changed = false;
- Object *ob = CTX_data_active_object(C);
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
- continue;
- }
-
- switch (gso->brush_type) {
- case GP_SCULPT_TYPE_SMOOTH: /* Smooth strokes */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_smooth_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_THICKNESS: /* Adjust stroke thickness */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_thickness_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_STRENGTH: /* Adjust stroke color strength */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_strength_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_GRAB: /* Grab points */
- {
- if (gso->first) {
- /* First time this brush stroke is being applied:
- * 1) Prepare data buffers (init/clear) for this stroke
- * 2) Use the points now under the cursor
- */
- gp_brush_grab_stroke_init(gso, gps);
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points);
- }
- else {
- /* Apply effect to the stored points */
- gp_brush_grab_apply_cached(gso, gps, diff_mat);
- changed |= true;
- }
- break;
- }
-
- case GP_SCULPT_TYPE_PUSH: /* Push points */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_push_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_PINCH: /* Pinch points */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_pinch_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_twist_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_RANDOMIZE: /* Apply jitter */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_randomize_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_WEIGHT: /* Adjust vertex group weight */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_weight_apply);
- break;
- }
-
-
- default:
- printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
- break;
- }
- /* Triangulation must be calculated if changed */
- if (changed) {
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
- }
- }
-
- return changed;
+ bool changed = false;
+ Object *ob = CTX_data_active_object(C);
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+
+ switch (gso->brush_type) {
+ case GP_SCULPT_TYPE_SMOOTH: /* Smooth strokes */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_smooth_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_THICKNESS: /* Adjust stroke thickness */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_thickness_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_STRENGTH: /* Adjust stroke color strength */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_strength_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_GRAB: /* Grab points */
+ {
+ if (gso->first) {
+ /* First time this brush stroke is being applied:
+ * 1) Prepare data buffers (init/clear) for this stroke
+ * 2) Use the points now under the cursor
+ */
+ gp_brush_grab_stroke_init(gso, gps);
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points);
+ }
+ else {
+ /* Apply effect to the stored points */
+ gp_brush_grab_apply_cached(gso, gps, diff_mat);
+ changed |= true;
+ }
+ break;
+ }
+
+ case GP_SCULPT_TYPE_PUSH: /* Push points */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_push_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_PINCH: /* Pinch points */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_pinch_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_twist_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_RANDOMIZE: /* Apply jitter */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_randomize_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_WEIGHT: /* Adjust vertex group weight */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_weight_apply);
+ break;
+ }
+
+ default:
+ printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
+ break;
+ }
+ /* Triangulation must be calculated if changed */
+ if (changed) {
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
+ }
+ }
+
+ return changed;
}
/* Perform two-pass brushes which modify the existing strokes */
static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *obact = gso->object;
- bGPdata *gpd = gso->gpd;
- bool changed = false;
-
- /* Calculate brush-specific data which applies equally to all points */
- switch (gso->brush_type) {
- case GP_SCULPT_TYPE_GRAB: /* Grab points */
- case GP_SCULPT_TYPE_PUSH: /* Push points */
- {
- /* calculate amount of displacement to apply */
- gp_brush_grab_calc_dvec(gso);
- break;
- }
-
- case GP_SCULPT_TYPE_PINCH: /* Pinch points */
- case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
- {
- /* calculate midpoint of the brush (in data space) */
- gp_brush_calc_midpoint(gso);
- break;
- }
-
- case GP_SCULPT_TYPE_RANDOMIZE: /* Random jitter */
- {
- /* compute the displacement vector for the cursor (in data space) */
- gp_brush_grab_calc_dvec(gso);
- break;
- }
-
- default:
- break;
- }
-
-
- /* Find visible strokes, and perform operations on those if hit */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- /* If no active frame, don't do anything... */
- if (gpl->actframe == NULL) {
- continue;
- }
-
- /* calculate difference matrix */
- float diff_mat[4][4];
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
-
- /* Active Frame or MultiFrame? */
- if (gso->is_multiframe) {
- /* init multiframe falloff options */
- int f_init = 0;
- int f_end = 0;
-
- if (gso->use_multiframe_falloff) {
- BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
- }
-
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- /* Always do active frame; Otherwise, only include selected frames */
- if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
- /* compute multiframe falloff factor */
- if (gso->use_multiframe_falloff) {
- /* Faloff depends on distance to active frame (relative to the overall frame range) */
- gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc(
- gpf, gpl->actframe->framenum,
- f_init, f_end,
- ts->gp_sculpt.cur_falloff);
- }
- else {
- /* No falloff */
- gso->mf_falloff = 1.0f;
- }
-
- /* affect strokes in this frame */
- changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat);
- }
- }
- }
- else {
- /* Apply to active frame's strokes */
- gso->mf_falloff = 1.0f;
- changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat);
- }
- }
- CTX_DATA_END;
-
- return changed;
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *obact = gso->object;
+ bGPdata *gpd = gso->gpd;
+ bool changed = false;
+
+ /* Calculate brush-specific data which applies equally to all points */
+ switch (gso->brush_type) {
+ case GP_SCULPT_TYPE_GRAB: /* Grab points */
+ case GP_SCULPT_TYPE_PUSH: /* Push points */
+ {
+ /* calculate amount of displacement to apply */
+ gp_brush_grab_calc_dvec(gso);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_PINCH: /* Pinch points */
+ case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
+ {
+ /* calculate midpoint of the brush (in data space) */
+ gp_brush_calc_midpoint(gso);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_RANDOMIZE: /* Random jitter */
+ {
+ /* compute the displacement vector for the cursor (in data space) */
+ gp_brush_grab_calc_dvec(gso);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ /* Find visible strokes, and perform operations on those if hit */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ /* If no active frame, don't do anything... */
+ if (gpl->actframe == NULL) {
+ continue;
+ }
+
+ /* calculate difference matrix */
+ float diff_mat[4][4];
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+
+ /* Active Frame or MultiFrame? */
+ if (gso->is_multiframe) {
+ /* init multiframe falloff options */
+ int f_init = 0;
+ int f_end = 0;
+
+ if (gso->use_multiframe_falloff) {
+ BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
+ }
+
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* Always do active frame; Otherwise, only include selected frames */
+ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
+ /* compute multiframe falloff factor */
+ if (gso->use_multiframe_falloff) {
+ /* Faloff depends on distance to active frame (relative to the overall frame range) */
+ gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc(
+ gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
+ }
+ else {
+ /* No falloff */
+ gso->mf_falloff = 1.0f;
+ }
+
+ /* affect strokes in this frame */
+ changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat);
+ }
+ }
+ }
+ else {
+ /* Apply to active frame's strokes */
+ gso->mf_falloff = 1.0f;
+ changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat);
+ }
+ }
+ CTX_DATA_END;
+
+ return changed;
}
/* Calculate settings for applying brush */
static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
{
- tGP_BrushEditData *gso = op->customdata;
- GP_Sculpt_Data *gp_brush = gso->gp_brush;
- const int radius = (
- (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
- gso->gp_brush->size * gso->pressure : gso->gp_brush->size);
- float mousef[2];
- int mouse[2];
- bool changed = false;
-
- /* Get latest mouse coordinates */
- RNA_float_get_array(itemptr, "mouse", mousef);
- gso->mval[0] = mouse[0] = (int)(mousef[0]);
- gso->mval[1] = mouse[1] = (int)(mousef[1]);
-
- gso->pressure = RNA_float_get(itemptr, "pressure");
-
- if (RNA_boolean_get(itemptr, "pen_flip"))
- gso->flag |= GP_SCULPT_FLAG_INVERT;
- else
- gso->flag &= ~GP_SCULPT_FLAG_INVERT;
-
-
- /* Store coordinates as reference, if operator just started running */
- if (gso->first) {
- gso->mval_prev[0] = gso->mval[0];
- gso->mval_prev[1] = gso->mval[1];
- gso->pressure_prev = gso->pressure;
- }
-
- /* Update brush_rect, so that it represents the bounding rectangle of brush */
- gso->brush_rect.xmin = mouse[0] - radius;
- gso->brush_rect.ymin = mouse[1] - radius;
- gso->brush_rect.xmax = mouse[0] + radius;
- gso->brush_rect.ymax = mouse[1] + radius;
-
-
- /* Apply brush */
- if (gso->brush_type == GP_SCULPT_TYPE_CLONE) {
- changed = gpsculpt_brush_apply_clone(C, gso);
- }
- else {
- changed = gpsculpt_brush_apply_standard(C, gso);
- }
-
-
- /* Updates */
- if (changed) {
- DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- }
-
- /* Store values for next step */
- gso->mval_prev[0] = gso->mval[0];
- gso->mval_prev[1] = gso->mval[1];
- gso->pressure_prev = gso->pressure;
- gso->first = false;
+ tGP_BrushEditData *gso = op->customdata;
+ GP_Sculpt_Data *gp_brush = gso->gp_brush;
+ const int radius = ((gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
+ gso->gp_brush->size * gso->pressure :
+ gso->gp_brush->size);
+ float mousef[2];
+ int mouse[2];
+ bool changed = false;
+
+ /* Get latest mouse coordinates */
+ RNA_float_get_array(itemptr, "mouse", mousef);
+ gso->mval[0] = mouse[0] = (int)(mousef[0]);
+ gso->mval[1] = mouse[1] = (int)(mousef[1]);
+
+ gso->pressure = RNA_float_get(itemptr, "pressure");
+
+ if (RNA_boolean_get(itemptr, "pen_flip"))
+ gso->flag |= GP_SCULPT_FLAG_INVERT;
+ else
+ gso->flag &= ~GP_SCULPT_FLAG_INVERT;
+
+ /* Store coordinates as reference, if operator just started running */
+ if (gso->first) {
+ gso->mval_prev[0] = gso->mval[0];
+ gso->mval_prev[1] = gso->mval[1];
+ gso->pressure_prev = gso->pressure;
+ }
+
+ /* Update brush_rect, so that it represents the bounding rectangle of brush */
+ gso->brush_rect.xmin = mouse[0] - radius;
+ gso->brush_rect.ymin = mouse[1] - radius;
+ gso->brush_rect.xmax = mouse[0] + radius;
+ gso->brush_rect.ymax = mouse[1] + radius;
+
+ /* Apply brush */
+ if (gso->brush_type == GP_SCULPT_TYPE_CLONE) {
+ changed = gpsculpt_brush_apply_clone(C, gso);
+ }
+ else {
+ changed = gpsculpt_brush_apply_standard(C, gso);
+ }
+
+ /* Updates */
+ if (changed) {
+ DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ /* Store values for next step */
+ gso->mval_prev[0] = gso->mval[0];
+ gso->mval_prev[1] = gso->mval[1];
+ gso->pressure_prev = gso->pressure;
+ gso->first = false;
}
/* Running --------------------------------------------- */
@@ -1806,370 +1766,380 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt
/* helper - a record stroke, and apply paint event */
static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGP_BrushEditData *gso = op->customdata;
- ToolSettings *ts = CTX_data_tool_settings(C);
- GP_Sculpt_Settings *gset = &ts->gp_sculpt;
- PointerRNA itemptr;
- float mouse[2];
- int tablet = 0;
-
- mouse[0] = event->mval[0] + 1;
- mouse[1] = event->mval[1] + 1;
-
- /* fill in stroke */
- RNA_collection_add(op->ptr, "stroke", &itemptr);
-
- RNA_float_set_array(&itemptr, "mouse", mouse);
- RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false);
- RNA_boolean_set(&itemptr, "is_start", gso->first);
-
- /* handle pressure sensitivity (which is supplied by tablets) */
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- float pressure = wmtab->Pressure;
-
- tablet = (wmtab->Active != EVT_TABLET_NONE);
-
- /* special exception here for too high pressure values on first touch in
- * windows for some tablets: clamp the values to be sane
- */
- if (tablet && (pressure >= 0.99f)) {
- pressure = 1.0f;
- }
- RNA_float_set(&itemptr, "pressure", pressure);
- }
- else {
- RNA_float_set(&itemptr, "pressure", 1.0f);
- }
-
- if (!gso->is_weight_mode) {
- if (event->shift) {
- gso->gp_brush_old = gso->gp_brush;
- gso->brush_type_old = gso->brush_type;
-
- gso->gp_brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
- gso->brush_type = GP_SCULPT_TYPE_SMOOTH;
- }
- else {
- if (gso->gp_brush_old != NULL) {
- gso->gp_brush = gso->gp_brush_old;
- gso->brush_type = gso->brush_type_old;
- }
- }
- }
-
- /* apply */
- gpsculpt_brush_apply(C, op, &itemptr);
+ tGP_BrushEditData *gso = op->customdata;
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ GP_Sculpt_Settings *gset = &ts->gp_sculpt;
+ PointerRNA itemptr;
+ float mouse[2];
+ int tablet = 0;
+
+ mouse[0] = event->mval[0] + 1;
+ mouse[1] = event->mval[1] + 1;
+
+ /* fill in stroke */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ RNA_float_set_array(&itemptr, "mouse", mouse);
+ RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false);
+ RNA_boolean_set(&itemptr, "is_start", gso->first);
+
+ /* handle pressure sensitivity (which is supplied by tablets) */
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+ float pressure = wmtab->Pressure;
+
+ tablet = (wmtab->Active != EVT_TABLET_NONE);
+
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets: clamp the values to be sane
+ */
+ if (tablet && (pressure >= 0.99f)) {
+ pressure = 1.0f;
+ }
+ RNA_float_set(&itemptr, "pressure", pressure);
+ }
+ else {
+ RNA_float_set(&itemptr, "pressure", 1.0f);
+ }
+
+ if (!gso->is_weight_mode) {
+ if (event->shift) {
+ gso->gp_brush_old = gso->gp_brush;
+ gso->brush_type_old = gso->brush_type;
+
+ gso->gp_brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
+ gso->brush_type = GP_SCULPT_TYPE_SMOOTH;
+ }
+ else {
+ if (gso->gp_brush_old != NULL) {
+ gso->gp_brush = gso->gp_brush_old;
+ gso->brush_type = gso->brush_type_old;
+ }
+ }
+ }
+
+ /* apply */
+ gpsculpt_brush_apply(C, op, &itemptr);
}
/* reapply */
static int gpsculpt_brush_exec(bContext *C, wmOperator *op)
{
- if (!gpsculpt_brush_init(C, op))
- return OPERATOR_CANCELLED;
+ if (!gpsculpt_brush_init(C, op))
+ return OPERATOR_CANCELLED;
- RNA_BEGIN(op->ptr, itemptr, "stroke")
- {
- gpsculpt_brush_apply(C, op, &itemptr);
- }
- RNA_END;
+ RNA_BEGIN (op->ptr, itemptr, "stroke") {
+ gpsculpt_brush_apply(C, op, &itemptr);
+ }
+ RNA_END;
- gpsculpt_brush_exit(C, op);
+ gpsculpt_brush_exit(C, op);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
-
/* start modal painting */
static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGP_BrushEditData *gso = NULL;
- const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
- const bool is_playing = ED_screen_animation_playing(CTX_wm_manager(C)) != NULL;
- bool needs_timer = false;
- float brush_rate = 0.0f;
-
- /* the operator cannot work while play animation */
- if (is_playing) {
- BKE_report(op->reports, RPT_ERROR, "Cannot sculpt while play animation");
-
- return OPERATOR_CANCELLED;
- }
-
- /* init painting data */
- if (!gpsculpt_brush_init(C, op))
- return OPERATOR_CANCELLED;
-
- gso = op->customdata;
-
- /* initialise type-specific data (used for the entire session) */
- switch (gso->brush_type) {
- /* Brushes requiring timer... */
- case GP_SCULPT_TYPE_THICKNESS:
- brush_rate = 0.01f; // XXX: hardcoded
- needs_timer = true;
- break;
-
- case GP_SCULPT_TYPE_STRENGTH:
- brush_rate = 0.01f; // XXX: hardcoded
- needs_timer = true;
- break;
-
- case GP_SCULPT_TYPE_PINCH:
- brush_rate = 0.001f; // XXX: hardcoded
- needs_timer = true;
- break;
-
- case GP_SCULPT_TYPE_TWIST:
- brush_rate = 0.01f; // XXX: hardcoded
- needs_timer = true;
- break;
-
- default:
- break;
- }
-
- /* register timer for increasing influence by hovering over an area */
- if (needs_timer) {
- gso->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, brush_rate);
- }
-
- /* register modal handler */
- WM_event_add_modal_handler(C, op);
-
- /* start drawing immediately? */
- if (is_modal == false) {
- ARegion *ar = CTX_wm_region(C);
-
- /* ensure that we'll have a new frame to draw on */
- gpsculpt_brush_init_stroke(gso);
-
- /* apply first dab... */
- gso->is_painting = true;
- gpsculpt_brush_apply_event(C, op, event);
-
- /* redraw view with feedback */
- ED_region_tag_redraw(ar);
- }
-
- return OPERATOR_RUNNING_MODAL;
+ tGP_BrushEditData *gso = NULL;
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ const bool is_playing = ED_screen_animation_playing(CTX_wm_manager(C)) != NULL;
+ bool needs_timer = false;
+ float brush_rate = 0.0f;
+
+ /* the operator cannot work while play animation */
+ if (is_playing) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot sculpt while play animation");
+
+ return OPERATOR_CANCELLED;
+ }
+
+ /* init painting data */
+ if (!gpsculpt_brush_init(C, op))
+ return OPERATOR_CANCELLED;
+
+ gso = op->customdata;
+
+ /* initialise type-specific data (used for the entire session) */
+ switch (gso->brush_type) {
+ /* Brushes requiring timer... */
+ case GP_SCULPT_TYPE_THICKNESS:
+ brush_rate = 0.01f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
+ case GP_SCULPT_TYPE_STRENGTH:
+ brush_rate = 0.01f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
+ case GP_SCULPT_TYPE_PINCH:
+ brush_rate = 0.001f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
+ case GP_SCULPT_TYPE_TWIST:
+ brush_rate = 0.01f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
+ default:
+ break;
+ }
+
+ /* register timer for increasing influence by hovering over an area */
+ if (needs_timer) {
+ gso->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, brush_rate);
+ }
+
+ /* register modal handler */
+ WM_event_add_modal_handler(C, op);
+
+ /* start drawing immediately? */
+ if (is_modal == false) {
+ ARegion *ar = CTX_wm_region(C);
+
+ /* ensure that we'll have a new frame to draw on */
+ gpsculpt_brush_init_stroke(gso);
+
+ /* apply first dab... */
+ gso->is_painting = true;
+ gpsculpt_brush_apply_event(C, op, event);
+
+ /* redraw view with feedback */
+ ED_region_tag_redraw(ar);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
}
/* painting - handle events */
static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGP_BrushEditData *gso = op->customdata;
- const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
- bool redraw_region = false;
- bool redraw_toolsettings = false;
-
- /* The operator can be in 2 states: Painting and Idling */
- if (gso->is_painting) {
- /* Painting */
- switch (event->type) {
- /* Mouse Move = Apply somewhere else */
- case MOUSEMOVE:
- case INBETWEEN_MOUSEMOVE:
- /* apply brush effect at new position */
- gpsculpt_brush_apply_event(C, op, event);
-
- /* force redraw, so that the cursor will at least be valid */
- redraw_region = true;
- break;
-
- /* Timer Tick - Only if this was our own timer */
- case TIMER:
- if (event->customdata == gso->timer) {
- gso->timerTick = true;
- gpsculpt_brush_apply_event(C, op, event);
- gso->timerTick = false;
- }
- break;
-
- /* Adjust brush settings */
- /* FIXME: Step increments and modifier keys are hardcoded here! */
- case WHEELUPMOUSE:
- case PADPLUSKEY:
- if (event->shift) {
- /* increase strength */
- gso->gp_brush->strength += 0.05f;
- CLAMP_MAX(gso->gp_brush->strength, 1.0f);
- }
- else {
- /* increase brush size */
- gso->gp_brush->size += 3;
- CLAMP_MAX(gso->gp_brush->size, 300);
- }
-
- redraw_region = true;
- redraw_toolsettings = true;
- break;
-
- case WHEELDOWNMOUSE:
- case PADMINUS:
- if (event->shift) {
- /* decrease strength */
- gso->gp_brush->strength -= 0.05f;
- CLAMP_MIN(gso->gp_brush->strength, 0.0f);
- }
- else {
- /* decrease brush size */
- gso->gp_brush->size -= 3;
- CLAMP_MIN(gso->gp_brush->size, 1);
- }
-
- redraw_region = true;
- redraw_toolsettings = true;
- break;
-
- /* Painting mbut release = Stop painting (back to idle) */
- case LEFTMOUSE:
- //BLI_assert(event->val == KM_RELEASE);
- if (is_modal) {
- /* go back to idling... */
- gso->is_painting = false;
- }
- else {
- /* end sculpt session, since we're not modal */
- gso->is_painting = false;
-
- gpsculpt_brush_exit(C, op);
- return OPERATOR_FINISHED;
- }
- break;
-
- /* Abort painting if any of the usual things are tried */
- case MIDDLEMOUSE:
- case RIGHTMOUSE:
- case ESCKEY:
- gpsculpt_brush_exit(C, op);
- return OPERATOR_FINISHED;
- }
- }
- else {
- /* Idling */
- BLI_assert(is_modal == true);
-
- switch (event->type) {
- /* Painting mbut press = Start painting (switch to painting state) */
- case LEFTMOUSE:
- /* do initial "click" apply */
- gso->is_painting = true;
- gso->first = true;
-
- gpsculpt_brush_init_stroke(gso);
- gpsculpt_brush_apply_event(C, op, event);
- break;
-
- /* Exit modal operator, based on the "standard" ops */
- case RIGHTMOUSE:
- case ESCKEY:
- gpsculpt_brush_exit(C, op);
- return OPERATOR_FINISHED;
-
- /* MMB is often used for view manipulations */
- case MIDDLEMOUSE:
- return OPERATOR_PASS_THROUGH;
-
- /* Mouse movements should update the brush cursor - Just redraw the active region */
- case MOUSEMOVE:
- case INBETWEEN_MOUSEMOVE:
- redraw_region = true;
- break;
-
- /* Adjust brush settings */
- /* FIXME: Step increments and modifier keys are hardcoded here! */
- case WHEELUPMOUSE:
- case PADPLUSKEY:
- if (event->shift) {
- /* increase strength */
- gso->gp_brush->strength += 0.05f;
- CLAMP_MAX(gso->gp_brush->strength, 1.0f);
- }
- else {
- /* increase brush size */
- gso->gp_brush->size += 3;
- CLAMP_MAX(gso->gp_brush->size, 300);
- }
-
- redraw_region = true;
- redraw_toolsettings = true;
- break;
-
- case WHEELDOWNMOUSE:
- case PADMINUS:
- if (event->shift) {
- /* decrease strength */
- gso->gp_brush->strength -= 0.05f;
- CLAMP_MIN(gso->gp_brush->strength, 0.0f);
- }
- else {
- /* decrease brush size */
- gso->gp_brush->size -= 3;
- CLAMP_MIN(gso->gp_brush->size, 1);
- }
-
- redraw_region = true;
- redraw_toolsettings = true;
- break;
-
- /* Change Frame - Allowed */
- case LEFTARROWKEY:
- case RIGHTARROWKEY:
- case UPARROWKEY:
- case DOWNARROWKEY:
- return OPERATOR_PASS_THROUGH;
-
- /* Camera/View Gizmo's - Allowed */
- /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
- case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
- case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
- return OPERATOR_PASS_THROUGH;
-
- /* Unhandled event */
- default:
- break;
- }
- }
-
- /* Redraw region? */
- if (redraw_region) {
- ARegion *ar = CTX_wm_region(C);
- ED_region_tag_redraw(ar);
- }
-
- /* Redraw toolsettings (brush settings)? */
- if (redraw_toolsettings) {
- DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
- }
-
- return OPERATOR_RUNNING_MODAL;
+ tGP_BrushEditData *gso = op->customdata;
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ bool redraw_region = false;
+ bool redraw_toolsettings = false;
+
+ /* The operator can be in 2 states: Painting and Idling */
+ if (gso->is_painting) {
+ /* Painting */
+ switch (event->type) {
+ /* Mouse Move = Apply somewhere else */
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE:
+ /* apply brush effect at new position */
+ gpsculpt_brush_apply_event(C, op, event);
+
+ /* force redraw, so that the cursor will at least be valid */
+ redraw_region = true;
+ break;
+
+ /* Timer Tick - Only if this was our own timer */
+ case TIMER:
+ if (event->customdata == gso->timer) {
+ gso->timerTick = true;
+ gpsculpt_brush_apply_event(C, op, event);
+ gso->timerTick = false;
+ }
+ break;
+
+ /* Adjust brush settings */
+ /* FIXME: Step increments and modifier keys are hardcoded here! */
+ case WHEELUPMOUSE:
+ case PADPLUSKEY:
+ if (event->shift) {
+ /* increase strength */
+ gso->gp_brush->strength += 0.05f;
+ CLAMP_MAX(gso->gp_brush->strength, 1.0f);
+ }
+ else {
+ /* increase brush size */
+ gso->gp_brush->size += 3;
+ CLAMP_MAX(gso->gp_brush->size, 300);
+ }
+
+ redraw_region = true;
+ redraw_toolsettings = true;
+ break;
+
+ case WHEELDOWNMOUSE:
+ case PADMINUS:
+ if (event->shift) {
+ /* decrease strength */
+ gso->gp_brush->strength -= 0.05f;
+ CLAMP_MIN(gso->gp_brush->strength, 0.0f);
+ }
+ else {
+ /* decrease brush size */
+ gso->gp_brush->size -= 3;
+ CLAMP_MIN(gso->gp_brush->size, 1);
+ }
+
+ redraw_region = true;
+ redraw_toolsettings = true;
+ break;
+
+ /* Painting mbut release = Stop painting (back to idle) */
+ case LEFTMOUSE:
+ //BLI_assert(event->val == KM_RELEASE);
+ if (is_modal) {
+ /* go back to idling... */
+ gso->is_painting = false;
+ }
+ else {
+ /* end sculpt session, since we're not modal */
+ gso->is_painting = false;
+
+ gpsculpt_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ break;
+
+ /* Abort painting if any of the usual things are tried */
+ case MIDDLEMOUSE:
+ case RIGHTMOUSE:
+ case ESCKEY:
+ gpsculpt_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else {
+ /* Idling */
+ BLI_assert(is_modal == true);
+
+ switch (event->type) {
+ /* Painting mbut press = Start painting (switch to painting state) */
+ case LEFTMOUSE:
+ /* do initial "click" apply */
+ gso->is_painting = true;
+ gso->first = true;
+
+ gpsculpt_brush_init_stroke(gso);
+ gpsculpt_brush_apply_event(C, op, event);
+ break;
+
+ /* Exit modal operator, based on the "standard" ops */
+ case RIGHTMOUSE:
+ case ESCKEY:
+ gpsculpt_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+
+ /* MMB is often used for view manipulations */
+ case MIDDLEMOUSE:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Mouse movements should update the brush cursor - Just redraw the active region */
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE:
+ redraw_region = true;
+ break;
+
+ /* Adjust brush settings */
+ /* FIXME: Step increments and modifier keys are hardcoded here! */
+ case WHEELUPMOUSE:
+ case PADPLUSKEY:
+ if (event->shift) {
+ /* increase strength */
+ gso->gp_brush->strength += 0.05f;
+ CLAMP_MAX(gso->gp_brush->strength, 1.0f);
+ }
+ else {
+ /* increase brush size */
+ gso->gp_brush->size += 3;
+ CLAMP_MAX(gso->gp_brush->size, 300);
+ }
+
+ redraw_region = true;
+ redraw_toolsettings = true;
+ break;
+
+ case WHEELDOWNMOUSE:
+ case PADMINUS:
+ if (event->shift) {
+ /* decrease strength */
+ gso->gp_brush->strength -= 0.05f;
+ CLAMP_MIN(gso->gp_brush->strength, 0.0f);
+ }
+ else {
+ /* decrease brush size */
+ gso->gp_brush->size -= 3;
+ CLAMP_MIN(gso->gp_brush->size, 1);
+ }
+
+ redraw_region = true;
+ redraw_toolsettings = true;
+ break;
+
+ /* Change Frame - Allowed */
+ case LEFTARROWKEY:
+ case RIGHTARROWKEY:
+ case UPARROWKEY:
+ case DOWNARROWKEY:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Camera/View Gizmo's - Allowed */
+ /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
+ case PAD0:
+ case PAD1:
+ case PAD2:
+ case PAD3:
+ case PAD4:
+ case PAD5:
+ case PAD6:
+ case PAD7:
+ case PAD8:
+ case PAD9:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Unhandled event */
+ default:
+ break;
+ }
+ }
+
+ /* Redraw region? */
+ if (redraw_region) {
+ ARegion *ar = CTX_wm_region(C);
+ ED_region_tag_redraw(ar);
+ }
+
+ /* Redraw toolsettings (brush settings)? */
+ if (redraw_toolsettings) {
+ DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
}
void GPENCIL_OT_sculpt_paint(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Stroke Sculpt";
- ot->idname = "GPENCIL_OT_sculpt_paint";
- ot->description = "Apply tweaks to strokes by painting over the strokes"; // XXX
-
- /* api callbacks */
- ot->exec = gpsculpt_brush_exec;
- ot->invoke = gpsculpt_brush_invoke;
- ot->modal = gpsculpt_brush_modal;
- ot->cancel = gpsculpt_brush_exit;
- ot->poll = gpsculpt_brush_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* properties */
- PropertyRNA *prop;
- prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input",
- "Enter a mini 'sculpt-mode' if enabled, otherwise, exit after drawing a single stroke");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ /* identifiers */
+ ot->name = "Stroke Sculpt";
+ ot->idname = "GPENCIL_OT_sculpt_paint";
+ ot->description = "Apply tweaks to strokes by painting over the strokes"; // XXX
+
+ /* api callbacks */
+ ot->exec = gpsculpt_brush_exec;
+ ot->invoke = gpsculpt_brush_invoke;
+ ot->modal = gpsculpt_brush_modal;
+ ot->cancel = gpsculpt_brush_exit;
+ ot->poll = gpsculpt_brush_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ PropertyRNA *prop;
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(
+ ot->srna,
+ "wait_for_input",
+ true,
+ "Wait for Input",
+ "Enter a mini 'sculpt-mode' if enabled, otherwise, exit after drawing a single stroke");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index af2c68d6c68..c1c797b15be 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -22,7 +22,6 @@
* \ingroup edgpencil
*/
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -88,50 +87,62 @@
/* defines for possible modes */
enum {
- GP_STROKECONVERT_PATH = 1,
- GP_STROKECONVERT_CURVE,
- GP_STROKECONVERT_POLY,
+ GP_STROKECONVERT_PATH = 1,
+ GP_STROKECONVERT_CURVE,
+ GP_STROKECONVERT_POLY,
};
/* Defines for possible timing modes */
enum {
- GP_STROKECONVERT_TIMING_NONE = 1,
- GP_STROKECONVERT_TIMING_LINEAR = 2,
- GP_STROKECONVERT_TIMING_FULL = 3,
- GP_STROKECONVERT_TIMING_CUSTOMGAP = 4,
+ GP_STROKECONVERT_TIMING_NONE = 1,
+ GP_STROKECONVERT_TIMING_LINEAR = 2,
+ GP_STROKECONVERT_TIMING_FULL = 3,
+ GP_STROKECONVERT_TIMING_CUSTOMGAP = 4,
};
/* RNA enum define */
static const EnumPropertyItem prop_gpencil_convertmodes[] = {
- {GP_STROKECONVERT_PATH, "PATH", ICON_CURVE_PATH, "Path", "Animation path"},
- {GP_STROKECONVERT_CURVE, "CURVE", ICON_CURVE_BEZCURVE, "Bezier Curve", "Smooth Bezier curve"},
- {GP_STROKECONVERT_POLY, "POLY", ICON_MESH_DATA, "Polygon Curve", "Bezier curve with straight-line segments (vector handles)"},
- {0, NULL, 0, NULL, NULL},
+ {GP_STROKECONVERT_PATH, "PATH", ICON_CURVE_PATH, "Path", "Animation path"},
+ {GP_STROKECONVERT_CURVE, "CURVE", ICON_CURVE_BEZCURVE, "Bezier Curve", "Smooth Bezier curve"},
+ {GP_STROKECONVERT_POLY,
+ "POLY",
+ ICON_MESH_DATA,
+ "Polygon Curve",
+ "Bezier curve with straight-line segments (vector handles)"},
+ {0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem prop_gpencil_convert_timingmodes_restricted[] = {
- {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
- {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
- {0, NULL, 0, NULL, NULL},
+ {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
+ {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
+ {0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem prop_gpencil_convert_timingmodes[] = {
- {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
- {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
- {GP_STROKECONVERT_TIMING_FULL, "FULL", 0, "Original", "Use the original timing, gaps included"},
- {GP_STROKECONVERT_TIMING_CUSTOMGAP, "CUSTOMGAP", 0, "Custom Gaps",
- "Use the original timing, but with custom gap lengths (in frames)"},
- {0, NULL, 0, NULL, NULL},
+ {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
+ {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
+ {GP_STROKECONVERT_TIMING_FULL,
+ "FULL",
+ 0,
+ "Original",
+ "Use the original timing, gaps included"},
+ {GP_STROKECONVERT_TIMING_CUSTOMGAP,
+ "CUSTOMGAP",
+ 0,
+ "Custom Gaps",
+ "Use the original timing, but with custom gap lengths (in frames)"},
+ {0, NULL, 0, NULL, NULL},
};
-static const EnumPropertyItem *rna_GPConvert_mode_items(
- bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop),
- bool *UNUSED(r_free))
+static const EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C),
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *UNUSED(r_free))
{
- if (RNA_boolean_get(ptr, "use_timing_data")) {
- return prop_gpencil_convert_timingmodes;
- }
- return prop_gpencil_convert_timingmodes_restricted;
+ if (RNA_boolean_get(ptr, "use_timing_data")) {
+ return prop_gpencil_convert_timingmodes;
+ }
+ return prop_gpencil_convert_timingmodes_restricted;
}
/* --- */
@@ -139,81 +150,84 @@ static const EnumPropertyItem *rna_GPConvert_mode_items(
/* convert the coordinates from the given stroke point into 3d-coordinates
* - assumes that the active space is the 3D-View
*/
-static void gp_strokepoint_convertcoords(
- bContext *C, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *source_pt,
- float p3d[3], const rctf *subrect)
+static void gp_strokepoint_convertcoords(bContext *C,
+ bGPdata *gpd,
+ bGPDlayer *gpl,
+ bGPDstroke *gps,
+ bGPDspoint *source_pt,
+ float p3d[3],
+ const rctf *subrect)
{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *obact = CTX_data_active_object(C);
- bGPDspoint mypt, *pt;
-
- float diff_mat[4][4];
- pt = &mypt;
-
- /* apply parent transform */
- float fpt[3];
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
- mul_v3_m4v3(fpt, diff_mat, &source_pt->x);
- copy_v3_v3(&pt->x, fpt);
-
-
- if (gps->flag & GP_STROKE_3DSPACE) {
- /* directly use 3d-coordinates */
- copy_v3_v3(p3d, &pt->x);
- }
- else {
- const float *fp = scene->cursor.location;
- float mvalf[2];
-
- /* get screen coordinate */
- if (gps->flag & GP_STROKE_2DSPACE) {
- View2D *v2d = &ar->v2d;
- UI_view2d_view_to_region_fl(v2d, pt->x, pt->y, &mvalf[0], &mvalf[1]);
- }
- else {
- if (subrect) {
- mvalf[0] = (((float)pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
- mvalf[1] = (((float)pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
- }
- else {
- mvalf[0] = (float)pt->x / 100.0f * ar->winx;
- mvalf[1] = (float)pt->y / 100.0f * ar->winy;
- }
- }
-
- ED_view3d_win_to_3d(v3d, ar, fp, mvalf, p3d);
- }
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *obact = CTX_data_active_object(C);
+ bGPDspoint mypt, *pt;
+
+ float diff_mat[4][4];
+ pt = &mypt;
+
+ /* apply parent transform */
+ float fpt[3];
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ mul_v3_m4v3(fpt, diff_mat, &source_pt->x);
+ copy_v3_v3(&pt->x, fpt);
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* directly use 3d-coordinates */
+ copy_v3_v3(p3d, &pt->x);
+ }
+ else {
+ const float *fp = scene->cursor.location;
+ float mvalf[2];
+
+ /* get screen coordinate */
+ if (gps->flag & GP_STROKE_2DSPACE) {
+ View2D *v2d = &ar->v2d;
+ UI_view2d_view_to_region_fl(v2d, pt->x, pt->y, &mvalf[0], &mvalf[1]);
+ }
+ else {
+ if (subrect) {
+ mvalf[0] = (((float)pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
+ mvalf[1] = (((float)pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
+ }
+ else {
+ mvalf[0] = (float)pt->x / 100.0f * ar->winx;
+ mvalf[1] = (float)pt->y / 100.0f * ar->winy;
+ }
+ }
+
+ ED_view3d_win_to_3d(v3d, ar, fp, mvalf, p3d);
+ }
}
/* --- */
/* temp struct for gp_stroke_path_animation() */
typedef struct tGpTimingData {
- /* Data set from operator settings */
- int mode;
- int frame_range; /* Number of frames evaluated for path animation */
- int start_frame, end_frame;
- bool realtime; /* Will overwrite end_frame in case of Original or CustomGap timing... */
- float gap_duration, gap_randomness; /* To be used with CustomGap mode*/
- int seed;
-
- /* Data set from points, used to compute final timing FCurve */
- int num_points, cur_point;
-
- /* Distances */
- float *dists;
- float tot_dist;
-
- /* Times */
- float *times; /* Note: Gap times will be negative! */
- float tot_time, gap_tot_time;
- double inittime;
-
- /* Only used during creation of dists & times lists. */
- float offset_time;
+ /* Data set from operator settings */
+ int mode;
+ int frame_range; /* Number of frames evaluated for path animation */
+ int start_frame, end_frame;
+ bool realtime; /* Will overwrite end_frame in case of Original or CustomGap timing... */
+ float gap_duration, gap_randomness; /* To be used with CustomGap mode*/
+ int seed;
+
+ /* Data set from points, used to compute final timing FCurve */
+ int num_points, cur_point;
+
+ /* Distances */
+ float *dists;
+ float tot_dist;
+
+ /* Times */
+ float *times; /* Note: Gap times will be negative! */
+ float tot_time, gap_tot_time;
+ double inittime;
+
+ /* Only used during creation of dists & times lists. */
+ float offset_time;
} tGpTimingData;
/* Init point buffers for timing data.
@@ -221,59 +235,61 @@ typedef struct tGpTimingData {
*/
static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr)
{
- float *tmp;
-
- BLI_assert(nbr > gtd->num_points);
-
- /* distances */
- tmp = gtd->dists;
- gtd->dists = MEM_callocN(sizeof(float) * nbr, __func__);
- if (tmp) {
- memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points);
- MEM_freeN(tmp);
- }
-
- /* times */
- tmp = gtd->times;
- gtd->times = MEM_callocN(sizeof(float) * nbr, __func__);
- if (tmp) {
- memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points);
- MEM_freeN(tmp);
- }
-
- gtd->num_points = nbr;
+ float *tmp;
+
+ BLI_assert(nbr > gtd->num_points);
+
+ /* distances */
+ tmp = gtd->dists;
+ gtd->dists = MEM_callocN(sizeof(float) * nbr, __func__);
+ if (tmp) {
+ memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points);
+ MEM_freeN(tmp);
+ }
+
+ /* times */
+ tmp = gtd->times;
+ gtd->times = MEM_callocN(sizeof(float) * nbr, __func__);
+ if (tmp) {
+ memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points);
+ MEM_freeN(tmp);
+ }
+
+ gtd->num_points = nbr;
}
/* add stroke point to timing buffers */
-static void gp_timing_data_add_point(
- tGpTimingData *gtd, const double stroke_inittime, const float time,
- const float delta_dist)
+static void gp_timing_data_add_point(tGpTimingData *gtd,
+ const double stroke_inittime,
+ const float time,
+ const float delta_dist)
{
- float delta_time = 0.0f;
- const int cur_point = gtd->cur_point;
-
- if (!cur_point) {
- /* Special case, first point, if time is not 0.0f we have to compensate! */
- gtd->offset_time = -time;
- gtd->times[cur_point] = 0.0f;
- }
- else if (time < 0.0f) {
- /* This is a gap, negative value! */
- gtd->times[cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
- delta_time = -gtd->times[cur_point] - gtd->times[cur_point - 1];
-
- gtd->gap_tot_time += delta_time;
- }
- else {
- gtd->times[cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
- delta_time = gtd->times[cur_point] - fabsf(gtd->times[cur_point - 1]);
- }
-
- gtd->tot_time += delta_time;
- gtd->tot_dist += delta_dist;
- gtd->dists[cur_point] = gtd->tot_dist;
-
- gtd->cur_point++;
+ float delta_time = 0.0f;
+ const int cur_point = gtd->cur_point;
+
+ if (!cur_point) {
+ /* Special case, first point, if time is not 0.0f we have to compensate! */
+ gtd->offset_time = -time;
+ gtd->times[cur_point] = 0.0f;
+ }
+ else if (time < 0.0f) {
+ /* This is a gap, negative value! */
+ gtd->times[cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time +
+ gtd->offset_time);
+ delta_time = -gtd->times[cur_point] - gtd->times[cur_point - 1];
+
+ gtd->gap_tot_time += delta_time;
+ }
+ else {
+ gtd->times[cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
+ delta_time = gtd->times[cur_point] - fabsf(gtd->times[cur_point - 1]);
+ }
+
+ gtd->tot_time += delta_time;
+ gtd->tot_dist += delta_dist;
+ gtd->dists[cur_point] = gtd->tot_dist;
+
+ gtd->cur_point++;
}
/* In frames! Binary search for FCurve keys have a threshold of 0.01, so we can't set
@@ -282,271 +298,301 @@ static void gp_timing_data_add_point(
#define MIN_TIME_DELTA 0.02f
/* Loop over next points to find the end of the stroke, and compute */
-static int gp_find_end_of_stroke_idx(
- tGpTimingData *gtd, RNG *rng, const int idx, const int nbr_gaps,
- int *nbr_done_gaps, const float tot_gaps_time, const float delta_time,
- float *next_delta_time)
+static int gp_find_end_of_stroke_idx(tGpTimingData *gtd,
+ RNG *rng,
+ const int idx,
+ const int nbr_gaps,
+ int *nbr_done_gaps,
+ const float tot_gaps_time,
+ const float delta_time,
+ float *next_delta_time)
{
- int j;
-
- for (j = idx + 1; j < gtd->num_points; j++) {
- if (gtd->times[j] < 0) {
- gtd->times[j] = -gtd->times[j];
- if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- /* In this mode, gap time between this stroke and the next should be 0 currently...
- * So we have to compute its final duration!
- */
- if (gtd->gap_randomness > 0.0f) {
- /* We want gaps that are in gtd->gap_duration +/- gtd->gap_randomness range,
- * and which sum to exactly tot_gaps_time...
- */
- int rem_gaps = nbr_gaps - (*nbr_done_gaps);
- if (rem_gaps < 2) {
- /* Last gap, just give remaining time! */
- *next_delta_time = tot_gaps_time;
- }
- else {
- float delta, min, max;
-
- /* This code ensures that if the first gaps have been shorter than average gap_duration,
- * next gaps will tend to be longer (i.e. try to recover the lateness), and vice-versa!
- */
- delta = delta_time - (gtd->gap_duration * (*nbr_done_gaps));
-
- /* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */
- min = -gtd->gap_randomness - delta;
- CLAMP(min, -gtd->gap_randomness, 0.0f);
-
- /* Clamp max between [0.0, gap_randomness], with lower delta giving higher max */
- max = gtd->gap_randomness - delta;
- CLAMP(max, 0.0f, gtd->gap_randomness);
- *next_delta_time += gtd->gap_duration + (BLI_rng_get_float(rng) * (max - min)) + min;
- }
- }
- else {
- *next_delta_time += gtd->gap_duration;
- }
- }
- (*nbr_done_gaps)++;
- break;
- }
- }
-
- return j - 1;
+ int j;
+
+ for (j = idx + 1; j < gtd->num_points; j++) {
+ if (gtd->times[j] < 0) {
+ gtd->times[j] = -gtd->times[j];
+ if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
+ /* In this mode, gap time between this stroke and the next should be 0 currently...
+ * So we have to compute its final duration!
+ */
+ if (gtd->gap_randomness > 0.0f) {
+ /* We want gaps that are in gtd->gap_duration +/- gtd->gap_randomness range,
+ * and which sum to exactly tot_gaps_time...
+ */
+ int rem_gaps = nbr_gaps - (*nbr_done_gaps);
+ if (rem_gaps < 2) {
+ /* Last gap, just give remaining time! */
+ *next_delta_time = tot_gaps_time;
+ }
+ else {
+ float delta, min, max;
+
+ /* This code ensures that if the first gaps have been shorter than average gap_duration,
+ * next gaps will tend to be longer (i.e. try to recover the lateness), and vice-versa!
+ */
+ delta = delta_time - (gtd->gap_duration * (*nbr_done_gaps));
+
+ /* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */
+ min = -gtd->gap_randomness - delta;
+ CLAMP(min, -gtd->gap_randomness, 0.0f);
+
+ /* Clamp max between [0.0, gap_randomness], with lower delta giving higher max */
+ max = gtd->gap_randomness - delta;
+ CLAMP(max, 0.0f, gtd->gap_randomness);
+ *next_delta_time += gtd->gap_duration + (BLI_rng_get_float(rng) * (max - min)) + min;
+ }
+ }
+ else {
+ *next_delta_time += gtd->gap_duration;
+ }
+ }
+ (*nbr_done_gaps)++;
+ break;
+ }
+ }
+
+ return j - 1;
}
-static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rng, int *nbr_gaps, float *tot_gaps_time)
+static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd,
+ RNG *rng,
+ int *nbr_gaps,
+ float *tot_gaps_time)
{
- int i;
- float delta_time = 0.0f;
-
- for (i = 0; i < gtd->num_points; i++) {
- if (gtd->times[i] < 0 && i) {
- (*nbr_gaps)++;
- gtd->times[i] = -gtd->times[i] - delta_time;
- delta_time += gtd->times[i] - gtd->times[i - 1];
- gtd->times[i] = -gtd->times[i - 1]; /* Temp marker, values *have* to be different! */
- }
- else {
- gtd->times[i] -= delta_time;
- }
- }
- gtd->tot_time -= delta_time;
-
- *tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration;
- gtd->tot_time += *tot_gaps_time;
- if (G.debug & G_DEBUG) {
- printf("%f, %f, %f, %d\n", gtd->tot_time, delta_time, *tot_gaps_time, *nbr_gaps);
- }
- if (gtd->gap_randomness > 0.0f) {
- BLI_rng_srandom(rng, gtd->seed);
- }
+ int i;
+ float delta_time = 0.0f;
+
+ for (i = 0; i < gtd->num_points; i++) {
+ if (gtd->times[i] < 0 && i) {
+ (*nbr_gaps)++;
+ gtd->times[i] = -gtd->times[i] - delta_time;
+ delta_time += gtd->times[i] - gtd->times[i - 1];
+ gtd->times[i] = -gtd->times[i - 1]; /* Temp marker, values *have* to be different! */
+ }
+ else {
+ gtd->times[i] -= delta_time;
+ }
+ }
+ gtd->tot_time -= delta_time;
+
+ *tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration;
+ gtd->tot_time += *tot_gaps_time;
+ if (G.debug & G_DEBUG) {
+ printf("%f, %f, %f, %d\n", gtd->tot_time, delta_time, *tot_gaps_time, *nbr_gaps);
+ }
+ if (gtd->gap_randomness > 0.0f) {
+ BLI_rng_srandom(rng, gtd->seed);
+ }
}
-static void gp_stroke_path_animation_add_keyframes(
- Depsgraph *depsgraph, ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu,
- Curve *cu, tGpTimingData *gtd, RNG *rng, const float time_range,
- const int nbr_gaps, const float tot_gaps_time)
+static void gp_stroke_path_animation_add_keyframes(Depsgraph *depsgraph,
+ ReportList *reports,
+ PointerRNA ptr,
+ PropertyRNA *prop,
+ FCurve *fcu,
+ Curve *cu,
+ tGpTimingData *gtd,
+ RNG *rng,
+ const float time_range,
+ const int nbr_gaps,
+ const float tot_gaps_time)
{
- /* Use actual recorded timing! */
- const float time_start = (float)gtd->start_frame;
-
- float last_valid_time = 0.0f;
- int end_stroke_idx = -1, start_stroke_idx = 0;
- float end_stroke_time = 0.0f;
-
- /* CustomGaps specific */
- float delta_time = 0.0f, next_delta_time = 0.0f;
- int nbr_done_gaps = 0;
-
- int i;
- float cfra;
-
- /* This is a bit tricky, as:
- * - We can't add arbitrarily close points on FCurve (in time).
- * - We *must* have all "caps" points of all strokes in FCurve, as much as possible!
- */
- for (i = 0; i < gtd->num_points; i++) {
- /* If new stroke... */
- if (i > end_stroke_idx) {
- start_stroke_idx = i;
- delta_time = next_delta_time;
- /* find end of that new stroke */
- end_stroke_idx = gp_find_end_of_stroke_idx(
- gtd, rng, i, nbr_gaps, &nbr_done_gaps,
- tot_gaps_time, delta_time, &next_delta_time);
- /* This one should *never* be negative! */
- end_stroke_time = time_start + ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range);
- }
-
- /* Simple proportional stuff... */
- cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen;
- cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range);
-
- /* And now, the checks about timing... */
- if (i == start_stroke_idx) {
- /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and
- * that the end point of the stroke is far enough!
- * In case it is not, we keep the end point...
- * Note that with CustomGaps mode, this is here we set the actual gap timing!
- */
- if ((end_stroke_time - last_valid_time) > MIN_TIME_DELTA * 2) {
- if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
- cfra = last_valid_time + MIN_TIME_DELTA;
- }
- insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, NULL, INSERTKEY_FAST);
- last_valid_time = cfra;
- }
- else if (G.debug & G_DEBUG) {
- printf("\t Skipping start point %d, too close from end point %d\n", i, end_stroke_idx);
- }
- }
- else if (i == end_stroke_idx) {
- /* Always try to insert end point of a curve (should be safe enough, anyway...) */
- if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
- cfra = last_valid_time + MIN_TIME_DELTA;
- }
- insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, NULL, INSERTKEY_FAST);
- last_valid_time = cfra;
- }
- else {
- /* Else ("middle" point), we only insert it if it's far enough from last keyframe,
- * and also far enough from (not yet added!) end_stroke keyframe!
- */
- if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) {
- insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_BREAKDOWN, NULL, INSERTKEY_FAST);
- last_valid_time = cfra;
- }
- else if (G.debug & G_DEBUG) {
- printf("\t Skipping \"middle\" point %d, too close from last added point or end point %d\n",
- i, end_stroke_idx);
- }
- }
- }
+ /* Use actual recorded timing! */
+ const float time_start = (float)gtd->start_frame;
+
+ float last_valid_time = 0.0f;
+ int end_stroke_idx = -1, start_stroke_idx = 0;
+ float end_stroke_time = 0.0f;
+
+ /* CustomGaps specific */
+ float delta_time = 0.0f, next_delta_time = 0.0f;
+ int nbr_done_gaps = 0;
+
+ int i;
+ float cfra;
+
+ /* This is a bit tricky, as:
+ * - We can't add arbitrarily close points on FCurve (in time).
+ * - We *must* have all "caps" points of all strokes in FCurve, as much as possible!
+ */
+ for (i = 0; i < gtd->num_points; i++) {
+ /* If new stroke... */
+ if (i > end_stroke_idx) {
+ start_stroke_idx = i;
+ delta_time = next_delta_time;
+ /* find end of that new stroke */
+ end_stroke_idx = gp_find_end_of_stroke_idx(
+ gtd, rng, i, nbr_gaps, &nbr_done_gaps, tot_gaps_time, delta_time, &next_delta_time);
+ /* This one should *never* be negative! */
+ end_stroke_time = time_start +
+ ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range);
+ }
+
+ /* Simple proportional stuff... */
+ cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen;
+ cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range);
+
+ /* And now, the checks about timing... */
+ if (i == start_stroke_idx) {
+ /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and
+ * that the end point of the stroke is far enough!
+ * In case it is not, we keep the end point...
+ * Note that with CustomGaps mode, this is here we set the actual gap timing!
+ */
+ if ((end_stroke_time - last_valid_time) > MIN_TIME_DELTA * 2) {
+ if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
+ cfra = last_valid_time + MIN_TIME_DELTA;
+ }
+ insert_keyframe_direct(
+ depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, NULL, INSERTKEY_FAST);
+ last_valid_time = cfra;
+ }
+ else if (G.debug & G_DEBUG) {
+ printf("\t Skipping start point %d, too close from end point %d\n", i, end_stroke_idx);
+ }
+ }
+ else if (i == end_stroke_idx) {
+ /* Always try to insert end point of a curve (should be safe enough, anyway...) */
+ if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
+ cfra = last_valid_time + MIN_TIME_DELTA;
+ }
+ insert_keyframe_direct(
+ depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, NULL, INSERTKEY_FAST);
+ last_valid_time = cfra;
+ }
+ else {
+ /* Else ("middle" point), we only insert it if it's far enough from last keyframe,
+ * and also far enough from (not yet added!) end_stroke keyframe!
+ */
+ if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) {
+ insert_keyframe_direct(depsgraph,
+ reports,
+ ptr,
+ prop,
+ fcu,
+ cfra,
+ BEZT_KEYTYPE_BREAKDOWN,
+ NULL,
+ INSERTKEY_FAST);
+ last_valid_time = cfra;
+ }
+ else if (G.debug & G_DEBUG) {
+ printf(
+ "\t Skipping \"middle\" point %d, too close from last added point or end point %d\n",
+ i,
+ end_stroke_idx);
+ }
+ }
+ }
}
-static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd)
+static void gp_stroke_path_animation(bContext *C,
+ ReportList *reports,
+ Curve *cu,
+ tGpTimingData *gtd)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- bAction *act;
- FCurve *fcu;
- PointerRNA ptr;
- PropertyRNA *prop = NULL;
- int nbr_gaps = 0, i;
-
- if (gtd->mode == GP_STROKECONVERT_TIMING_NONE)
- return;
-
- /* gap_duration and gap_randomness are in frames, but we need seconds!!! */
- gtd->gap_duration = FRA2TIME(gtd->gap_duration);
- gtd->gap_randomness = FRA2TIME(gtd->gap_randomness);
-
- /* Enable path! */
- cu->flag |= CU_PATH;
- cu->pathlen = gtd->frame_range;
-
- /* Get RNA pointer to read/write path time values */
- RNA_id_pointer_create((ID *)cu, &ptr);
- prop = RNA_struct_find_property(&ptr, "eval_time");
-
- /* Ensure we have an F-Curve to add keyframes to */
- act = verify_adt_action(bmain, (ID *)cu, true);
- fcu = verify_fcurve(bmain, act, NULL, &ptr, "eval_time", 0, true);
-
- if (G.debug & G_DEBUG) {
- printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
- for (i = 0; i < gtd->num_points; i++) {
- printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
- }
- }
-
- if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) {
- float cfra;
-
- /* Linear extrapolation! */
- fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
-
- cu->ctime = 0.0f;
- cfra = (float)gtd->start_frame;
- insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, NULL, INSERTKEY_FAST);
-
- cu->ctime = cu->pathlen;
- if (gtd->realtime) {
- cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
- }
- else {
- cfra = (float)gtd->end_frame;
- }
- insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, NULL, INSERTKEY_FAST);
- }
- else {
- /* Use actual recorded timing! */
- RNG *rng = BLI_rng_new(0);
- float time_range;
-
- /* CustomGaps specific */
- float tot_gaps_time = 0.0f;
-
- /* Pre-process gaps, in case we don't want to keep their original timing */
- if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- gp_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time);
- }
-
- if (gtd->realtime) {
- time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
- }
- else {
- time_range = (float)(gtd->end_frame - gtd->start_frame);
- }
-
- if (G.debug & G_DEBUG) {
- printf("GP Stroke Path Conversion: Starting keying!\n");
- }
-
- gp_stroke_path_animation_add_keyframes(
- depsgraph, reports, ptr, prop, fcu, cu, gtd, rng, time_range,
- nbr_gaps, tot_gaps_time);
-
- BLI_rng_free(rng);
- }
-
- /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */
- calchandles_fcurve(fcu);
-
- if (G.debug & G_DEBUG) {
- printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
- for (i = 0; i < gtd->num_points; i++) {
- printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
- }
- printf("\n\n");
- }
-
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
-
- /* send updates */
- DEG_id_tag_update(&cu->id, 0);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ bAction *act;
+ FCurve *fcu;
+ PointerRNA ptr;
+ PropertyRNA *prop = NULL;
+ int nbr_gaps = 0, i;
+
+ if (gtd->mode == GP_STROKECONVERT_TIMING_NONE)
+ return;
+
+ /* gap_duration and gap_randomness are in frames, but we need seconds!!! */
+ gtd->gap_duration = FRA2TIME(gtd->gap_duration);
+ gtd->gap_randomness = FRA2TIME(gtd->gap_randomness);
+
+ /* Enable path! */
+ cu->flag |= CU_PATH;
+ cu->pathlen = gtd->frame_range;
+
+ /* Get RNA pointer to read/write path time values */
+ RNA_id_pointer_create((ID *)cu, &ptr);
+ prop = RNA_struct_find_property(&ptr, "eval_time");
+
+ /* Ensure we have an F-Curve to add keyframes to */
+ act = verify_adt_action(bmain, (ID *)cu, true);
+ fcu = verify_fcurve(bmain, act, NULL, &ptr, "eval_time", 0, true);
+
+ if (G.debug & G_DEBUG) {
+ printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
+ for (i = 0; i < gtd->num_points; i++) {
+ printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
+ }
+ }
+
+ if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) {
+ float cfra;
+
+ /* Linear extrapolation! */
+ fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
+
+ cu->ctime = 0.0f;
+ cfra = (float)gtd->start_frame;
+ insert_keyframe_direct(
+ depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, NULL, INSERTKEY_FAST);
+
+ cu->ctime = cu->pathlen;
+ if (gtd->realtime) {
+ cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
+ }
+ else {
+ cfra = (float)gtd->end_frame;
+ }
+ insert_keyframe_direct(
+ depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, NULL, INSERTKEY_FAST);
+ }
+ else {
+ /* Use actual recorded timing! */
+ RNG *rng = BLI_rng_new(0);
+ float time_range;
+
+ /* CustomGaps specific */
+ float tot_gaps_time = 0.0f;
+
+ /* Pre-process gaps, in case we don't want to keep their original timing */
+ if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
+ gp_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time);
+ }
+
+ if (gtd->realtime) {
+ time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
+ }
+ else {
+ time_range = (float)(gtd->end_frame - gtd->start_frame);
+ }
+
+ if (G.debug & G_DEBUG) {
+ printf("GP Stroke Path Conversion: Starting keying!\n");
+ }
+
+ gp_stroke_path_animation_add_keyframes(
+ depsgraph, reports, ptr, prop, fcu, cu, gtd, rng, time_range, nbr_gaps, tot_gaps_time);
+
+ BLI_rng_free(rng);
+ }
+
+ /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */
+ calchandles_fcurve(fcu);
+
+ if (G.debug & G_DEBUG) {
+ printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
+ for (i = 0; i < gtd->num_points; i++) {
+ printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
+ }
+ printf("\n\n");
+ }
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ /* send updates */
+ DEG_id_tag_update(&cu->id, 0);
}
#undef MIN_TIME_DELTA
@@ -558,486 +604,559 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
/* convert stroke to 3d path */
/* helper */
-static void gp_stroke_to_path_add_point(
- tGpTimingData *gtd, BPoint *bp, const float p[3], const float prev_p[3],
- const bool do_gtd, const double inittime, const float time,
- const float width, const float rad_fac, float minmax_weights[2])
+static void gp_stroke_to_path_add_point(tGpTimingData *gtd,
+ BPoint *bp,
+ const float p[3],
+ const float prev_p[3],
+ const bool do_gtd,
+ const double inittime,
+ const float time,
+ const float width,
+ const float rad_fac,
+ float minmax_weights[2])
{
- copy_v3_v3(bp->vec, p);
- bp->vec[3] = 1.0f;
-
- /* set settings */
- bp->f1 = SELECT;
- bp->radius = width * rad_fac;
- bp->weight = width;
- CLAMP(bp->weight, 0.0f, 1.0f);
- if (bp->weight < minmax_weights[0]) {
- minmax_weights[0] = bp->weight;
- }
- else if (bp->weight > minmax_weights[1]) {
- minmax_weights[1] = bp->weight;
- }
-
- /* Update timing data */
- if (do_gtd) {
- gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
- }
+ copy_v3_v3(bp->vec, p);
+ bp->vec[3] = 1.0f;
+
+ /* set settings */
+ bp->f1 = SELECT;
+ bp->radius = width * rad_fac;
+ bp->weight = width;
+ CLAMP(bp->weight, 0.0f, 1.0f);
+ if (bp->weight < minmax_weights[0]) {
+ minmax_weights[0] = bp->weight;
+ }
+ else if (bp->weight > minmax_weights[1]) {
+ minmax_weights[1] = bp->weight;
+ }
+
+ /* Update timing data */
+ if (do_gtd) {
+ gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
+ }
}
-static void gp_stroke_to_path(
- bContext *C, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
- float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
- const bool add_end_point, tGpTimingData *gtd)
+static void gp_stroke_to_path(bContext *C,
+ bGPdata *gpd,
+ bGPDlayer *gpl,
+ bGPDstroke *gps,
+ Curve *cu,
+ rctf *subrect,
+ Nurb **curnu,
+ float minmax_weights[2],
+ const float rad_fac,
+ bool stitch,
+ const bool add_start_point,
+ const bool add_end_point,
+ tGpTimingData *gtd)
{
- bGPDspoint *pt;
- Nurb *nu = (curnu) ? *curnu : NULL;
- BPoint *bp, *prev_bp = NULL;
- const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
- const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
- int i, old_nbp = 0;
-
- /* create new 'nurb' or extend current one within the curve */
- if (nu) {
- old_nbp = nu->pntsu;
-
- /* If stitch, the first point of this stroke is already present in current nu.
- * Else, we have to add two additional points to make the zero-radius link between strokes.
- */
- BKE_nurb_points_add(nu, gps->totpoints + (stitch ? -1 : 2) + add_start_end_points);
- }
- else {
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
-
- nu->pntsu = gps->totpoints + add_start_end_points;
- nu->pntsv = 1;
- nu->orderu = 2; /* point-to-point! */
- nu->type = CU_NURBS;
- nu->flagu = CU_NURB_ENDPOINT;
- nu->resolu = cu->resolu;
- nu->resolv = cu->resolv;
- nu->knotsu = NULL;
-
- nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints");
-
- stitch = false; /* Security! */
- }
-
- if (do_gtd) {
- gp_timing_data_set_nbr(gtd, nu->pntsu);
- }
-
- /* If needed, make the link between both strokes with two zero-radius additional points */
- /* About "zero-radius" point interpolations:
- * - If we have at least two points in current curve (most common case), we linearly extrapolate
- * the last segment to get the first point (p1) position and timing.
- * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
- * with the first point of the current stroke.
- * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
- * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
- */
- if (curnu && !stitch && old_nbp) {
- float p1[3], p2[3], p[3], next_p[3];
- float dt1 = 0.0f, dt2 = 0.0f;
-
- BLI_assert(gps->prev != NULL);
-
- prev_bp = NULL;
- if ((old_nbp > 1) && (gps->prev->totpoints > 1)) {
- /* Only use last curve segment if previous stroke was not a single-point one! */
- prev_bp = &nu->bp[old_nbp - 2];
- }
- bp = &nu->bp[old_nbp - 1];
-
- /* First point */
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect);
- if (prev_bp) {
- interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->prev->totpoints - 1;
- dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p1, bp->vec, p, GAP_DFAC);
- if (do_gtd) {
- dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
- }
- }
- bp++;
- gp_stroke_to_path_add_point(
- gtd, bp, p1, (bp - 1)->vec, do_gtd, gps->prev->inittime, dt1,
- 0.0f, rad_fac, minmax_weights);
-
- /* Second point */
- /* Note dt2 is always negative, which marks the gap. */
- if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect);
- interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p2, p, bp->vec, GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
- }
- }
- bp++;
- gp_stroke_to_path_add_point(gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights);
-
- old_nbp += 2;
- }
- else if (add_start_point) {
- float p[3], next_p[3];
- float dt = 0.0f;
-
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect);
- if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect);
- interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
- if (do_gtd) {
- dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- p[0] -= GAP_DFAC; /* Rather arbitrary... */
- dt = -GAP_DFAC; /* Rather arbitrary too! */
- }
- bp = &nu->bp[old_nbp];
- /* Note we can't give anything else than 0.0 as time here, since a negative one (which would be expected value)
- * would not work (it would be *before* gtd->inittime, which is not supported currently).
- */
- gp_stroke_to_path_add_point(gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
-
- old_nbp++;
- }
-
- if (old_nbp) {
- prev_bp = &nu->bp[old_nbp - 1];
- }
-
- /* add points */
- for (i = (stitch) ? 1 : 0, pt = &gps->points[(stitch) ? 1 : 0], bp = &nu->bp[old_nbp];
- i < gps->totpoints;
- i++, pt++, bp++)
- {
- float p[3];
- float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC;
-
- /* get coordinates to add at */
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, p, subrect);
-
- gp_stroke_to_path_add_point(
- gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time,
- width, rad_fac, minmax_weights);
-
- prev_bp = bp;
- }
-
- if (add_end_point) {
- float p[3];
- float dt = 0.0f;
-
- if (gps->totpoints > 1) {
- interp_v3_v3v3(p, prev_bp->vec, (prev_bp - 1)->vec, -GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->totpoints - 1;
- dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- copy_v3_v3(p, prev_bp->vec);
- p[0] += GAP_DFAC; /* Rather arbitrary... */
- dt = GAP_DFAC; /* Rather arbitrary too! */
- }
- /* Note bp has already been incremented in main loop above, so it points to the right place. */
- gp_stroke_to_path_add_point(gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
- }
-
- /* add nurb to curve */
- if (!curnu || !*curnu) {
- BLI_addtail(&cu->nurb, nu);
- }
- if (curnu) {
- *curnu = nu;
- }
-
- BKE_nurb_knot_calc_u(nu);
+ bGPDspoint *pt;
+ Nurb *nu = (curnu) ? *curnu : NULL;
+ BPoint *bp, *prev_bp = NULL;
+ const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
+ const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
+ int i, old_nbp = 0;
+
+ /* create new 'nurb' or extend current one within the curve */
+ if (nu) {
+ old_nbp = nu->pntsu;
+
+ /* If stitch, the first point of this stroke is already present in current nu.
+ * Else, we have to add two additional points to make the zero-radius link between strokes.
+ */
+ BKE_nurb_points_add(nu, gps->totpoints + (stitch ? -1 : 2) + add_start_end_points);
+ }
+ else {
+ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
+
+ nu->pntsu = gps->totpoints + add_start_end_points;
+ nu->pntsv = 1;
+ nu->orderu = 2; /* point-to-point! */
+ nu->type = CU_NURBS;
+ nu->flagu = CU_NURB_ENDPOINT;
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+ nu->knotsu = NULL;
+
+ nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints");
+
+ stitch = false; /* Security! */
+ }
+
+ if (do_gtd) {
+ gp_timing_data_set_nbr(gtd, nu->pntsu);
+ }
+
+ /* If needed, make the link between both strokes with two zero-radius additional points */
+ /* About "zero-radius" point interpolations:
+ * - If we have at least two points in current curve (most common case), we linearly extrapolate
+ * the last segment to get the first point (p1) position and timing.
+ * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
+ * with the first point of the current stroke.
+ * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
+ * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
+ */
+ if (curnu && !stitch && old_nbp) {
+ float p1[3], p2[3], p[3], next_p[3];
+ float dt1 = 0.0f, dt2 = 0.0f;
+
+ BLI_assert(gps->prev != NULL);
+
+ prev_bp = NULL;
+ if ((old_nbp > 1) && (gps->prev->totpoints > 1)) {
+ /* Only use last curve segment if previous stroke was not a single-point one! */
+ prev_bp = &nu->bp[old_nbp - 2];
+ }
+ bp = &nu->bp[old_nbp - 1];
+
+ /* First point */
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect);
+ if (prev_bp) {
+ interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->prev->totpoints - 1;
+ dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p1, bp->vec, p, GAP_DFAC);
+ if (do_gtd) {
+ dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+ bp++;
+ gp_stroke_to_path_add_point(gtd,
+ bp,
+ p1,
+ (bp - 1)->vec,
+ do_gtd,
+ gps->prev->inittime,
+ dt1,
+ 0.0f,
+ rad_fac,
+ minmax_weights);
+
+ /* Second point */
+ /* Note dt2 is always negative, which marks the gap. */
+ if (gps->totpoints > 1) {
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect);
+ interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p2, p, bp->vec, GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+ bp++;
+ gp_stroke_to_path_add_point(
+ gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights);
+
+ old_nbp += 2;
+ }
+ else if (add_start_point) {
+ float p[3], next_p[3];
+ float dt = 0.0f;
+
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect);
+ if (gps->totpoints > 1) {
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect);
+ interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
+ if (do_gtd) {
+ dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ p[0] -= GAP_DFAC; /* Rather arbitrary... */
+ dt = -GAP_DFAC; /* Rather arbitrary too! */
+ }
+ bp = &nu->bp[old_nbp];
+ /* Note we can't give anything else than 0.0 as time here, since a negative one (which would be expected value)
+ * would not work (it would be *before* gtd->inittime, which is not supported currently).
+ */
+ gp_stroke_to_path_add_point(
+ gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
+
+ old_nbp++;
+ }
+
+ if (old_nbp) {
+ prev_bp = &nu->bp[old_nbp - 1];
+ }
+
+ /* add points */
+ for (i = (stitch) ? 1 : 0, pt = &gps->points[(stitch) ? 1 : 0], bp = &nu->bp[old_nbp];
+ i < gps->totpoints;
+ i++, pt++, bp++) {
+ float p[3];
+ float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC;
+
+ /* get coordinates to add at */
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, p, subrect);
+
+ gp_stroke_to_path_add_point(gtd,
+ bp,
+ p,
+ (prev_bp) ? prev_bp->vec : p,
+ do_gtd,
+ gps->inittime,
+ pt->time,
+ width,
+ rad_fac,
+ minmax_weights);
+
+ prev_bp = bp;
+ }
+
+ if (add_end_point) {
+ float p[3];
+ float dt = 0.0f;
+
+ if (gps->totpoints > 1) {
+ interp_v3_v3v3(p, prev_bp->vec, (prev_bp - 1)->vec, -GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->totpoints - 1;
+ dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ copy_v3_v3(p, prev_bp->vec);
+ p[0] += GAP_DFAC; /* Rather arbitrary... */
+ dt = GAP_DFAC; /* Rather arbitrary too! */
+ }
+ /* Note bp has already been incremented in main loop above, so it points to the right place. */
+ gp_stroke_to_path_add_point(
+ gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
+ }
+
+ /* add nurb to curve */
+ if (!curnu || !*curnu) {
+ BLI_addtail(&cu->nurb, nu);
+ }
+ if (curnu) {
+ *curnu = nu;
+ }
+
+ BKE_nurb_knot_calc_u(nu);
}
/* convert stroke to 3d bezier */
/* helper */
-static void gp_stroke_to_bezier_add_point(
- tGpTimingData *gtd, BezTriple *bezt,
- const float p[3], const float h1[3], const float h2[3], const float prev_p[3],
- const bool do_gtd, const double inittime, const float time,
- const float width, const float rad_fac, float minmax_weights[2])
+static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd,
+ BezTriple *bezt,
+ const float p[3],
+ const float h1[3],
+ const float h2[3],
+ const float prev_p[3],
+ const bool do_gtd,
+ const double inittime,
+ const float time,
+ const float width,
+ const float rad_fac,
+ float minmax_weights[2])
{
- copy_v3_v3(bezt->vec[0], h1);
- copy_v3_v3(bezt->vec[1], p);
- copy_v3_v3(bezt->vec[2], h2);
-
- /* set settings */
- bezt->h1 = bezt->h2 = HD_FREE;
- bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
- bezt->radius = width * rad_fac;
- bezt->weight = width;
- CLAMP(bezt->weight, 0.0f, 1.0f);
- if (bezt->weight < minmax_weights[0]) {
- minmax_weights[0] = bezt->weight;
- }
- else if (bezt->weight > minmax_weights[1]) {
- minmax_weights[1] = bezt->weight;
- }
-
- /* Update timing data */
- if (do_gtd) {
- gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
- }
+ copy_v3_v3(bezt->vec[0], h1);
+ copy_v3_v3(bezt->vec[1], p);
+ copy_v3_v3(bezt->vec[2], h2);
+
+ /* set settings */
+ bezt->h1 = bezt->h2 = HD_FREE;
+ bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
+ bezt->radius = width * rad_fac;
+ bezt->weight = width;
+ CLAMP(bezt->weight, 0.0f, 1.0f);
+ if (bezt->weight < minmax_weights[0]) {
+ minmax_weights[0] = bezt->weight;
+ }
+ else if (bezt->weight > minmax_weights[1]) {
+ minmax_weights[1] = bezt->weight;
+ }
+
+ /* Update timing data */
+ if (do_gtd) {
+ gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
+ }
}
-static void gp_stroke_to_bezier(
- bContext *C, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
- float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
- const bool add_end_point, tGpTimingData *gtd)
+static void gp_stroke_to_bezier(bContext *C,
+ bGPdata *gpd,
+ bGPDlayer *gpl,
+ bGPDstroke *gps,
+ Curve *cu,
+ rctf *subrect,
+ Nurb **curnu,
+ float minmax_weights[2],
+ const float rad_fac,
+ bool stitch,
+ const bool add_start_point,
+ const bool add_end_point,
+ tGpTimingData *gtd)
{
- bGPDspoint *pt;
- Nurb *nu = (curnu) ? *curnu : NULL;
- BezTriple *bezt, *prev_bezt = NULL;
- int i, tot, old_nbezt = 0;
- const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
- float p3d_cur[3], p3d_prev[3], p3d_next[3], h1[3], h2[3];
- const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
-
- /* create new 'nurb' or extend current one within the curve */
- if (nu) {
- old_nbezt = nu->pntsu;
- /* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke,
- * so no need to add it.
- * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes.
- */
- BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2) + add_start_end_points);
- }
- else {
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
-
- nu->pntsu = gps->totpoints + add_start_end_points;
- nu->resolu = 12;
- nu->resolv = 12;
- nu->type = CU_BEZIER;
- nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * nu->pntsu, "bezts");
-
- stitch = false; /* Security! */
- }
-
- if (do_gtd) {
- gp_timing_data_set_nbr(gtd, nu->pntsu);
- }
-
- tot = gps->totpoints;
-
- /* get initial coordinates */
- pt = gps->points;
- if (tot) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
- if (tot > 1) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
- }
- if (stitch && tot > 2) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect);
- }
- }
-
- /* If needed, make the link between both strokes with two zero-radius additional points */
- if (curnu && old_nbezt) {
- BLI_assert(gps->prev != NULL);
-
- /* Update last point's second handle */
- if (stitch) {
- bezt = &nu->bezt[old_nbezt - 1];
- interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC);
- copy_v3_v3(bezt->vec[2], h2);
- pt++;
- }
-
- /* Create "link points" */
- /* About "zero-radius" point interpolations:
- * - If we have at least two points in current curve (most common case), we linearly extrapolate
- * the last segment to get the first point (p1) position and timing.
- * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
- * with the first point of the current stroke.
- * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
- * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
- */
- else {
- float p1[3], p2[3];
- float dt1 = 0.0f, dt2 = 0.0f;
-
- prev_bezt = NULL;
- if ((old_nbezt > 1) && (gps->prev->totpoints > 1)) {
- /* Only use last curve segment if previous stroke was not a single-point one! */
- prev_bezt = &nu->bezt[old_nbezt - 2];
- }
- bezt = &nu->bezt[old_nbezt - 1];
-
- /* First point */
- if (prev_bezt) {
- interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->prev->totpoints - 1;
- dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC);
- if (do_gtd) {
- dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
- }
- }
-
- /* Second point */
- /* Note dt2 is always negative, which marks the gap. */
- if (tot > 1) {
- interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
- }
- }
-
- /* Second handle of last point of previous stroke. */
- interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC);
- copy_v3_v3(bezt->vec[2], h2);
-
- /* First point */
- interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC);
- bezt++;
- gp_stroke_to_bezier_add_point(
- gtd, bezt, p1, h1, h2, (bezt - 1)->vec[1], do_gtd, gps->prev->inittime, dt1,
- 0.0f, rad_fac, minmax_weights);
-
- /* Second point */
- interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC);
- bezt++;
- gp_stroke_to_bezier_add_point(
- gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2,
- 0.0f, rad_fac, minmax_weights);
-
- old_nbezt += 2;
- copy_v3_v3(p3d_prev, p2);
- }
- }
- else if (add_start_point) {
- float p[3];
- float dt = 0.0f;
-
- if (gps->totpoints > 1) {
- interp_v3_v3v3(p, p3d_cur, p3d_next, -GAP_DFAC);
- if (do_gtd) {
- dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- copy_v3_v3(p, p3d_cur);
- p[0] -= GAP_DFAC; /* Rather arbitrary... */
- dt = -GAP_DFAC; /* Rather arbitrary too! */
- }
- interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC);
- bezt = &nu->bezt[old_nbezt];
- gp_stroke_to_bezier_add_point(
- gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt,
- 0.0f, rad_fac, minmax_weights);
-
- old_nbezt++;
- copy_v3_v3(p3d_prev, p);
- }
-
- if (old_nbezt) {
- prev_bezt = &nu->bezt[old_nbezt - 1];
- }
-
- /* add points */
- for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
- float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC;
-
- if (i || old_nbezt) {
- interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
- }
- else {
- interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC);
- }
-
- if (i < tot - 1) {
- interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC);
- }
- else {
- interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC);
- }
-
- gp_stroke_to_bezier_add_point(
- gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur,
- do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights);
-
- /* shift coord vects */
- copy_v3_v3(p3d_prev, p3d_cur);
- copy_v3_v3(p3d_cur, p3d_next);
-
- if (i + 2 < tot) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect);
- }
-
- prev_bezt = bezt;
- }
-
- if (add_end_point) {
- float p[3];
- float dt = 0.0f;
-
- if (gps->totpoints > 1) {
- interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->totpoints - 1;
- dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- copy_v3_v3(p, prev_bezt->vec[1]);
- p[0] += GAP_DFAC; /* Rather arbitrary... */
- dt = GAP_DFAC; /* Rather arbitrary too! */
- }
-
- /* Second handle of last point of this stroke. */
- interp_v3_v3v3(h2, prev_bezt->vec[1], p, BEZT_HANDLE_FAC);
- copy_v3_v3(prev_bezt->vec[2], h2);
-
- /* The end point */
- interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC);
- /* Note bezt has already been incremented in main loop above, so it points to the right place. */
- gp_stroke_to_bezier_add_point(
- gtd, bezt, p, h1, h2, prev_bezt->vec[1], do_gtd, gps->inittime, dt,
- 0.0f, rad_fac, minmax_weights);
- }
-
- /* must calculate handles or else we crash */
- BKE_nurb_handles_calc(nu);
-
- if (!curnu || !*curnu) {
- BLI_addtail(&cu->nurb, nu);
- }
- if (curnu) {
- *curnu = nu;
- }
+ bGPDspoint *pt;
+ Nurb *nu = (curnu) ? *curnu : NULL;
+ BezTriple *bezt, *prev_bezt = NULL;
+ int i, tot, old_nbezt = 0;
+ const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
+ float p3d_cur[3], p3d_prev[3], p3d_next[3], h1[3], h2[3];
+ const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
+
+ /* create new 'nurb' or extend current one within the curve */
+ if (nu) {
+ old_nbezt = nu->pntsu;
+ /* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke,
+ * so no need to add it.
+ * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes.
+ */
+ BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2) + add_start_end_points);
+ }
+ else {
+ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
+
+ nu->pntsu = gps->totpoints + add_start_end_points;
+ nu->resolu = 12;
+ nu->resolv = 12;
+ nu->type = CU_BEZIER;
+ nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * nu->pntsu, "bezts");
+
+ stitch = false; /* Security! */
+ }
+
+ if (do_gtd) {
+ gp_timing_data_set_nbr(gtd, nu->pntsu);
+ }
+
+ tot = gps->totpoints;
+
+ /* get initial coordinates */
+ pt = gps->points;
+ if (tot) {
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
+ if (tot > 1) {
+ gp_strokepoint_convertcoords(
+ C, gpd, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
+ }
+ if (stitch && tot > 2) {
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect);
+ }
+ }
+
+ /* If needed, make the link between both strokes with two zero-radius additional points */
+ if (curnu && old_nbezt) {
+ BLI_assert(gps->prev != NULL);
+
+ /* Update last point's second handle */
+ if (stitch) {
+ bezt = &nu->bezt[old_nbezt - 1];
+ interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC);
+ copy_v3_v3(bezt->vec[2], h2);
+ pt++;
+ }
+
+ /* Create "link points" */
+ /* About "zero-radius" point interpolations:
+ * - If we have at least two points in current curve (most common case), we linearly extrapolate
+ * the last segment to get the first point (p1) position and timing.
+ * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
+ * with the first point of the current stroke.
+ * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
+ * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
+ */
+ else {
+ float p1[3], p2[3];
+ float dt1 = 0.0f, dt2 = 0.0f;
+
+ prev_bezt = NULL;
+ if ((old_nbezt > 1) && (gps->prev->totpoints > 1)) {
+ /* Only use last curve segment if previous stroke was not a single-point one! */
+ prev_bezt = &nu->bezt[old_nbezt - 2];
+ }
+ bezt = &nu->bezt[old_nbezt - 1];
+
+ /* First point */
+ if (prev_bezt) {
+ interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->prev->totpoints - 1;
+ dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC);
+ if (do_gtd) {
+ dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+
+ /* Second point */
+ /* Note dt2 is always negative, which marks the gap. */
+ if (tot > 1) {
+ interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+
+ /* Second handle of last point of previous stroke. */
+ interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC);
+ copy_v3_v3(bezt->vec[2], h2);
+
+ /* First point */
+ interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC);
+ bezt++;
+ gp_stroke_to_bezier_add_point(gtd,
+ bezt,
+ p1,
+ h1,
+ h2,
+ (bezt - 1)->vec[1],
+ do_gtd,
+ gps->prev->inittime,
+ dt1,
+ 0.0f,
+ rad_fac,
+ minmax_weights);
+
+ /* Second point */
+ interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC);
+ bezt++;
+ gp_stroke_to_bezier_add_point(
+ gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights);
+
+ old_nbezt += 2;
+ copy_v3_v3(p3d_prev, p2);
+ }
+ }
+ else if (add_start_point) {
+ float p[3];
+ float dt = 0.0f;
+
+ if (gps->totpoints > 1) {
+ interp_v3_v3v3(p, p3d_cur, p3d_next, -GAP_DFAC);
+ if (do_gtd) {
+ dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ copy_v3_v3(p, p3d_cur);
+ p[0] -= GAP_DFAC; /* Rather arbitrary... */
+ dt = -GAP_DFAC; /* Rather arbitrary too! */
+ }
+ interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC);
+ bezt = &nu->bezt[old_nbezt];
+ gp_stroke_to_bezier_add_point(
+ gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
+
+ old_nbezt++;
+ copy_v3_v3(p3d_prev, p);
+ }
+
+ if (old_nbezt) {
+ prev_bezt = &nu->bezt[old_nbezt - 1];
+ }
+
+ /* add points */
+ for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
+ float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC;
+
+ if (i || old_nbezt) {
+ interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
+ }
+ else {
+ interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC);
+ }
+
+ if (i < tot - 1) {
+ interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC);
+ }
+ else {
+ interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC);
+ }
+
+ gp_stroke_to_bezier_add_point(gtd,
+ bezt,
+ p3d_cur,
+ h1,
+ h2,
+ prev_bezt ? prev_bezt->vec[1] : p3d_cur,
+ do_gtd,
+ gps->inittime,
+ pt->time,
+ width,
+ rad_fac,
+ minmax_weights);
+
+ /* shift coord vects */
+ copy_v3_v3(p3d_prev, p3d_cur);
+ copy_v3_v3(p3d_cur, p3d_next);
+
+ if (i + 2 < tot) {
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect);
+ }
+
+ prev_bezt = bezt;
+ }
+
+ if (add_end_point) {
+ float p[3];
+ float dt = 0.0f;
+
+ if (gps->totpoints > 1) {
+ interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->totpoints - 1;
+ dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ copy_v3_v3(p, prev_bezt->vec[1]);
+ p[0] += GAP_DFAC; /* Rather arbitrary... */
+ dt = GAP_DFAC; /* Rather arbitrary too! */
+ }
+
+ /* Second handle of last point of this stroke. */
+ interp_v3_v3v3(h2, prev_bezt->vec[1], p, BEZT_HANDLE_FAC);
+ copy_v3_v3(prev_bezt->vec[2], h2);
+
+ /* The end point */
+ interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC);
+ /* Note bezt has already been incremented in main loop above, so it points to the right place. */
+ gp_stroke_to_bezier_add_point(gtd,
+ bezt,
+ p,
+ h1,
+ h2,
+ prev_bezt->vec[1],
+ do_gtd,
+ gps->inittime,
+ dt,
+ 0.0f,
+ rad_fac,
+ minmax_weights);
+ }
+
+ /* must calculate handles or else we crash */
+ BKE_nurb_handles_calc(nu);
+
+ if (!curnu || !*curnu) {
+ BLI_addtail(&cu->nurb, nu);
+ }
+ if (curnu) {
+ *curnu = nu;
+ }
}
#undef GAP_DFAC
@@ -1046,200 +1165,226 @@ static void gp_stroke_to_bezier(
static void gp_stroke_finalize_curve_endpoints(Curve *cu)
{
- /* start */
- Nurb *nu = cu->nurb.first;
- int i = 0;
- if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
- if (bezt) {
- bezt[i].weight = bezt[i].radius = 0.0f;
- }
- }
- else if (nu->bp) {
- BPoint *bp = nu->bp;
- if (bp) {
- bp[i].weight = bp[i].radius = 0.0f;
- }
- }
-
- /* end */
- nu = cu->nurb.last;
- i = nu->pntsu - 1;
- if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
- if (bezt) {
- bezt[i].weight = bezt[i].radius = 0.0f;
- }
- }
- else if (nu->bp) {
- BPoint *bp = nu->bp;
- if (bp) {
- bp[i].weight = bp[i].radius = 0.0f;
- }
- }
+ /* start */
+ Nurb *nu = cu->nurb.first;
+ int i = 0;
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+ if (bezt) {
+ bezt[i].weight = bezt[i].radius = 0.0f;
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+ if (bp) {
+ bp[i].weight = bp[i].radius = 0.0f;
+ }
+ }
+
+ /* end */
+ nu = cu->nurb.last;
+ i = nu->pntsu - 1;
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+ if (bezt) {
+ bezt[i].weight = bezt[i].radius = 0.0f;
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+ if (bp) {
+ bp[i].weight = bp[i].radius = 0.0f;
+ }
+ }
}
static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2])
{
- Nurb *nu;
- const float delta = minmax_weights[0];
- float fac;
- int i;
-
- /* when delta == minmax_weights[0] == minmax_weights[1], we get div by zero [#35686] */
- if (IS_EQF(delta, minmax_weights[1]))
- fac = 1.0f;
- else
- fac = 1.0f / (minmax_weights[1] - delta);
-
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
- for (i = 0; i < nu->pntsu; i++, bezt++) {
- bezt->weight = (bezt->weight - delta) * fac;
- }
- }
- else if (nu->bp) {
- BPoint *bp = nu->bp;
- for (i = 0; i < nu->pntsu; i++, bp++) {
- bp->weight = (bp->weight - delta) * fac;
- }
- }
- }
+ Nurb *nu;
+ const float delta = minmax_weights[0];
+ float fac;
+ int i;
+
+ /* when delta == minmax_weights[0] == minmax_weights[1], we get div by zero [#35686] */
+ if (IS_EQF(delta, minmax_weights[1]))
+ fac = 1.0f;
+ else
+ fac = 1.0f / (minmax_weights[1] - delta);
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+ for (i = 0; i < nu->pntsu; i++, bezt++) {
+ bezt->weight = (bezt->weight - delta) * fac;
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+ for (i = 0; i < nu->pntsu; i++, bp++) {
+ bp->weight = (bp->weight - delta) * fac;
+ }
+ }
+ }
}
static int gp_camera_view_subrect(bContext *C, rctf *subrect)
{
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
-
- if (v3d) {
- RegionView3D *rv3d = ar->regiondata;
-
- /* for camera view set the subrect */
- if (rv3d->persp == RV3D_CAMOB) {
- Scene *scene = CTX_data_scene(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, subrect, true);
- return 1;
- }
- }
-
- return 0;
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (v3d) {
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* for camera view set the subrect */
+ if (rv3d->persp == RV3D_CAMOB) {
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, subrect, true);
+ return 1;
+ }
+ }
+
+ return 0;
}
/* convert a given grease-pencil layer to a 3d-curve representation
* (using current view if appropriate) */
-static void gp_layer_to_curve(
- bContext *C, ReportList *reports, bGPdata *gpd, bGPDlayer *gpl, const int mode,
- const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd)
+static void gp_layer_to_curve(bContext *C,
+ ReportList *reports,
+ bGPdata *gpd,
+ bGPDlayer *gpl,
+ const int mode,
+ const bool norm_weights,
+ const float rad_fac,
+ const bool link_strokes,
+ tGpTimingData *gtd)
{
- struct Main *bmain = CTX_data_main(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Collection *collection = CTX_data_collection(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
-
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
- bGPDstroke *gps, *prev_gps = NULL;
- Object *ob;
- Curve *cu;
- Nurb *nu = NULL;
- Base *base_new = NULL;
- float minmax_weights[2] = {1.0f, 0.0f};
-
- /* camera framing */
- rctf subrect, *subrect_ptr = NULL;
-
- /* error checking */
- if (ELEM(NULL, gpd, gpl, gpf))
- return;
-
- /* only convert if there are any strokes on this layer's frame to convert */
- if (BLI_listbase_is_empty(&gpf->strokes))
- return;
-
- /* initialize camera framing */
- if (gp_camera_view_subrect(C, &subrect)) {
- subrect_ptr = &subrect;
- }
-
- /* init the curve object (remove rotation and get curve data from it)
- * - must clear transforms set on object, as those skew our results
- */
- ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info);
- cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE);
- BKE_collection_object_add(bmain, collection, ob);
- base_new = BKE_view_layer_base_find(view_layer, ob);
- DEG_relations_tag_update(bmain); /* added object */
-
- cu->flag |= CU_3D;
-
- gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime;
-
- /* add points to curve */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- const bool add_start_point = (link_strokes && !(prev_gps));
- const bool add_end_point = (link_strokes && !(gps->next));
-
- /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached,
- * and stitch them to previous one. */
- bool stitch = false;
- if (prev_gps) {
- bGPDspoint *pt1 = &prev_gps->points[prev_gps->totpoints - 1];
- bGPDspoint *pt2 = &gps->points[0];
-
- if ((pt1->x == pt2->x) && (pt1->y == pt2->y)) {
- stitch = true;
- }
- }
-
- /* Decide whether we connect this stroke to previous one */
- if (!(stitch || link_strokes)) {
- nu = NULL;
- }
-
- switch (mode) {
- case GP_STROKECONVERT_PATH:
- gp_stroke_to_path(
- C, gpd, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
- add_start_point, add_end_point, gtd);
- break;
- case GP_STROKECONVERT_CURVE:
- case GP_STROKECONVERT_POLY: /* convert after */
- gp_stroke_to_bezier(
- C, gpd, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
- add_start_point, add_end_point, gtd);
- break;
- default:
- BLI_assert(!"invalid mode");
- break;
- }
- prev_gps = gps;
- }
-
- /* If link_strokes, be sure first and last points have a zero weight/size! */
- if (link_strokes) {
- gp_stroke_finalize_curve_endpoints(cu);
- }
-
- /* Update curve's weights, if needed */
- if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) {
- gp_stroke_norm_curve_weights(cu, minmax_weights);
- }
-
- /* Create the path animation, if needed */
- gp_stroke_path_animation(C, reports, cu, gtd);
-
- if (mode == GP_STROKECONVERT_POLY) {
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- BKE_nurb_type_convert(nu, CU_POLY, false);
- }
- }
-
- /* set the layer and select */
- base_new->flag |= SELECT;
- BKE_scene_object_base_flag_sync_from_base(base_new);
+ struct Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Collection *collection = CTX_data_collection(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
+ bGPDstroke *gps, *prev_gps = NULL;
+ Object *ob;
+ Curve *cu;
+ Nurb *nu = NULL;
+ Base *base_new = NULL;
+ float minmax_weights[2] = {1.0f, 0.0f};
+
+ /* camera framing */
+ rctf subrect, *subrect_ptr = NULL;
+
+ /* error checking */
+ if (ELEM(NULL, gpd, gpl, gpf))
+ return;
+
+ /* only convert if there are any strokes on this layer's frame to convert */
+ if (BLI_listbase_is_empty(&gpf->strokes))
+ return;
+
+ /* initialize camera framing */
+ if (gp_camera_view_subrect(C, &subrect)) {
+ subrect_ptr = &subrect;
+ }
+
+ /* init the curve object (remove rotation and get curve data from it)
+ * - must clear transforms set on object, as those skew our results
+ */
+ ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info);
+ cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE);
+ BKE_collection_object_add(bmain, collection, ob);
+ base_new = BKE_view_layer_base_find(view_layer, ob);
+ DEG_relations_tag_update(bmain); /* added object */
+
+ cu->flag |= CU_3D;
+
+ gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime;
+
+ /* add points to curve */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ const bool add_start_point = (link_strokes && !(prev_gps));
+ const bool add_end_point = (link_strokes && !(gps->next));
+
+ /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached,
+ * and stitch them to previous one. */
+ bool stitch = false;
+ if (prev_gps) {
+ bGPDspoint *pt1 = &prev_gps->points[prev_gps->totpoints - 1];
+ bGPDspoint *pt2 = &gps->points[0];
+
+ if ((pt1->x == pt2->x) && (pt1->y == pt2->y)) {
+ stitch = true;
+ }
+ }
+
+ /* Decide whether we connect this stroke to previous one */
+ if (!(stitch || link_strokes)) {
+ nu = NULL;
+ }
+
+ switch (mode) {
+ case GP_STROKECONVERT_PATH:
+ gp_stroke_to_path(C,
+ gpd,
+ gpl,
+ gps,
+ cu,
+ subrect_ptr,
+ &nu,
+ minmax_weights,
+ rad_fac,
+ stitch,
+ add_start_point,
+ add_end_point,
+ gtd);
+ break;
+ case GP_STROKECONVERT_CURVE:
+ case GP_STROKECONVERT_POLY: /* convert after */
+ gp_stroke_to_bezier(C,
+ gpd,
+ gpl,
+ gps,
+ cu,
+ subrect_ptr,
+ &nu,
+ minmax_weights,
+ rad_fac,
+ stitch,
+ add_start_point,
+ add_end_point,
+ gtd);
+ break;
+ default:
+ BLI_assert(!"invalid mode");
+ break;
+ }
+ prev_gps = gps;
+ }
+
+ /* If link_strokes, be sure first and last points have a zero weight/size! */
+ if (link_strokes) {
+ gp_stroke_finalize_curve_endpoints(cu);
+ }
+
+ /* Update curve's weights, if needed */
+ if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) {
+ gp_stroke_norm_curve_weights(cu, minmax_weights);
+ }
+
+ /* Create the path animation, if needed */
+ gp_stroke_path_animation(C, reports, cu, gtd);
+
+ if (mode == GP_STROKECONVERT_POLY) {
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ BKE_nurb_type_convert(nu, CU_POLY, false);
+ }
+ }
+
+ /* set the layer and select */
+ base_new->flag |= SELECT;
+ BKE_scene_object_base_flag_sync_from_base(base_new);
}
/* --- */
@@ -1249,279 +1394,348 @@ static void gp_layer_to_curve(
*/
static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
-
- bGPDframe *gpf = NULL;
- bGPDstroke *gps = NULL;
- bGPDspoint *pt;
- double base_time, cur_time, prev_time = -1.0;
- int i;
- bool valid = true;
-
- if (!gpl || !(gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV)) || !(gps = gpf->strokes.first))
- return false;
-
- do {
- base_time = cur_time = gps->inittime;
- if (cur_time <= prev_time) {
- valid = false;
- break;
- }
-
- prev_time = cur_time;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- cur_time = base_time + (double)pt->time;
- /* First point of a stroke should have the same time as stroke's inittime,
- * so it's the only case where equality is allowed!
- */
- if ((i && cur_time <= prev_time) || (cur_time < prev_time)) {
- valid = false;
- break;
- }
- prev_time = cur_time;
- }
-
- if (!valid) {
- break;
- }
- } while ((gps = gps->next));
-
- if (op) {
- RNA_boolean_set(op->ptr, "use_timing_data", valid);
- }
- return valid;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDframe *gpf = NULL;
+ bGPDstroke *gps = NULL;
+ bGPDspoint *pt;
+ double base_time, cur_time, prev_time = -1.0;
+ int i;
+ bool valid = true;
+
+ if (!gpl || !(gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV)) ||
+ !(gps = gpf->strokes.first))
+ return false;
+
+ do {
+ base_time = cur_time = gps->inittime;
+ if (cur_time <= prev_time) {
+ valid = false;
+ break;
+ }
+
+ prev_time = cur_time;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ cur_time = base_time + (double)pt->time;
+ /* First point of a stroke should have the same time as stroke's inittime,
+ * so it's the only case where equality is allowed!
+ */
+ if ((i && cur_time <= prev_time) || (cur_time < prev_time)) {
+ valid = false;
+ break;
+ }
+ prev_time = cur_time;
+ }
+
+ if (!valid) {
+ break;
+ }
+ } while ((gps = gps->next));
+
+ if (op) {
+ RNA_boolean_set(op->ptr, "use_timing_data", valid);
+ }
+ return valid;
}
/* Check end_frame is always > start frame! */
-static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UNUSED(scene), struct PointerRNA *ptr)
+static void gp_convert_set_end_frame(struct Main *UNUSED(main),
+ struct Scene *UNUSED(scene),
+ struct PointerRNA *ptr)
{
- int start_frame = RNA_int_get(ptr, "start_frame");
- int end_frame = RNA_int_get(ptr, "end_frame");
+ int start_frame = RNA_int_get(ptr, "start_frame");
+ int end_frame = RNA_int_get(ptr, "end_frame");
- if (end_frame <= start_frame) {
- RNA_int_set(ptr, "end_frame", start_frame + 1);
- }
+ if (end_frame <= start_frame) {
+ RNA_int_set(ptr, "end_frame", start_frame + 1);
+ }
}
static bool gp_convert_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
-
- if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
- return false;
- }
-
- bGPdata *gpd = (bGPdata *)ob->data;
- bGPDlayer *gpl = NULL;
- bGPDframe *gpf = NULL;
- ScrArea *sa = CTX_wm_area(C);
-
- /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
- * and if we are not in edit mode!
- */
- return ((sa && sa->spacetype == SPACE_VIEW3D) &&
- (gpl = BKE_gpencil_layer_getactive(gpd)) &&
- (gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV)) &&
- (gpf->strokes.first) &&
- (!GPENCIL_ANY_EDIT_MODE(gpd)));
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDlayer *gpl = NULL;
+ bGPDframe *gpf = NULL;
+ ScrArea *sa = CTX_wm_area(C);
+
+ /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
+ * and if we are not in edit mode!
+ */
+ return ((sa && sa->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_getactive(gpd)) &&
+ (gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV)) &&
+ (gpf->strokes.first) && (!GPENCIL_ANY_EDIT_MODE(gpd)));
}
static int gp_convert_layer_exec(bContext *C, wmOperator *op)
{
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data");
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = (bGPdata *)ob->data;
-
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- Scene *scene = CTX_data_scene(C);
- const int mode = RNA_enum_get(op->ptr, "type");
- const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights");
- const float rad_fac = RNA_float_get(op->ptr, "radius_multiplier");
- const bool link_strokes = RNA_boolean_get(op->ptr, "use_link_strokes");
- bool valid_timing;
- tGpTimingData gtd;
-
- /* check if there's data to work with */
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on");
- return OPERATOR_CANCELLED;
- }
-
- if (!RNA_property_is_set(op->ptr, prop) && !gp_convert_check_has_valid_timing(C, gpl, op)) {
- BKE_report(op->reports, RPT_WARNING,
- "Current Grease Pencil strokes have no valid timing data, most timing options will be hidden!");
- }
- valid_timing = RNA_property_boolean_get(op->ptr, prop);
-
- gtd.mode = RNA_enum_get(op->ptr, "timing_mode");
- /* Check for illegal timing mode! */
- if (!valid_timing && !ELEM(gtd.mode, GP_STROKECONVERT_TIMING_NONE, GP_STROKECONVERT_TIMING_LINEAR)) {
- gtd.mode = GP_STROKECONVERT_TIMING_LINEAR;
- RNA_enum_set(op->ptr, "timing_mode", gtd.mode);
- }
- if (!link_strokes) {
- gtd.mode = GP_STROKECONVERT_TIMING_NONE;
- }
-
- /* grab all relevant settings */
- gtd.frame_range = RNA_int_get(op->ptr, "frame_range");
- gtd.start_frame = RNA_int_get(op->ptr, "start_frame");
- gtd.realtime = valid_timing ? RNA_boolean_get(op->ptr, "use_realtime") : false;
- gtd.end_frame = RNA_int_get(op->ptr, "end_frame");
- gtd.gap_duration = RNA_float_get(op->ptr, "gap_duration");
- gtd.gap_randomness = RNA_float_get(op->ptr, "gap_randomness");
- gtd.gap_randomness = min_ff(gtd.gap_randomness, gtd.gap_duration);
- gtd.seed = RNA_int_get(op->ptr, "seed");
- gtd.num_points = gtd.cur_point = 0;
- gtd.dists = gtd.times = NULL;
- gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f;
- gtd.inittime = 0.0;
- gtd.offset_time = 0.0f;
-
- /* perform conversion */
- gp_layer_to_curve(C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, &gtd);
-
- /* free temp memory */
- if (gtd.dists) {
- MEM_freeN(gtd.dists);
- gtd.dists = NULL;
- }
- if (gtd.times) {
- MEM_freeN(gtd.times);
- gtd.times = NULL;
- }
-
- /* notifiers */
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
-
- /* done */
- return OPERATOR_FINISHED;
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data");
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ Scene *scene = CTX_data_scene(C);
+ const int mode = RNA_enum_get(op->ptr, "type");
+ const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights");
+ const float rad_fac = RNA_float_get(op->ptr, "radius_multiplier");
+ const bool link_strokes = RNA_boolean_get(op->ptr, "use_link_strokes");
+ bool valid_timing;
+ tGpTimingData gtd;
+
+ /* check if there's data to work with */
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!RNA_property_is_set(op->ptr, prop) && !gp_convert_check_has_valid_timing(C, gpl, op)) {
+ BKE_report(op->reports,
+ RPT_WARNING,
+ "Current Grease Pencil strokes have no valid timing data, most timing options will "
+ "be hidden!");
+ }
+ valid_timing = RNA_property_boolean_get(op->ptr, prop);
+
+ gtd.mode = RNA_enum_get(op->ptr, "timing_mode");
+ /* Check for illegal timing mode! */
+ if (!valid_timing &&
+ !ELEM(gtd.mode, GP_STROKECONVERT_TIMING_NONE, GP_STROKECONVERT_TIMING_LINEAR)) {
+ gtd.mode = GP_STROKECONVERT_TIMING_LINEAR;
+ RNA_enum_set(op->ptr, "timing_mode", gtd.mode);
+ }
+ if (!link_strokes) {
+ gtd.mode = GP_STROKECONVERT_TIMING_NONE;
+ }
+
+ /* grab all relevant settings */
+ gtd.frame_range = RNA_int_get(op->ptr, "frame_range");
+ gtd.start_frame = RNA_int_get(op->ptr, "start_frame");
+ gtd.realtime = valid_timing ? RNA_boolean_get(op->ptr, "use_realtime") : false;
+ gtd.end_frame = RNA_int_get(op->ptr, "end_frame");
+ gtd.gap_duration = RNA_float_get(op->ptr, "gap_duration");
+ gtd.gap_randomness = RNA_float_get(op->ptr, "gap_randomness");
+ gtd.gap_randomness = min_ff(gtd.gap_randomness, gtd.gap_duration);
+ gtd.seed = RNA_int_get(op->ptr, "seed");
+ gtd.num_points = gtd.cur_point = 0;
+ gtd.dists = gtd.times = NULL;
+ gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f;
+ gtd.inittime = 0.0;
+ gtd.offset_time = 0.0f;
+
+ /* perform conversion */
+ gp_layer_to_curve(C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, &gtd);
+
+ /* free temp memory */
+ if (gtd.dists) {
+ MEM_freeN(gtd.dists);
+ gtd.dists = NULL;
+ }
+ if (gtd.times) {
+ MEM_freeN(gtd.times);
+ gtd.times = NULL;
+ }
+
+ /* notifiers */
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+
+ /* done */
+ return OPERATOR_FINISHED;
}
-static bool gp_convert_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop)
+static bool gp_convert_poll_property(const bContext *UNUSED(C),
+ wmOperator *op,
+ const PropertyRNA *prop)
{
- PointerRNA *ptr = op->ptr;
- const char *prop_id = RNA_property_identifier(prop);
- const bool link_strokes = RNA_boolean_get(ptr, "use_link_strokes");
- int timing_mode = RNA_enum_get(ptr, "timing_mode");
- bool realtime = RNA_boolean_get(ptr, "use_realtime");
- float gap_duration = RNA_float_get(ptr, "gap_duration");
- float gap_randomness = RNA_float_get(ptr, "gap_randomness");
- const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data");
-
- /* Always show those props */
- if (STREQ(prop_id, "type") ||
- STREQ(prop_id, "use_normalize_weights") ||
- STREQ(prop_id, "radius_multiplier") ||
- STREQ(prop_id, "use_link_strokes"))
- {
- return true;
- }
-
- /* Never show this prop */
- if (STREQ(prop_id, "use_timing_data"))
- return false;
-
- if (link_strokes) {
- /* Only show when link_stroke is true */
- if (STREQ(prop_id, "timing_mode"))
- return true;
-
- if (timing_mode != GP_STROKECONVERT_TIMING_NONE) {
- /* Only show when link_stroke is true and stroke timing is enabled */
- if (STREQ(prop_id, "frame_range") ||
- STREQ(prop_id, "start_frame"))
- {
- return true;
- }
-
- /* Only show if we have valid timing data! */
- if (valid_timing && STREQ(prop_id, "use_realtime"))
- return true;
-
- /* Only show if realtime or valid_timing is false! */
- if ((!realtime || !valid_timing) && STREQ(prop_id, "end_frame"))
- return true;
-
- if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- /* Only show for custom gaps! */
- if (STREQ(prop_id, "gap_duration"))
- return true;
-
- /* Only show randomness for non-null custom gaps! */
- if (STREQ(prop_id, "gap_randomness") && (gap_duration > 0.0f))
- return true;
-
- /* Only show seed for randomize action! */
- if (STREQ(prop_id, "seed") && (gap_duration > 0.0f) && (gap_randomness > 0.0f))
- return true;
- }
- }
- }
-
- /* Else, hidden! */
- return false;
+ PointerRNA *ptr = op->ptr;
+ const char *prop_id = RNA_property_identifier(prop);
+ const bool link_strokes = RNA_boolean_get(ptr, "use_link_strokes");
+ int timing_mode = RNA_enum_get(ptr, "timing_mode");
+ bool realtime = RNA_boolean_get(ptr, "use_realtime");
+ float gap_duration = RNA_float_get(ptr, "gap_duration");
+ float gap_randomness = RNA_float_get(ptr, "gap_randomness");
+ const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data");
+
+ /* Always show those props */
+ if (STREQ(prop_id, "type") || STREQ(prop_id, "use_normalize_weights") ||
+ STREQ(prop_id, "radius_multiplier") || STREQ(prop_id, "use_link_strokes")) {
+ return true;
+ }
+
+ /* Never show this prop */
+ if (STREQ(prop_id, "use_timing_data"))
+ return false;
+
+ if (link_strokes) {
+ /* Only show when link_stroke is true */
+ if (STREQ(prop_id, "timing_mode"))
+ return true;
+
+ if (timing_mode != GP_STROKECONVERT_TIMING_NONE) {
+ /* Only show when link_stroke is true and stroke timing is enabled */
+ if (STREQ(prop_id, "frame_range") || STREQ(prop_id, "start_frame")) {
+ return true;
+ }
+
+ /* Only show if we have valid timing data! */
+ if (valid_timing && STREQ(prop_id, "use_realtime"))
+ return true;
+
+ /* Only show if realtime or valid_timing is false! */
+ if ((!realtime || !valid_timing) && STREQ(prop_id, "end_frame"))
+ return true;
+
+ if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
+ /* Only show for custom gaps! */
+ if (STREQ(prop_id, "gap_duration"))
+ return true;
+
+ /* Only show randomness for non-null custom gaps! */
+ if (STREQ(prop_id, "gap_randomness") && (gap_duration > 0.0f))
+ return true;
+
+ /* Only show seed for randomize action! */
+ if (STREQ(prop_id, "seed") && (gap_duration > 0.0f) && (gap_randomness > 0.0f))
+ return true;
+ }
+ }
+ }
+
+ /* Else, hidden! */
+ return false;
}
void GPENCIL_OT_convert(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Convert Grease Pencil";
- ot->idname = "GPENCIL_OT_convert";
- ot->description = "Convert the active Grease Pencil layer to a new Curve Object";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = gp_convert_layer_exec;
- ot->poll = gp_convert_poll;
- ot->poll_property = gp_convert_poll_property;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "Which type of curve to convert to");
-
- RNA_def_boolean(ot->srna, "use_normalize_weights", true, "Normalize Weight",
- "Normalize weight (set from stroke width)");
- RNA_def_float(ot->srna, "radius_multiplier", 1.0f, 0.0f, 1000.0f, "Radius Fac",
- "Multiplier for the points' radii (set from stroke width)", 0.0f, 10.0f);
- RNA_def_boolean(ot->srna, "use_link_strokes", false, "Link Strokes",
- "Whether to link strokes with zero-radius sections of curves");
-
- prop = RNA_def_enum(ot->srna, "timing_mode", prop_gpencil_convert_timingmodes, GP_STROKECONVERT_TIMING_FULL,
- "Timing Mode", "How to use timing data stored in strokes");
- RNA_def_enum_funcs(prop, rna_GPConvert_mode_items);
-
- RNA_def_int(ot->srna, "frame_range", 100, 1, 10000, "Frame Range",
- "The duration of evaluation of the path control curve", 1, 1000);
- RNA_def_int(ot->srna, "start_frame", 1, 1, 100000, "Start Frame",
- "The start frame of the path control curve", 1, 100000);
- RNA_def_boolean(ot->srna, "use_realtime", false, "Realtime",
- "Whether the path control curve reproduces the drawing in realtime, starting from Start Frame");
- prop = RNA_def_int(ot->srna, "end_frame", 250, 1, 100000, "End Frame",
- "The end frame of the path control curve (if Realtime is not set)", 1, 100000);
- RNA_def_property_update_runtime(prop, gp_convert_set_end_frame);
-
- RNA_def_float(ot->srna, "gap_duration", 0.0f, 0.0f, 10000.0f, "Gap Duration",
- "Custom Gap mode: (Average) length of gaps, in frames "
- "(Note: Realtime value, will be scaled if Realtime is not set)", 0.0f, 1000.0f);
- RNA_def_float(ot->srna, "gap_randomness", 0.0f, 0.0f, 10000.0f, "Gap Randomness",
- "Custom Gap mode: Number of frames that gap lengths can vary", 0.0f, 1000.0f);
- RNA_def_int(ot->srna, "seed", 0, 0, 1000, "Random Seed",
- "Custom Gap mode: Random generator seed", 0, 100);
-
- /* Note: Internal use, this one will always be hidden by UI code... */
- prop = RNA_def_boolean(ot->srna, "use_timing_data", false, "Has Valid Timing",
- "Whether the converted Grease Pencil layer has valid timing data (internal use)");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Convert Grease Pencil";
+ ot->idname = "GPENCIL_OT_convert";
+ ot->description = "Convert the active Grease Pencil layer to a new Curve Object";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gp_convert_layer_exec;
+ ot->poll = gp_convert_poll;
+ ot->poll_property = gp_convert_poll_property;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(
+ ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "Which type of curve to convert to");
+
+ RNA_def_boolean(ot->srna,
+ "use_normalize_weights",
+ true,
+ "Normalize Weight",
+ "Normalize weight (set from stroke width)");
+ RNA_def_float(ot->srna,
+ "radius_multiplier",
+ 1.0f,
+ 0.0f,
+ 1000.0f,
+ "Radius Fac",
+ "Multiplier for the points' radii (set from stroke width)",
+ 0.0f,
+ 10.0f);
+ RNA_def_boolean(ot->srna,
+ "use_link_strokes",
+ false,
+ "Link Strokes",
+ "Whether to link strokes with zero-radius sections of curves");
+
+ prop = RNA_def_enum(ot->srna,
+ "timing_mode",
+ prop_gpencil_convert_timingmodes,
+ GP_STROKECONVERT_TIMING_FULL,
+ "Timing Mode",
+ "How to use timing data stored in strokes");
+ RNA_def_enum_funcs(prop, rna_GPConvert_mode_items);
+
+ RNA_def_int(ot->srna,
+ "frame_range",
+ 100,
+ 1,
+ 10000,
+ "Frame Range",
+ "The duration of evaluation of the path control curve",
+ 1,
+ 1000);
+ RNA_def_int(ot->srna,
+ "start_frame",
+ 1,
+ 1,
+ 100000,
+ "Start Frame",
+ "The start frame of the path control curve",
+ 1,
+ 100000);
+ RNA_def_boolean(ot->srna,
+ "use_realtime",
+ false,
+ "Realtime",
+ "Whether the path control curve reproduces the drawing in realtime, starting "
+ "from Start Frame");
+ prop = RNA_def_int(ot->srna,
+ "end_frame",
+ 250,
+ 1,
+ 100000,
+ "End Frame",
+ "The end frame of the path control curve (if Realtime is not set)",
+ 1,
+ 100000);
+ RNA_def_property_update_runtime(prop, gp_convert_set_end_frame);
+
+ RNA_def_float(ot->srna,
+ "gap_duration",
+ 0.0f,
+ 0.0f,
+ 10000.0f,
+ "Gap Duration",
+ "Custom Gap mode: (Average) length of gaps, in frames "
+ "(Note: Realtime value, will be scaled if Realtime is not set)",
+ 0.0f,
+ 1000.0f);
+ RNA_def_float(ot->srna,
+ "gap_randomness",
+ 0.0f,
+ 0.0f,
+ 10000.0f,
+ "Gap Randomness",
+ "Custom Gap mode: Number of frames that gap lengths can vary",
+ 0.0f,
+ 1000.0f);
+ RNA_def_int(ot->srna,
+ "seed",
+ 0,
+ 0,
+ 1000,
+ "Random Seed",
+ "Custom Gap mode: Random generator seed",
+ 0,
+ 100);
+
+ /* Note: Internal use, this one will always be hidden by UI code... */
+ prop = RNA_def_boolean(
+ ot->srna,
+ "use_timing_data",
+ false,
+ "Has Valid Timing",
+ "Whether the converted Grease Pencil layer has valid timing data (internal use)");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index a49f6a0d414..c91c543e746 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -22,7 +22,6 @@
* \ingroup edgpencil
*/
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -91,81 +90,81 @@
/* ******************* Add New Data ************************ */
static bool gp_data_add_poll(bContext *C)
{
- Object *obact = CTX_data_active_object(C);
- if (obact && obact->type == OB_GPENCIL) {
- if (obact->mode != OB_MODE_OBJECT) {
- return false;
- }
- }
+ Object *obact = CTX_data_active_object(C);
+ if (obact && obact->type == OB_GPENCIL) {
+ if (obact->mode != OB_MODE_OBJECT) {
+ return false;
+ }
+ }
- /* the base line we have is that we have somewhere to add Grease Pencil data */
- return ED_gpencil_data_get_pointers(C, NULL) != NULL;
+ /* the base line we have is that we have somewhere to add Grease Pencil data */
+ return ED_gpencil_data_get_pointers(C, NULL) != NULL;
}
/* add new datablock - wrapper around API */
static int gp_data_add_exec(bContext *C, wmOperator *op)
{
- PointerRNA gpd_owner = {{NULL}};
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner);
- bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner);
+ PointerRNA gpd_owner = {{NULL}};
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner);
+ bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner);
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
- return OPERATOR_CANCELLED;
- }
- else {
- /* decrement user count and add new datablock */
- /* TODO: if a datablock exists,
- * we should make a copy of it instead of starting fresh (as in other areas) */
- Main *bmain = CTX_data_main(C);
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* decrement user count and add new datablock */
+ /* TODO: if a datablock exists,
+ * we should make a copy of it instead of starting fresh (as in other areas) */
+ Main *bmain = CTX_data_main(C);
- /* decrement user count of old GP datablock */
- if (*gpd_ptr) {
- bGPdata *gpd = (*gpd_ptr);
- id_us_min(&gpd->id);
- }
+ /* decrement user count of old GP datablock */
+ if (*gpd_ptr) {
+ bGPdata *gpd = (*gpd_ptr);
+ id_us_min(&gpd->id);
+ }
- /* add new datablock, with a single layer ready to use (so users don't have to perform an extra step) */
- if (is_annotation) {
- bGPdata *gpd = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
- *gpd_ptr = gpd;
+ /* add new datablock, with a single layer ready to use (so users don't have to perform an extra step) */
+ if (is_annotation) {
+ bGPdata *gpd = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
+ *gpd_ptr = gpd;
- /* tag for annotations */
- gpd->flag |= GP_DATA_ANNOTATIONS;
+ /* tag for annotations */
+ gpd->flag |= GP_DATA_ANNOTATIONS;
- /* add new layer (i.e. a "note") */
- BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
- }
- else {
- /* GP Object Case - This shouldn't happen! */
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
+ /* add new layer (i.e. a "note") */
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
+ }
+ else {
+ /* GP Object Case - This shouldn't happen! */
+ *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
- /* add default sets of colors and brushes */
- Object *ob = CTX_data_active_object(C);
- ED_gpencil_add_defaults(C, ob);
+ /* add default sets of colors and brushes */
+ Object *ob = CTX_data_active_object(C);
+ ED_gpencil_add_defaults(C, ob);
- /* add new layer */
- BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
- }
- }
+ /* add new layer */
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
+ }
+ }
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_data_add(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Grease Pencil Add New";
- ot->idname = "GPENCIL_OT_data_add";
- ot->description = "Add new Grease Pencil data-block";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Grease Pencil Add New";
+ ot->idname = "GPENCIL_OT_data_add";
+ ot->description = "Add new Grease Pencil data-block";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* callbacks */
- ot->exec = gp_data_add_exec;
- ot->poll = gp_data_add_poll;
+ /* callbacks */
+ ot->exec = gp_data_add_exec;
+ ot->poll = gp_data_add_poll;
}
/* ******************* Unlink Data ************************ */
@@ -173,57 +172,55 @@ void GPENCIL_OT_data_add(wmOperatorType *ot)
/* poll callback for adding data/layers - special */
static bool gp_data_unlink_poll(bContext *C)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
- /* only unlink annotation datablocks */
- if ((gpd_ptr != NULL) && (*gpd_ptr != NULL)) {
- bGPdata *gpd = (*gpd_ptr);
- if ((gpd->flag & GP_DATA_ANNOTATIONS) == 0) {
- return false;
- }
- }
- /* if we have access to some active data, make sure there's a datablock before enabling this */
- return (gpd_ptr && *gpd_ptr);
+ /* only unlink annotation datablocks */
+ if ((gpd_ptr != NULL) && (*gpd_ptr != NULL)) {
+ bGPdata *gpd = (*gpd_ptr);
+ if ((gpd->flag & GP_DATA_ANNOTATIONS) == 0) {
+ return false;
+ }
+ }
+ /* if we have access to some active data, make sure there's a datablock before enabling this */
+ return (gpd_ptr && *gpd_ptr);
}
-
/* unlink datablock - wrapper around API */
static int gp_data_unlink_exec(bContext *C, wmOperator *op)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
- return OPERATOR_CANCELLED;
- }
- else {
- /* just unlink datablock now, decreasing its user count */
- bGPdata *gpd = (*gpd_ptr);
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* just unlink datablock now, decreasing its user count */
+ bGPdata *gpd = (*gpd_ptr);
- id_us_min(&gpd->id);
- *gpd_ptr = NULL;
- }
+ id_us_min(&gpd->id);
+ *gpd_ptr = NULL;
+ }
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_data_unlink(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Annotation Unlink";
- ot->idname = "GPENCIL_OT_data_unlink";
- ot->description = "Unlink active Annotation data-block";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Annotation Unlink";
+ ot->idname = "GPENCIL_OT_data_unlink";
+ ot->description = "Unlink active Annotation data-block";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* callbacks */
- ot->exec = gp_data_unlink_exec;
- ot->poll = gp_data_unlink_poll;
+ /* callbacks */
+ ot->exec = gp_data_unlink_exec;
+ ot->poll = gp_data_unlink_poll;
}
-
/* ************************************************ */
/* Layer Operators */
@@ -232,618 +229,636 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot)
/* add new layer - wrapper around API */
static int gp_layer_add_exec(bContext *C, wmOperator *op)
{
- PointerRNA gpd_owner = {{NULL}};
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner);
- bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner);
-
- /* if there's no existing Grease-Pencil data there, add some */
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
- return OPERATOR_CANCELLED;
- }
-
- if (*gpd_ptr == NULL) {
- Main *bmain = CTX_data_main(C);
- if (is_annotation) {
- /* Annotations */
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
-
- /* mark as annotation */
- (*gpd_ptr)->flag |= GP_DATA_ANNOTATIONS;
- }
- else {
- /* GP Object */
- /* NOTE: This shouldn't actually happen in practice */
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
-
- /* add default sets of colors and brushes */
- Object *ob = CTX_data_active_object(C);
- ED_gpencil_add_defaults(C, ob);
- }
- }
-
- /* add new layer now */
- if (is_annotation) {
- BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
- }
- else {
- BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
- }
-
- /* notifiers */
- bGPdata *gpd = *gpd_ptr;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ PointerRNA gpd_owner = {{NULL}};
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner);
+ bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner);
+
+ /* if there's no existing Grease-Pencil data there, add some */
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (*gpd_ptr == NULL) {
+ Main *bmain = CTX_data_main(C);
+ if (is_annotation) {
+ /* Annotations */
+ *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
+
+ /* mark as annotation */
+ (*gpd_ptr)->flag |= GP_DATA_ANNOTATIONS;
+ }
+ else {
+ /* GP Object */
+ /* NOTE: This shouldn't actually happen in practice */
+ *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
+
+ /* add default sets of colors and brushes */
+ Object *ob = CTX_data_active_object(C);
+ ED_gpencil_add_defaults(C, ob);
+ }
+ }
+
+ /* add new layer now */
+ if (is_annotation) {
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
+ }
+ else {
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
+ }
+
+ /* notifiers */
+ bGPdata *gpd = *gpd_ptr;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_layer_add(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Add New Layer";
- ot->idname = "GPENCIL_OT_layer_add";
- ot->description = "Add new layer or note for the active data-block";
+ /* identifiers */
+ ot->name = "Add New Layer";
+ ot->idname = "GPENCIL_OT_layer_add";
+ ot->description = "Add new layer or note for the active data-block";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* callbacks */
- ot->exec = gp_layer_add_exec;
- ot->poll = gp_add_poll;
+ /* callbacks */
+ ot->exec = gp_layer_add_exec;
+ ot->poll = gp_add_poll;
}
/* ******************* Remove Active Layer ************************* */
static int gp_layer_remove_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl))
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
- if (gpl->flag & GP_LAYER_LOCKED) {
- BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
- return OPERATOR_CANCELLED;
- }
+ if (gpl->flag & GP_LAYER_LOCKED) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
+ return OPERATOR_CANCELLED;
+ }
- /* make the layer before this the new active layer
- * - use the one after if this is the first
- * - if this is the only layer, this naturally becomes NULL
- */
- if (gpl->prev)
- BKE_gpencil_layer_setactive(gpd, gpl->prev);
- else
- BKE_gpencil_layer_setactive(gpd, gpl->next);
+ /* make the layer before this the new active layer
+ * - use the one after if this is the first
+ * - if this is the only layer, this naturally becomes NULL
+ */
+ if (gpl->prev)
+ BKE_gpencil_layer_setactive(gpd, gpl->prev);
+ else
+ BKE_gpencil_layer_setactive(gpd, gpl->next);
- /* delete the layer now... */
- BKE_gpencil_layer_delete(gpd, gpl);
+ /* delete the layer now... */
+ BKE_gpencil_layer_delete(gpd, gpl);
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_layer_remove(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Remove Layer";
- ot->idname = "GPENCIL_OT_layer_remove";
- ot->description = "Remove active Grease Pencil layer";
+ /* identifiers */
+ ot->name = "Remove Layer";
+ ot->idname = "GPENCIL_OT_layer_remove";
+ ot->description = "Remove active Grease Pencil layer";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* callbacks */
- ot->exec = gp_layer_remove_exec;
- ot->poll = gp_active_layer_poll;
+ /* callbacks */
+ ot->exec = gp_layer_remove_exec;
+ ot->poll = gp_active_layer_poll;
}
/* ******************* Move Layer Up/Down ************************** */
enum {
- GP_LAYER_MOVE_UP = -1,
- GP_LAYER_MOVE_DOWN = 1,
+ GP_LAYER_MOVE_UP = -1,
+ GP_LAYER_MOVE_DOWN = 1,
};
static int gp_layer_move_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- const int direction = RNA_enum_get(op->ptr, "type") * -1;
+ const int direction = RNA_enum_get(op->ptr, "type") * -1;
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl))
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
- BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
- if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- }
+ BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
+ if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_layer_move(wmOperatorType *ot)
{
- static const EnumPropertyItem slot_move[] = {
- {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
- {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
- };
+ static const EnumPropertyItem slot_move[] = {
+ {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
+ {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
- /* identifiers */
- ot->name = "Move Grease Pencil Layer";
- ot->idname = "GPENCIL_OT_layer_move";
- ot->description = "Move the active Grease Pencil layer up/down in the list";
+ /* identifiers */
+ ot->name = "Move Grease Pencil Layer";
+ ot->idname = "GPENCIL_OT_layer_move";
+ ot->description = "Move the active Grease Pencil layer up/down in the list";
- /* api callbacks */
- ot->exec = gp_layer_move_exec;
- ot->poll = gp_active_layer_poll;
+ /* api callbacks */
+ ot->exec = gp_layer_move_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
}
/* ********************* Duplicate Layer ************************** */
static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- bGPDlayer *new_layer;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *new_layer;
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl))
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
- /* make copy of layer, and add it immediately after the existing layer */
- new_layer = BKE_gpencil_layer_duplicate(gpl);
- BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
+ /* make copy of layer, and add it immediately after the existing layer */
+ new_layer = BKE_gpencil_layer_duplicate(gpl);
+ BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
- /* ensure new layer has a unique name, and is now the active layer */
- BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info));
- BKE_gpencil_layer_setactive(gpd, new_layer);
+ /* ensure new layer has a unique name, and is now the active layer */
+ BLI_uniquename(&gpd->layers,
+ new_layer,
+ DATA_("GP_Layer"),
+ '.',
+ offsetof(bGPDlayer, info),
+ sizeof(new_layer->info));
+ BKE_gpencil_layer_setactive(gpd, new_layer);
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Duplicate Layer";
- ot->idname = "GPENCIL_OT_layer_duplicate";
- ot->description = "Make a copy of the active Grease Pencil layer";
+ /* identifiers */
+ ot->name = "Duplicate Layer";
+ ot->idname = "GPENCIL_OT_layer_duplicate";
+ ot->description = "Make a copy of the active Grease Pencil layer";
- /* callbacks */
- ot->exec = gp_layer_copy_exec;
- ot->poll = gp_active_layer_poll;
+ /* callbacks */
+ ot->exec = gp_layer_copy_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************* Duplicate Layer in a new object ************************** */
enum {
- GP_LAYER_COPY_OBJECT_ALL_FRAME = 0,
- GP_LAYER_COPY_OBJECT_ACT_FRAME = 1,
+ GP_LAYER_COPY_OBJECT_ALL_FRAME = 0,
+ GP_LAYER_COPY_OBJECT_ACT_FRAME = 1,
};
static bool gp_layer_duplicate_object_poll(bContext *C)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = CTX_data_active_object(C);
- if ((ob == NULL) || (ob->type != OB_GPENCIL))
- return false;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL))
+ return false;
- bGPdata *gpd = (bGPdata *)ob->data;
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- if (gpl == NULL)
- return false;
+ if (gpl == NULL)
+ return false;
- /* check there are more grease pencil objects */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if ((base->object != ob) && (base->object->type == OB_GPENCIL))
- return true;
- }
+ /* check there are more grease pencil objects */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if ((base->object != ob) && (base->object->type == OB_GPENCIL))
+ return true;
+ }
- return false;
+ return false;
}
static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "object", name);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "object", name);
- if (name[0] == '\0') {
- return OPERATOR_CANCELLED;
- }
+ if (name[0] == '\0') {
+ return OPERATOR_CANCELLED;
+ }
- Object *ob_dst = (Object *)BKE_scene_object_find_by_name(scene, name);
+ Object *ob_dst = (Object *)BKE_scene_object_find_by_name(scene, name);
- int mode = RNA_enum_get(op->ptr, "mode");
+ int mode = RNA_enum_get(op->ptr, "mode");
- Object *ob_src = CTX_data_active_object(C);
- bGPdata *gpd_src = (bGPdata *)ob_src->data;
- bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src);
+ Object *ob_src = CTX_data_active_object(C);
+ bGPdata *gpd_src = (bGPdata *)ob_src->data;
+ bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src);
- /* sanity checks */
- if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
- return OPERATOR_CANCELLED;
- }
- /* cannot copy itself and check destination type */
- if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) {
- return OPERATOR_CANCELLED;
- }
+ /* sanity checks */
+ if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
+ return OPERATOR_CANCELLED;
+ }
+ /* cannot copy itself and check destination type */
+ if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) {
+ return OPERATOR_CANCELLED;
+ }
- bGPdata *gpd_dst = (bGPdata *)ob_dst->data;
+ bGPdata *gpd_dst = (bGPdata *)ob_dst->data;
- /* make copy of layer */
- bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src);
- gpl_dst->prev = gpl_dst->next = NULL;
- BLI_addtail(&gpd_dst->layers, gpl_dst);
- BLI_uniquename(&gpd_dst->layers, gpl_dst, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl_dst->info));
+ /* make copy of layer */
+ bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src);
+ gpl_dst->prev = gpl_dst->next = NULL;
+ BLI_addtail(&gpd_dst->layers, gpl_dst);
+ BLI_uniquename(&gpd_dst->layers,
+ gpl_dst,
+ DATA_("GP_Layer"),
+ '.',
+ offsetof(bGPDlayer, info),
+ sizeof(gpl_dst->info));
- /* copy frames */
- BLI_listbase_clear(&gpl_dst->frames);
- for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
+ /* copy frames */
+ BLI_listbase_clear(&gpl_dst->frames);
+ for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
- if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
- continue;
- }
+ if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
+ continue;
+ }
- /* make a copy of source frame */
- bGPDframe *gpf_dst = MEM_dupallocN(gpf_src);
- gpf_dst->prev = gpf_dst->next = NULL;
- BLI_addtail(&gpl_dst->frames, gpf_dst);
+ /* make a copy of source frame */
+ bGPDframe *gpf_dst = MEM_dupallocN(gpf_src);
+ gpf_dst->prev = gpf_dst->next = NULL;
+ BLI_addtail(&gpl_dst->frames, gpf_dst);
- /* copy strokes */
- BLI_listbase_clear(&gpf_dst->strokes);
- for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+ /* copy strokes */
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
- /* make copy of source stroke */
- bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
+ /* make copy of source stroke */
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
- /* check if material is in destination object,
- * otherwise add the slot with the material
- */
- Material *ma_src = give_current_material(ob_src, gps_src->mat_nr + 1);
- int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
+ /* check if material is in destination object,
+ * otherwise add the slot with the material
+ */
+ Material *ma_src = give_current_material(ob_src, gps_src->mat_nr + 1);
+ int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
- /* reasign the stroke material to the right slot in destination object */
- gps_dst->mat_nr = idx;
+ /* reasign the stroke material to the right slot in destination object */
+ gps_dst->mat_nr = idx;
- /* add new stroke to frame */
- BLI_addtail(&gpf_dst->strokes, gps_dst);
- }
- }
+ /* add new stroke to frame */
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+ }
+ }
- /* notifiers */
- DEG_id_tag_update(&gpd_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
- DEG_id_tag_update(&ob_dst->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ DEG_id_tag_update(&gpd_dst->id,
+ ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&ob_dst->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
{
- static const EnumPropertyItem copy_mode[] = {
- {GP_LAYER_COPY_OBJECT_ALL_FRAME, "ALL", 0, "All Frames", ""},
- {GP_LAYER_COPY_OBJECT_ACT_FRAME, "ACTIVE", 0, "Active Frame", ""},
- {0, NULL, 0, NULL, NULL},
- };
+ static const EnumPropertyItem copy_mode[] = {
+ {GP_LAYER_COPY_OBJECT_ALL_FRAME, "ALL", 0, "All Frames", ""},
+ {GP_LAYER_COPY_OBJECT_ACT_FRAME, "ACTIVE", 0, "Active Frame", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
- /* identifiers */
- ot->name = "Duplicate Layer to new Object";
- ot->idname = "GPENCIL_OT_layer_duplicate_object";
- ot->description = "Make a copy of the active Grease Pencil layer to new object";
+ /* identifiers */
+ ot->name = "Duplicate Layer to new Object";
+ ot->idname = "GPENCIL_OT_layer_duplicate_object";
+ ot->description = "Make a copy of the active Grease Pencil layer to new object";
- /* callbacks */
- ot->exec = gp_layer_duplicate_object_exec;
- ot->poll = gp_layer_duplicate_object_poll;
+ /* callbacks */
+ ot->exec = gp_layer_duplicate_object_exec;
+ ot->poll = gp_layer_duplicate_object_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_string(ot->srna, "object", NULL, MAX_ID_NAME - 2, "Object", "Name of the destination object");
- RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ ot->prop = RNA_def_string(
+ ot->srna, "object", NULL, MAX_ID_NAME - 2, "Object", "Name of the destination object");
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_COPY_OBJECT_ALL_FRAME, "Mode", "");
+ RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_COPY_OBJECT_ALL_FRAME, "Mode", "");
}
/* ********************* Duplicate Frame ************************** */
enum {
- GP_FRAME_DUP_ACTIVE = 0,
- GP_FRAME_DUP_ALL = 1,
+ GP_FRAME_DUP_ACTIVE = 0,
+ GP_FRAME_DUP_ALL = 1,
};
static int gp_frame_duplicate_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
- int mode = RNA_enum_get(op->ptr, "mode");
+ int mode = RNA_enum_get(op->ptr, "mode");
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl))
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
- if (mode == 0) {
- BKE_gpencil_frame_addcopy(gpl, cfra_eval);
- }
- else {
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
- BKE_gpencil_frame_addcopy(gpl, cfra_eval);
- }
- }
+ if (mode == 0) {
+ BKE_gpencil_frame_addcopy(gpl, cfra_eval);
+ }
+ else {
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
+ BKE_gpencil_frame_addcopy(gpl, cfra_eval);
+ }
+ }
+ }
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- }
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_frame_duplicate(wmOperatorType *ot)
{
- static const EnumPropertyItem duplicate_mode[] = {
- {GP_FRAME_DUP_ACTIVE, "ACTIVE", 0, "Active", "Duplicate frame in active layer only"},
- {GP_FRAME_DUP_ALL, "ALL", 0, "All", "Duplicate active frames in all layers"},
- {0, NULL, 0, NULL, NULL},
- };
+ static const EnumPropertyItem duplicate_mode[] = {
+ {GP_FRAME_DUP_ACTIVE, "ACTIVE", 0, "Active", "Duplicate frame in active layer only"},
+ {GP_FRAME_DUP_ALL, "ALL", 0, "All", "Duplicate active frames in all layers"},
+ {0, NULL, 0, NULL, NULL},
+ };
- /* identifiers */
- ot->name = "Duplicate Frame";
- ot->idname = "GPENCIL_OT_frame_duplicate";
- ot->description = "Make a copy of the active Grease Pencil Frame";
+ /* identifiers */
+ ot->name = "Duplicate Frame";
+ ot->idname = "GPENCIL_OT_frame_duplicate";
+ ot->description = "Make a copy of the active Grease Pencil Frame";
- /* callbacks */
- ot->exec = gp_frame_duplicate_exec;
- ot->poll = gp_active_layer_poll;
+ /* callbacks */
+ ot->exec = gp_frame_duplicate_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
+ ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
}
/* ********************* Clean Fill Boundaries on Frame ************************** */
enum {
- GP_FRAME_CLEAN_FILL_ACTIVE = 0,
- GP_FRAME_CLEAN_FILL_ALL = 1,
+ GP_FRAME_CLEAN_FILL_ACTIVE = 0,
+ GP_FRAME_CLEAN_FILL_ALL = 1,
};
static int gp_frame_clean_fill_exec(bContext *C, wmOperator *op)
{
- bool changed = false;
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- int mode = RNA_enum_get(op->ptr, "mode");
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- if (mode == GP_FRAME_CLEAN_FILL_ALL) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || (mode == GP_FRAME_CLEAN_FILL_ALL)) {
- bGPDstroke *gps, *gpsn;
-
- if (gpf == NULL)
- continue;
-
- /* simply delete strokes which are no fill */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- /* free stroke */
- if (gps->flag & GP_STROKE_NOFILL) {
- /* free stroke memory arrays, then stroke itself */
- if (gps->points) {
- MEM_freeN(gps->points);
- }
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
- MEM_SAFE_FREE(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
-
- changed = true;
- }
- }
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- if (changed) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- }
-
- return OPERATOR_FINISHED;
+ bool changed = false;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (mode == GP_FRAME_CLEAN_FILL_ALL) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || (mode == GP_FRAME_CLEAN_FILL_ALL)) {
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL)
+ continue;
+
+ /* simply delete strokes which are no fill */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ /* free stroke */
+ if (gps->flag & GP_STROKE_NOFILL) {
+ /* free stroke memory arrays, then stroke itself */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ MEM_SAFE_FREE(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_frame_clean_fill(wmOperatorType *ot)
{
- static const EnumPropertyItem duplicate_mode[] = {
- {GP_FRAME_CLEAN_FILL_ACTIVE, "ACTIVE", 0, "Active Frame Only", "Clean active frame only"},
- {GP_FRAME_CLEAN_FILL_ALL, "ALL", 0, "All Frames", "Clean all frames in all layers"},
- {0, NULL, 0, NULL, NULL},
- };
+ static const EnumPropertyItem duplicate_mode[] = {
+ {GP_FRAME_CLEAN_FILL_ACTIVE, "ACTIVE", 0, "Active Frame Only", "Clean active frame only"},
+ {GP_FRAME_CLEAN_FILL_ALL, "ALL", 0, "All Frames", "Clean all frames in all layers"},
+ {0, NULL, 0, NULL, NULL},
+ };
- /* identifiers */
- ot->name = "Clean Fill Boundaries";
- ot->idname = "GPENCIL_OT_frame_clean_fill";
- ot->description = "Remove 'no fill' boundary strokes";
+ /* identifiers */
+ ot->name = "Clean Fill Boundaries";
+ ot->idname = "GPENCIL_OT_frame_clean_fill";
+ ot->description = "Remove 'no fill' boundary strokes";
- /* callbacks */
- ot->exec = gp_frame_clean_fill_exec;
- ot->poll = gp_active_layer_poll;
+ /* callbacks */
+ ot->exec = gp_frame_clean_fill_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
+ ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
}
/* ********************* Clean Loose Boundaries on Frame ************************** */
static int gp_frame_clean_loose_exec(bContext *C, wmOperator *op)
{
- bool changed = false;
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- int limit = RNA_int_get(op->ptr, "limit");
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- bGPDstroke *gps = NULL;
- bGPDstroke *gpsn = NULL;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- if (gpf == NULL)
- continue;
-
- /* simply delete strokes which are no loose */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- /* free stroke */
- if (gps->totpoints <= limit) {
- /* free stroke memory arrays, then stroke itself */
- if (gps->points) {
- MEM_freeN(gps->points);
- }
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
- MEM_SAFE_FREE(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
-
- changed = true;
- }
- }
- }
-
- /* if not multiedit, exit loop*/
- if (!is_multiedit) {
- break;
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- if (changed) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- }
-
- return OPERATOR_FINISHED;
+ bool changed = false;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ int limit = RNA_int_get(op->ptr, "limit");
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ bGPDstroke *gps = NULL;
+ bGPDstroke *gpsn = NULL;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ /* simply delete strokes which are no loose */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ /* free stroke */
+ if (gps->totpoints <= limit) {
+ /* free stroke memory arrays, then stroke itself */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ MEM_SAFE_FREE(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+
+ changed = true;
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Clean Loose points";
- ot->idname = "GPENCIL_OT_frame_clean_loose";
- ot->description = "Remove loose points";
+ /* identifiers */
+ ot->name = "Clean Loose points";
+ ot->idname = "GPENCIL_OT_frame_clean_loose";
+ ot->description = "Remove loose points";
- /* callbacks */
- ot->exec = gp_frame_clean_loose_exec;
- ot->poll = gp_active_layer_poll;
+ /* callbacks */
+ ot->exec = gp_frame_clean_loose_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int(ot->srna, "limit", 1, 1, INT_MAX, "Limit", "Number of points to consider stroke as loose", 1, INT_MAX);
+ RNA_def_int(ot->srna,
+ "limit",
+ 1,
+ 1,
+ INT_MAX,
+ "Limit",
+ "Number of points to consider stroke as loose",
+ 1,
+ INT_MAX);
}
/* *********************** Hide Layers ******************************** */
static int gp_hide_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
- bool unselected = RNA_boolean_get(op->ptr, "unselected");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
+ bool unselected = RNA_boolean_get(op->ptr, "unselected");
- /* sanity checks */
- if (ELEM(NULL, gpd, layer))
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ELEM(NULL, gpd, layer))
+ return OPERATOR_CANCELLED;
- if (unselected) {
- bGPDlayer *gpl;
+ if (unselected) {
+ bGPDlayer *gpl;
- /* hide unselected */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl != layer) {
- gpl->flag |= GP_LAYER_HIDE;
- }
- }
- }
- else {
- /* hide selected/active */
- layer->flag |= GP_LAYER_HIDE;
- }
+ /* hide unselected */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl != layer) {
+ gpl->flag |= GP_LAYER_HIDE;
+ }
+ }
+ }
+ else {
+ /* hide selected/active */
+ layer->flag |= GP_LAYER_HIDE;
+ }
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_hide(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Hide Layer(s)";
- ot->idname = "GPENCIL_OT_hide";
- ot->description = "Hide selected/unselected Grease Pencil layers";
+ /* identifiers */
+ ot->name = "Hide Layer(s)";
+ ot->idname = "GPENCIL_OT_hide";
+ ot->description = "Hide selected/unselected Grease Pencil layers";
- /* callbacks */
- ot->exec = gp_hide_exec;
- ot->poll = gp_active_layer_poll; /* NOTE: we need an active layer to play with */
+ /* callbacks */
+ ot->exec = gp_hide_exec;
+ ot->poll = gp_active_layer_poll; /* NOTE: we need an active layer to play with */
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers");
+ /* props */
+ RNA_def_boolean(
+ ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers");
}
/* ********************** Show All Layers ***************************** */
@@ -851,368 +866,375 @@ void GPENCIL_OT_hide(wmOperatorType *ot)
/* poll callback for showing layers */
static bool gp_reveal_poll(bContext *C)
{
- return ED_gpencil_data_get_active(C) != NULL;
+ return ED_gpencil_data_get_active(C) != NULL;
}
static void gp_reveal_select_frame(bContext *C, bGPDframe *frame, bool select)
{
- bGPDstroke *gps;
- for (gps = frame->strokes.first; gps; gps = gps->next) {
+ bGPDstroke *gps;
+ for (gps = frame->strokes.first; gps; gps = gps->next) {
- /* only deselect strokes that are valid in this view */
- if (ED_gpencil_stroke_can_use(C, gps)) {
+ /* only deselect strokes that are valid in this view */
+ if (ED_gpencil_stroke_can_use(C, gps)) {
- /* (de)select points */
- int i;
- bGPDspoint *pt;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- SET_FLAG_FROM_TEST(pt->flag, select, GP_SPOINT_SELECT);
- }
+ /* (de)select points */
+ int i;
+ bGPDspoint *pt;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ SET_FLAG_FROM_TEST(pt->flag, select, GP_SPOINT_SELECT);
+ }
- /* (de)select stroke */
- SET_FLAG_FROM_TEST(gps->flag, select, GP_STROKE_SELECT);
- }
- }
+ /* (de)select stroke */
+ SET_FLAG_FROM_TEST(gps->flag, select, GP_STROKE_SELECT);
+ }
+ }
}
static int gp_reveal_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl;
- const bool select = RNA_boolean_get(op->ptr, "select");
-
- /* sanity checks */
- if (gpd == NULL)
- return OPERATOR_CANCELLED;
-
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
-
- if (gpl->flag & GP_LAYER_HIDE) {
- gpl->flag &= ~GP_LAYER_HIDE;
-
- /* select or deselect if requested, only on hidden layers */
- if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
- if (select) {
- /* select all strokes on active frame only (same as select all operator) */
- if (gpl->actframe) {
- gp_reveal_select_frame(C, gpl->actframe, true);
- }
- }
- else {
- /* deselect strokes on all frames (same as deselect all operator) */
- bGPDframe *gpf;
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- gp_reveal_select_frame(C, gpf, false);
- }
- }
- }
- }
- }
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl;
+ const bool select = RNA_boolean_get(op->ptr, "select");
+
+ /* sanity checks */
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+
+ if (gpl->flag & GP_LAYER_HIDE) {
+ gpl->flag &= ~GP_LAYER_HIDE;
+
+ /* select or deselect if requested, only on hidden layers */
+ if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ if (select) {
+ /* select all strokes on active frame only (same as select all operator) */
+ if (gpl->actframe) {
+ gp_reveal_select_frame(C, gpl->actframe, true);
+ }
+ }
+ else {
+ /* deselect strokes on all frames (same as deselect all operator) */
+ bGPDframe *gpf;
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ gp_reveal_select_frame(C, gpf, false);
+ }
+ }
+ }
+ }
+ }
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_reveal(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Show All Layers";
- ot->idname = "GPENCIL_OT_reveal";
- ot->description = "Show all Grease Pencil layers";
+ /* identifiers */
+ ot->name = "Show All Layers";
+ ot->idname = "GPENCIL_OT_reveal";
+ ot->description = "Show all Grease Pencil layers";
- /* callbacks */
- ot->exec = gp_reveal_exec;
- ot->poll = gp_reveal_poll;
+ /* callbacks */
+ ot->exec = gp_reveal_exec;
+ ot->poll = gp_reveal_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- RNA_def_boolean(ot->srna, "select", true, "Select", "");
+ /* props */
+ RNA_def_boolean(ot->srna, "select", true, "Select", "");
}
/* ***************** Lock/Unlock All Layers ************************ */
static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl;
- /* sanity checks */
- if (gpd == NULL)
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
- /* make all layers non-editable */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- gpl->flag |= GP_LAYER_LOCKED;
- }
+ /* make all layers non-editable */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag |= GP_LAYER_LOCKED;
+ }
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_lock_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Lock All Layers";
- ot->idname = "GPENCIL_OT_lock_all";
- ot->description = "Lock all Grease Pencil layers to prevent them from being accidentally modified";
+ /* identifiers */
+ ot->name = "Lock All Layers";
+ ot->idname = "GPENCIL_OT_lock_all";
+ ot->description =
+ "Lock all Grease Pencil layers to prevent them from being accidentally modified";
- /* callbacks */
- ot->exec = gp_lock_all_exec;
- ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */
+ /* callbacks */
+ ot->exec = gp_lock_all_exec;
+ ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* -------------------------- */
static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl;
- /* sanity checks */
- if (gpd == NULL)
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
- /* make all layers editable again */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- gpl->flag &= ~GP_LAYER_LOCKED;
- }
+ /* make all layers editable again */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag &= ~GP_LAYER_LOCKED;
+ }
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_unlock_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Unlock All Layers";
- ot->idname = "GPENCIL_OT_unlock_all";
- ot->description = "Unlock all Grease Pencil layers so that they can be edited";
+ /* identifiers */
+ ot->name = "Unlock All Layers";
+ ot->idname = "GPENCIL_OT_unlock_all";
+ ot->description = "Unlock all Grease Pencil layers so that they can be edited";
- /* callbacks */
- ot->exec = gp_unlock_all_exec;
- ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */
+ /* callbacks */
+ ot->exec = gp_unlock_all_exec;
+ ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************** Isolate Layer **************************** */
static int gp_isolate_layer_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
- bGPDlayer *gpl;
- int flags = GP_LAYER_LOCKED;
- bool isolate = false;
-
- if (RNA_boolean_get(op->ptr, "affect_visibility"))
- flags |= GP_LAYER_HIDE;
-
- if (ELEM(NULL, gpd, layer)) {
- BKE_report(op->reports, RPT_ERROR, "No active layer to isolate");
- return OPERATOR_CANCELLED;
- }
-
- /* Test whether to isolate or clear all flags */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* Skip if this is the active layer */
- if (gpl == layer)
- continue;
-
- /* If the flags aren't set, that means that the layer is
- * not alone, so we have some layers to isolate still
- */
- if ((gpl->flag & flags) == 0) {
- isolate = true;
- break;
- }
- }
-
- /* Set/Clear flags as appropriate */
- /* TODO: Include onionskinning on this list? */
- if (isolate) {
- /* Set flags on all "other" layers */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl == layer)
- continue;
- else
- gpl->flag |= flags;
- }
- }
- else {
- /* Clear flags - Restore everything else */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- gpl->flag &= ~flags;
- }
- }
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl;
+ int flags = GP_LAYER_LOCKED;
+ bool isolate = false;
+
+ if (RNA_boolean_get(op->ptr, "affect_visibility"))
+ flags |= GP_LAYER_HIDE;
+
+ if (ELEM(NULL, gpd, layer)) {
+ BKE_report(op->reports, RPT_ERROR, "No active layer to isolate");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Test whether to isolate or clear all flags */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* Skip if this is the active layer */
+ if (gpl == layer)
+ continue;
+
+ /* If the flags aren't set, that means that the layer is
+ * not alone, so we have some layers to isolate still
+ */
+ if ((gpl->flag & flags) == 0) {
+ isolate = true;
+ break;
+ }
+ }
+
+ /* Set/Clear flags as appropriate */
+ /* TODO: Include onionskinning on this list? */
+ if (isolate) {
+ /* Set flags on all "other" layers */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl == layer)
+ continue;
+ else
+ gpl->flag |= flags;
+ }
+ }
+ else {
+ /* Clear flags - Restore everything else */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag &= ~flags;
+ }
+ }
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_layer_isolate(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Isolate Layer";
- ot->idname = "GPENCIL_OT_layer_isolate";
- ot->description = "Toggle whether the active layer is the only one that can be edited and/or visible";
+ /* identifiers */
+ ot->name = "Isolate Layer";
+ ot->idname = "GPENCIL_OT_layer_isolate";
+ ot->description =
+ "Toggle whether the active layer is the only one that can be edited and/or visible";
- /* callbacks */
- ot->exec = gp_isolate_layer_exec;
- ot->poll = gp_active_layer_poll;
+ /* callbacks */
+ ot->exec = gp_isolate_layer_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility",
- "In addition to toggling the editability, also affect the visibility");
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "affect_visibility",
+ false,
+ "Affect Visibility",
+ "In addition to toggling the editability, also affect the visibility");
}
/* ********************** Merge Layer with the next layer **************************** */
static int gp_merge_layer_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl_next = BKE_gpencil_layer_getactive(gpd);
- bGPDlayer *gpl_current = gpl_next->prev;
-
- if (ELEM(NULL, gpd, gpl_current, gpl_next)) {
- BKE_report(op->reports, RPT_ERROR, "No layers to merge");
- return OPERATOR_CANCELLED;
- }
-
- /* Collect frames of gpl_current in hash table to avoid O(n^2) lookups */
- GHash *gh_frames_cur = BLI_ghash_int_new_ex(__func__, 64);
- for (bGPDframe *gpf = gpl_current->frames.first; gpf; gpf = gpf->next) {
- BLI_ghash_insert(gh_frames_cur, POINTER_FROM_INT(gpf->framenum), gpf);
- }
-
- /* read all frames from next layer and add any missing in current layer */
- for (bGPDframe *gpf = gpl_next->frames.first; gpf; gpf = gpf->next) {
- /* try to find frame in current layer */
- bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, POINTER_FROM_INT(gpf->framenum));
- if (!frame) {
- bGPDframe *actframe = BKE_gpencil_layer_getframe(gpl_current, gpf->framenum, GP_GETFRAME_USE_PREV);
- frame = BKE_gpencil_frame_addnew(gpl_current, gpf->framenum);
- /* duplicate strokes of current active frame */
- if (actframe) {
- BKE_gpencil_frame_copy_strokes(actframe, frame);
- }
- }
- /* add to tail all strokes */
- BLI_movelisttolist(&frame->strokes, &gpf->strokes);
- }
-
- /* Now delete next layer */
- BKE_gpencil_layer_delete(gpd, gpl_next);
- BLI_ghash_free(gh_frames_cur, NULL, NULL);
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl_next = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl_current = gpl_next->prev;
+
+ if (ELEM(NULL, gpd, gpl_current, gpl_next)) {
+ BKE_report(op->reports, RPT_ERROR, "No layers to merge");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Collect frames of gpl_current in hash table to avoid O(n^2) lookups */
+ GHash *gh_frames_cur = BLI_ghash_int_new_ex(__func__, 64);
+ for (bGPDframe *gpf = gpl_current->frames.first; gpf; gpf = gpf->next) {
+ BLI_ghash_insert(gh_frames_cur, POINTER_FROM_INT(gpf->framenum), gpf);
+ }
+
+ /* read all frames from next layer and add any missing in current layer */
+ for (bGPDframe *gpf = gpl_next->frames.first; gpf; gpf = gpf->next) {
+ /* try to find frame in current layer */
+ bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, POINTER_FROM_INT(gpf->framenum));
+ if (!frame) {
+ bGPDframe *actframe = BKE_gpencil_layer_getframe(
+ gpl_current, gpf->framenum, GP_GETFRAME_USE_PREV);
+ frame = BKE_gpencil_frame_addnew(gpl_current, gpf->framenum);
+ /* duplicate strokes of current active frame */
+ if (actframe) {
+ BKE_gpencil_frame_copy_strokes(actframe, frame);
+ }
+ }
+ /* add to tail all strokes */
+ BLI_movelisttolist(&frame->strokes, &gpf->strokes);
+ }
+
+ /* Now delete next layer */
+ BKE_gpencil_layer_delete(gpd, gpl_next);
+ BLI_ghash_free(gh_frames_cur, NULL, NULL);
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_layer_merge(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Merge Down";
- ot->idname = "GPENCIL_OT_layer_merge";
- ot->description = "Merge the current layer with the layer below";
+ /* identifiers */
+ ot->name = "Merge Down";
+ ot->idname = "GPENCIL_OT_layer_merge";
+ ot->description = "Merge the current layer with the layer below";
- /* callbacks */
- ot->exec = gp_merge_layer_exec;
- ot->poll = gp_active_layer_poll;
+ /* callbacks */
+ ot->exec = gp_merge_layer_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************** Change Layer ***************************** */
static int gp_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
{
- uiPopupMenu *pup;
- uiLayout *layout;
+ uiPopupMenu *pup;
+ uiLayout *layout;
- /* call the menu, which will call this operator again, hence the canceled */
- pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
- layout = UI_popup_menu_layout(pup);
- uiItemsEnumO(layout, "GPENCIL_OT_layer_change", "layer");
- UI_popup_menu_end(C, pup);
+ /* call the menu, which will call this operator again, hence the canceled */
+ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
+ uiItemsEnumO(layout, "GPENCIL_OT_layer_change", "layer");
+ UI_popup_menu_end(C, pup);
- return OPERATOR_INTERFACE;
+ return OPERATOR_INTERFACE;
}
static int gp_layer_change_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDlayer *gpl = NULL;
- int layer_num = RNA_enum_get(op->ptr, "layer");
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = NULL;
+ int layer_num = RNA_enum_get(op->ptr, "layer");
- /* Get layer or create new one */
- if (layer_num == -1) {
- /* Create layer */
- gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
- }
- else {
- /* Try to get layer */
- gpl = BLI_findlink(&gpd->layers, layer_num);
+ /* Get layer or create new one */
+ if (layer_num == -1) {
+ /* Create layer */
+ gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ }
+ else {
+ /* Try to get layer */
+ gpl = BLI_findlink(&gpd->layers, layer_num);
- if (gpl == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent layer (index = %d)", layer_num);
- return OPERATOR_CANCELLED;
- }
- }
+ if (gpl == NULL) {
+ BKE_reportf(
+ op->reports, RPT_ERROR, "Cannot change to non-existent layer (index = %d)", layer_num);
+ return OPERATOR_CANCELLED;
+ }
+ }
- /* Set active layer */
- BKE_gpencil_layer_setactive(gpd, gpl);
+ /* Set active layer */
+ BKE_gpencil_layer_setactive(gpd, gpl);
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_layer_change(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Change Layer";
- ot->idname = "GPENCIL_OT_layer_change";
- ot->description = "Change active Grease Pencil layer";
+ /* identifiers */
+ ot->name = "Change Layer";
+ ot->idname = "GPENCIL_OT_layer_change";
+ ot->description = "Change active Grease Pencil layer";
- /* callbacks */
- ot->invoke = gp_layer_change_invoke;
- ot->exec = gp_layer_change_exec;
- ot->poll = gp_active_layer_poll;
+ /* callbacks */
+ ot->invoke = gp_layer_change_invoke;
+ ot->exec = gp_layer_change_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* gp layer to use (dynamic enum) */
- ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", "");
- RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
+ /* gp layer to use (dynamic enum) */
+ ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", "");
+ RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
}
/* ************************************************ */
@@ -1220,309 +1242,305 @@ void GPENCIL_OT_layer_change(wmOperatorType *ot)
/* ******************* Arrange Stroke Up/Down in drawing order ************************** */
enum {
- GP_STROKE_MOVE_UP = -1,
- GP_STROKE_MOVE_DOWN = 1,
- GP_STROKE_MOVE_TOP = 2,
- GP_STROKE_MOVE_BOTTOM = 3,
+ GP_STROKE_MOVE_UP = -1,
+ GP_STROKE_MOVE_DOWN = 1,
+ GP_STROKE_MOVE_TOP = 2,
+ GP_STROKE_MOVE_BOTTOM = 3,
};
static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- bGPDstroke *gps;
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl, gpl->actframe)) {
- return OPERATOR_CANCELLED;
- }
-
- const int direction = RNA_enum_get(op->ptr, "direction");
-
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* temp listbase to store selected strokes by layer */
- ListBase selected = { NULL };
- bGPDframe *gpf = gpl->actframe;
- if (gpl->flag & GP_LAYER_LOCKED) {
- continue;
- }
-
- if (gpf == NULL) {
- continue;
- }
- bool gpf_lock = false;
- /* verify if any selected stroke is in the extreme of the stack and select to move */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- /* only if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
- continue;
- }
- /* some stroke is already at front*/
- if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) {
- if (gps == gpf->strokes.last) {
- gpf_lock = true;
- continue;
- }
- }
- /* some stroke is already at botom */
- if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) {
- if (gps == gpf->strokes.first) {
- gpf_lock = true;
- continue;
- }
- }
- /* add to list (if not locked) */
- if (!gpf_lock) {
- BLI_addtail(&selected, BLI_genericNodeN(gps));
- }
- }
- }
- /* Now do the movement of the stroke */
- if (!gpf_lock) {
- switch (direction) {
- /* Bring to Front */
- case GP_STROKE_MOVE_TOP:
- for (LinkData *link = selected.first; link; link = link->next) {
- gps = link->data;
- BLI_remlink(&gpf->strokes, gps);
- BLI_addtail(&gpf->strokes, gps);
- }
- break;
- /* Bring Forward */
- case GP_STROKE_MOVE_UP:
- for (LinkData *link = selected.last; link; link = link->prev) {
- gps = link->data;
- BLI_listbase_link_move(&gpf->strokes, gps, 1);
- }
- break;
- /* Send Backward */
- case GP_STROKE_MOVE_DOWN:
- for (LinkData *link = selected.first; link; link = link->next) {
- gps = link->data;
- BLI_listbase_link_move(&gpf->strokes, gps, -1);
- }
- break;
- /* Send to Back */
- case GP_STROKE_MOVE_BOTTOM:
- for (LinkData *link = selected.last; link; link = link->prev) {
- gps = link->data;
- BLI_remlink(&gpf->strokes, gps);
- BLI_addhead(&gpf->strokes, gps);
- }
- break;
- default:
- BLI_assert(0);
- break;
- }
- }
- BLI_freelistN(&selected);
- }
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDstroke *gps;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl, gpl->actframe)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const int direction = RNA_enum_get(op->ptr, "direction");
+
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* temp listbase to store selected strokes by layer */
+ ListBase selected = {NULL};
+ bGPDframe *gpf = gpl->actframe;
+ if (gpl->flag & GP_LAYER_LOCKED) {
+ continue;
+ }
+
+ if (gpf == NULL) {
+ continue;
+ }
+ bool gpf_lock = false;
+ /* verify if any selected stroke is in the extreme of the stack and select to move */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ /* some stroke is already at front*/
+ if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) {
+ if (gps == gpf->strokes.last) {
+ gpf_lock = true;
+ continue;
+ }
+ }
+ /* some stroke is already at botom */
+ if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) {
+ if (gps == gpf->strokes.first) {
+ gpf_lock = true;
+ continue;
+ }
+ }
+ /* add to list (if not locked) */
+ if (!gpf_lock) {
+ BLI_addtail(&selected, BLI_genericNodeN(gps));
+ }
+ }
+ }
+ /* Now do the movement of the stroke */
+ if (!gpf_lock) {
+ switch (direction) {
+ /* Bring to Front */
+ case GP_STROKE_MOVE_TOP:
+ for (LinkData *link = selected.first; link; link = link->next) {
+ gps = link->data;
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_addtail(&gpf->strokes, gps);
+ }
+ break;
+ /* Bring Forward */
+ case GP_STROKE_MOVE_UP:
+ for (LinkData *link = selected.last; link; link = link->prev) {
+ gps = link->data;
+ BLI_listbase_link_move(&gpf->strokes, gps, 1);
+ }
+ break;
+ /* Send Backward */
+ case GP_STROKE_MOVE_DOWN:
+ for (LinkData *link = selected.first; link; link = link->next) {
+ gps = link->data;
+ BLI_listbase_link_move(&gpf->strokes, gps, -1);
+ }
+ break;
+ /* Send to Back */
+ case GP_STROKE_MOVE_BOTTOM:
+ for (LinkData *link = selected.last; link; link = link->prev) {
+ gps = link->data;
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_addhead(&gpf->strokes, gps);
+ }
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ }
+ BLI_freelistN(&selected);
+ }
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_arrange(wmOperatorType *ot)
{
- static const EnumPropertyItem slot_move[] = {
- {GP_STROKE_MOVE_UP, "UP", 0, "Bring Forward", ""},
- {GP_STROKE_MOVE_DOWN, "DOWN", 0, "Send Backward", ""},
- {GP_STROKE_MOVE_TOP, "TOP", 0, "Bring to Front", ""},
- {GP_STROKE_MOVE_BOTTOM, "BOTTOM", 0, "Send to Back", ""},
- {0, NULL, 0, NULL, NULL }
- };
+ static const EnumPropertyItem slot_move[] = {
+ {GP_STROKE_MOVE_UP, "UP", 0, "Bring Forward", ""},
+ {GP_STROKE_MOVE_DOWN, "DOWN", 0, "Send Backward", ""},
+ {GP_STROKE_MOVE_TOP, "TOP", 0, "Bring to Front", ""},
+ {GP_STROKE_MOVE_BOTTOM, "BOTTOM", 0, "Send to Back", ""},
+ {0, NULL, 0, NULL, NULL}};
- /* identifiers */
- ot->name = "Arrange Stroke";
- ot->idname = "GPENCIL_OT_stroke_arrange";
- ot->description = "Arrange selected strokes up/down in the drawing order of the active layer";
+ /* identifiers */
+ ot->name = "Arrange Stroke";
+ ot->idname = "GPENCIL_OT_stroke_arrange";
+ ot->description = "Arrange selected strokes up/down in the drawing order of the active layer";
- /* callbacks */
- ot->exec = gp_stroke_arrange_exec;
- ot->poll = gp_active_layer_poll;
+ /* callbacks */
+ ot->exec = gp_stroke_arrange_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_STROKE_MOVE_UP, "Direction", "");
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_STROKE_MOVE_UP, "Direction", "");
}
/* ******************* Move Stroke to new color ************************** */
static int gp_stroke_change_color_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- Material *ma = NULL;
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "material", name);
-
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- Object *ob = CTX_data_active_object(C);
- if (name[0] == '\0') {
- ma = give_current_material(ob, ob->actcol);
- }
- else {
- ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, name);
- if (ma == NULL) {
- return OPERATOR_CANCELLED;
- }
- }
- /* try to find slot */
- int idx = BKE_gpencil_object_material_get_index(ob, ma);
- if (idx < 0) {
- return OPERATOR_CANCELLED;
- }
-
- /* sanity checks */
- if (ELEM(NULL, gpd)) {
- return OPERATOR_CANCELLED;
- }
-
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- if (ELEM(NULL, ma)) {
- return OPERATOR_CANCELLED;
- }
-
- /* loop all strokes */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- if (gpf == NULL)
- continue;
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* only if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
- continue;
-
- /* assign new color */
- gps->mat_nr = idx;
- }
- }
- }
- /* if not multiedit, exit loop*/
- if (!is_multiedit) {
- break;
- }
-
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ Main *bmain = CTX_data_main(C);
+ Material *ma = NULL;
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "material", name);
+
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+ if (name[0] == '\0') {
+ ma = give_current_material(ob, ob->actcol);
+ }
+ else {
+ ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, name);
+ if (ma == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+ /* try to find slot */
+ int idx = BKE_gpencil_object_material_get_index(ob, ma);
+ if (idx < 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ if (ELEM(NULL, ma)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* loop all strokes */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
+ continue;
+
+ /* assign new color */
+ gps->mat_nr = idx;
+ }
+ }
+ }
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_change_color(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Change Stroke Color";
- ot->idname = "GPENCIL_OT_stroke_change_color";
- ot->description = "Move selected strokes to active material";
-
- /* callbacks */
- ot->exec = gp_stroke_change_color_exec;
- ot->poll = gp_active_layer_poll;
+ /* identifiers */
+ ot->name = "Change Stroke Color";
+ ot->idname = "GPENCIL_OT_stroke_change_color";
+ ot->description = "Move selected strokes to active material";
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* callbacks */
+ ot->exec = gp_stroke_change_color_exec;
+ ot->poll = gp_active_layer_poll;
- RNA_def_string(ot->srna, "material", NULL, MAX_ID_NAME - 2, "Material", "Name of the material");
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_string(ot->srna, "material", NULL, MAX_ID_NAME - 2, "Material", "Name of the material");
}
/* ******************* Lock color of non selected Strokes colors ************************** */
static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- short *totcol = give_totcolp(ob);
+ short *totcol = give_totcolp(ob);
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
- /* first lock all colors */
- for (short i = 0; i < *totcol; i++) {
- Material *tmp_ma = give_current_material(ob, i + 1);
- tmp_ma->gp_style->flag |= GP_STYLE_COLOR_LOCKED;
- DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
- }
+ /* first lock all colors */
+ for (short i = 0; i < *totcol; i++) {
+ Material *tmp_ma = give_current_material(ob, i + 1);
+ tmp_ma->gp_style->flag |= GP_STYLE_COLOR_LOCKED;
+ DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
+ }
- /* loop all selected strokes and unlock any color */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
- /* only if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* unlock color */
- Material *tmp_ma = give_current_material(ob, gps->mat_nr + 1);
+ /* loop all selected strokes and unlock any color */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* unlock color */
+ Material *tmp_ma = give_current_material(ob, gps->mat_nr + 1);
- tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
- DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
- }
- }
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+ tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
+ DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ }
+ }
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Lock Unused Colors";
- ot->idname = "GPENCIL_OT_stroke_lock_color";
- ot->description = "Lock any color not used in any selected stroke";
+ /* identifiers */
+ ot->name = "Lock Unused Colors";
+ ot->idname = "GPENCIL_OT_stroke_lock_color";
+ ot->description = "Lock any color not used in any selected stroke";
- /* api callbacks */
- ot->exec = gp_stroke_lock_color_exec;
- ot->poll = gp_active_layer_poll;
+ /* api callbacks */
+ ot->exec = gp_stroke_lock_color_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ************************************************ */
@@ -1531,1111 +1549,1111 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
/* ******************* Brush create presets ************************** */
static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
{
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(C);
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_brush_presets_create(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Create Preset Brushes";
- ot->idname = "GPENCIL_OT_brush_presets_create";
- ot->description = "Create a set of predefined Grease Pencil drawing brushes";
+ /* identifiers */
+ ot->name = "Create Preset Brushes";
+ ot->idname = "GPENCIL_OT_brush_presets_create";
+ ot->description = "Create a set of predefined Grease Pencil drawing brushes";
- /* api callbacks */
- ot->exec = gp_brush_presets_create_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* api callbacks */
+ ot->exec = gp_brush_presets_create_exec;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/*********************** Vertex Groups ***********************************/
static bool gpencil_vertex_group_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- if ((ob) && (ob->type == OB_GPENCIL)) {
- if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
- if (ELEM(ob->mode,
- OB_MODE_EDIT_GPENCIL,
- OB_MODE_SCULPT_GPENCIL))
- {
- return true;
- }
- }
- }
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
+ if (ELEM(ob->mode, OB_MODE_EDIT_GPENCIL, OB_MODE_SCULPT_GPENCIL)) {
+ return true;
+ }
+ }
+ }
- return false;
+ return false;
}
static bool gpencil_vertex_group_weight_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- if ((ob) && (ob->type == OB_GPENCIL)) {
- if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
- if (ob->mode == OB_MODE_WEIGHT_GPENCIL) {
- return true;
- }
- }
- }
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
+ if (ob->mode == OB_MODE_WEIGHT_GPENCIL) {
+ return true;
+ }
+ }
+ }
- return false;
+ return false;
}
static int gpencil_vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op))
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- Object *ob = CTX_data_active_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
- /* sanity checks */
- if (ELEM(NULL, ts, ob, ob->data))
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ELEM(NULL, ts, ob, ob->data))
+ return OPERATOR_CANCELLED;
- ED_gpencil_vgroup_assign(C, ob, ts->vgroup_weight);
+ ED_gpencil_vgroup_assign(C, ob, ts->vgroup_weight);
- /* notifiers */
- bGPdata *gpd = ob->data;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
+ /* notifiers */
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_vertex_group_assign(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Assign to Vertex Group";
- ot->idname = "GPENCIL_OT_vertex_group_assign";
- ot->description = "Assign the selected vertices to the active vertex group";
+ /* identifiers */
+ ot->name = "Assign to Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_assign";
+ ot->description = "Assign the selected vertices to the active vertex group";
- /* api callbacks */
- ot->poll = gpencil_vertex_group_poll;
- ot->exec = gpencil_vertex_group_assign_exec;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_poll;
+ ot->exec = gpencil_vertex_group_assign_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* remove point from vertex group */
static int gpencil_vertex_group_remove_from_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- /* sanity checks */
- if (ELEM(NULL, ob, ob->data))
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ELEM(NULL, ob, ob->data))
+ return OPERATOR_CANCELLED;
- ED_gpencil_vgroup_remove(C, ob);
+ ED_gpencil_vgroup_remove(C, ob);
- /* notifiers */
- bGPdata *gpd = ob->data;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
+ /* notifiers */
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_vertex_group_remove_from(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Remove from Vertex Group";
- ot->idname = "GPENCIL_OT_vertex_group_remove_from";
- ot->description = "Remove the selected vertices from active or all vertex group(s)";
-
- /* api callbacks */
- ot->poll = gpencil_vertex_group_poll;
- ot->exec = gpencil_vertex_group_remove_from_exec;
+ /* identifiers */
+ ot->name = "Remove from Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_remove_from";
+ ot->description = "Remove the selected vertices from active or all vertex group(s)";
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_poll;
+ ot->exec = gpencil_vertex_group_remove_from_exec;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int gpencil_vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- /* sanity checks */
- if (ELEM(NULL, ob, ob->data))
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ELEM(NULL, ob, ob->data))
+ return OPERATOR_CANCELLED;
- ED_gpencil_vgroup_select(C, ob);
+ ED_gpencil_vgroup_select(C, ob);
- /* notifiers */
- bGPdata *gpd = ob->data;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
+ /* notifiers */
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_vertex_group_select(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Vertex Group";
- ot->idname = "GPENCIL_OT_vertex_group_select";
- ot->description = "Select all the vertices assigned to the active vertex group";
+ /* identifiers */
+ ot->name = "Select Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_select";
+ ot->description = "Select all the vertices assigned to the active vertex group";
- /* api callbacks */
- ot->poll = gpencil_vertex_group_poll;
- ot->exec = gpencil_vertex_group_select_exec;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_poll;
+ ot->exec = gpencil_vertex_group_select_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int gpencil_vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- /* sanity checks */
- if (ELEM(NULL, ob, ob->data))
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ELEM(NULL, ob, ob->data))
+ return OPERATOR_CANCELLED;
- ED_gpencil_vgroup_deselect(C, ob);
+ ED_gpencil_vgroup_deselect(C, ob);
- /* notifiers */
- bGPdata *gpd = ob->data;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
+ /* notifiers */
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_vertex_group_deselect(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Deselect Vertex Group";
- ot->idname = "GPENCIL_OT_vertex_group_deselect";
- ot->description = "Deselect all selected vertices assigned to the active vertex group";
+ /* identifiers */
+ ot->name = "Deselect Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_deselect";
+ ot->description = "Deselect all selected vertices assigned to the active vertex group";
- /* api callbacks */
- ot->poll = gpencil_vertex_group_poll;
- ot->exec = gpencil_vertex_group_deselect_exec;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_poll;
+ ot->exec = gpencil_vertex_group_deselect_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* invert */
static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *op)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- Object *ob = CTX_data_active_object(C);
-
- /* sanity checks */
- if (ELEM(NULL, ts, ob, ob->data)) {
- return OPERATOR_CANCELLED;
- }
-
- MDeformVert *dvert;
- const int def_nr = ob->actdef - 1;
- bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
- if (defgroup == NULL) {
- return OPERATOR_CANCELLED;
- }
- if (defgroup->flag & DG_LOCK_WEIGHT) {
- BKE_report(op->reports, RPT_ERROR, "Current Vertex Group is locked");
- return OPERATOR_CANCELLED;
- }
-
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- for (int i = 0; i < gps->totpoints; i++) {
- dvert = &gps->dvert[i];
- MDeformWeight *dw = defvert_find_index(dvert, def_nr);
- if (dw == NULL) {
- defvert_add_index_notest(dvert, def_nr, 1.0f);
- }
- else if (dw->weight == 1.0f) {
- defvert_remove_group(dvert, dw);
- }
- else {
- dw->weight = 1.0f - dw->weight;
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- bGPdata *gpd = ob->data;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
-
- return OPERATOR_FINISHED;
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* sanity checks */
+ if (ELEM(NULL, ts, ob, ob->data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ MDeformVert *dvert;
+ const int def_nr = ob->actdef - 1;
+ bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
+ if (defgroup == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+ if (defgroup->flag & DG_LOCK_WEIGHT) {
+ BKE_report(op->reports, RPT_ERROR, "Current Vertex Group is locked");
+ return OPERATOR_CANCELLED;
+ }
+
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ dvert = &gps->dvert[i];
+ MDeformWeight *dw = defvert_find_index(dvert, def_nr);
+ if (dw == NULL) {
+ defvert_add_index_notest(dvert, def_nr, 1.0f);
+ }
+ else if (dw->weight == 1.0f) {
+ defvert_remove_group(dvert, dw);
+ }
+ else {
+ dw->weight = 1.0f - dw->weight;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_vertex_group_invert(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Invert Vertex Group";
- ot->idname = "GPENCIL_OT_vertex_group_invert";
- ot->description = "Invert weights to the active vertex group";
+ /* identifiers */
+ ot->name = "Invert Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_invert";
+ ot->description = "Invert weights to the active vertex group";
- /* api callbacks */
- ot->poll = gpencil_vertex_group_weight_poll;
- ot->exec = gpencil_vertex_group_invert_exec;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_weight_poll;
+ ot->exec = gpencil_vertex_group_invert_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* smooth */
static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op)
{
- const float fac = RNA_float_get(op->ptr, "factor");
- const int repeat = RNA_int_get(op->ptr, "repeat");
-
- ToolSettings *ts = CTX_data_tool_settings(C);
- Object *ob = CTX_data_active_object(C);
-
- /* sanity checks */
- if (ELEM(NULL, ts, ob, ob->data)) {
- return OPERATOR_CANCELLED;
- }
-
- const int def_nr = ob->actdef - 1;
- bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
- if (defgroup == NULL) {
- return OPERATOR_CANCELLED;
- }
- if (defgroup->flag & DG_LOCK_WEIGHT) {
- BKE_report(op->reports, RPT_ERROR, "Current Vertex Group is locked");
- return OPERATOR_CANCELLED;
- }
-
- bGPDspoint *pta, *ptb, *ptc;
- MDeformVert *dverta, *dvertb;
-
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- if (gps->dvert == NULL) {
- continue;
- }
-
- for (int s = 0; s < repeat; s++) {
- for (int i = 0; i < gps->totpoints; i++) {
- /* previous point */
- if (i > 0) {
- pta = &gps->points[i - 1];
- dverta = &gps->dvert[i - 1];
- }
- else {
- pta = &gps->points[i];
- dverta = &gps->dvert[i];
- }
- /* current */
- ptb = &gps->points[i];
- dvertb = &gps->dvert[i];
- /* next point */
- if (i + 1 < gps->totpoints) {
- ptc = &gps->points[i + 1];
- }
- else {
- ptc = &gps->points[i];
- }
-
- float wa = defvert_find_weight(dverta, def_nr);
- float wb = defvert_find_weight(dvertb, def_nr);
-
- /* the optimal value is the corresponding to the interpolation of the weight
- * at the distance of point b
- */
- const float opfac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
- const float optimal = interpf(wa, wb, opfac);
- /* Based on influence factor, blend between original and optimal */
- MDeformWeight *dw = defvert_verify_index(dvertb, def_nr);
- if (dw) {
- dw->weight = interpf(wb, optimal, fac);
- CLAMP(dw->weight, 0.0, 1.0f);
- }
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- bGPdata *gpd = ob->data;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
-
- return OPERATOR_FINISHED;
+ const float fac = RNA_float_get(op->ptr, "factor");
+ const int repeat = RNA_int_get(op->ptr, "repeat");
+
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* sanity checks */
+ if (ELEM(NULL, ts, ob, ob->data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const int def_nr = ob->actdef - 1;
+ bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
+ if (defgroup == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+ if (defgroup->flag & DG_LOCK_WEIGHT) {
+ BKE_report(op->reports, RPT_ERROR, "Current Vertex Group is locked");
+ return OPERATOR_CANCELLED;
+ }
+
+ bGPDspoint *pta, *ptb, *ptc;
+ MDeformVert *dverta, *dvertb;
+
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if (gps->dvert == NULL) {
+ continue;
+ }
+
+ for (int s = 0; s < repeat; s++) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ /* previous point */
+ if (i > 0) {
+ pta = &gps->points[i - 1];
+ dverta = &gps->dvert[i - 1];
+ }
+ else {
+ pta = &gps->points[i];
+ dverta = &gps->dvert[i];
+ }
+ /* current */
+ ptb = &gps->points[i];
+ dvertb = &gps->dvert[i];
+ /* next point */
+ if (i + 1 < gps->totpoints) {
+ ptc = &gps->points[i + 1];
+ }
+ else {
+ ptc = &gps->points[i];
+ }
+
+ float wa = defvert_find_weight(dverta, def_nr);
+ float wb = defvert_find_weight(dvertb, def_nr);
+
+ /* the optimal value is the corresponding to the interpolation of the weight
+ * at the distance of point b
+ */
+ const float opfac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ const float optimal = interpf(wa, wb, opfac);
+ /* Based on influence factor, blend between original and optimal */
+ MDeformWeight *dw = defvert_verify_index(dvertb, def_nr);
+ if (dw) {
+ dw->weight = interpf(wb, optimal, fac);
+ CLAMP(dw->weight, 0.0, 1.0f);
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_vertex_group_smooth(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Smooth Vertex Group";
- ot->idname = "GPENCIL_OT_vertex_group_smooth";
- ot->description = "Smooth weights to the active vertex group";
+ /* identifiers */
+ ot->name = "Smooth Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_smooth";
+ ot->description = "Smooth weights to the active vertex group";
- /* api callbacks */
- ot->poll = gpencil_vertex_group_weight_poll;
- ot->exec = gpencil_vertex_group_smooth_exec;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_weight_poll;
+ ot->exec = gpencil_vertex_group_smooth_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f);
- RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
+ RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
}
/* normalize */
static int gpencil_vertex_group_normalize_exec(bContext *C, wmOperator *op)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- Object *ob = CTX_data_active_object(C);
-
- /* sanity checks */
- if (ELEM(NULL, ts, ob, ob->data)) {
- return OPERATOR_CANCELLED;
- }
-
- MDeformVert *dvert = NULL;
- MDeformWeight *dw = NULL;
- const int def_nr = ob->actdef - 1;
- bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
- if (defgroup == NULL) {
- return OPERATOR_CANCELLED;
- }
- if (defgroup->flag & DG_LOCK_WEIGHT) {
- BKE_report(op->reports, RPT_ERROR, "Current Vertex Group is locked");
- return OPERATOR_CANCELLED;
- }
-
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- /* look for max value */
- float maxvalue = 0.0f;
- for (int i = 0; i < gps->totpoints; i++) {
- dvert = &gps->dvert[i];
- dw = defvert_find_index(dvert, def_nr);
- if ((dw != NULL) && (dw->weight > maxvalue)) {
- maxvalue = dw->weight;
- }
- }
-
- /* normalize weights */
- if (maxvalue > 0.0f) {
- for (int i = 0; i < gps->totpoints; i++) {
- dvert = &gps->dvert[i];
- dw = defvert_find_index(dvert, def_nr);
- if (dw != NULL) {
- dw->weight = dw->weight / maxvalue;
- }
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- bGPdata *gpd = ob->data;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
-
- return OPERATOR_FINISHED;
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* sanity checks */
+ if (ELEM(NULL, ts, ob, ob->data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ MDeformVert *dvert = NULL;
+ MDeformWeight *dw = NULL;
+ const int def_nr = ob->actdef - 1;
+ bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
+ if (defgroup == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+ if (defgroup->flag & DG_LOCK_WEIGHT) {
+ BKE_report(op->reports, RPT_ERROR, "Current Vertex Group is locked");
+ return OPERATOR_CANCELLED;
+ }
+
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ /* look for max value */
+ float maxvalue = 0.0f;
+ for (int i = 0; i < gps->totpoints; i++) {
+ dvert = &gps->dvert[i];
+ dw = defvert_find_index(dvert, def_nr);
+ if ((dw != NULL) && (dw->weight > maxvalue)) {
+ maxvalue = dw->weight;
+ }
+ }
+
+ /* normalize weights */
+ if (maxvalue > 0.0f) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ dvert = &gps->dvert[i];
+ dw = defvert_find_index(dvert, def_nr);
+ if (dw != NULL) {
+ dw->weight = dw->weight / maxvalue;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_vertex_group_normalize(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Normalize Vertex Group";
- ot->idname = "GPENCIL_OT_vertex_group_normalize";
- ot->description = "Normalize weights to the active vertex group";
+ /* identifiers */
+ ot->name = "Normalize Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_normalize";
+ ot->description = "Normalize weights to the active vertex group";
- /* api callbacks */
- ot->poll = gpencil_vertex_group_weight_poll;
- ot->exec = gpencil_vertex_group_normalize_exec;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_weight_poll;
+ ot->exec = gpencil_vertex_group_normalize_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* normalize all */
static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- Object *ob = CTX_data_active_object(C);
- bool lock_active = RNA_boolean_get(op->ptr, "lock_active");
-
- /* sanity checks */
- if (ELEM(NULL, ts, ob, ob->data)) {
- return OPERATOR_CANCELLED;
- }
-
- bDeformGroup *defgroup = NULL;
- MDeformVert *dvert = NULL;
- MDeformWeight *dw = NULL;
- const int def_nr = ob->actdef - 1;
- const int defbase_tot = BLI_listbase_count(&ob->defbase);
- if (defbase_tot == 0) {
- return OPERATOR_CANCELLED;
- }
-
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- /* verify the strokes has something to change */
- if (gps->totpoints == 0) {
- continue;
- }
- /* look for tot value */
- float *tot_values = MEM_callocN(gps->totpoints * sizeof(float), __func__);
-
- for (int i = 0; i < gps->totpoints; i++) {
- dvert = &gps->dvert[i];
- for (int v = 0; v < defbase_tot; v++) {
- defgroup = BLI_findlink(&ob->defbase, v);
- /* skip NULL or locked groups */
- if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) {
- continue;
- }
-
- /* skip current */
- if ((lock_active) && (v == def_nr)) {
- continue;
- }
-
- dw = defvert_find_index(dvert, v);
- if (dw != NULL) {
- tot_values[i] += dw->weight;
- }
- }
- }
-
- /* normalize weights */
- for (int i = 0; i < gps->totpoints; i++) {
- if (tot_values[i] == 0.0f) {
- continue;
- }
-
- dvert = &gps->dvert[i];
- for (int v = 0; v < defbase_tot; v++) {
- defgroup = BLI_findlink(&ob->defbase, v);
- /* skip NULL or locked groups */
- if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) {
- continue;
- }
-
- /* skip current */
- if ((lock_active) && (v == def_nr)) {
- continue;
- }
-
- dw = defvert_find_index(dvert, v);
- if (dw != NULL) {
- dw->weight = dw->weight / tot_values[i];
- }
- }
- }
-
- /* free temp array */
- MEM_SAFE_FREE(tot_values);
- }
- CTX_DATA_END;
-
- /* notifiers */
- bGPdata *gpd = ob->data;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
-
- return OPERATOR_FINISHED;
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
+ bool lock_active = RNA_boolean_get(op->ptr, "lock_active");
+
+ /* sanity checks */
+ if (ELEM(NULL, ts, ob, ob->data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bDeformGroup *defgroup = NULL;
+ MDeformVert *dvert = NULL;
+ MDeformWeight *dw = NULL;
+ const int def_nr = ob->actdef - 1;
+ const int defbase_tot = BLI_listbase_count(&ob->defbase);
+ if (defbase_tot == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ /* verify the strokes has something to change */
+ if (gps->totpoints == 0) {
+ continue;
+ }
+ /* look for tot value */
+ float *tot_values = MEM_callocN(gps->totpoints * sizeof(float), __func__);
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ dvert = &gps->dvert[i];
+ for (int v = 0; v < defbase_tot; v++) {
+ defgroup = BLI_findlink(&ob->defbase, v);
+ /* skip NULL or locked groups */
+ if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) {
+ continue;
+ }
+
+ /* skip current */
+ if ((lock_active) && (v == def_nr)) {
+ continue;
+ }
+
+ dw = defvert_find_index(dvert, v);
+ if (dw != NULL) {
+ tot_values[i] += dw->weight;
+ }
+ }
+ }
+
+ /* normalize weights */
+ for (int i = 0; i < gps->totpoints; i++) {
+ if (tot_values[i] == 0.0f) {
+ continue;
+ }
+
+ dvert = &gps->dvert[i];
+ for (int v = 0; v < defbase_tot; v++) {
+ defgroup = BLI_findlink(&ob->defbase, v);
+ /* skip NULL or locked groups */
+ if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) {
+ continue;
+ }
+
+ /* skip current */
+ if ((lock_active) && (v == def_nr)) {
+ continue;
+ }
+
+ dw = defvert_find_index(dvert, v);
+ if (dw != NULL) {
+ dw->weight = dw->weight / tot_values[i];
+ }
+ }
+ }
+
+ /* free temp array */
+ MEM_SAFE_FREE(tot_values);
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_vertex_group_normalize_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Normalize All Vertex Group";
- ot->idname = "GPENCIL_OT_vertex_group_normalize_all";
- ot->description = "Normalize all weights of all vertex groups, "
- "so that for each vertex, the sum of all weights is 1.0";
+ /* identifiers */
+ ot->name = "Normalize All Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_normalize_all";
+ ot->description =
+ "Normalize all weights of all vertex groups, "
+ "so that for each vertex, the sum of all weights is 1.0";
- /* api callbacks */
- ot->poll = gpencil_vertex_group_weight_poll;
- ot->exec = gpencil_vertex_group_normalize_all_exec;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_weight_poll;
+ ot->exec = gpencil_vertex_group_normalize_all_exec;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- RNA_def_boolean(ot->srna, "lock_active", true, "Lock Active",
- "Keep the values of the active group while normalizing others");
+ /* props */
+ RNA_def_boolean(ot->srna,
+ "lock_active",
+ true,
+ "Lock Active",
+ "Keep the values of the active group while normalizing others");
}
/****************************** Join ***********************************/
/* userdata for joined_gpencil_fix_animdata_cb() */
typedef struct tJoinGPencil_AdtFixData {
- bGPdata *src_gpd;
- bGPdata *tar_gpd;
+ bGPdata *src_gpd;
+ bGPdata *tar_gpd;
- GHash *names_map;
+ GHash *names_map;
} tJoinGPencil_AdtFixData;
/* Callback to pass to BKE_fcurves_main_cb() for RNA Paths attached to each F-Curve used in the AnimData */
static void joined_gpencil_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
{
- tJoinGPencil_AdtFixData *afd = (tJoinGPencil_AdtFixData *)user_data;
- ID *src_id = &afd->src_gpd->id;
- ID *dst_id = &afd->tar_gpd->id;
-
- GHashIterator gh_iter;
-
- /* Fix paths - If this is the target datablock, it will have some "dirty" paths */
- if ((id == src_id) && fcu->rna_path && strstr(fcu->rna_path, "layers[")) {
- GHASH_ITER(gh_iter, afd->names_map) {
- const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
- const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
-
- /* only remap if changed;
- * this still means there will be some waste if there aren't many drivers/keys */
- if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) {
- fcu->rna_path = BKE_animsys_fix_rna_path_rename(
- id, fcu->rna_path, "layers",
- old_name, new_name, 0, 0, false);
-
- /* we don't want to apply a second remapping on this F-Curve now,
- * so stop trying to fix names names
- */
- break;
- }
- }
- }
-
- /* Fix driver targets */
- if (fcu->driver) {
- /* Fix driver references to invalid ID's */
- for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) {
- /* only change the used targets, since the others will need fixing manually anyway */
- DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
- {
- /* change the ID's used... */
- if (dtar->id == src_id) {
- dtar->id = dst_id;
-
- /* also check on the subtarget...
- * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own
- * little twists so that we know that it isn't going to clobber the wrong data
- */
- if (dtar->rna_path && strstr(dtar->rna_path, "layers[")) {
- GHASH_ITER(gh_iter, afd->names_map) {
- const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
- const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
-
- /* only remap if changed */
- if (!STREQ(old_name, new_name)) {
- if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) {
- /* Fix up path */
- dtar->rna_path = BKE_animsys_fix_rna_path_rename(
- id, dtar->rna_path, "layers",
- old_name, new_name, 0, 0, false);
- break; /* no need to try any more names for layer path */
- }
- }
- }
- }
- }
- }
- DRIVER_TARGETS_LOOPER_END;
- }
- }
+ tJoinGPencil_AdtFixData *afd = (tJoinGPencil_AdtFixData *)user_data;
+ ID *src_id = &afd->src_gpd->id;
+ ID *dst_id = &afd->tar_gpd->id;
+
+ GHashIterator gh_iter;
+
+ /* Fix paths - If this is the target datablock, it will have some "dirty" paths */
+ if ((id == src_id) && fcu->rna_path && strstr(fcu->rna_path, "layers[")) {
+ GHASH_ITER (gh_iter, afd->names_map) {
+ const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
+ const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* only remap if changed;
+ * this still means there will be some waste if there aren't many drivers/keys */
+ if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) {
+ fcu->rna_path = BKE_animsys_fix_rna_path_rename(
+ id, fcu->rna_path, "layers", old_name, new_name, 0, 0, false);
+
+ /* we don't want to apply a second remapping on this F-Curve now,
+ * so stop trying to fix names names
+ */
+ break;
+ }
+ }
+ }
+
+ /* Fix driver targets */
+ if (fcu->driver) {
+ /* Fix driver references to invalid ID's */
+ for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) {
+ /* only change the used targets, since the others will need fixing manually anyway */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ /* change the ID's used... */
+ if (dtar->id == src_id) {
+ dtar->id = dst_id;
+
+ /* also check on the subtarget...
+ * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own
+ * little twists so that we know that it isn't going to clobber the wrong data
+ */
+ if (dtar->rna_path && strstr(dtar->rna_path, "layers[")) {
+ GHASH_ITER (gh_iter, afd->names_map) {
+ const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
+ const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* only remap if changed */
+ if (!STREQ(old_name, new_name)) {
+ if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) {
+ /* Fix up path */
+ dtar->rna_path = BKE_animsys_fix_rna_path_rename(
+ id, dtar->rna_path, "layers", old_name, new_name, 0, 0, false);
+ break; /* no need to try any more names for layer path */
+ }
+ }
+ }
+ }
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
}
/* join objects called from OBJECT_OT_join */
int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *ob_active = CTX_data_active_object(C);
- bGPdata *gpd_dst = NULL;
- bool ok = false;
-
- /* Ensure we're in right mode and that the active object is correct */
- if (!ob_active || ob_active->type != OB_GPENCIL)
- return OPERATOR_CANCELLED;
-
- bGPdata *gpd = (bGPdata *)ob_active->data;
- if ((!gpd) || GPENCIL_ANY_MODE(gpd)) {
- return OPERATOR_CANCELLED;
- }
-
- /* Ensure all rotations are applied before */
- // XXX: Why don't we apply them here instead of warning?
- CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
- {
- if (ob_iter->type == OB_GPENCIL) {
- if ((ob_iter->rot[0] != 0) ||
- (ob_iter->rot[1] != 0) ||
- (ob_iter->rot[2] != 0))
- {
- BKE_report(op->reports, RPT_ERROR, "Apply all rotations before join objects");
- return OPERATOR_CANCELLED;
- }
- }
- }
- CTX_DATA_END;
-
- CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
- {
- if (ob_iter == ob_active) {
- ok = true;
- break;
- }
- }
- CTX_DATA_END;
-
- /* that way the active object is always selected */
- if (ok == false) {
- BKE_report(op->reports, RPT_WARNING, "Active object is not a selected grease pencil");
- return OPERATOR_CANCELLED;
- }
-
- gpd_dst = ob_active->data;
- Object *ob_dst = ob_active;
-
- /* loop and join all data */
- CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
- {
- if ((ob_iter->type == OB_GPENCIL) && (ob_iter != ob_active)) {
- /* we assume that each datablock is not already used in active object */
- if (ob_active->data != ob_iter->data) {
- Object *ob_src = ob_iter;
- bGPdata *gpd_src = ob_iter->data;
-
- /* Apply all GP modifiers before */
- for (GpencilModifierData *md = ob_iter->greasepencil_modifiers.first; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
- if (mti->bakeModifier) {
- mti->bakeModifier(bmain, depsgraph, md, ob_iter);
- }
- }
-
- /* copy vertex groups to the base one's */
- int old_idx = 0;
- for (bDeformGroup *dg = ob_iter->defbase.first; dg; dg = dg->next) {
- bDeformGroup *vgroup = MEM_dupallocN(dg);
- int idx = BLI_listbase_count(&ob_active->defbase);
- defgroup_unique_name(vgroup, ob_active);
- BLI_addtail(&ob_active->defbase, vgroup);
- /* update vertex groups in strokes in original data */
- for (bGPDlayer *gpl_src = gpd->layers.first; gpl_src; gpl_src = gpl_src->next) {
- for (bGPDframe *gpf = gpl_src->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- MDeformVert *dvert;
- int i;
- for (i = 0, dvert = gps->dvert; i < gps->totpoints; i++, dvert++) {
- if ((dvert->dw) && (dvert->dw->def_nr == old_idx)) {
- dvert->dw->def_nr = idx;
- }
- }
- }
- }
- }
- old_idx++;
- }
- if (ob_active->defbase.first && ob_active->actdef == 0) {
- ob_active->actdef = 1;
- }
-
- /* add missing materials reading source materials and checking in destination object */
- short *totcol = give_totcolp(ob_src);
-
- for (short i = 0; i < *totcol; i++) {
- Material *tmp_ma = give_current_material(ob_src, i + 1);
- BKE_gpencil_object_material_ensure(bmain, ob_dst, tmp_ma);
- }
-
- /* duplicate bGPDlayers */
- tJoinGPencil_AdtFixData afd = {0};
- afd.src_gpd = gpd_src;
- afd.tar_gpd = gpd_dst;
- afd.names_map = BLI_ghash_str_new("joined_gp_layers_map");
-
- float imat[3][3], bmat[3][3];
- float offset_global[3];
- float offset_local[3];
-
- sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->obmat[3]);
- copy_m3_m4(bmat, ob_active->obmat);
- invert_m3_m3(imat, bmat);
- mul_m3_v3(imat, offset_global);
- mul_v3_m3v3(offset_local, imat, offset_global);
-
-
- for (bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
- bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src);
- float diff_mat[4][4];
- float inverse_diff_mat[4][4];
-
- /* recalculate all stroke points */
- ED_gpencil_parent_location(depsgraph, ob_iter, gpd_src, gpl_src, diff_mat);
- invert_m4_m4(inverse_diff_mat, diff_mat);
-
- Material *ma_src = NULL;
- for (bGPDframe *gpf = gpl_new->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
-
- /* reasign material. Look old material and try to find in dst */
- ma_src = give_current_material(ob_src, gps->mat_nr + 1);
- gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
-
- bGPDspoint *pt;
- int i;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- float mpt[3];
- mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
- sub_v3_v3(mpt, offset_local);
- mul_v3_m4v3(&pt->x, diff_mat, mpt);
- }
- }
- }
-
- /* be sure name is unique in new object */
- BLI_uniquename(&gpd_dst->layers, gpl_new, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl_new->info));
- BLI_ghash_insert(afd.names_map, BLI_strdup(gpl_src->info), gpl_new->info);
-
- /* add to destination datablock */
- BLI_addtail(&gpd_dst->layers, gpl_new);
- }
-
- /* Fix all the animation data */
- BKE_fcurves_main_cb(bmain, joined_gpencil_fix_animdata_cb, &afd);
- BLI_ghash_free(afd.names_map, MEM_freeN, NULL);
-
- /* Only copy over animdata now, after all the remapping has been done,
- * so that we don't have to worry about ambiguities re which datablock
- * a layer came from!
- */
- if (ob_iter->adt) {
- if (ob_active->adt == NULL) {
- /* no animdata, so just use a copy of the whole thing */
- ob_active->adt = BKE_animdata_copy(bmain, ob_iter->adt, 0);
- }
- else {
- /* merge in data - we'll fix the drivers manually */
- BKE_animdata_merge_copy(bmain, &ob_active->id, &ob_iter->id, ADT_MERGECOPY_KEEP_DST, false);
- }
- }
-
- if (gpd_src->adt) {
- if (gpd_dst->adt == NULL) {
- /* no animdata, so just use a copy of the whole thing */
- gpd_dst->adt = BKE_animdata_copy(bmain, gpd_src->adt, 0);
- }
- else {
- /* merge in data - we'll fix the drivers manually */
- BKE_animdata_merge_copy(bmain, &gpd_dst->id, &gpd_src->id, ADT_MERGECOPY_KEEP_DST, false);
- }
- }
- DEG_id_tag_update(&gpd_src->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
- }
-
- /* Free the old object */
- ED_object_base_free_and_unlink(bmain, scene, ob_iter);
- }
- }
- CTX_DATA_END;
-
- DEG_id_tag_update(&gpd_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
- DEG_relations_tag_update(bmain); /* because we removed object(s) */
-
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
-
- return OPERATOR_FINISHED;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob_active = CTX_data_active_object(C);
+ bGPdata *gpd_dst = NULL;
+ bool ok = false;
+
+ /* Ensure we're in right mode and that the active object is correct */
+ if (!ob_active || ob_active->type != OB_GPENCIL)
+ return OPERATOR_CANCELLED;
+
+ bGPdata *gpd = (bGPdata *)ob_active->data;
+ if ((!gpd) || GPENCIL_ANY_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Ensure all rotations are applied before */
+ // XXX: Why don't we apply them here instead of warning?
+ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
+ if (ob_iter->type == OB_GPENCIL) {
+ if ((ob_iter->rot[0] != 0) || (ob_iter->rot[1] != 0) || (ob_iter->rot[2] != 0)) {
+ BKE_report(op->reports, RPT_ERROR, "Apply all rotations before join objects");
+ return OPERATOR_CANCELLED;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
+ if (ob_iter == ob_active) {
+ ok = true;
+ break;
+ }
+ }
+ CTX_DATA_END;
+
+ /* that way the active object is always selected */
+ if (ok == false) {
+ BKE_report(op->reports, RPT_WARNING, "Active object is not a selected grease pencil");
+ return OPERATOR_CANCELLED;
+ }
+
+ gpd_dst = ob_active->data;
+ Object *ob_dst = ob_active;
+
+ /* loop and join all data */
+ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
+ if ((ob_iter->type == OB_GPENCIL) && (ob_iter != ob_active)) {
+ /* we assume that each datablock is not already used in active object */
+ if (ob_active->data != ob_iter->data) {
+ Object *ob_src = ob_iter;
+ bGPdata *gpd_src = ob_iter->data;
+
+ /* Apply all GP modifiers before */
+ for (GpencilModifierData *md = ob_iter->greasepencil_modifiers.first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ if (mti->bakeModifier) {
+ mti->bakeModifier(bmain, depsgraph, md, ob_iter);
+ }
+ }
+
+ /* copy vertex groups to the base one's */
+ int old_idx = 0;
+ for (bDeformGroup *dg = ob_iter->defbase.first; dg; dg = dg->next) {
+ bDeformGroup *vgroup = MEM_dupallocN(dg);
+ int idx = BLI_listbase_count(&ob_active->defbase);
+ defgroup_unique_name(vgroup, ob_active);
+ BLI_addtail(&ob_active->defbase, vgroup);
+ /* update vertex groups in strokes in original data */
+ for (bGPDlayer *gpl_src = gpd->layers.first; gpl_src; gpl_src = gpl_src->next) {
+ for (bGPDframe *gpf = gpl_src->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ MDeformVert *dvert;
+ int i;
+ for (i = 0, dvert = gps->dvert; i < gps->totpoints; i++, dvert++) {
+ if ((dvert->dw) && (dvert->dw->def_nr == old_idx)) {
+ dvert->dw->def_nr = idx;
+ }
+ }
+ }
+ }
+ }
+ old_idx++;
+ }
+ if (ob_active->defbase.first && ob_active->actdef == 0) {
+ ob_active->actdef = 1;
+ }
+
+ /* add missing materials reading source materials and checking in destination object */
+ short *totcol = give_totcolp(ob_src);
+
+ for (short i = 0; i < *totcol; i++) {
+ Material *tmp_ma = give_current_material(ob_src, i + 1);
+ BKE_gpencil_object_material_ensure(bmain, ob_dst, tmp_ma);
+ }
+
+ /* duplicate bGPDlayers */
+ tJoinGPencil_AdtFixData afd = {0};
+ afd.src_gpd = gpd_src;
+ afd.tar_gpd = gpd_dst;
+ afd.names_map = BLI_ghash_str_new("joined_gp_layers_map");
+
+ float imat[3][3], bmat[3][3];
+ float offset_global[3];
+ float offset_local[3];
+
+ sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->obmat[3]);
+ copy_m3_m4(bmat, ob_active->obmat);
+ invert_m3_m3(imat, bmat);
+ mul_m3_v3(imat, offset_global);
+ mul_v3_m3v3(offset_local, imat, offset_global);
+
+ for (bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
+ bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src);
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+
+ /* recalculate all stroke points */
+ ED_gpencil_parent_location(depsgraph, ob_iter, gpd_src, gpl_src, diff_mat);
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+
+ Material *ma_src = NULL;
+ for (bGPDframe *gpf = gpl_new->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ /* reasign material. Look old material and try to find in dst */
+ ma_src = give_current_material(ob_src, gps->mat_nr + 1);
+ gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
+
+ bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float mpt[3];
+ mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
+ sub_v3_v3(mpt, offset_local);
+ mul_v3_m4v3(&pt->x, diff_mat, mpt);
+ }
+ }
+ }
+
+ /* be sure name is unique in new object */
+ BLI_uniquename(&gpd_dst->layers,
+ gpl_new,
+ DATA_("GP_Layer"),
+ '.',
+ offsetof(bGPDlayer, info),
+ sizeof(gpl_new->info));
+ BLI_ghash_insert(afd.names_map, BLI_strdup(gpl_src->info), gpl_new->info);
+
+ /* add to destination datablock */
+ BLI_addtail(&gpd_dst->layers, gpl_new);
+ }
+
+ /* Fix all the animation data */
+ BKE_fcurves_main_cb(bmain, joined_gpencil_fix_animdata_cb, &afd);
+ BLI_ghash_free(afd.names_map, MEM_freeN, NULL);
+
+ /* Only copy over animdata now, after all the remapping has been done,
+ * so that we don't have to worry about ambiguities re which datablock
+ * a layer came from!
+ */
+ if (ob_iter->adt) {
+ if (ob_active->adt == NULL) {
+ /* no animdata, so just use a copy of the whole thing */
+ ob_active->adt = BKE_animdata_copy(bmain, ob_iter->adt, 0);
+ }
+ else {
+ /* merge in data - we'll fix the drivers manually */
+ BKE_animdata_merge_copy(
+ bmain, &ob_active->id, &ob_iter->id, ADT_MERGECOPY_KEEP_DST, false);
+ }
+ }
+
+ if (gpd_src->adt) {
+ if (gpd_dst->adt == NULL) {
+ /* no animdata, so just use a copy of the whole thing */
+ gpd_dst->adt = BKE_animdata_copy(bmain, gpd_src->adt, 0);
+ }
+ else {
+ /* merge in data - we'll fix the drivers manually */
+ BKE_animdata_merge_copy(
+ bmain, &gpd_dst->id, &gpd_src->id, ADT_MERGECOPY_KEEP_DST, false);
+ }
+ }
+ DEG_id_tag_update(&gpd_src->id,
+ ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ }
+
+ /* Free the old object */
+ ED_object_base_free_and_unlink(bmain, scene, ob_iter);
+ }
+ }
+ CTX_DATA_END;
+
+ DEG_id_tag_update(&gpd_dst->id,
+ ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain); /* because we removed object(s) */
+
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+
+ return OPERATOR_FINISHED;
}
/* Color Handle operator */
static bool gpencil_active_color_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
- if (ob && ob->data && (ob->type == OB_GPENCIL)) {
- short *totcolp = give_totcolp(ob);
- return *totcolp > 0;
- }
- return false;
+ Object *ob = CTX_data_active_object(C);
+ if (ob && ob->data && (ob->type == OB_GPENCIL)) {
+ short *totcolp = give_totcolp(ob);
+ return *totcolp > 0;
+ }
+ return false;
}
-
/* ******************* Lock and hide any color non used in current layer ************************** */
static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- Object *ob = CTX_data_active_object(C);
- MaterialGPencilStyle *gp_style = NULL;
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- /* first lock and hide all colors */
- Material *ma = NULL;
- short *totcol = give_totcolp(ob);
- if (totcol == 0)
- return OPERATOR_CANCELLED;
-
- for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
- gp_style = ma->gp_style;
- gp_style->flag |= GP_STYLE_COLOR_LOCKED;
- gp_style->flag |= GP_STYLE_COLOR_HIDE;
- DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
- }
-
- /* loop all selected strokes and unlock any color used in active layer */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL) && (gpl->flag & GP_LAYER_ACTIVE)) {
- for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- ma = give_current_material(ob, gps->mat_nr + 1);
- DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
-
- gp_style = ma->gp_style;
- /* unlock/unhide color if not unlocked before */
- if (gp_style != NULL) {
- gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
- gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
- }
- }
- }
- }
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+ MaterialGPencilStyle *gp_style = NULL;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* first lock and hide all colors */
+ Material *ma = NULL;
+ short *totcol = give_totcolp(ob);
+ if (totcol == 0)
+ return OPERATOR_CANCELLED;
+
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ gp_style = ma->gp_style;
+ gp_style->flag |= GP_STYLE_COLOR_LOCKED;
+ gp_style->flag |= GP_STYLE_COLOR_HIDE;
+ DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
+ }
+
+ /* loop all selected strokes and unlock any color used in active layer */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL) &&
+ (gpl->flag & GP_LAYER_ACTIVE)) {
+ for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ ma = give_current_material(ob, gps->mat_nr + 1);
+ DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
+
+ gp_style = ma->gp_style;
+ /* unlock/unhide color if not unlocked before */
+ if (gp_style != NULL) {
+ gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
+ gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
+ }
+ }
+ }
+ }
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_lock_layer(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Disable Unused Layer Colors";
- ot->idname = "GPENCIL_OT_lock_layer";
- ot->description = "Lock and hide any color not used in any layer";
+ /* identifiers */
+ ot->name = "Disable Unused Layer Colors";
+ ot->idname = "GPENCIL_OT_lock_layer";
+ ot->description = "Lock and hide any color not used in any layer";
- /* api callbacks */
- ot->exec = gpencil_lock_layer_exec;
- ot->poll = gp_active_layer_poll;
+ /* api callbacks */
+ ot->exec = gpencil_lock_layer_exec;
+ ot->poll = gp_active_layer_poll;
}
/* ********************** Isolate gpencil_ color **************************** */
static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- Object *ob = CTX_data_active_object(C);
- Material *active_ma = give_current_material(ob, ob->actcol);
- MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
- MaterialGPencilStyle *gp_style;
-
- int flags = GP_STYLE_COLOR_LOCKED;
- bool isolate = false;
-
- if (RNA_boolean_get(op->ptr, "affect_visibility"))
- flags |= GP_STYLE_COLOR_HIDE;
-
- if (ELEM(NULL, gpd, active_color)) {
- BKE_report(op->reports, RPT_ERROR, "No active color to isolate");
- return OPERATOR_CANCELLED;
- }
-
- /* Test whether to isolate or clear all flags */
- Material *ma = NULL;
- short *totcol = give_totcolp(ob);
- for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
- /* Skip if this is the active one */
- if (ma == active_ma)
- continue;
-
- /* If the flags aren't set, that means that the color is
- * not alone, so we have some colors to isolate still
- */
- gp_style = ma->gp_style;
- if ((gp_style->flag & flags) == 0) {
- isolate = true;
- break;
- }
- }
-
- /* Set/Clear flags as appropriate */
- if (isolate) {
- /* Set flags on all "other" colors */
- for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
- gp_style = ma->gp_style;
- if (gp_style == active_color)
- continue;
- else
- gp_style->flag |= flags;
- DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
- else {
- /* Clear flags - Restore everything else */
- for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
- gp_style = ma->gp_style;
- gp_style->flag &= ~flags;
- DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+ Material *active_ma = give_current_material(ob, ob->actcol);
+ MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
+ MaterialGPencilStyle *gp_style;
+
+ int flags = GP_STYLE_COLOR_LOCKED;
+ bool isolate = false;
+
+ if (RNA_boolean_get(op->ptr, "affect_visibility"))
+ flags |= GP_STYLE_COLOR_HIDE;
+
+ if (ELEM(NULL, gpd, active_color)) {
+ BKE_report(op->reports, RPT_ERROR, "No active color to isolate");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Test whether to isolate or clear all flags */
+ Material *ma = NULL;
+ short *totcol = give_totcolp(ob);
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ /* Skip if this is the active one */
+ if (ma == active_ma)
+ continue;
+
+ /* If the flags aren't set, that means that the color is
+ * not alone, so we have some colors to isolate still
+ */
+ gp_style = ma->gp_style;
+ if ((gp_style->flag & flags) == 0) {
+ isolate = true;
+ break;
+ }
+ }
+
+ /* Set/Clear flags as appropriate */
+ if (isolate) {
+ /* Set flags on all "other" colors */
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ gp_style = ma->gp_style;
+ if (gp_style == active_color)
+ continue;
+ else
+ gp_style->flag |= flags;
+ DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ else {
+ /* Clear flags - Restore everything else */
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ gp_style = ma->gp_style;
+ gp_style->flag &= ~flags;
+ DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_color_isolate(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Isolate Color";
- ot->idname = "GPENCIL_OT_color_isolate";
- ot->description = "Toggle whether the active color is the only one that is editable and/or visible";
+ /* identifiers */
+ ot->name = "Isolate Color";
+ ot->idname = "GPENCIL_OT_color_isolate";
+ ot->description =
+ "Toggle whether the active color is the only one that is editable and/or visible";
- /* callbacks */
- ot->exec = gpencil_color_isolate_exec;
- ot->poll = gpencil_active_color_poll;
+ /* callbacks */
+ ot->exec = gpencil_color_isolate_exec;
+ ot->poll = gpencil_active_color_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility", "In addition to toggling "
- "the editability, also affect the visibility");
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "affect_visibility",
+ false,
+ "Affect Visibility",
+ "In addition to toggling "
+ "the editability, also affect the visibility");
}
/* *********************** Hide colors ******************************** */
static int gpencil_color_hide_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = (bGPdata *)ob->data;
- MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
- bool unselected = RNA_boolean_get(op->ptr, "unselected");
+ bool unselected = RNA_boolean_get(op->ptr, "unselected");
- Material *ma = NULL;
- short *totcol = give_totcolp(ob);
- if (totcol == 0)
- return OPERATOR_CANCELLED;
+ Material *ma = NULL;
+ short *totcol = give_totcolp(ob);
+ if (totcol == 0)
+ return OPERATOR_CANCELLED;
- if (unselected) {
- /* hide unselected */
- MaterialGPencilStyle *color = NULL;
- for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
- color = ma->gp_style;
- if (active_color != color) {
- color->flag |= GP_STYLE_COLOR_HIDE;
- DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
- }
- else {
- /* hide selected/active */
- active_color->flag |= GP_STYLE_COLOR_HIDE;
- }
+ if (unselected) {
+ /* hide unselected */
+ MaterialGPencilStyle *color = NULL;
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ color = ma->gp_style;
+ if (active_color != color) {
+ color->flag |= GP_STYLE_COLOR_HIDE;
+ DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ }
+ else {
+ /* hide selected/active */
+ active_color->flag |= GP_STYLE_COLOR_HIDE;
+ }
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_color_hide(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Hide Color(s)";
- ot->idname = "GPENCIL_OT_color_hide";
- ot->description = "Hide selected/unselected Grease Pencil colors";
+ /* identifiers */
+ ot->name = "Hide Color(s)";
+ ot->idname = "GPENCIL_OT_color_hide";
+ ot->description = "Hide selected/unselected Grease Pencil colors";
- /* callbacks */
- ot->exec = gpencil_color_hide_exec;
- ot->poll = gpencil_active_color_poll; /* NOTE: we need an active color to play with */
+ /* callbacks */
+ ot->exec = gpencil_color_hide_exec;
+ ot->poll = gpencil_active_color_poll; /* NOTE: we need an active color to play with */
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected colors");
+ /* props */
+ RNA_def_boolean(
+ ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected colors");
}
/* ********************** Show All Colors ***************************** */
static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = (bGPdata *)ob->data;
- Material *ma = NULL;
- short *totcol = give_totcolp(ob);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ Material *ma = NULL;
+ short *totcol = give_totcolp(ob);
- if (totcol == 0)
- return OPERATOR_CANCELLED;
+ if (totcol == 0)
+ return OPERATOR_CANCELLED;
- /* make all colors visible */
- MaterialGPencilStyle *gp_style = NULL;
+ /* make all colors visible */
+ MaterialGPencilStyle *gp_style = NULL;
- for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
- gp_style = ma->gp_style;
- gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
- DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
- }
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ gp_style = ma->gp_style;
+ gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
+ DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
+ }
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_color_reveal(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Show All Colors";
- ot->idname = "GPENCIL_OT_color_reveal";
- ot->description = "Unhide all hidden Grease Pencil colors";
+ /* identifiers */
+ ot->name = "Show All Colors";
+ ot->idname = "GPENCIL_OT_color_reveal";
+ ot->description = "Unhide all hidden Grease Pencil colors";
- /* callbacks */
- ot->exec = gpencil_color_reveal_exec;
- ot->poll = gpencil_active_color_poll;
+ /* callbacks */
+ ot->exec = gpencil_color_reveal_exec;
+ ot->poll = gpencil_active_color_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ***************** Lock/Unlock All colors ************************ */
@@ -2643,189 +2661,187 @@ void GPENCIL_OT_color_reveal(wmOperatorType *ot)
static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = (bGPdata *)ob->data;
- Material *ma = NULL;
- short *totcol = give_totcolp(ob);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ Material *ma = NULL;
+ short *totcol = give_totcolp(ob);
- if (totcol == 0)
- return OPERATOR_CANCELLED;
+ if (totcol == 0)
+ return OPERATOR_CANCELLED;
- /* make all layers non-editable */
- MaterialGPencilStyle *gp_style = NULL;
+ /* make all layers non-editable */
+ MaterialGPencilStyle *gp_style = NULL;
- for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
- gp_style = ma->gp_style;
- gp_style->flag |= GP_STYLE_COLOR_LOCKED;
- DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
- }
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ gp_style = ma->gp_style;
+ gp_style->flag |= GP_STYLE_COLOR_LOCKED;
+ DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
+ }
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_color_lock_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Lock All Colors";
- ot->idname = "GPENCIL_OT_color_lock_all";
- ot->description = "Lock all Grease Pencil colors to prevent them from being accidentally modified";
+ /* identifiers */
+ ot->name = "Lock All Colors";
+ ot->idname = "GPENCIL_OT_color_lock_all";
+ ot->description =
+ "Lock all Grease Pencil colors to prevent them from being accidentally modified";
- /* callbacks */
- ot->exec = gpencil_color_lock_all_exec;
- ot->poll = gpencil_active_color_poll;
+ /* callbacks */
+ ot->exec = gpencil_color_lock_all_exec;
+ ot->poll = gpencil_active_color_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* -------------------------- */
static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = (bGPdata *)ob->data;
- Material *ma = NULL;
- short *totcol = give_totcolp(ob);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ Material *ma = NULL;
+ short *totcol = give_totcolp(ob);
- if (totcol == 0)
- return OPERATOR_CANCELLED;
+ if (totcol == 0)
+ return OPERATOR_CANCELLED;
- /* make all layers editable again*/
- MaterialGPencilStyle *gp_style = NULL;
+ /* make all layers editable again*/
+ MaterialGPencilStyle *gp_style = NULL;
- for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
- gp_style = ma->gp_style;
- gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
- DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
- }
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ gp_style = ma->gp_style;
+ gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
+ DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
+ }
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_color_unlock_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Unlock All Colors";
- ot->idname = "GPENCIL_OT_color_unlock_all";
- ot->description = "Unlock all Grease Pencil colors so that they can be edited";
+ /* identifiers */
+ ot->name = "Unlock All Colors";
+ ot->idname = "GPENCIL_OT_color_unlock_all";
+ ot->description = "Unlock all Grease Pencil colors so that they can be edited";
- /* callbacks */
- ot->exec = gpencil_color_unlock_all_exec;
- ot->poll = gpencil_active_color_poll;
+ /* callbacks */
+ ot->exec = gpencil_color_unlock_all_exec;
+ ot->poll = gpencil_active_color_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
/* ***************** Select all strokes using color ************************ */
static int gpencil_color_select_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- Object *ob = CTX_data_active_object(C);
- MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const bool deselected = RNA_boolean_get(op->ptr, "deselect");
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gp_style))
- return OPERATOR_CANCELLED;
-
- /* read all strokes and select*/
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
-
- /* verify something to do */
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
- continue;
-
- /* select */
- if (ob->actcol == gps->mat_nr + 1) {
- bGPDspoint *pt;
- int i;
-
- if (!deselected) {
- gps->flag |= GP_STROKE_SELECT;
- }
- else {
- gps->flag &= ~GP_STROKE_SELECT;
- }
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (!deselected) {
- pt->flag |= GP_SPOINT_SELECT;
- }
- else {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
- }
- }
- }
- }
- /* if not multiedit, exit loop*/
- if (!is_multiedit) {
- break;
- }
-
- }
- }
- CTX_DATA_END;
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool deselected = RNA_boolean_get(op->ptr, "deselect");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gp_style))
+ return OPERATOR_CANCELLED;
+
+ /* read all strokes and select*/
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+
+ /* verify something to do */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
+ continue;
+
+ /* select */
+ if (ob->actcol == gps->mat_nr + 1) {
+ bGPDspoint *pt;
+ int i;
+
+ if (!deselected) {
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ else {
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (!deselected) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+ }
+ }
+ }
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_color_select(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Color";
- ot->idname = "GPENCIL_OT_color_select";
- ot->description = "Select all Grease Pencil strokes using current color";
+ /* identifiers */
+ ot->name = "Select Color";
+ ot->idname = "GPENCIL_OT_color_select";
+ ot->description = "Select all Grease Pencil strokes using current color";
- /* callbacks */
- ot->exec = gpencil_color_select_exec;
- ot->poll = gpencil_active_color_poll;
+ /* callbacks */
+ ot->exec = gpencil_color_select_exec;
+ ot->poll = gpencil_active_color_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- ot->prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Unselect strokes");
- RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ /* props */
+ ot->prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Unselect strokes");
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index e1eaedd435c..40e1e483f41 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -86,452 +86,455 @@
#include "gpencil_intern.h"
- /* ************************************************ */
- /* Stroke Edit Mode Management */
+/* ************************************************ */
+/* Stroke Edit Mode Management */
/* poll callback for all stroke editing operators */
static bool gp_stroke_edit_poll(bContext *C)
{
- /* edit only supported with grease pencil objects */
- Object *ob = CTX_data_active_object(C);
- if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
- return false;
- }
-
- /* NOTE: this is a bit slower, but is the most accurate... */
- return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
+ /* edit only supported with grease pencil objects */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ /* NOTE: this is a bit slower, but is the most accurate... */
+ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
}
/* poll callback to verify edit mode in 3D view only */
static bool gp_strokes_edit3d_poll(bContext *C)
{
- /* edit only supported with grease pencil objects */
- Object *ob = CTX_data_active_object(C);
- if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
- return false;
- }
-
-
- /* 2 Requirements:
- * - 1) Editable GP data
- * - 2) 3D View only
- */
- return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C));
+ /* edit only supported with grease pencil objects */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ /* 2 Requirements:
+ * - 1) Editable GP data
+ * - 2) 3D View only
+ */
+ return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C));
}
static bool gpencil_editmode_toggle_poll(bContext *C)
{
- /* edit only supported with grease pencil objects */
- Object *ob = CTX_data_active_object(C);
- if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
- return false;
- }
-
- /* if using gpencil object, use this gpd */
- if (ob->type == OB_GPENCIL) {
- return ob->data != NULL;
- }
-
- return ED_gpencil_data_get_active(C) != NULL;
+ /* edit only supported with grease pencil objects */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ /* if using gpencil object, use this gpd */
+ if (ob->type == OB_GPENCIL) {
+ return ob->data != NULL;
+ }
+
+ return ED_gpencil_data_get_active(C) != NULL;
}
static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *op)
{
- const int back = RNA_boolean_get(op->ptr, "back");
-
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bool is_object = false;
- short mode;
- /* if using a gpencil object, use this datablock */
- Object *ob = CTX_data_active_object(C);
- if ((ob) && (ob->type == OB_GPENCIL)) {
- gpd = ob->data;
- is_object = true;
- }
-
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active GP data");
- return OPERATOR_CANCELLED;
- }
-
- /* Just toggle editmode flag... */
- gpd->flag ^= GP_DATA_STROKE_EDITMODE;
- /* recalculate parent matrix */
- if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
- ED_gpencil_reset_layers_parent(depsgraph, ob, gpd);
- }
- /* set mode */
- if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
- mode = OB_MODE_EDIT_GPENCIL;
- }
- else {
- mode = OB_MODE_OBJECT;
- }
-
- if (is_object) {
- /* try to back previous mode */
- if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_EDITMODE) == 0) && (back == 1)) {
- mode = ob->restore_mode;
- }
- ob->restore_mode = ob->mode;
- ob->mode = mode;
- }
-
- /* setup other modes */
- ED_gpencil_setup_modes(C, gpd, mode);
- /* set cache as dirty */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
- WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
-
- if (is_object) {
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
- }
- if (G.background == false) {
- WM_toolsystem_update_from_context_view3d(C);
- }
-
- return OPERATOR_FINISHED;
+ const int back = RNA_boolean_get(op->ptr, "back");
+
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bool is_object = false;
+ short mode;
+ /* if using a gpencil object, use this datablock */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ gpd = ob->data;
+ is_object = true;
+ }
+
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active GP data");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Just toggle editmode flag... */
+ gpd->flag ^= GP_DATA_STROKE_EDITMODE;
+ /* recalculate parent matrix */
+ if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ ED_gpencil_reset_layers_parent(depsgraph, ob, gpd);
+ }
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ mode = OB_MODE_EDIT_GPENCIL;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
+ }
+
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_EDITMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
+ }
+
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ if (is_object) {
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+ }
+ if (G.background == false) {
+ WM_toolsystem_update_from_context_view3d(C);
+ }
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_editmode_toggle(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ PropertyRNA *prop;
- /* identifiers */
- ot->name = "Strokes Edit Mode Toggle";
- ot->idname = "GPENCIL_OT_editmode_toggle";
- ot->description = "Enter/Exit edit mode for Grease Pencil strokes";
+ /* identifiers */
+ ot->name = "Strokes Edit Mode Toggle";
+ ot->idname = "GPENCIL_OT_editmode_toggle";
+ ot->description = "Enter/Exit edit mode for Grease Pencil strokes";
- /* callbacks */
- ot->exec = gpencil_editmode_toggle_exec;
- ot->poll = gpencil_editmode_toggle_poll;
+ /* callbacks */
+ ot->exec = gpencil_editmode_toggle_exec;
+ ot->poll = gpencil_editmode_toggle_poll;
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
- /* properties */
- prop = RNA_def_boolean(ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ /* properties */
+ prop = RNA_def_boolean(
+ ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/* set select mode */
static int gpencil_selectmode_toggle_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- const int mode = RNA_int_get(op->ptr, "mode");
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ const int mode = RNA_int_get(op->ptr, "mode");
- /* Just set mode */
- ts->gpencil_selectmode = mode;
+ /* Just set mode */
+ ts->gpencil_selectmode = mode;
- WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
- DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_selectmode_toggle(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ PropertyRNA *prop;
- /* identifiers */
- ot->name = "Select Mode Toggle";
- ot->idname = "GPENCIL_OT_selectmode_toggle";
- ot->description = "Set selection mode for Grease Pencil strokes";
+ /* identifiers */
+ ot->name = "Select Mode Toggle";
+ ot->idname = "GPENCIL_OT_selectmode_toggle";
+ ot->description = "Set selection mode for Grease Pencil strokes";
- /* callbacks */
- ot->exec = gpencil_selectmode_toggle_exec;
- ot->poll = gp_strokes_edit3d_poll;
+ /* callbacks */
+ ot->exec = gpencil_selectmode_toggle_exec;
+ ot->poll = gp_strokes_edit3d_poll;
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
- /* properties */
- prop = RNA_def_int(ot->srna, "mode", 0, 0, 2, "Select mode", "Select mode", 0, 2);
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ /* properties */
+ prop = RNA_def_int(ot->srna, "mode", 0, 0, 2, "Select mode", "Select mode", 0, 2);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/* Stroke Paint Mode Management */
static bool gpencil_paintmode_toggle_poll(bContext *C)
{
- /* if using gpencil object, use this gpd */
- Object *ob = CTX_data_active_object(C);
- if ((ob) && (ob->type == OB_GPENCIL)) {
- return ob->data != NULL;
- }
- return ED_gpencil_data_get_active(C) != NULL;
+ /* if using gpencil object, use this gpd */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return ob->data != NULL;
+ }
+ return ED_gpencil_data_get_active(C) != NULL;
}
static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op)
{
- const bool back = RNA_boolean_get(op->ptr, "back");
-
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Main *bmain = CTX_data_main(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- bool is_object = false;
- short mode;
- /* if using a gpencil object, use this datablock */
- Object *ob = CTX_data_active_object(C);
- if ((ob) && (ob->type == OB_GPENCIL)) {
- gpd = ob->data;
- is_object = true;
- }
-
- if (gpd == NULL)
- return OPERATOR_CANCELLED;
-
- /* Just toggle paintmode flag... */
- gpd->flag ^= GP_DATA_STROKE_PAINTMODE;
- /* set mode */
- if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
- mode = OB_MODE_PAINT_GPENCIL;
- }
- else {
- mode = OB_MODE_OBJECT;
- }
-
- if (is_object) {
- /* try to back previous mode */
- if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0) && (back == 1)) {
- mode = ob->restore_mode;
- }
- ob->restore_mode = ob->mode;
- ob->mode = mode;
- }
-
- if (mode == OB_MODE_PAINT_GPENCIL) {
- /* be sure we have brushes */
- BKE_paint_ensure(ts, (Paint **)&ts->gp_paint);
- Paint *paint = &ts->gp_paint->paint;
- /* if not exist, create a new one */
- if (paint->brush == NULL) {
- BKE_brush_gpencil_presets(C);
- }
- BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint);
- }
-
- /* setup other modes */
- ED_gpencil_setup_modes(C, gpd, mode);
- /* set cache as dirty */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
-
- if (is_object) {
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
- }
- if (G.background == false) {
- WM_toolsystem_update_from_context_view3d(C);
- }
-
- return OPERATOR_FINISHED;
+ const bool back = RNA_boolean_get(op->ptr, "back");
+
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Main *bmain = CTX_data_main(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ bool is_object = false;
+ short mode;
+ /* if using a gpencil object, use this datablock */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ gpd = ob->data;
+ is_object = true;
+ }
+
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* Just toggle paintmode flag... */
+ gpd->flag ^= GP_DATA_STROKE_PAINTMODE;
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
+ mode = OB_MODE_PAINT_GPENCIL;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
+ }
+
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
+ }
+
+ if (mode == OB_MODE_PAINT_GPENCIL) {
+ /* be sure we have brushes */
+ BKE_paint_ensure(ts, (Paint **)&ts->gp_paint);
+ Paint *paint = &ts->gp_paint->paint;
+ /* if not exist, create a new one */
+ if (paint->brush == NULL) {
+ BKE_brush_gpencil_presets(C);
+ }
+ BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint);
+ }
+
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ if (is_object) {
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+ }
+ if (G.background == false) {
+ WM_toolsystem_update_from_context_view3d(C);
+ }
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_paintmode_toggle(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ PropertyRNA *prop;
- /* identifiers */
- ot->name = "Strokes Paint Mode Toggle";
- ot->idname = "GPENCIL_OT_paintmode_toggle";
- ot->description = "Enter/Exit paint mode for Grease Pencil strokes";
+ /* identifiers */
+ ot->name = "Strokes Paint Mode Toggle";
+ ot->idname = "GPENCIL_OT_paintmode_toggle";
+ ot->description = "Enter/Exit paint mode for Grease Pencil strokes";
- /* callbacks */
- ot->exec = gpencil_paintmode_toggle_exec;
- ot->poll = gpencil_paintmode_toggle_poll;
+ /* callbacks */
+ ot->exec = gpencil_paintmode_toggle_exec;
+ ot->poll = gpencil_paintmode_toggle_poll;
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
- /* properties */
- prop = RNA_def_boolean(ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ /* properties */
+ prop = RNA_def_boolean(
+ ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/* Stroke Sculpt Mode Management */
static bool gpencil_sculptmode_toggle_poll(bContext *C)
{
- /* if using gpencil object, use this gpd */
- Object *ob = CTX_data_active_object(C);
- if ((ob) && (ob->type == OB_GPENCIL)) {
- return ob->data != NULL;
- }
- return ED_gpencil_data_get_active(C) != NULL;
+ /* if using gpencil object, use this gpd */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return ob->data != NULL;
+ }
+ return ED_gpencil_data_get_active(C) != NULL;
}
static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
{
- const bool back = RNA_boolean_get(op->ptr, "back");
-
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bool is_object = false;
- short mode;
- /* if using a gpencil object, use this datablock */
- Object *ob = CTX_data_active_object(C);
- if ((ob) && (ob->type == OB_GPENCIL)) {
- gpd = ob->data;
- is_object = true;
- }
-
- if (gpd == NULL)
- return OPERATOR_CANCELLED;
-
- /* Just toggle sculptmode flag... */
- gpd->flag ^= GP_DATA_STROKE_SCULPTMODE;
- /* set mode */
- if (gpd->flag & GP_DATA_STROKE_SCULPTMODE) {
- mode = OB_MODE_SCULPT_GPENCIL;
- }
- else {
- mode = OB_MODE_OBJECT;
- }
-
- if (is_object) {
- /* try to back previous mode */
- if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_SCULPTMODE) == 0) && (back == 1)) {
- mode = ob->restore_mode;
- }
- ob->restore_mode = ob->mode;
- ob->mode = mode;
- }
-
- /* setup other modes */
- ED_gpencil_setup_modes(C, gpd, mode);
- /* set cache as dirty */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
-
- if (is_object) {
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
- }
- if (G.background == false) {
- WM_toolsystem_update_from_context_view3d(C);
- }
-
- return OPERATOR_FINISHED;
+ const bool back = RNA_boolean_get(op->ptr, "back");
+
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bool is_object = false;
+ short mode;
+ /* if using a gpencil object, use this datablock */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ gpd = ob->data;
+ is_object = true;
+ }
+
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* Just toggle sculptmode flag... */
+ gpd->flag ^= GP_DATA_STROKE_SCULPTMODE;
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_SCULPTMODE) {
+ mode = OB_MODE_SCULPT_GPENCIL;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
+ }
+
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_SCULPTMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
+ }
+
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ if (is_object) {
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+ }
+ if (G.background == false) {
+ WM_toolsystem_update_from_context_view3d(C);
+ }
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_sculptmode_toggle(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ PropertyRNA *prop;
- /* identifiers */
- ot->name = "Strokes Sculpt Mode Toggle";
- ot->idname = "GPENCIL_OT_sculptmode_toggle";
- ot->description = "Enter/Exit sculpt mode for Grease Pencil strokes";
+ /* identifiers */
+ ot->name = "Strokes Sculpt Mode Toggle";
+ ot->idname = "GPENCIL_OT_sculptmode_toggle";
+ ot->description = "Enter/Exit sculpt mode for Grease Pencil strokes";
- /* callbacks */
- ot->exec = gpencil_sculptmode_toggle_exec;
- ot->poll = gpencil_sculptmode_toggle_poll;
+ /* callbacks */
+ ot->exec = gpencil_sculptmode_toggle_exec;
+ ot->poll = gpencil_sculptmode_toggle_poll;
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
- /* properties */
- prop = RNA_def_boolean(ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ /* properties */
+ prop = RNA_def_boolean(
+ ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/* Stroke Weight Paint Mode Management */
static bool gpencil_weightmode_toggle_poll(bContext *C)
{
- /* if using gpencil object, use this gpd */
- Object *ob = CTX_data_active_object(C);
- if ((ob) && (ob->type == OB_GPENCIL)) {
- return ob->data != NULL;
- }
- return ED_gpencil_data_get_active(C) != NULL;
+ /* if using gpencil object, use this gpd */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return ob->data != NULL;
+ }
+ return ED_gpencil_data_get_active(C) != NULL;
}
static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op)
{
- const bool back = RNA_boolean_get(op->ptr, "back");
-
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bool is_object = false;
- short mode;
- /* if using a gpencil object, use this datablock */
- Object *ob = CTX_data_active_object(C);
- if ((ob) && (ob->type == OB_GPENCIL)) {
- gpd = ob->data;
- is_object = true;
- }
-
- if (gpd == NULL)
- return OPERATOR_CANCELLED;
-
- /* Just toggle weightmode flag... */
- gpd->flag ^= GP_DATA_STROKE_WEIGHTMODE;
- /* set mode */
- if (gpd->flag & GP_DATA_STROKE_WEIGHTMODE) {
- mode = OB_MODE_WEIGHT_GPENCIL;
- }
- else {
- mode = OB_MODE_OBJECT;
- }
-
- if (is_object) {
- /* try to back previous mode */
- if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && (back == 1)) {
- mode = ob->restore_mode;
- }
- ob->restore_mode = ob->mode;
- ob->mode = mode;
- }
-
- /* setup other modes */
- ED_gpencil_setup_modes(C, gpd, mode);
- /* set cache as dirty */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
-
- if (is_object) {
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
- }
- if (G.background == false) {
- WM_toolsystem_update_from_context_view3d(C);
- }
-
- return OPERATOR_FINISHED;
+ const bool back = RNA_boolean_get(op->ptr, "back");
+
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bool is_object = false;
+ short mode;
+ /* if using a gpencil object, use this datablock */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ gpd = ob->data;
+ is_object = true;
+ }
+
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* Just toggle weightmode flag... */
+ gpd->flag ^= GP_DATA_STROKE_WEIGHTMODE;
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_WEIGHTMODE) {
+ mode = OB_MODE_WEIGHT_GPENCIL;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
+ }
+
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
+ }
+
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ if (is_object) {
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+ }
+ if (G.background == false) {
+ WM_toolsystem_update_from_context_view3d(C);
+ }
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_weightmode_toggle(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ PropertyRNA *prop;
- /* identifiers */
- ot->name = "Strokes Weight Mode Toggle";
- ot->idname = "GPENCIL_OT_weightmode_toggle";
- ot->description = "Enter/Exit weight paint mode for Grease Pencil strokes";
+ /* identifiers */
+ ot->name = "Strokes Weight Mode Toggle";
+ ot->idname = "GPENCIL_OT_weightmode_toggle";
+ ot->description = "Enter/Exit weight paint mode for Grease Pencil strokes";
- /* callbacks */
- ot->exec = gpencil_weightmode_toggle_exec;
- ot->poll = gpencil_weightmode_toggle_poll;
+ /* callbacks */
+ ot->exec = gpencil_weightmode_toggle_exec;
+ ot->poll = gpencil_weightmode_toggle_poll;
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
- /* properties */
- prop = RNA_def_boolean(ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ /* properties */
+ prop = RNA_def_boolean(
+ ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/* ************************************************ */
@@ -541,440 +544,437 @@ void GPENCIL_OT_weightmode_toggle(wmOperatorType *ot)
static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
- View3D *v3d = CTX_wm_view3d(C);
- if (v3d == NULL)
- return OPERATOR_CANCELLED;
-
- /* Just toggle alpha... */
- if (v3d->vertex_opacity > 0.0f) {
- v3d->vertex_opacity = 0.0f;
- }
- else {
- v3d->vertex_opacity = 1.0f;
- }
-
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
- WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
-
- return OPERATOR_FINISHED;
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* Just toggle alpha... */
+ if (v3d->vertex_opacity > 0.0f) {
+ v3d->vertex_opacity = 0.0f;
+ }
+ else {
+ v3d->vertex_opacity = 1.0f;
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_selection_opacity_toggle(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Hide Selected";
- ot->idname = "GPENCIL_OT_selection_opacity_toggle";
- ot->description = "Hide/Unhide selected points for Grease Pencil strokes setting alpha factor";
+ /* identifiers */
+ ot->name = "Hide Selected";
+ ot->idname = "GPENCIL_OT_selection_opacity_toggle";
+ ot->description = "Hide/Unhide selected points for Grease Pencil strokes setting alpha factor";
- /* callbacks */
- ot->exec = gpencil_hideselect_toggle_exec;
- ot->poll = gp_stroke_edit_poll;
+ /* callbacks */
+ ot->exec = gpencil_hideselect_toggle_exec;
+ ot->poll = gp_stroke_edit_poll;
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
}
/* ************** Duplicate Selected Strokes **************** */
/* Make copies of selected point segments in a selected stroke */
-static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, const char *layername)
+static void gp_duplicate_points(const bGPDstroke *gps,
+ ListBase *new_strokes,
+ const char *layername)
{
- bGPDspoint *pt;
- int i;
-
- int start_idx = -1;
-
-
- /* Step through the original stroke's points:
- * - We accumulate selected points (from start_idx to current index)
- * and then convert that to a new stroke
- */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- /* searching for start, are waiting for end? */
- if (start_idx == -1) {
- /* is this the first selected point for a new island? */
- if (pt->flag & GP_SPOINT_SELECT) {
- start_idx = i;
- }
- }
- else {
- size_t len = 0;
-
- /* is this the end of current island yet?
- * 1) Point i-1 was the last one that was selected
- * 2) Point i is the last in the array
- */
- if ((pt->flag & GP_SPOINT_SELECT) == 0) {
- len = i - start_idx;
- }
- else if (i == gps->totpoints - 1) {
- len = i - start_idx + 1;
- }
- //printf("copying from %d to %d = %d\n", start_idx, i, len);
-
- /* make copies of the relevant data */
- if (len) {
- bGPDstroke *gpsd;
-
- /* make a stupid copy first of the entire stroke (to get the flags too) */
- gpsd = MEM_dupallocN(gps);
-
- /* saves original layer name */
- BLI_strncpy(gpsd->runtime.tmp_layerinfo, layername, sizeof(gpsd->runtime.tmp_layerinfo));
-
- /* initialize triangle memory - will be calculated on next redraw */
- gpsd->triangles = NULL;
- gpsd->flag |= GP_STROKE_RECALC_GEOMETRY;
- gpsd->tot_triangles = 0;
-
- /* now, make a new points array, and copy of the relevant parts */
- gpsd->points = MEM_callocN(sizeof(bGPDspoint) * len, "gps stroke points copy");
- memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len);
- gpsd->totpoints = len;
-
- if (gps->dvert != NULL) {
- gpsd->dvert = MEM_callocN(sizeof(MDeformVert) * len, "gps stroke weights copy");
- memcpy(gpsd->dvert, gps->dvert + start_idx, sizeof(MDeformVert) * len);
-
- /* Copy weights */
- int e = start_idx;
- for (int j = 0; j < gpsd->totpoints; j++) {
- MDeformVert *dvert_dst = &gps->dvert[e];
- MDeformVert *dvert_src = &gps->dvert[j];
- dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
- e++;
- }
- }
-
- /* add to temp buffer */
- gpsd->next = gpsd->prev = NULL;
- BLI_addtail(new_strokes, gpsd);
-
- /* cleanup + reset for next */
- start_idx = -1;
- }
- }
- }
+ bGPDspoint *pt;
+ int i;
+
+ int start_idx = -1;
+
+ /* Step through the original stroke's points:
+ * - We accumulate selected points (from start_idx to current index)
+ * and then convert that to a new stroke
+ */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ /* searching for start, are waiting for end? */
+ if (start_idx == -1) {
+ /* is this the first selected point for a new island? */
+ if (pt->flag & GP_SPOINT_SELECT) {
+ start_idx = i;
+ }
+ }
+ else {
+ size_t len = 0;
+
+ /* is this the end of current island yet?
+ * 1) Point i-1 was the last one that was selected
+ * 2) Point i is the last in the array
+ */
+ if ((pt->flag & GP_SPOINT_SELECT) == 0) {
+ len = i - start_idx;
+ }
+ else if (i == gps->totpoints - 1) {
+ len = i - start_idx + 1;
+ }
+ //printf("copying from %d to %d = %d\n", start_idx, i, len);
+
+ /* make copies of the relevant data */
+ if (len) {
+ bGPDstroke *gpsd;
+
+ /* make a stupid copy first of the entire stroke (to get the flags too) */
+ gpsd = MEM_dupallocN(gps);
+
+ /* saves original layer name */
+ BLI_strncpy(gpsd->runtime.tmp_layerinfo, layername, sizeof(gpsd->runtime.tmp_layerinfo));
+
+ /* initialize triangle memory - will be calculated on next redraw */
+ gpsd->triangles = NULL;
+ gpsd->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gpsd->tot_triangles = 0;
+
+ /* now, make a new points array, and copy of the relevant parts */
+ gpsd->points = MEM_callocN(sizeof(bGPDspoint) * len, "gps stroke points copy");
+ memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len);
+ gpsd->totpoints = len;
+
+ if (gps->dvert != NULL) {
+ gpsd->dvert = MEM_callocN(sizeof(MDeformVert) * len, "gps stroke weights copy");
+ memcpy(gpsd->dvert, gps->dvert + start_idx, sizeof(MDeformVert) * len);
+
+ /* Copy weights */
+ int e = start_idx;
+ for (int j = 0; j < gpsd->totpoints; j++) {
+ MDeformVert *dvert_dst = &gps->dvert[e];
+ MDeformVert *dvert_src = &gps->dvert[j];
+ dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ e++;
+ }
+ }
+
+ /* add to temp buffer */
+ gpsd->next = gpsd->prev = NULL;
+ BLI_addtail(new_strokes, gpsd);
+
+ /* cleanup + reset for next */
+ start_idx = -1;
+ }
+ }
+ }
}
static int gp_duplicate_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
-
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
- return OPERATOR_CANCELLED;
- }
-
- if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
- BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
- return OPERATOR_CANCELLED;
- }
-
- /* for each visible (and editable) layer's selected strokes,
- * copy the strokes into a temporary buffer, then append
- * once all done
- */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- ListBase new_strokes = {NULL, NULL};
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
-
- if (gpf == NULL)
- continue;
-
- /* make copies of selected strokes, and deselect these once we're done */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
-
- if (gps->flag & GP_STROKE_SELECT) {
- if (gps->totpoints == 1) {
- /* Special Case: If there's just a single point in this stroke... */
- bGPDstroke *gpsd;
-
- /* make direct copies of the stroke and its points */
- gpsd = MEM_dupallocN(gps);
- BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo));
- gpsd->points = MEM_dupallocN(gps->points);
- if (gps->dvert != NULL) {
- gpsd->dvert = MEM_dupallocN(gps->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps, gpsd);
- }
-
- /* triangle information - will be calculated on next redraw */
- gpsd->flag |= GP_STROKE_RECALC_GEOMETRY;
- gpsd->triangles = NULL;
-
- /* add to temp buffer */
- gpsd->next = gpsd->prev = NULL;
- BLI_addtail(&new_strokes, gpsd);
- }
- else {
- /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
- gp_duplicate_points(gps, &new_strokes, gpl->info);
- }
-
- /* deselect original stroke, or else the originals get moved too
- * (when using the copy + move macro)
- */
- gps->flag &= ~GP_STROKE_SELECT;
- }
- }
-
- /* add all new strokes in temp buffer to the frame (preventing double-copies) */
- BLI_movelisttolist(&gpf->strokes, &new_strokes);
- BLI_assert(new_strokes.first == NULL);
- }
- CTX_DATA_END;
-
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* for each visible (and editable) layer's selected strokes,
+ * copy the strokes into a temporary buffer, then append
+ * once all done
+ */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ ListBase new_strokes = {NULL, NULL};
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+
+ if (gpf == NULL)
+ continue;
+
+ /* make copies of selected strokes, and deselect these once we're done */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+
+ if (gps->flag & GP_STROKE_SELECT) {
+ if (gps->totpoints == 1) {
+ /* Special Case: If there's just a single point in this stroke... */
+ bGPDstroke *gpsd;
+
+ /* make direct copies of the stroke and its points */
+ gpsd = MEM_dupallocN(gps);
+ BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo));
+ gpsd->points = MEM_dupallocN(gps->points);
+ if (gps->dvert != NULL) {
+ gpsd->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, gpsd);
+ }
+
+ /* triangle information - will be calculated on next redraw */
+ gpsd->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gpsd->triangles = NULL;
+
+ /* add to temp buffer */
+ gpsd->next = gpsd->prev = NULL;
+ BLI_addtail(&new_strokes, gpsd);
+ }
+ else {
+ /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
+ gp_duplicate_points(gps, &new_strokes, gpl->info);
+ }
+
+ /* deselect original stroke, or else the originals get moved too
+ * (when using the copy + move macro)
+ */
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ }
+
+ /* add all new strokes in temp buffer to the frame (preventing double-copies) */
+ BLI_movelisttolist(&gpf->strokes, &new_strokes);
+ BLI_assert(new_strokes.first == NULL);
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_duplicate(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Duplicate Strokes";
- ot->idname = "GPENCIL_OT_duplicate";
- ot->description = "Duplicate the selected Grease Pencil strokes";
+ /* identifiers */
+ ot->name = "Duplicate Strokes";
+ ot->idname = "GPENCIL_OT_duplicate";
+ ot->description = "Duplicate the selected Grease Pencil strokes";
- /* callbacks */
- ot->exec = gp_duplicate_exec;
- ot->poll = gp_stroke_edit_poll;
+ /* callbacks */
+ ot->exec = gp_duplicate_exec;
+ ot->poll = gp_stroke_edit_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ************** Extrude Selected Strokes **************** */
/* helper to copy a point to temp area */
-static void copy_move_point(
- bGPDstroke *gps,
- bGPDspoint *temp_points,
- MDeformVert *temp_dverts,
- int from_idx, int to_idx, const bool copy)
+static void copy_move_point(bGPDstroke *gps,
+ bGPDspoint *temp_points,
+ MDeformVert *temp_dverts,
+ int from_idx,
+ int to_idx,
+ const bool copy)
{
- bGPDspoint *pt = &temp_points[from_idx];
- bGPDspoint *pt_final = &gps->points[to_idx];
-
- copy_v3_v3(&pt_final->x, &pt->x);
- pt_final->pressure = pt->pressure;
- pt_final->strength = pt->strength;
- pt_final->time = pt->time;
- pt_final->flag = pt->flag;
- pt_final->uv_fac = pt->uv_fac;
- pt_final->uv_rot = pt->uv_rot;
-
- if (gps->dvert != NULL) {
- MDeformVert *dvert = &temp_dverts[from_idx];
- MDeformVert *dvert_final = &gps->dvert[to_idx];
-
- dvert_final->totweight = dvert->totweight;
- /* if copy, duplicate memory, otherwise move only the pointer */
- if (copy) {
- dvert_final->dw = MEM_dupallocN(dvert->dw);
- }
- else {
- dvert_final->dw = dvert->dw;
- }
- }
+ bGPDspoint *pt = &temp_points[from_idx];
+ bGPDspoint *pt_final = &gps->points[to_idx];
+
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+ pt_final->uv_fac = pt->uv_fac;
+ pt_final->uv_rot = pt->uv_rot;
+
+ if (gps->dvert != NULL) {
+ MDeformVert *dvert = &temp_dverts[from_idx];
+ MDeformVert *dvert_final = &gps->dvert[to_idx];
+
+ dvert_final->totweight = dvert->totweight;
+ /* if copy, duplicate memory, otherwise move only the pointer */
+ if (copy) {
+ dvert_final->dw = MEM_dupallocN(dvert->dw);
+ }
+ else {
+ dvert_final->dw = dvert->dw;
+ }
+ }
}
static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps)
{
- bGPDspoint *temp_points = NULL;
- MDeformVert *temp_dverts = NULL;
- bGPDspoint *pt = NULL;
- const bGPDspoint *pt_start = &gps->points[0];
- const bGPDspoint *pt_last = &gps->points[gps->totpoints - 1];
- const bool do_first = (pt_start->flag & GP_SPOINT_SELECT);
- const bool do_last = ((pt_last->flag & GP_SPOINT_SELECT) && (pt_start != pt_last));
- const bool do_stroke = (do_first || do_last);
-
- /* review points in the middle of stroke to create new strokes */
- for (int i = 0; i < gps->totpoints; i++) {
- /* skip first and last point */
- if ((i == 0) || (i == gps->totpoints - 1)) {
- continue;
- }
-
- pt = &gps->points[i];
- if (pt->flag == GP_SPOINT_SELECT) {
- /* duplicate original stroke data */
- bGPDstroke *gps_new = MEM_dupallocN(gps);
- gps_new->prev = gps_new->next = NULL;
-
- /* add new points array */
- gps_new->totpoints = 1;
- gps_new->points = MEM_callocN(sizeof(bGPDspoint), __func__);
- gps_new->dvert = NULL;
-
- if (gps->dvert != NULL) {
- gps_new->dvert = MEM_callocN(sizeof(MDeformVert), __func__);
- }
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps_new->triangles = NULL;
- gps_new->tot_triangles = 0;
- BLI_insertlinkafter(&gpf->strokes, gps, gps_new);
-
- /* copy selected point data to new stroke */
- copy_move_point(gps_new, gps->points, gps->dvert, i, 0, true);
-
- /* deselect orinal point */
- pt->flag &= ~GP_SPOINT_SELECT;
- }
- }
-
- /* review first and last point to reuse same stroke */
- int i2 = 0;
- int totnewpoints, oldtotpoints;
- /* if first or last, reuse stroke and resize */
- if ((do_first) || (do_last)) {
- totnewpoints = gps->totpoints;
- if (do_first) {
- totnewpoints++;
- }
- if (do_last) {
- totnewpoints++;
- }
-
- /* duplicate points in a temp area */
- temp_points = MEM_dupallocN(gps->points);
- oldtotpoints = gps->totpoints;
- if (gps->dvert != NULL) {
- temp_dverts = MEM_dupallocN(gps->dvert);
- }
-
- /* if first point, need move all one position */
- if (do_first) {
- i2 = 1;
- }
-
- /* resize the points arrays */
- gps->totpoints = totnewpoints;
- gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
- if (gps->dvert != NULL) {
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
- }
-
- /* move points to new position */
- for (int i = 0; i < oldtotpoints; i++) {
- copy_move_point(gps, temp_points, temp_dverts, i, i2, false);
- i2++;
- }
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* if first point, add new point at the begining */
- if (do_first) {
- copy_move_point(gps, temp_points, temp_dverts, 0, 0, true);
- /* deselect old */
- pt = &gps->points[1];
- pt->flag &= ~GP_SPOINT_SELECT;
- /* select new */
- pt = &gps->points[0];
- pt->flag |= GP_SPOINT_SELECT;
- }
-
- /* if last point, add new point at the end */
- if (do_last) {
- copy_move_point(
- gps, temp_points, temp_dverts,
- oldtotpoints - 1, gps->totpoints - 1, true);
-
- /* deselect old */
- pt = &gps->points[gps->totpoints - 2];
- pt->flag &= ~GP_SPOINT_SELECT;
- /* select new */
- pt = &gps->points[gps->totpoints - 1];
- pt->flag |= GP_SPOINT_SELECT;
- }
-
- MEM_SAFE_FREE(temp_points);
- MEM_SAFE_FREE(temp_dverts);
- }
-
- /* if the stroke is not reused, deselect */
- if (!do_stroke) {
- gps->flag &= ~GP_STROKE_SELECT;
- }
+ bGPDspoint *temp_points = NULL;
+ MDeformVert *temp_dverts = NULL;
+ bGPDspoint *pt = NULL;
+ const bGPDspoint *pt_start = &gps->points[0];
+ const bGPDspoint *pt_last = &gps->points[gps->totpoints - 1];
+ const bool do_first = (pt_start->flag & GP_SPOINT_SELECT);
+ const bool do_last = ((pt_last->flag & GP_SPOINT_SELECT) && (pt_start != pt_last));
+ const bool do_stroke = (do_first || do_last);
+
+ /* review points in the middle of stroke to create new strokes */
+ for (int i = 0; i < gps->totpoints; i++) {
+ /* skip first and last point */
+ if ((i == 0) || (i == gps->totpoints - 1)) {
+ continue;
+ }
+
+ pt = &gps->points[i];
+ if (pt->flag == GP_SPOINT_SELECT) {
+ /* duplicate original stroke data */
+ bGPDstroke *gps_new = MEM_dupallocN(gps);
+ gps_new->prev = gps_new->next = NULL;
+
+ /* add new points array */
+ gps_new->totpoints = 1;
+ gps_new->points = MEM_callocN(sizeof(bGPDspoint), __func__);
+ gps_new->dvert = NULL;
+
+ if (gps->dvert != NULL) {
+ gps_new->dvert = MEM_callocN(sizeof(MDeformVert), __func__);
+ }
+
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps_new->triangles = NULL;
+ gps_new->tot_triangles = 0;
+ BLI_insertlinkafter(&gpf->strokes, gps, gps_new);
+
+ /* copy selected point data to new stroke */
+ copy_move_point(gps_new, gps->points, gps->dvert, i, 0, true);
+
+ /* deselect orinal point */
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+
+ /* review first and last point to reuse same stroke */
+ int i2 = 0;
+ int totnewpoints, oldtotpoints;
+ /* if first or last, reuse stroke and resize */
+ if ((do_first) || (do_last)) {
+ totnewpoints = gps->totpoints;
+ if (do_first) {
+ totnewpoints++;
+ }
+ if (do_last) {
+ totnewpoints++;
+ }
+
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+ if (gps->dvert != NULL) {
+ temp_dverts = MEM_dupallocN(gps->dvert);
+ }
+
+ /* if first point, need move all one position */
+ if (do_first) {
+ i2 = 1;
+ }
+
+ /* resize the points arrays */
+ gps->totpoints = totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ }
+
+ /* move points to new position */
+ for (int i = 0; i < oldtotpoints; i++) {
+ copy_move_point(gps, temp_points, temp_dverts, i, i2, false);
+ i2++;
+ }
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* if first point, add new point at the begining */
+ if (do_first) {
+ copy_move_point(gps, temp_points, temp_dverts, 0, 0, true);
+ /* deselect old */
+ pt = &gps->points[1];
+ pt->flag &= ~GP_SPOINT_SELECT;
+ /* select new */
+ pt = &gps->points[0];
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+
+ /* if last point, add new point at the end */
+ if (do_last) {
+ copy_move_point(gps, temp_points, temp_dverts, oldtotpoints - 1, gps->totpoints - 1, true);
+
+ /* deselect old */
+ pt = &gps->points[gps->totpoints - 2];
+ pt->flag &= ~GP_SPOINT_SELECT;
+ /* select new */
+ pt = &gps->points[gps->totpoints - 1];
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+
+ MEM_SAFE_FREE(temp_points);
+ MEM_SAFE_FREE(temp_dverts);
+ }
+
+ /* if the stroke is not reused, deselect */
+ if (!do_stroke) {
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
}
static int gp_extrude_exec(bContext *C, wmOperator *op)
{
- Object *obact = CTX_data_active_object(C);
- bGPdata *gpd = (bGPdata *)obact->data;
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- bGPDstroke *gps = NULL;
-
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
- return OPERATOR_CANCELLED;
- }
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- if (gpf == NULL)
- continue;
-
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- if (gps->flag & GP_STROKE_SELECT) {
- gpencil_add_move_points(gpf, gps);
- }
- }
- /* if not multiedit, exit loop*/
- if (!is_multiedit) {
- break;
- }
- }
- }
- }
- CTX_DATA_END;
-
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
- DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ Object *obact = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)obact->data;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ bGPDstroke *gps = NULL;
+
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ if (gps->flag & GP_STROKE_SELECT) {
+ gpencil_add_move_points(gpf, gps);
+ }
+ }
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_extrude(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Extrude Stroke Points";
- ot->idname = "GPENCIL_OT_extrude";
- ot->description = "Extrude the selected Grease Pencil points";
+ /* identifiers */
+ ot->name = "Extrude Stroke Points";
+ ot->idname = "GPENCIL_OT_extrude";
+ ot->description = "Extrude the selected Grease Pencil points";
- /* callbacks */
- ot->exec = gp_extrude_exec;
- ot->poll = gp_stroke_edit_poll;
+ /* callbacks */
+ ot->exec = gp_extrude_exec;
+ ot->poll = gp_stroke_edit_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
/* ******************* Copy/Paste Strokes ************************* */
/* Grease Pencil stroke data copy/paste buffer:
* - The copy operation collects all segments of selected strokes,
@@ -984,8 +984,8 @@ void GPENCIL_OT_extrude(wmOperatorType *ot)
* from several different layers into a single layer.
*/
- /* list of bGPDstroke instances */
- /* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */
+/* list of bGPDstroke instances */
+/* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */
ListBase gp_strokes_copypastebuf = {NULL, NULL};
/* Hash for hanging on to all the colors used by strokes in the buffer
@@ -997,69 +997,69 @@ static GHash *gp_strokes_copypastebuf_colors = NULL;
static GHash *gp_strokes_copypastebuf_colors_material_to_name_create(Main *bmain)
{
- GHash *ma_to_name = BLI_ghash_ptr_new(__func__);
+ GHash *ma_to_name = BLI_ghash_ptr_new(__func__);
- for (Material *ma = bmain->materials.first; ma != NULL; ma = ma->id.next) {
- char *name = BKE_id_to_unique_string_key(&ma->id);
- BLI_ghash_insert(ma_to_name, ma, name);
- }
+ for (Material *ma = bmain->materials.first; ma != NULL; ma = ma->id.next) {
+ char *name = BKE_id_to_unique_string_key(&ma->id);
+ BLI_ghash_insert(ma_to_name, ma, name);
+ }
- return ma_to_name;
+ return ma_to_name;
}
static void gp_strokes_copypastebuf_colors_material_to_name_free(GHash *ma_to_name)
{
- BLI_ghash_free(ma_to_name, NULL, MEM_freeN);
+ BLI_ghash_free(ma_to_name, NULL, MEM_freeN);
}
static GHash *gp_strokes_copypastebuf_colors_name_to_material_create(Main *bmain)
{
- GHash *name_to_ma = BLI_ghash_str_new(__func__);
+ GHash *name_to_ma = BLI_ghash_str_new(__func__);
- for (Material *ma = bmain->materials.first; ma != NULL; ma = ma->id.next) {
- char *name = BKE_id_to_unique_string_key(&ma->id);
- BLI_ghash_insert(name_to_ma, name, ma);
- }
+ for (Material *ma = bmain->materials.first; ma != NULL; ma = ma->id.next) {
+ char *name = BKE_id_to_unique_string_key(&ma->id);
+ BLI_ghash_insert(name_to_ma, name, ma);
+ }
- return name_to_ma;
+ return name_to_ma;
}
static void gp_strokes_copypastebuf_colors_name_to_material_free(GHash *name_to_ma)
{
- BLI_ghash_free(name_to_ma, MEM_freeN, NULL);
+ BLI_ghash_free(name_to_ma, MEM_freeN, NULL);
}
/* Free copy/paste buffer data */
void ED_gpencil_strokes_copybuf_free(void)
{
- bGPDstroke *gps, *gpsn;
-
- /* Free the colors buffer
- * NOTE: This is done before the strokes so that the ptrs are still safe
- */
- if (gp_strokes_copypastebuf_colors) {
- BLI_ghash_free(gp_strokes_copypastebuf_colors, NULL, MEM_freeN);
- gp_strokes_copypastebuf_colors = NULL;
- }
-
- /* Free the stroke buffer */
- for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- if (gps->points) {
- MEM_freeN(gps->points);
- }
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
-
- MEM_SAFE_FREE(gps->triangles);
-
- BLI_freelinkN(&gp_strokes_copypastebuf, gps);
- }
-
- gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL;
+ bGPDstroke *gps, *gpsn;
+
+ /* Free the colors buffer
+ * NOTE: This is done before the strokes so that the ptrs are still safe
+ */
+ if (gp_strokes_copypastebuf_colors) {
+ BLI_ghash_free(gp_strokes_copypastebuf_colors, NULL, MEM_freeN);
+ gp_strokes_copypastebuf_colors = NULL;
+ }
+
+ /* Free the stroke buffer */
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+
+ MEM_SAFE_FREE(gps->triangles);
+
+ BLI_freelinkN(&gp_strokes_copypastebuf, gps);
+ }
+
+ gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL;
}
/* Ensure that destination datablock has all the colours the pasted strokes need
@@ -1067,30 +1067,30 @@ void ED_gpencil_strokes_copybuf_free(void)
*/
GHash *gp_copybuf_validate_colormap(bContext *C)
{
- Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_active_object(C);
- GHash *new_colors = BLI_ghash_int_new("GPencil Paste Dst Colors");
- GHashIterator gh_iter;
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ GHash *new_colors = BLI_ghash_int_new("GPencil Paste Dst Colors");
+ GHashIterator gh_iter;
- /* For each color, check if exist and add if not */
- GHash *name_to_ma = gp_strokes_copypastebuf_colors_name_to_material_create(bmain);
+ /* For each color, check if exist and add if not */
+ GHash *name_to_ma = gp_strokes_copypastebuf_colors_name_to_material_create(bmain);
- GHASH_ITER(gh_iter, gp_strokes_copypastebuf_colors) {
- int *key = BLI_ghashIterator_getKey(&gh_iter);
- char *ma_name = BLI_ghashIterator_getValue(&gh_iter);
- Material *ma = BLI_ghash_lookup(name_to_ma, ma_name);
+ GHASH_ITER (gh_iter, gp_strokes_copypastebuf_colors) {
+ int *key = BLI_ghashIterator_getKey(&gh_iter);
+ char *ma_name = BLI_ghashIterator_getValue(&gh_iter);
+ Material *ma = BLI_ghash_lookup(name_to_ma, ma_name);
- BKE_gpencil_object_material_ensure(bmain, ob, ma);
+ BKE_gpencil_object_material_ensure(bmain, ob, ma);
- /* Store this mapping (for use later when pasting) */
- if (!BLI_ghash_haskey(new_colors, POINTER_FROM_INT(*key))) {
- BLI_ghash_insert(new_colors, POINTER_FROM_INT(*key), ma);
- }
- }
+ /* Store this mapping (for use later when pasting) */
+ if (!BLI_ghash_haskey(new_colors, POINTER_FROM_INT(*key))) {
+ BLI_ghash_insert(new_colors, POINTER_FROM_INT(*key), ma);
+ }
+ }
- gp_strokes_copypastebuf_colors_name_to_material_free(name_to_ma);
+ gp_strokes_copypastebuf_colors_name_to_material_free(name_to_ma);
- return new_colors;
+ return new_colors;
}
/* --------------------- */
@@ -1098,111 +1098,111 @@ GHash *gp_copybuf_validate_colormap(bContext *C)
static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
-
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
- return OPERATOR_CANCELLED;
- }
-
- if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
- BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
- return OPERATOR_CANCELLED;
- }
-
- /* clear the buffer first */
- ED_gpencil_strokes_copybuf_free();
-
- /* for each visible (and editable) layer's selected strokes,
- * copy the strokes into a temporary buffer, then append
- * once all done
- */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
-
- if (gpf == NULL)
- continue;
-
- /* make copies of selected strokes, and deselect these once we're done */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- if (gps->flag & GP_STROKE_SELECT) {
- if (gps->totpoints == 1) {
- /* Special Case: If there's just a single point in this stroke... */
- bGPDstroke *gpsd;
-
- /* make direct copies of the stroke and its points */
- gpsd = MEM_dupallocN(gps);
- /* saves original layer name */
- BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo));
- gpsd->points = MEM_dupallocN(gps->points);
- if (gps->dvert != NULL) {
- gpsd->dvert = MEM_dupallocN(gps->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps, gpsd);
- }
-
- /* triangles cache - will be recalculated on next redraw */
- gpsd->flag |= GP_STROKE_RECALC_GEOMETRY;
- gpsd->tot_triangles = 0;
- gpsd->triangles = NULL;
-
- /* add to temp buffer */
- gpsd->next = gpsd->prev = NULL;
- BLI_addtail(&gp_strokes_copypastebuf, gpsd);
- }
- else {
- /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
- gp_duplicate_points(gps, &gp_strokes_copypastebuf, gpl->info);
- }
- }
- }
- }
- CTX_DATA_END;
-
- /* Build up hash of material colors used in these strokes */
- if (gp_strokes_copypastebuf.first) {
- gp_strokes_copypastebuf_colors = BLI_ghash_int_new("GPencil CopyBuf Colors");
- GHash *ma_to_name = gp_strokes_copypastebuf_colors_material_to_name_create(bmain);
- for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- char **ma_name_val;
- if (!BLI_ghash_ensure_p(gp_strokes_copypastebuf_colors, &gps->mat_nr, (void ***)&ma_name_val)) {
- Material *ma = give_current_material(ob, gps->mat_nr + 1);
- char *ma_name = BLI_ghash_lookup(ma_to_name, ma);
- *ma_name_val = MEM_dupallocN(ma_name);
- }
- }
- }
- gp_strokes_copypastebuf_colors_material_to_name_free(ma_to_name);
- }
-
- /* updates (to ensure operator buttons are refreshed, when used via hotkeys) */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); // XXX?
-
- /* done */
- return OPERATOR_FINISHED;
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* clear the buffer first */
+ ED_gpencil_strokes_copybuf_free();
+
+ /* for each visible (and editable) layer's selected strokes,
+ * copy the strokes into a temporary buffer, then append
+ * once all done
+ */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+
+ if (gpf == NULL)
+ continue;
+
+ /* make copies of selected strokes, and deselect these once we're done */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ if (gps->flag & GP_STROKE_SELECT) {
+ if (gps->totpoints == 1) {
+ /* Special Case: If there's just a single point in this stroke... */
+ bGPDstroke *gpsd;
+
+ /* make direct copies of the stroke and its points */
+ gpsd = MEM_dupallocN(gps);
+ /* saves original layer name */
+ BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo));
+ gpsd->points = MEM_dupallocN(gps->points);
+ if (gps->dvert != NULL) {
+ gpsd->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, gpsd);
+ }
+
+ /* triangles cache - will be recalculated on next redraw */
+ gpsd->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gpsd->tot_triangles = 0;
+ gpsd->triangles = NULL;
+
+ /* add to temp buffer */
+ gpsd->next = gpsd->prev = NULL;
+ BLI_addtail(&gp_strokes_copypastebuf, gpsd);
+ }
+ else {
+ /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
+ gp_duplicate_points(gps, &gp_strokes_copypastebuf, gpl->info);
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* Build up hash of material colors used in these strokes */
+ if (gp_strokes_copypastebuf.first) {
+ gp_strokes_copypastebuf_colors = BLI_ghash_int_new("GPencil CopyBuf Colors");
+ GHash *ma_to_name = gp_strokes_copypastebuf_colors_material_to_name_create(bmain);
+ for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ char **ma_name_val;
+ if (!BLI_ghash_ensure_p(
+ gp_strokes_copypastebuf_colors, &gps->mat_nr, (void ***)&ma_name_val)) {
+ Material *ma = give_current_material(ob, gps->mat_nr + 1);
+ char *ma_name = BLI_ghash_lookup(ma_to_name, ma);
+ *ma_name_val = MEM_dupallocN(ma_name);
+ }
+ }
+ }
+ gp_strokes_copypastebuf_colors_material_to_name_free(ma_to_name);
+ }
+
+ /* updates (to ensure operator buttons are refreshed, when used via hotkeys) */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); // XXX?
+
+ /* done */
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_copy(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Copy Strokes";
- ot->idname = "GPENCIL_OT_copy";
- ot->description = "Copy selected Grease Pencil points and strokes";
+ /* identifiers */
+ ot->name = "Copy Strokes";
+ ot->idname = "GPENCIL_OT_copy";
+ ot->description = "Copy selected Grease Pencil points and strokes";
- /* callbacks */
- ot->exec = gp_strokes_copy_exec;
- ot->poll = gp_stroke_edit_poll;
+ /* callbacks */
+ ot->exec = gp_strokes_copy_exec;
+ ot->poll = gp_stroke_edit_poll;
- /* flags */
- //ot->flag = OPTYPE_REGISTER;
+ /* flags */
+ //ot->flag = OPTYPE_REGISTER;
}
/* --------------------- */
@@ -1210,299 +1210,302 @@ void GPENCIL_OT_copy(wmOperatorType *ot)
static bool gp_strokes_paste_poll(bContext *C)
{
- /* 1) Must have GP datablock to paste to
- * - We don't need to have an active layer though, as that can easily get added
- * - If the active layer is locked, we can't paste there, but that should prompt a warning instead
- * 2) Copy buffer must at least have something (though it may be the wrong sort...)
- */
- return (ED_gpencil_data_get_active(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf));
+ /* 1) Must have GP datablock to paste to
+ * - We don't need to have an active layer though, as that can easily get added
+ * - If the active layer is locked, we can't paste there, but that should prompt a warning instead
+ * 2) Copy buffer must at least have something (though it may be the wrong sort...)
+ */
+ return (ED_gpencil_data_get_active(C) != NULL) &&
+ (!BLI_listbase_is_empty(&gp_strokes_copypastebuf));
}
typedef enum eGP_PasteMode {
- GP_COPY_ONLY = -1,
- GP_COPY_MERGE = 1,
+ GP_COPY_ONLY = -1,
+ GP_COPY_MERGE = 1,
} eGP_PasteMode;
static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only use active for copy merge */
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
- bGPDframe *gpf;
-
- eGP_PasteMode type = RNA_enum_get(op->ptr, "type");
- GHash *new_colors;
-
- /* check for various error conditions */
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
- return OPERATOR_CANCELLED;
- }
- else if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
- BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
- return OPERATOR_CANCELLED;
- }
- else if (BLI_listbase_is_empty(&gp_strokes_copypastebuf)) {
- BKE_report(op->reports, RPT_ERROR, "No strokes to paste, select and copy some points before trying again");
- return OPERATOR_CANCELLED;
- }
- else if (gpl == NULL) {
- /* no active layer - let's just create one */
- gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
- }
- else if ((gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_MERGE)) {
- BKE_report(op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked");
- return OPERATOR_CANCELLED;
- }
- else {
- /* Check that some of the strokes in the buffer can be used */
- bGPDstroke *gps;
- bool ok = false;
-
- for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- ok = true;
- break;
- }
- }
-
- if (ok == false) {
- /* XXX: this check is not 100% accurate (i.e. image editor is incompatible with normal 2D strokes),
- * but should be enough to give users a good idea of what's going on
- */
- if (CTX_wm_area(C)->spacetype == SPACE_VIEW3D)
- BKE_report(op->reports, RPT_ERROR, "Cannot paste 2D strokes in 3D View");
- else
- BKE_report(op->reports, RPT_ERROR, "Cannot paste 3D strokes in 2D editors");
-
- return OPERATOR_CANCELLED;
- }
- }
-
- /* Deselect all strokes first */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- bGPDspoint *pt;
- int i;
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
-
- gps->flag &= ~GP_STROKE_SELECT;
- }
- CTX_DATA_END;
-
- /* Ensure that all the necessary colors exist */
- new_colors = gp_copybuf_validate_colormap(C);
-
- /* Copy over the strokes from the buffer (and adjust the colors) */
- for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- /* Need to verify if layer exists */
- if (type != GP_COPY_MERGE) {
- gpl = BLI_findstring(&gpd->layers, gps->runtime.tmp_layerinfo, offsetof(bGPDlayer, info));
- if (gpl == NULL) {
- /* no layer - use active (only if layer deleted before paste) */
- gpl = CTX_data_active_gpencil_layer(C);
- }
- }
-
- /* Ensure we have a frame to draw into
- * NOTE: Since this is an op which creates strokes,
- * we are obliged to add a new frame if one
- * doesn't exist already
- */
- gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
- if (gpf) {
- /* Create new stroke */
- bGPDstroke *new_stroke = MEM_dupallocN(gps);
- new_stroke->runtime.tmp_layerinfo[0] = '\0';
-
- new_stroke->points = MEM_dupallocN(gps->points);
- if (gps->dvert != NULL) {
- new_stroke->dvert = MEM_dupallocN(gps->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps, new_stroke);
- }
- new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
- new_stroke->triangles = NULL;
-
- new_stroke->next = new_stroke->prev = NULL;
- BLI_addtail(&gpf->strokes, new_stroke);
-
- /* Remap material */
- Material *ma = BLI_ghash_lookup(new_colors, POINTER_FROM_INT(new_stroke->mat_nr));
- new_stroke->mat_nr = BKE_gpencil_object_material_get_index(ob, ma);
- BLI_assert(new_stroke->mat_nr >= 0); /* have to add the material first */
- }
- }
- }
-
- /* free temp data */
- BLI_ghash_free(new_colors, NULL, NULL);
-
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only use active for copy merge */
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+ bGPDframe *gpf;
+
+ eGP_PasteMode type = RNA_enum_get(op->ptr, "type");
+ GHash *new_colors;
+
+ /* check for various error conditions */
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
+ else if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
+ return OPERATOR_CANCELLED;
+ }
+ else if (BLI_listbase_is_empty(&gp_strokes_copypastebuf)) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "No strokes to paste, select and copy some points before trying again");
+ return OPERATOR_CANCELLED;
+ }
+ else if (gpl == NULL) {
+ /* no active layer - let's just create one */
+ gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ }
+ else if ((gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_MERGE)) {
+ BKE_report(
+ op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* Check that some of the strokes in the buffer can be used */
+ bGPDstroke *gps;
+ bool ok = false;
+
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ ok = true;
+ break;
+ }
+ }
+
+ if (ok == false) {
+ /* XXX: this check is not 100% accurate (i.e. image editor is incompatible with normal 2D strokes),
+ * but should be enough to give users a good idea of what's going on
+ */
+ if (CTX_wm_area(C)->spacetype == SPACE_VIEW3D)
+ BKE_report(op->reports, RPT_ERROR, "Cannot paste 2D strokes in 3D View");
+ else
+ BKE_report(op->reports, RPT_ERROR, "Cannot paste 3D strokes in 2D editors");
+
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ /* Deselect all strokes first */
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ CTX_DATA_END;
+
+ /* Ensure that all the necessary colors exist */
+ new_colors = gp_copybuf_validate_colormap(C);
+
+ /* Copy over the strokes from the buffer (and adjust the colors) */
+ for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ /* Need to verify if layer exists */
+ if (type != GP_COPY_MERGE) {
+ gpl = BLI_findstring(&gpd->layers, gps->runtime.tmp_layerinfo, offsetof(bGPDlayer, info));
+ if (gpl == NULL) {
+ /* no layer - use active (only if layer deleted before paste) */
+ gpl = CTX_data_active_gpencil_layer(C);
+ }
+ }
+
+ /* Ensure we have a frame to draw into
+ * NOTE: Since this is an op which creates strokes,
+ * we are obliged to add a new frame if one
+ * doesn't exist already
+ */
+ gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
+ if (gpf) {
+ /* Create new stroke */
+ bGPDstroke *new_stroke = MEM_dupallocN(gps);
+ new_stroke->runtime.tmp_layerinfo[0] = '\0';
+
+ new_stroke->points = MEM_dupallocN(gps->points);
+ if (gps->dvert != NULL) {
+ new_stroke->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, new_stroke);
+ }
+ new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
+ new_stroke->triangles = NULL;
+
+ new_stroke->next = new_stroke->prev = NULL;
+ BLI_addtail(&gpf->strokes, new_stroke);
+
+ /* Remap material */
+ Material *ma = BLI_ghash_lookup(new_colors, POINTER_FROM_INT(new_stroke->mat_nr));
+ new_stroke->mat_nr = BKE_gpencil_object_material_get_index(ob, ma);
+ BLI_assert(new_stroke->mat_nr >= 0); /* have to add the material first */
+ }
+ }
+ }
+
+ /* free temp data */
+ BLI_ghash_free(new_colors, NULL, NULL);
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_paste(wmOperatorType *ot)
{
- static const EnumPropertyItem copy_type[] = {
- {GP_COPY_ONLY, "COPY", 0, "Copy", ""},
- {GP_COPY_MERGE, "MERGE", 0, "Merge", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Paste Strokes";
- ot->idname = "GPENCIL_OT_paste";
- ot->description = "Paste previously copied strokes or copy and merge in active layer";
-
- /* callbacks */
- ot->exec = gp_strokes_paste_exec;
- ot->poll = gp_strokes_paste_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", copy_type, 0, "Type", "");
+ static const EnumPropertyItem copy_type[] = {
+ {GP_COPY_ONLY, "COPY", 0, "Copy", ""},
+ {GP_COPY_MERGE, "MERGE", 0, "Merge", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Paste Strokes";
+ ot->idname = "GPENCIL_OT_paste";
+ ot->description = "Paste previously copied strokes or copy and merge in active layer";
+
+ /* callbacks */
+ ot->exec = gp_strokes_paste_exec;
+ ot->poll = gp_strokes_paste_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", copy_type, 0, "Type", "");
}
/* ******************* Move To Layer ****************************** */
static int gp_move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
{
- uiPopupMenu *pup;
- uiLayout *layout;
+ uiPopupMenu *pup;
+ uiLayout *layout;
- /* call the menu, which will call this operator again, hence the canceled */
- pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
- layout = UI_popup_menu_layout(pup);
- uiItemsEnumO(layout, "GPENCIL_OT_move_to_layer", "layer");
- UI_popup_menu_end(C, pup);
+ /* call the menu, which will call this operator again, hence the canceled */
+ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
+ uiItemsEnumO(layout, "GPENCIL_OT_move_to_layer", "layer");
+ UI_popup_menu_end(C, pup);
- return OPERATOR_INTERFACE;
+ return OPERATOR_INTERFACE;
}
// FIXME: allow moving partial strokes
static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
- bGPDlayer *target_layer = NULL;
- ListBase strokes = {NULL, NULL};
- int layer_num = RNA_enum_get(op->ptr, "layer");
- const bool use_autolock = (bool)(gpd->flag & GP_DATA_AUTOLOCK_LAYERS);
-
- if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
- BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
- return OPERATOR_CANCELLED;
- }
-
- /* if autolock enabled, disabled now */
- if (use_autolock) {
- gpd->flag &= ~GP_DATA_AUTOLOCK_LAYERS;
- }
-
- /* Get layer or create new one */
- if (layer_num == -1) {
- /* Create layer */
- target_layer = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
- }
- else {
- /* Try to get layer */
- target_layer = BLI_findlink(&gpd->layers, layer_num);
-
- if (target_layer == NULL) {
- /* back autolock status */
- if (use_autolock) {
- gpd->flag |= GP_DATA_AUTOLOCK_LAYERS;
- }
- BKE_reportf(op->reports, RPT_ERROR, "There is no layer number %d", layer_num);
- return OPERATOR_CANCELLED;
- }
- }
-
- /* Extract all strokes to move to this layer
- * NOTE: We need to do this in a two-pass system to avoid conflicts with strokes
- * getting repeatedly moved
- */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps, *gpsn;
-
- /* skip if no frame with strokes, or if this is the layer we're moving strokes to */
- if ((gpl == target_layer) || (gpf == NULL))
- continue;
-
- /* make copies of selected strokes, and deselect these once we're done */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- /* TODO: Don't just move entire strokes - instead, only copy the selected portions... */
- if (gps->flag & GP_STROKE_SELECT) {
- BLI_remlink(&gpf->strokes, gps);
- BLI_addtail(&strokes, gps);
- }
- }
-
- /* if new layer and autolock, lock old layer */
- if ((layer_num == -1) && (use_autolock)) {
- gpl->flag |= GP_LAYER_LOCKED;
- }
- }
- CTX_DATA_END;
-
- /* Paste them all in one go */
- if (strokes.first) {
- bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, cfra_eval, GP_GETFRAME_ADD_NEW);
-
- BLI_movelisttolist(&gpf->strokes, &strokes);
- BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL));
- }
-
- /* back autolock status */
- if (use_autolock) {
- gpd->flag |= GP_DATA_AUTOLOCK_LAYERS;
- }
-
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+ bGPDlayer *target_layer = NULL;
+ ListBase strokes = {NULL, NULL};
+ int layer_num = RNA_enum_get(op->ptr, "layer");
+ const bool use_autolock = (bool)(gpd->flag & GP_DATA_AUTOLOCK_LAYERS);
+
+ if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* if autolock enabled, disabled now */
+ if (use_autolock) {
+ gpd->flag &= ~GP_DATA_AUTOLOCK_LAYERS;
+ }
+
+ /* Get layer or create new one */
+ if (layer_num == -1) {
+ /* Create layer */
+ target_layer = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ }
+ else {
+ /* Try to get layer */
+ target_layer = BLI_findlink(&gpd->layers, layer_num);
+
+ if (target_layer == NULL) {
+ /* back autolock status */
+ if (use_autolock) {
+ gpd->flag |= GP_DATA_AUTOLOCK_LAYERS;
+ }
+ BKE_reportf(op->reports, RPT_ERROR, "There is no layer number %d", layer_num);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ /* Extract all strokes to move to this layer
+ * NOTE: We need to do this in a two-pass system to avoid conflicts with strokes
+ * getting repeatedly moved
+ */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps, *gpsn;
+
+ /* skip if no frame with strokes, or if this is the layer we're moving strokes to */
+ if ((gpl == target_layer) || (gpf == NULL))
+ continue;
+
+ /* make copies of selected strokes, and deselect these once we're done */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ /* TODO: Don't just move entire strokes - instead, only copy the selected portions... */
+ if (gps->flag & GP_STROKE_SELECT) {
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_addtail(&strokes, gps);
+ }
+ }
+
+ /* if new layer and autolock, lock old layer */
+ if ((layer_num == -1) && (use_autolock)) {
+ gpl->flag |= GP_LAYER_LOCKED;
+ }
+ }
+ CTX_DATA_END;
+
+ /* Paste them all in one go */
+ if (strokes.first) {
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, cfra_eval, GP_GETFRAME_ADD_NEW);
+
+ BLI_movelisttolist(&gpf->strokes, &strokes);
+ BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL));
+ }
+
+ /* back autolock status */
+ if (use_autolock) {
+ gpd->flag |= GP_DATA_AUTOLOCK_LAYERS;
+ }
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Move Strokes to Layer";
- ot->idname = "GPENCIL_OT_move_to_layer";
- ot->description = "Move selected strokes to another layer"; // XXX: allow moving individual points too?
-
- /* callbacks */
- ot->invoke = gp_move_to_layer_invoke;
- ot->exec = gp_move_to_layer_exec;
- ot->poll = gp_stroke_edit_poll; // XXX?
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* gp layer to use (dynamic enum) */
- ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", "");
- RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
+ /* identifiers */
+ ot->name = "Move Strokes to Layer";
+ ot->idname = "GPENCIL_OT_move_to_layer";
+ ot->description =
+ "Move selected strokes to another layer"; // XXX: allow moving individual points too?
+
+ /* callbacks */
+ ot->invoke = gp_move_to_layer_invoke;
+ ot->exec = gp_move_to_layer_exec;
+ ot->poll = gp_stroke_edit_poll; // XXX?
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* gp layer to use (dynamic enum) */
+ ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", "");
+ RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
}
/* ********************* Add Blank Frame *************************** */
@@ -1510,221 +1513,224 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
/* Basically the same as the drawing op */
static bool UNUSED_FUNCTION(gp_blank_frame_add_poll)(bContext *C)
{
- if (ED_operator_regionactive(C)) {
- /* check if current context can support GPencil data */
- if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
- return 1;
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
- }
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Active region not set");
- }
-
- return 0;
+ if (ED_operator_regionactive(C)) {
+ /* check if current context can support GPencil data */
+ if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
+ return 1;
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
+ }
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ }
+
+ return 0;
}
static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
-
- bGPDlayer *active_gpl = BKE_gpencil_layer_getactive(gpd);
-
- const bool all_layers = RNA_boolean_get(op->ptr, "all_layers");
-
- /* Initialise datablock and an active layer if nothing exists yet */
- if (ELEM(NULL, gpd, active_gpl)) {
- /* let's just be lazy, and call the "Add New Layer" operator, which sets everything up as required */
- WM_operator_name_call(C, "GPENCIL_OT_layer_add", WM_OP_EXEC_DEFAULT, NULL);
- }
-
- /* Go through each layer, adding a frame after the active one
- * and/or shunting all the others out of the way
- */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- if ((all_layers == false) && (gpl != active_gpl)) {
- continue;
- }
-
- /* 1) Check for an existing frame on the current frame */
- bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, cfra_eval);
- if (gpf) {
- /* Shunt all frames after (and including) the existing one later by 1-frame */
- for (; gpf; gpf = gpf->next) {
- gpf->framenum += 1;
- }
- }
-
- /* 2) Now add a new frame, with nothing in it */
- gpl->actframe = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
- }
- CTX_DATA_END;
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDlayer *active_gpl = BKE_gpencil_layer_getactive(gpd);
+
+ const bool all_layers = RNA_boolean_get(op->ptr, "all_layers");
+
+ /* Initialise datablock and an active layer if nothing exists yet */
+ if (ELEM(NULL, gpd, active_gpl)) {
+ /* let's just be lazy, and call the "Add New Layer" operator, which sets everything up as required */
+ WM_operator_name_call(C, "GPENCIL_OT_layer_add", WM_OP_EXEC_DEFAULT, NULL);
+ }
+
+ /* Go through each layer, adding a frame after the active one
+ * and/or shunting all the others out of the way
+ */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ if ((all_layers == false) && (gpl != active_gpl)) {
+ continue;
+ }
+
+ /* 1) Check for an existing frame on the current frame */
+ bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, cfra_eval);
+ if (gpf) {
+ /* Shunt all frames after (and including) the existing one later by 1-frame */
+ for (; gpf; gpf = gpf->next) {
+ gpf->framenum += 1;
+ }
+ }
+
+ /* 2) Now add a new frame, with nothing in it */
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_blank_frame_add(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Insert Blank Frame";
- ot->idname = "GPENCIL_OT_blank_frame_add";
- ot->description = "Insert a blank frame on the current frame "
- "(all subsequently existing frames, if any, are shifted right by one frame)";
-
- /* callbacks */
- ot->exec = gp_blank_frame_add_exec;
- ot->poll = gp_add_poll;
-
- /* properties */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "all_layers", false, "All Layers", "Create blank frame in all layers, not only active");
+ /* identifiers */
+ ot->name = "Insert Blank Frame";
+ ot->idname = "GPENCIL_OT_blank_frame_add";
+ ot->description =
+ "Insert a blank frame on the current frame "
+ "(all subsequently existing frames, if any, are shifted right by one frame)";
+
+ /* callbacks */
+ ot->exec = gp_blank_frame_add_exec;
+ ot->poll = gp_add_poll;
+
+ /* properties */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_boolean(ot->srna,
+ "all_layers",
+ false,
+ "All Layers",
+ "Create blank frame in all layers, not only active");
}
/* ******************* Delete Active Frame ************************ */
static bool gp_actframe_delete_poll(bContext *C)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- /* only if there's an active layer with an active frame */
- return (gpl && gpl->actframe);
+ /* only if there's an active layer with an active frame */
+ return (gpl && gpl->actframe);
}
/* delete active frame - wrapper around API calls */
static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
- /* if there's no existing Grease-Pencil data there, add some */
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No grease pencil data");
- return OPERATOR_CANCELLED;
- }
- if (ELEM(NULL, gpl, gpf)) {
- BKE_report(op->reports, RPT_ERROR, "No active frame to delete");
- return OPERATOR_CANCELLED;
- }
+ /* if there's no existing Grease-Pencil data there, add some */
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No grease pencil data");
+ return OPERATOR_CANCELLED;
+ }
+ if (ELEM(NULL, gpl, gpf)) {
+ BKE_report(op->reports, RPT_ERROR, "No active frame to delete");
+ return OPERATOR_CANCELLED;
+ }
- /* delete it... */
- BKE_gpencil_layer_delframe(gpl, gpf);
+ /* delete it... */
+ BKE_gpencil_layer_delframe(gpl, gpf);
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Delete Active Frame";
- ot->idname = "GPENCIL_OT_active_frame_delete";
- ot->description = "Delete the active frame for the active Grease Pencil Layer";
+ /* identifiers */
+ ot->name = "Delete Active Frame";
+ ot->idname = "GPENCIL_OT_active_frame_delete";
+ ot->description = "Delete the active frame for the active Grease Pencil Layer";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* callbacks */
- ot->exec = gp_actframe_delete_exec;
- ot->poll = gp_actframe_delete_poll;
+ /* callbacks */
+ ot->exec = gp_actframe_delete_exec;
+ ot->poll = gp_actframe_delete_poll;
}
/* **************** Delete All Active Frames ****************** */
static bool gp_actframe_delete_all_poll(bContext *C)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
- /* 1) There must be grease pencil data
- * 2) Hopefully some of the layers have stuff we can use
- */
- return (gpd && gpd->layers.first);
+ /* 1) There must be grease pencil data
+ * 2) Hopefully some of the layers have stuff we can use
+ */
+ return (gpd && gpd->layers.first);
}
static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
-
- bool success = false;
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- /* try to get the "active" frame - but only if it actually occurs on this frame */
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
-
- if (gpf == NULL)
- continue;
-
- /* delete it... */
- BKE_gpencil_layer_delframe(gpl, gpf);
-
- /* we successfully modified something */
- success = true;
- }
- CTX_DATA_END;
-
- /* updates */
- if (success) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
- }
- else {
- BKE_report(op->reports, RPT_ERROR, "No active frame(s) to delete");
- return OPERATOR_CANCELLED;
- }
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bool success = false;
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ /* try to get the "active" frame - but only if it actually occurs on this frame */
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
+
+ if (gpf == NULL)
+ continue;
+
+ /* delete it... */
+ BKE_gpencil_layer_delframe(gpl, gpf);
+
+ /* we successfully modified something */
+ success = true;
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ if (success) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No active frame(s) to delete");
+ return OPERATOR_CANCELLED;
+ }
}
void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Delete All Active Frames";
- ot->idname = "GPENCIL_OT_active_frames_delete_all";
- ot->description = "Delete the active frame(s) of all editable Grease Pencil layers";
+ /* identifiers */
+ ot->name = "Delete All Active Frames";
+ ot->idname = "GPENCIL_OT_active_frames_delete_all";
+ ot->description = "Delete the active frame(s) of all editable Grease Pencil layers";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* callbacks */
- ot->exec = gp_actframe_delete_all_exec;
- ot->poll = gp_actframe_delete_all_poll;
+ /* callbacks */
+ ot->exec = gp_actframe_delete_all_exec;
+ ot->poll = gp_actframe_delete_all_poll;
}
/* ******************* Delete Operator ************************ */
typedef enum eGP_DeleteMode {
- /* delete selected stroke points */
- GP_DELETEOP_POINTS = 0,
- /* delete selected strokes */
- GP_DELETEOP_STROKES = 1,
- /* delete active frame */
- GP_DELETEOP_FRAME = 2,
+ /* delete selected stroke points */
+ GP_DELETEOP_POINTS = 0,
+ /* delete selected strokes */
+ GP_DELETEOP_STROKES = 1,
+ /* delete active frame */
+ GP_DELETEOP_FRAME = 2,
} eGP_DeleteMode;
typedef enum eGP_DissolveMode {
- /* dissolve all selected points */
- GP_DISSOLVE_POINTS = 0,
- /* dissolve between selected points */
- GP_DISSOLVE_BETWEEN = 1,
- /* dissolve unselected points */
- GP_DISSOLVE_UNSELECT = 2,
+ /* dissolve all selected points */
+ GP_DISSOLVE_POINTS = 0,
+ /* dissolve between selected points */
+ GP_DISSOLVE_BETWEEN = 1,
+ /* dissolve unselected points */
+ GP_DISSOLVE_UNSELECT = 2,
} eGP_DissolveMode;
/* ----------------------------------- */
@@ -1732,61 +1738,60 @@ typedef enum eGP_DissolveMode {
/* Delete selected strokes */
static int gp_delete_selected_strokes(bContext *C)
{
- bool changed = false;
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- bGPDstroke *gps, *gpsn;
-
- if (gpf == NULL)
- continue;
-
- /* simply delete strokes which are selected */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- /* free stroke if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- /* free stroke memory arrays, then stroke itself */
- if (gps->points) {
- MEM_freeN(gps->points);
- }
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
- MEM_SAFE_FREE(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
-
- changed = true;
- }
- }
- }
- }
- }
- CTX_DATA_END;
-
- if (changed) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ bool changed = false;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL)
+ continue;
+
+ /* simply delete strokes which are selected */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ /* free stroke if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* free stroke memory arrays, then stroke itself */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ MEM_SAFE_FREE(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
/* ----------------------------------- */
@@ -1794,242 +1799,242 @@ static int gp_delete_selected_strokes(bContext *C)
/* Delete selected points but keep the stroke */
static int gp_dissolve_selected_points(bContext *C, eGP_DissolveMode mode)
{
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- bool changed = false;
- int first = 0;
- int last = 0;
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
-
- bGPDstroke *gps, *gpsn;
-
- if (gpf == NULL)
- continue;
-
- /* simply delete points from selected strokes
- * NOTE: we may still have to remove the stroke if it ends up having no points!
- */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
- continue;
-
- /* the stroke must have at least one point selected for any operator */
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- MDeformVert *dvert = NULL;
- int i;
-
- int tot = gps->totpoints; /* number of points in new buffer */
-
- /* first pass: count points to remove */
- switch (mode) {
- case GP_DISSOLVE_POINTS:
- /* Count how many points are selected (i.e. how many to remove) */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- /* selected point - one of the points to remove */
- tot--;
- }
- }
- break;
- case GP_DISSOLVE_BETWEEN:
- /* need to find first and last point selected */
- first = -1;
- last = 0;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- if (first < 0) {
- first = i;
- }
- last = i;
- }
- }
- /* count unselected points in the range */
- for (i = first, pt = gps->points + first; i < last; i++, pt++) {
- if ((pt->flag & GP_SPOINT_SELECT) == 0) {
- tot--;
- }
- }
- break;
- case GP_DISSOLVE_UNSELECT:
- /* count number of unselected points */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if ((pt->flag & GP_SPOINT_SELECT) == 0) {
- tot--;
- }
- }
- break;
- default:
- return false;
- break;
- }
-
- /* if no points are left, we simply delete the entire stroke */
- if (tot <= 0) {
- /* remove the entire stroke */
- if (gps->points) {
- MEM_freeN(gps->points);
- }
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
- if (gps->triangles) {
- MEM_freeN(gps->triangles);
- }
- BLI_freelinkN(&gpf->strokes, gps);
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- }
- else {
- /* just copy all points to keep into a smaller buffer */
- bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy");
- bGPDspoint *npt = new_points;
-
- MDeformVert *new_dvert = NULL;
- MDeformVert *ndvert = NULL;
-
- if (gps->dvert != NULL) {
- new_dvert = MEM_callocN(sizeof(MDeformVert) * tot, "new gp stroke weights copy");
- ndvert = new_dvert;
- }
-
- switch (mode) {
- case GP_DISSOLVE_POINTS:
- (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if ((pt->flag & GP_SPOINT_SELECT) == 0) {
- *npt = *pt;
- npt++;
-
- if (gps->dvert != NULL) {
- *ndvert = *dvert;
- ndvert->dw = MEM_dupallocN(dvert->dw);
- ndvert++;
- dvert++;
- }
- }
- }
- break;
- case GP_DISSOLVE_BETWEEN:
- /* copy first segment */
- (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
- for (i = 0, pt = gps->points; i < first; i++, pt++) {
- *npt = *pt;
- npt++;
-
- if (gps->dvert != NULL) {
- *ndvert = *dvert;
- ndvert->dw = MEM_dupallocN(dvert->dw);
- ndvert++;
- dvert++;
- }
- }
- /* copy segment (selected points) */
- (gps->dvert != NULL) ? dvert = gps->dvert + first : NULL;
- for (i = first, pt = gps->points + first; i < last; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- *npt = *pt;
- npt++;
-
- if (gps->dvert != NULL) {
- *ndvert = *dvert;
- ndvert->dw = MEM_dupallocN(dvert->dw);
- ndvert++;
- dvert++;
- }
- }
- }
- /* copy last segment */
- (gps->dvert != NULL) ? dvert = gps->dvert + last : NULL;
- for (i = last, pt = gps->points + last; i < gps->totpoints; i++, pt++) {
- *npt = *pt;
- npt++;
-
- if (gps->dvert != NULL) {
- *ndvert = *dvert;
- ndvert->dw = MEM_dupallocN(dvert->dw);
- ndvert++;
- dvert++;
- }
- }
-
- break;
- case GP_DISSOLVE_UNSELECT:
- /* copy any selected point */
- (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- *npt = *pt;
- npt++;
-
- if (gps->dvert != NULL) {
- *ndvert = *dvert;
- ndvert->dw = MEM_dupallocN(dvert->dw);
- ndvert++;
- dvert++;
- }
- }
- }
- break;
- }
-
- /* free the old buffer */
- if (gps->points) {
- MEM_freeN(gps->points);
- }
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
-
- /* save the new buffer */
- gps->points = new_points;
- gps->dvert = new_dvert;
- gps->totpoints = tot;
-
- /* triangles cache needs to be recalculated */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
-
- /* deselect the stroke, since none of its selected points will still be selected */
- gps->flag &= ~GP_STROKE_SELECT;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
- }
-
- changed = true;
- }
- }
- }
- }
- }
- CTX_DATA_END;
-
- if (changed) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ bool changed = false;
+ int first = 0;
+ int last = 0;
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL)
+ continue;
+
+ /* simply delete points from selected strokes
+ * NOTE: we may still have to remove the stroke if it ends up having no points!
+ */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
+ continue;
+
+ /* the stroke must have at least one point selected for any operator */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ MDeformVert *dvert = NULL;
+ int i;
+
+ int tot = gps->totpoints; /* number of points in new buffer */
+
+ /* first pass: count points to remove */
+ switch (mode) {
+ case GP_DISSOLVE_POINTS:
+ /* Count how many points are selected (i.e. how many to remove) */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* selected point - one of the points to remove */
+ tot--;
+ }
+ }
+ break;
+ case GP_DISSOLVE_BETWEEN:
+ /* need to find first and last point selected */
+ first = -1;
+ last = 0;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (first < 0) {
+ first = i;
+ }
+ last = i;
+ }
+ }
+ /* count unselected points in the range */
+ for (i = first, pt = gps->points + first; i < last; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) == 0) {
+ tot--;
+ }
+ }
+ break;
+ case GP_DISSOLVE_UNSELECT:
+ /* count number of unselected points */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) == 0) {
+ tot--;
+ }
+ }
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ /* if no points are left, we simply delete the entire stroke */
+ if (tot <= 0) {
+ /* remove the entire stroke */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ if (gps->triangles) {
+ MEM_freeN(gps->triangles);
+ }
+ BLI_freelinkN(&gpf->strokes, gps);
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+ else {
+ /* just copy all points to keep into a smaller buffer */
+ bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot,
+ "new gp stroke points copy");
+ bGPDspoint *npt = new_points;
+
+ MDeformVert *new_dvert = NULL;
+ MDeformVert *ndvert = NULL;
+
+ if (gps->dvert != NULL) {
+ new_dvert = MEM_callocN(sizeof(MDeformVert) * tot, "new gp stroke weights copy");
+ ndvert = new_dvert;
+ }
+
+ switch (mode) {
+ case GP_DISSOLVE_POINTS:
+ (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) == 0) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+ }
+ break;
+ case GP_DISSOLVE_BETWEEN:
+ /* copy first segment */
+ (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
+ for (i = 0, pt = gps->points; i < first; i++, pt++) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+ /* copy segment (selected points) */
+ (gps->dvert != NULL) ? dvert = gps->dvert + first : NULL;
+ for (i = first, pt = gps->points + first; i < last; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+ }
+ /* copy last segment */
+ (gps->dvert != NULL) ? dvert = gps->dvert + last : NULL;
+ for (i = last, pt = gps->points + last; i < gps->totpoints; i++, pt++) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+
+ break;
+ case GP_DISSOLVE_UNSELECT:
+ /* copy any selected point */
+ (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+ }
+ break;
+ }
+
+ /* free the old buffer */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+
+ /* save the new buffer */
+ gps->points = new_points;
+ gps->dvert = new_dvert;
+ gps->totpoints = tot;
+
+ /* triangles cache needs to be recalculated */
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
+
+ /* deselect the stroke, since none of its selected points will still be selected */
+ gps->flag &= ~GP_STROKE_SELECT;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
/* ----------------------------------- */
@@ -2039,94 +2044,93 @@ static int gp_dissolve_selected_points(bContext *C, eGP_DissolveMode mode)
* gp_stroke_delete_tagged_points()
*/
typedef struct tGPDeleteIsland {
- int start_idx;
- int end_idx;
+ int start_idx;
+ int end_idx;
} tGPDeleteIsland;
static void gp_stroke_join_islands(bGPDframe *gpf, bGPDstroke *gps_first, bGPDstroke *gps_last)
{
- bGPDspoint *pt = NULL;
- bGPDspoint *pt_final = NULL;
- const int totpoints = gps_first->totpoints + gps_last->totpoints;
-
- /* create new stroke */
- bGPDstroke *join_stroke = MEM_dupallocN(gps_first);
-
- join_stroke->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__);
- join_stroke->totpoints = totpoints;
- join_stroke->flag &= ~GP_STROKE_CYCLIC;
-
- /* copy points (last before) */
- int e1 = 0;
- int e2 = 0;
- float delta = 0.0f;
-
- for (int i = 0; i < totpoints; i++) {
- pt_final = &join_stroke->points[i];
- if (i < gps_last->totpoints) {
- pt = &gps_last->points[e1];
- e1++;
- }
- else {
- pt = &gps_first->points[e2];
- e2++;
- }
-
- /* copy current point */
- copy_v3_v3(&pt_final->x, &pt->x);
- pt_final->pressure = pt->pressure;
- pt_final->strength = pt->strength;
- pt_final->time = delta;
- pt_final->flag = pt->flag;
-
- /* retiming with fixed time interval (we cannot determine real time) */
- delta += 0.01f;
- }
-
- /* Copy over vertex weight data (if available) */
- if ((gps_first->dvert != NULL) || (gps_last->dvert != NULL)) {
- join_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * totpoints, __func__);
- MDeformVert *dvert_src = NULL;
- MDeformVert *dvert_dst = NULL;
-
- /* Copy weights (last before)*/
- e1 = 0;
- e2 = 0;
- for (int i = 0; i < totpoints; i++) {
- dvert_dst = &join_stroke->dvert[i];
- dvert_src = NULL;
- if (i < gps_last->totpoints) {
- if (gps_last->dvert) {
- dvert_src = &gps_last->dvert[e1];
- e1++;
- }
- }
- else {
- if (gps_first->dvert) {
- dvert_src = &gps_first->dvert[e2];
- e2++;
- }
- }
-
- if ((dvert_src) && (dvert_src->dw)) {
- dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
- }
- }
- }
-
- /* add new stroke at head */
- BLI_addhead(&gpf->strokes, join_stroke);
-
- /* remove first stroke */
- BLI_remlink(&gpf->strokes, gps_first);
- BKE_gpencil_free_stroke(gps_first);
-
- /* remove last stroke */
- BLI_remlink(&gpf->strokes, gps_last);
- BKE_gpencil_free_stroke(gps_last);
+ bGPDspoint *pt = NULL;
+ bGPDspoint *pt_final = NULL;
+ const int totpoints = gps_first->totpoints + gps_last->totpoints;
+
+ /* create new stroke */
+ bGPDstroke *join_stroke = MEM_dupallocN(gps_first);
+
+ join_stroke->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__);
+ join_stroke->totpoints = totpoints;
+ join_stroke->flag &= ~GP_STROKE_CYCLIC;
+
+ /* copy points (last before) */
+ int e1 = 0;
+ int e2 = 0;
+ float delta = 0.0f;
+
+ for (int i = 0; i < totpoints; i++) {
+ pt_final = &join_stroke->points[i];
+ if (i < gps_last->totpoints) {
+ pt = &gps_last->points[e1];
+ e1++;
+ }
+ else {
+ pt = &gps_first->points[e2];
+ e2++;
+ }
+
+ /* copy current point */
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = delta;
+ pt_final->flag = pt->flag;
+
+ /* retiming with fixed time interval (we cannot determine real time) */
+ delta += 0.01f;
+ }
+
+ /* Copy over vertex weight data (if available) */
+ if ((gps_first->dvert != NULL) || (gps_last->dvert != NULL)) {
+ join_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * totpoints, __func__);
+ MDeformVert *dvert_src = NULL;
+ MDeformVert *dvert_dst = NULL;
+
+ /* Copy weights (last before)*/
+ e1 = 0;
+ e2 = 0;
+ for (int i = 0; i < totpoints; i++) {
+ dvert_dst = &join_stroke->dvert[i];
+ dvert_src = NULL;
+ if (i < gps_last->totpoints) {
+ if (gps_last->dvert) {
+ dvert_src = &gps_last->dvert[e1];
+ e1++;
+ }
+ }
+ else {
+ if (gps_first->dvert) {
+ dvert_src = &gps_first->dvert[e2];
+ e2++;
+ }
+ }
+
+ if ((dvert_src) && (dvert_src->dw)) {
+ dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ }
+ }
+ }
+
+ /* add new stroke at head */
+ BLI_addhead(&gpf->strokes, join_stroke);
+
+ /* remove first stroke */
+ BLI_remlink(&gpf->strokes, gps_first);
+ BKE_gpencil_free_stroke(gps_first);
+
+ /* remove last stroke */
+ BLI_remlink(&gpf->strokes, gps_last);
+ BKE_gpencil_free_stroke(gps_last);
}
-
/* Split the given stroke into several new strokes, partitioning
* it based on whether the stroke points have a particular flag
* is set (e.g. "GP_SPOINT_SELECT" in most cases, but not always)
@@ -2141,290 +2145,315 @@ static void gp_stroke_join_islands(bGPDframe *gpf, bGPDstroke *gps_first, bGPDst
* 2) Each island gets converted to a new stroke
* If the number of points is <= limit, the stroke is deleted
*/
-void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke,
- int tag_flags, bool select, int limit)
+void gp_stroke_delete_tagged_points(bGPDframe *gpf,
+ bGPDstroke *gps,
+ bGPDstroke *next_stroke,
+ int tag_flags,
+ bool select,
+ int limit)
{
- tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands");
- bool in_island = false;
- int num_islands = 0;
-
- bGPDstroke *gps_first = NULL;
- const bool is_cyclic = (bool)(gps->flag & GP_STROKE_CYCLIC);
-
- /* First Pass: Identify start/end of islands */
- bGPDspoint *pt = gps->points;
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- if (pt->flag & tag_flags) {
- /* selected - stop accumulating to island */
- in_island = false;
- }
- else {
- /* unselected - start of a new island? */
- int idx;
-
- if (in_island) {
- /* extend existing island */
- idx = num_islands - 1;
- islands[idx].end_idx = i;
- }
- else {
- /* start of new island */
- in_island = true;
- num_islands++;
-
- idx = num_islands - 1;
- islands[idx].start_idx = islands[idx].end_idx = i;
- }
- }
- }
-
- /* Watch out for special case where No islands = All points selected = Delete Stroke only */
- if (num_islands) {
- /* there are islands, so create a series of new strokes, adding them before the "next" stroke */
- int idx;
- bGPDstroke *new_stroke = NULL;
-
- /* Create each new stroke... */
- for (idx = 0; idx < num_islands; idx++) {
- tGPDeleteIsland *island = &islands[idx];
- new_stroke = MEM_dupallocN(gps);
-
- /* if cyclic and first stroke, save to join later */
- if ((is_cyclic) && (gps_first == NULL)) {
- gps_first = new_stroke;
- }
-
- /* initialize triangle memory - to be calculated on next redraw */
- new_stroke->triangles = NULL;
- new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
- new_stroke->flag &= ~GP_STROKE_CYCLIC;
- new_stroke->tot_triangles = 0;
-
- /* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */
- new_stroke->totpoints = island->end_idx - island->start_idx + 1;
-
- /* Copy over the relevant point data */
- new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment");
- memcpy(new_stroke->points, gps->points + island->start_idx, sizeof(bGPDspoint) * new_stroke->totpoints);
-
- /* Copy over vertex weight data (if available) */
- if (gps->dvert != NULL) {
- /* Copy over the relevant vertex-weight points */
- new_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints, "gp delete stroke fragment weight");
- memcpy(new_stroke->dvert, gps->dvert + island->start_idx, sizeof(MDeformVert) * new_stroke->totpoints);
-
- /* Copy weights */
- int e = island->start_idx;
- for (int i = 0; i < new_stroke->totpoints; i++) {
- MDeformVert *dvert_src = &gps->dvert[e];
- MDeformVert *dvert_dst = &new_stroke->dvert[i];
- if (dvert_src->dw) {
- dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
- }
- e++;
- }
- }
- /* Each island corresponds to a new stroke. We must adjust the
- * timings of these new strokes:
- *
- * Each point's timing data is a delta from stroke's inittime, so as we erase some points from
- * the start of the stroke, we have to offset this inittime and all remaining points' delta values.
- * This way we get a new stroke with exactly the same timing as if user had started drawing from
- * the first non-removed point...
- */
- {
- bGPDspoint *pts;
- float delta = gps->points[island->start_idx].time;
- int j;
-
- new_stroke->inittime += (double)delta;
-
- pts = new_stroke->points;
- for (j = 0; j < new_stroke->totpoints; j++, pts++) {
- pts->time -= delta;
- /* set flag for select again later */
- if (select == true) {
- pts->flag &= ~GP_SPOINT_SELECT;
- pts->flag |= GP_SPOINT_TAG;
- }
- }
- }
-
- /* Add new stroke to the frame or delete if below limit */
- if ((limit > 0) && (new_stroke->totpoints <= limit)) {
- BKE_gpencil_free_stroke(new_stroke);
- }
- else {
- if (next_stroke) {
- BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke);
- }
- else {
- BLI_addtail(&gpf->strokes, new_stroke);
- }
- }
- }
- /* if cyclic, need to join last stroke with first stroke */
- if ((is_cyclic) && (gps_first != NULL) && (gps_first != new_stroke)) {
- gp_stroke_join_islands(gpf, gps_first, new_stroke);
- }
-
- }
-
- /* free islands */
- MEM_freeN(islands);
-
- /* Delete the old stroke */
- BLI_remlink(&gpf->strokes, gps);
- BKE_gpencil_free_stroke(gps);
+ tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2,
+ "gp_point_islands");
+ bool in_island = false;
+ int num_islands = 0;
+
+ bGPDstroke *gps_first = NULL;
+ const bool is_cyclic = (bool)(gps->flag & GP_STROKE_CYCLIC);
+
+ /* First Pass: Identify start/end of islands */
+ bGPDspoint *pt = gps->points;
+ for (int i = 0; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & tag_flags) {
+ /* selected - stop accumulating to island */
+ in_island = false;
+ }
+ else {
+ /* unselected - start of a new island? */
+ int idx;
+
+ if (in_island) {
+ /* extend existing island */
+ idx = num_islands - 1;
+ islands[idx].end_idx = i;
+ }
+ else {
+ /* start of new island */
+ in_island = true;
+ num_islands++;
+
+ idx = num_islands - 1;
+ islands[idx].start_idx = islands[idx].end_idx = i;
+ }
+ }
+ }
+
+ /* Watch out for special case where No islands = All points selected = Delete Stroke only */
+ if (num_islands) {
+ /* there are islands, so create a series of new strokes, adding them before the "next" stroke */
+ int idx;
+ bGPDstroke *new_stroke = NULL;
+
+ /* Create each new stroke... */
+ for (idx = 0; idx < num_islands; idx++) {
+ tGPDeleteIsland *island = &islands[idx];
+ new_stroke = MEM_dupallocN(gps);
+
+ /* if cyclic and first stroke, save to join later */
+ if ((is_cyclic) && (gps_first == NULL)) {
+ gps_first = new_stroke;
+ }
+
+ /* initialize triangle memory - to be calculated on next redraw */
+ new_stroke->triangles = NULL;
+ new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
+ new_stroke->flag &= ~GP_STROKE_CYCLIC;
+ new_stroke->tot_triangles = 0;
+
+ /* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */
+ new_stroke->totpoints = island->end_idx - island->start_idx + 1;
+
+ /* Copy over the relevant point data */
+ new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints,
+ "gp delete stroke fragment");
+ memcpy(new_stroke->points,
+ gps->points + island->start_idx,
+ sizeof(bGPDspoint) * new_stroke->totpoints);
+
+ /* Copy over vertex weight data (if available) */
+ if (gps->dvert != NULL) {
+ /* Copy over the relevant vertex-weight points */
+ new_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints,
+ "gp delete stroke fragment weight");
+ memcpy(new_stroke->dvert,
+ gps->dvert + island->start_idx,
+ sizeof(MDeformVert) * new_stroke->totpoints);
+
+ /* Copy weights */
+ int e = island->start_idx;
+ for (int i = 0; i < new_stroke->totpoints; i++) {
+ MDeformVert *dvert_src = &gps->dvert[e];
+ MDeformVert *dvert_dst = &new_stroke->dvert[i];
+ if (dvert_src->dw) {
+ dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ }
+ e++;
+ }
+ }
+ /* Each island corresponds to a new stroke. We must adjust the
+ * timings of these new strokes:
+ *
+ * Each point's timing data is a delta from stroke's inittime, so as we erase some points from
+ * the start of the stroke, we have to offset this inittime and all remaining points' delta values.
+ * This way we get a new stroke with exactly the same timing as if user had started drawing from
+ * the first non-removed point...
+ */
+ {
+ bGPDspoint *pts;
+ float delta = gps->points[island->start_idx].time;
+ int j;
+
+ new_stroke->inittime += (double)delta;
+
+ pts = new_stroke->points;
+ for (j = 0; j < new_stroke->totpoints; j++, pts++) {
+ pts->time -= delta;
+ /* set flag for select again later */
+ if (select == true) {
+ pts->flag &= ~GP_SPOINT_SELECT;
+ pts->flag |= GP_SPOINT_TAG;
+ }
+ }
+ }
+
+ /* Add new stroke to the frame or delete if below limit */
+ if ((limit > 0) && (new_stroke->totpoints <= limit)) {
+ BKE_gpencil_free_stroke(new_stroke);
+ }
+ else {
+ if (next_stroke) {
+ BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke);
+ }
+ else {
+ BLI_addtail(&gpf->strokes, new_stroke);
+ }
+ }
+ }
+ /* if cyclic, need to join last stroke with first stroke */
+ if ((is_cyclic) && (gps_first != NULL) && (gps_first != new_stroke)) {
+ gp_stroke_join_islands(gpf, gps_first, new_stroke);
+ }
+ }
+
+ /* free islands */
+ MEM_freeN(islands);
+
+ /* Delete the old stroke */
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
}
/* Split selected strokes into segments, splitting on selected points */
static int gp_delete_selected_points(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- bool changed = false;
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- bGPDstroke *gps, *gpsn;
-
- if (gpf == NULL)
- continue;
-
- /* simply delete strokes which are selected */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
- continue;
-
-
- if (gps->flag & GP_STROKE_SELECT) {
- /* deselect old stroke, since it will be used as template for the new strokes */
- gps->flag &= ~GP_STROKE_SELECT;
-
- /* delete unwanted points by splitting stroke into several smaller ones */
- gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false, 0);
-
- changed = true;
- }
- }
- }
- }
- }
- CTX_DATA_END;
-
- if (changed) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ bool changed = false;
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL)
+ continue;
+
+ /* simply delete strokes which are selected */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
+ continue;
+
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* deselect old stroke, since it will be used as template for the new strokes */
+ gps->flag &= ~GP_STROKE_SELECT;
+
+ /* delete unwanted points by splitting stroke into several smaller ones */
+ gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false, 0);
+
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
/* simple wrapper to external call */
int gp_delete_selected_point_wrap(bContext *C)
{
- return gp_delete_selected_points(C);
+ return gp_delete_selected_points(C);
}
/* ----------------------------------- */
static int gp_delete_exec(bContext *C, wmOperator *op)
{
- eGP_DeleteMode mode = RNA_enum_get(op->ptr, "type");
- int result = OPERATOR_CANCELLED;
+ eGP_DeleteMode mode = RNA_enum_get(op->ptr, "type");
+ int result = OPERATOR_CANCELLED;
- switch (mode) {
- case GP_DELETEOP_STROKES: /* selected strokes */
- result = gp_delete_selected_strokes(C);
- break;
+ switch (mode) {
+ case GP_DELETEOP_STROKES: /* selected strokes */
+ result = gp_delete_selected_strokes(C);
+ break;
- case GP_DELETEOP_POINTS: /* selected points (breaks the stroke into segments) */
- result = gp_delete_selected_points(C);
- break;
+ case GP_DELETEOP_POINTS: /* selected points (breaks the stroke into segments) */
+ result = gp_delete_selected_points(C);
+ break;
- case GP_DELETEOP_FRAME: /* active frame */
- result = gp_actframe_delete_exec(C, op);
- break;
- }
+ case GP_DELETEOP_FRAME: /* active frame */
+ result = gp_actframe_delete_exec(C, op);
+ break;
+ }
- return result;
+ return result;
}
void GPENCIL_OT_delete(wmOperatorType *ot)
{
- static const EnumPropertyItem prop_gpencil_delete_types[] = {
- {GP_DELETEOP_POINTS, "POINTS", 0, "Points", "Delete selected points and split strokes into segments"},
- {GP_DELETEOP_STROKES, "STROKES", 0, "Strokes", "Delete selected strokes"},
- {GP_DELETEOP_FRAME, "FRAME", 0, "Frame", "Delete active frame"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Delete";
- ot->idname = "GPENCIL_OT_delete";
- ot->description = "Delete selected Grease Pencil strokes, vertices, or frames";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = gp_delete_exec;
- ot->poll = gp_stroke_edit_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
-
- /* props */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_delete_types, 0, "Type", "Method used for deleting Grease Pencil data");
+ static const EnumPropertyItem prop_gpencil_delete_types[] = {
+ {GP_DELETEOP_POINTS,
+ "POINTS",
+ 0,
+ "Points",
+ "Delete selected points and split strokes into segments"},
+ {GP_DELETEOP_STROKES, "STROKES", 0, "Strokes", "Delete selected strokes"},
+ {GP_DELETEOP_FRAME, "FRAME", 0, "Frame", "Delete active frame"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Delete";
+ ot->idname = "GPENCIL_OT_delete";
+ ot->description = "Delete selected Grease Pencil strokes, vertices, or frames";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gp_delete_exec;
+ ot->poll = gp_stroke_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* props */
+ ot->prop = RNA_def_enum(ot->srna,
+ "type",
+ prop_gpencil_delete_types,
+ 0,
+ "Type",
+ "Method used for deleting Grease Pencil data");
}
static int gp_dissolve_exec(bContext *C, wmOperator *op)
{
- eGP_DissolveMode mode = RNA_enum_get(op->ptr, "type");
+ eGP_DissolveMode mode = RNA_enum_get(op->ptr, "type");
- return gp_dissolve_selected_points(C, mode);
+ return gp_dissolve_selected_points(C, mode);
}
void GPENCIL_OT_dissolve(wmOperatorType *ot)
{
- static EnumPropertyItem prop_gpencil_dissolve_types[] = {
- {GP_DISSOLVE_POINTS, "POINTS", 0, "Dissolve", "Dissolve selected points"},
- {GP_DISSOLVE_BETWEEN, "BETWEEN", 0, "Dissolve Between", "Dissolve points between selected points"},
- {GP_DISSOLVE_UNSELECT, "UNSELECT", 0, "Dissolve Unselect", "Dissolve all unselected points"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Dissolve";
- ot->idname = "GPENCIL_OT_dissolve";
- ot->description = "Delete selected points without splitting strokes";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = gp_dissolve_exec;
- ot->poll = gp_stroke_edit_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
-
- /* props */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_dissolve_types, 0,
- "Type", "Method used for dissolving Stroke points");
+ static EnumPropertyItem prop_gpencil_dissolve_types[] = {
+ {GP_DISSOLVE_POINTS, "POINTS", 0, "Dissolve", "Dissolve selected points"},
+ {GP_DISSOLVE_BETWEEN,
+ "BETWEEN",
+ 0,
+ "Dissolve Between",
+ "Dissolve points between selected points"},
+ {GP_DISSOLVE_UNSELECT, "UNSELECT", 0, "Dissolve Unselect", "Dissolve all unselected points"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Dissolve";
+ ot->idname = "GPENCIL_OT_dissolve";
+ ot->description = "Delete selected points without splitting strokes";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gp_dissolve_exec;
+ ot->poll = gp_stroke_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* props */
+ ot->prop = RNA_def_enum(ot->srna,
+ "type",
+ prop_gpencil_dissolve_types,
+ 0,
+ "Type",
+ "Method used for dissolving Stroke points");
}
/* ****************** Snapping - Strokes <-> Cursor ************************ */
@@ -2435,370 +2464,369 @@ void GPENCIL_OT_dissolve(wmOperatorType *ot)
*/
static bool gp_snap_poll(bContext *C)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- ScrArea *sa = CTX_wm_area(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ ScrArea *sa = CTX_wm_area(C);
- return (gpd != NULL) && ((sa != NULL) && (sa->spacetype == SPACE_VIEW3D));
+ return (gpd != NULL) && ((sa != NULL) && (sa->spacetype == SPACE_VIEW3D));
}
/* --------------------------------- */
static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- RegionView3D *rv3d = CTX_wm_region_data(C);
- View3D *v3d = CTX_wm_view3d(C);
- Scene *scene = CTX_data_scene(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *obact = CTX_data_active_object(C);
- const float gridf = ED_view3d_grid_view_scale(scene, v3d, rv3d, NULL);
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- bGPDframe *gpf = gpl->actframe;
- float diff_mat[4][4];
-
- /* calculate difference matrix object */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- bGPDspoint *pt;
- int i;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false)
- continue;
-
- // TODO: if entire stroke is selected, offset entire stroke by same amount?
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- /* only if point is selected */
- if (pt->flag & GP_SPOINT_SELECT) {
- /* apply parent transformations */
- float fpt[3];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
-
- fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf);
- fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf);
- fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf);
-
- /* return data */
- copy_v3_v3(&pt->x, fpt);
- gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
- }
- }
- }
- }
- }
-
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ RegionView3D *rv3d = CTX_wm_region_data(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *obact = CTX_data_active_object(C);
+ const float gridf = ED_view3d_grid_view_scale(scene, v3d, rv3d, NULL);
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *gpf = gpl->actframe;
+ float diff_mat[4][4];
+
+ /* calculate difference matrix object */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false)
+ continue;
+
+ // TODO: if entire stroke is selected, offset entire stroke by same amount?
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ /* only if point is selected */
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* apply parent transformations */
+ float fpt[3];
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+
+ fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf);
+ fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf);
+ fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf);
+
+ /* return data */
+ copy_v3_v3(&pt->x, fpt);
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
+ }
+ }
+ }
+ }
+ }
+
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_snap_to_grid(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Snap Selection to Grid";
- ot->idname = "GPENCIL_OT_snap_to_grid";
- ot->description = "Snap selected points to the nearest grid points";
+ /* identifiers */
+ ot->name = "Snap Selection to Grid";
+ ot->idname = "GPENCIL_OT_snap_to_grid";
+ ot->description = "Snap selected points to the nearest grid points";
- /* callbacks */
- ot->exec = gp_snap_to_grid;
- ot->poll = gp_snap_poll;
+ /* callbacks */
+ ot->exec = gp_snap_to_grid;
+ ot->poll = gp_snap_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ------------------------------- */
static int gp_snap_to_cursor(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
-
- Scene *scene = CTX_data_scene(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *obact = CTX_data_active_object(C);
-
- const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
- const float *cursor_global = scene->cursor.location;
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- bGPDframe *gpf = gpl->actframe;
- float diff_mat[4][4];
-
- /* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- bGPDspoint *pt;
- int i;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false)
- continue;
- /* only continue if this stroke is selected (editable doesn't guarantee this)... */
- if ((gps->flag & GP_STROKE_SELECT) == 0)
- continue;
-
- if (use_offset) {
- float offset[3];
-
- /* compute offset from first point of stroke to cursor */
- /* TODO: Allow using midpoint instead? */
- sub_v3_v3v3(offset, cursor_global, &gps->points->x);
-
- /* apply offset to all points in the stroke */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- add_v3_v3(&pt->x, offset);
- }
- }
- else {
- /* affect each selected point */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- copy_v3_v3(&pt->x, cursor_global);
- gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
- }
- }
- }
- }
-
- }
- }
-
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *obact = CTX_data_active_object(C);
+
+ const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
+ const float *cursor_global = scene->cursor.location;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *gpf = gpl->actframe;
+ float diff_mat[4][4];
+
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false)
+ continue;
+ /* only continue if this stroke is selected (editable doesn't guarantee this)... */
+ if ((gps->flag & GP_STROKE_SELECT) == 0)
+ continue;
+
+ if (use_offset) {
+ float offset[3];
+
+ /* compute offset from first point of stroke to cursor */
+ /* TODO: Allow using midpoint instead? */
+ sub_v3_v3v3(offset, cursor_global, &gps->points->x);
+
+ /* apply offset to all points in the stroke */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ add_v3_v3(&pt->x, offset);
+ }
+ }
+ else {
+ /* affect each selected point */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ copy_v3_v3(&pt->x, cursor_global);
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Snap Selection to Cursor";
- ot->idname = "GPENCIL_OT_snap_to_cursor";
- ot->description = "Snap selected points/strokes to the cursor";
-
- /* callbacks */
- ot->exec = gp_snap_to_cursor;
- ot->poll = gp_snap_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- ot->prop = RNA_def_boolean(
- ot->srna, "use_offset", true, "With Offset",
- "Offset the entire stroke instead of selected points only");
+ /* identifiers */
+ ot->name = "Snap Selection to Cursor";
+ ot->idname = "GPENCIL_OT_snap_to_cursor";
+ ot->description = "Snap selected points/strokes to the cursor";
+
+ /* callbacks */
+ ot->exec = gp_snap_to_cursor;
+ ot->poll = gp_snap_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ ot->prop = RNA_def_boolean(ot->srna,
+ "use_offset",
+ true,
+ "With Offset",
+ "Offset the entire stroke instead of selected points only");
}
/* ------------------------------- */
static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
-
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *obact = CTX_data_active_object(C);
-
- float *cursor = scene->cursor.location;
- float centroid[3] = {0.0f};
- float min[3], max[3];
- size_t count = 0;
-
- INIT_MINMAX(min, max);
-
- /* calculate midpoints from selected points */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- bGPDframe *gpf = gpl->actframe;
- float diff_mat[4][4];
-
- /* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- bGPDspoint *pt;
- int i;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false)
- continue;
- /* only continue if this stroke is selected (editable doesn't guarantee this)... */
- if ((gps->flag & GP_STROKE_SELECT) == 0)
- continue;
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- /* apply parent transformations */
- float fpt[3];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
-
- add_v3_v3(centroid, fpt);
- minmax_v3v3_v3(min, max, fpt);
-
- count++;
- }
- }
-
- }
- }
- }
-
- if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEDIAN && count) {
- mul_v3_fl(centroid, 1.0f / (float)count);
- copy_v3_v3(cursor, centroid);
- }
- else {
- mid_v3_v3v3(cursor, min, max);
- }
-
-
- DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *obact = CTX_data_active_object(C);
+
+ float *cursor = scene->cursor.location;
+ float centroid[3] = {0.0f};
+ float min[3], max[3];
+ size_t count = 0;
+
+ INIT_MINMAX(min, max);
+
+ /* calculate midpoints from selected points */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *gpf = gpl->actframe;
+ float diff_mat[4][4];
+
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false)
+ continue;
+ /* only continue if this stroke is selected (editable doesn't guarantee this)... */
+ if ((gps->flag & GP_STROKE_SELECT) == 0)
+ continue;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* apply parent transformations */
+ float fpt[3];
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+
+ add_v3_v3(centroid, fpt);
+ minmax_v3v3_v3(min, max, fpt);
+
+ count++;
+ }
+ }
+ }
+ }
+ }
+
+ if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEDIAN && count) {
+ mul_v3_fl(centroid, 1.0f / (float)count);
+ copy_v3_v3(cursor, centroid);
+ }
+ else {
+ mid_v3_v3v3(cursor, min, max);
+ }
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Snap Cursor to Selected Points";
- ot->idname = "GPENCIL_OT_snap_cursor_to_selected";
- ot->description = "Snap cursor to center of selected points";
+ /* identifiers */
+ ot->name = "Snap Cursor to Selected Points";
+ ot->idname = "GPENCIL_OT_snap_cursor_to_selected";
+ ot->description = "Snap cursor to center of selected points";
- /* callbacks */
- ot->exec = gp_snap_cursor_to_sel;
- ot->poll = gp_snap_poll;
+ /* callbacks */
+ ot->exec = gp_snap_cursor_to_sel;
+ ot->poll = gp_snap_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ******************* Apply layer thickness change to strokes ************************** */
static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl, gpl->frames.first))
- return OPERATOR_CANCELLED;
-
- /* loop all strokes */
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* Apply thickness */
- if ((gps->thickness == 0) && (gpl->line_change == 0)) {
- gps->thickness = gpl->thickness;
- }
- else {
- gps->thickness = gps->thickness + gpl->line_change;
- }
- }
- }
- /* clear value */
- gpl->thickness = 0.0f;
- gpl->line_change = 0;
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl, gpl->frames.first))
+ return OPERATOR_CANCELLED;
+
+ /* loop all strokes */
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* Apply thickness */
+ if ((gps->thickness == 0) && (gpl->line_change == 0)) {
+ gps->thickness = gpl->thickness;
+ }
+ else {
+ gps->thickness = gps->thickness + gpl->line_change;
+ }
+ }
+ }
+ /* clear value */
+ gpl->thickness = 0.0f;
+ gpl->line_change = 0;
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Apply Stroke Thickness";
- ot->idname = "GPENCIL_OT_stroke_apply_thickness";
- ot->description = "Apply the thickness change of the layer to its strokes";
-
- /* api callbacks */
- ot->exec = gp_stroke_apply_thickness_exec;
- ot->poll = gp_active_layer_poll;
+ /* identifiers */
+ ot->name = "Apply Stroke Thickness";
+ ot->idname = "GPENCIL_OT_stroke_apply_thickness";
+ ot->description = "Apply the thickness change of the layer to its strokes";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_apply_thickness_exec;
+ ot->poll = gp_active_layer_poll;
}
/* ******************* Close Strokes ************************** */
enum {
- GP_STROKE_CYCLIC_CLOSE = 1,
- GP_STROKE_CYCLIC_OPEN = 2,
- GP_STROKE_CYCLIC_TOGGLE = 3,
+ GP_STROKE_CYCLIC_CLOSE = 1,
+ GP_STROKE_CYCLIC_OPEN = 2,
+ GP_STROKE_CYCLIC_TOGGLE = 3,
};
static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- Object *ob = CTX_data_active_object(C);
-
- const int type = RNA_enum_get(op->ptr, "type");
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- /* loop all selected strokes */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- if (gpl->actframe == NULL)
- continue;
-
- for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
- MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
-
- /* skip strokes that are not selected or invalid for current view */
- if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* skip hidden or locked colors */
- if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) || (gp_style->flag & GP_STYLE_COLOR_LOCKED))
- continue;
-
- switch (type) {
- case GP_STROKE_CYCLIC_CLOSE:
- /* Close all (enable) */
- gps->flag |= GP_STROKE_CYCLIC;
- break;
- case GP_STROKE_CYCLIC_OPEN:
- /* Open all (disable) */
- gps->flag &= ~GP_STROKE_CYCLIC;
- break;
- case GP_STROKE_CYCLIC_TOGGLE:
- /* Just toggle flag... */
- gps->flag ^= GP_STROKE_CYCLIC;
- break;
- default:
- BLI_assert(0);
- break;
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* loop all selected strokes */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ if (gpl->actframe == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+ /* skip strokes that are not selected or invalid for current view */
+ if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* skip hidden or locked colors */
+ if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
+ (gp_style->flag & GP_STYLE_COLOR_LOCKED))
+ continue;
+
+ switch (type) {
+ case GP_STROKE_CYCLIC_CLOSE:
+ /* Close all (enable) */
+ gps->flag |= GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_OPEN:
+ /* Open all (disable) */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_TOGGLE:
+ /* Just toggle flag... */
+ gps->flag ^= GP_STROKE_CYCLIC;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
/**
@@ -2807,101 +2835,92 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
*/
void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
{
- static const EnumPropertyItem cyclic_type[] = {
- {GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""},
- {GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""},
- {GP_STROKE_CYCLIC_TOGGLE, "TOGGLE", 0, "Toggle", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Set Cyclical State";
- ot->idname = "GPENCIL_OT_stroke_cyclical_set";
- ot->description = "Close or open the selected stroke adding an edge from last to first point";
-
- /* api callbacks */
- ot->exec = gp_stroke_cyclical_set_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", "");
+ static const EnumPropertyItem cyclic_type[] = {
+ {GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""},
+ {GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""},
+ {GP_STROKE_CYCLIC_TOGGLE, "TOGGLE", 0, "Toggle", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Set Cyclical State";
+ ot->idname = "GPENCIL_OT_stroke_cyclical_set";
+ ot->description = "Close or open the selected stroke adding an edge from last to first point";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_cyclical_set_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", "");
}
/* ******************* Flat Stroke Caps ************************** */
enum {
- GP_STROKE_CAPS_TOGGLE_BOTH = 0,
- GP_STROKE_CAPS_TOGGLE_START = 1,
- GP_STROKE_CAPS_TOGGLE_END = 2,
- GP_STROKE_CAPS_TOGGLE_DEFAULT = 3,
+ GP_STROKE_CAPS_TOGGLE_BOTH = 0,
+ GP_STROKE_CAPS_TOGGLE_START = 1,
+ GP_STROKE_CAPS_TOGGLE_END = 2,
+ GP_STROKE_CAPS_TOGGLE_DEFAULT = 3,
};
static int gp_stroke_caps_set_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- Object *ob = CTX_data_active_object(C);
-
- const int type = RNA_enum_get(op->ptr, "type");
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- /* loop all selected strokes */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- if (gpl->actframe == NULL)
- continue;
-
- for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
- MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
-
- /* skip strokes that are not selected or invalid for current view */
- if (((gps->flag & GP_STROKE_SELECT) == 0) ||
- (ED_gpencil_stroke_can_use(C, gps) == false))
- {
- continue;
- }
- /* skip hidden or locked colors */
- if (!gp_style ||
- (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
- (gp_style->flag & GP_STYLE_COLOR_LOCKED))
- {
- continue;
- }
-
- if ((type == GP_STROKE_CAPS_TOGGLE_BOTH) ||
- (type == GP_STROKE_CAPS_TOGGLE_START))
- {
- ++gps->caps[0];
- if (gps->caps[0] >= GP_STROKE_CAP_MAX) {
- gps->caps[0] = GP_STROKE_CAP_ROUND;
- }
- }
- if ((type == GP_STROKE_CAPS_TOGGLE_BOTH) ||
- (type == GP_STROKE_CAPS_TOGGLE_END))
- {
- ++gps->caps[1];
- if (gps->caps[1] >= GP_STROKE_CAP_MAX) {
- gps->caps[1] = GP_STROKE_CAP_ROUND;
- }
- }
- if (type == GP_STROKE_CAPS_TOGGLE_DEFAULT) {
- gps->caps[0] = GP_STROKE_CAP_ROUND;
- gps->caps[1] = GP_STROKE_CAP_ROUND;
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* loop all selected strokes */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ if (gpl->actframe == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+ /* skip strokes that are not selected or invalid for current view */
+ if (((gps->flag & GP_STROKE_SELECT) == 0) || (ED_gpencil_stroke_can_use(C, gps) == false)) {
+ continue;
+ }
+ /* skip hidden or locked colors */
+ if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
+ (gp_style->flag & GP_STYLE_COLOR_LOCKED)) {
+ continue;
+ }
+
+ if ((type == GP_STROKE_CAPS_TOGGLE_BOTH) || (type == GP_STROKE_CAPS_TOGGLE_START)) {
+ ++gps->caps[0];
+ if (gps->caps[0] >= GP_STROKE_CAP_MAX) {
+ gps->caps[0] = GP_STROKE_CAP_ROUND;
+ }
+ }
+ if ((type == GP_STROKE_CAPS_TOGGLE_BOTH) || (type == GP_STROKE_CAPS_TOGGLE_END)) {
+ ++gps->caps[1];
+ if (gps->caps[1] >= GP_STROKE_CAP_MAX) {
+ gps->caps[1] = GP_STROKE_CAP_ROUND;
+ }
+ }
+ if (type == GP_STROKE_CAPS_TOGGLE_DEFAULT) {
+ gps->caps[0] = GP_STROKE_CAP_ROUND;
+ gps->caps[1] = GP_STROKE_CAP_ROUND;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
/**
@@ -2909,28 +2928,28 @@ static int gp_stroke_caps_set_exec(bContext *C, wmOperator *op)
*/
void GPENCIL_OT_stroke_caps_set(wmOperatorType *ot)
{
- static const EnumPropertyItem toggle_type[] = {
- {GP_STROKE_CAPS_TOGGLE_BOTH, "TOGGLE", 0, "Both", ""},
- {GP_STROKE_CAPS_TOGGLE_START, "START", 0, "Start", ""},
- {GP_STROKE_CAPS_TOGGLE_END, "END", 0, "End", ""},
- {GP_STROKE_CAPS_TOGGLE_DEFAULT, "TOGGLE", 0, "Default", "Set as default rounded"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Set Caps Mode";
- ot->idname = "GPENCIL_OT_stroke_caps_set";
- ot->description = "Change Stroke caps mode (rounded or flat)";
-
- /* api callbacks */
- ot->exec = gp_stroke_caps_set_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", toggle_type, GP_STROKE_CAPS_TOGGLE_BOTH, "Type", "");
+ static const EnumPropertyItem toggle_type[] = {
+ {GP_STROKE_CAPS_TOGGLE_BOTH, "TOGGLE", 0, "Both", ""},
+ {GP_STROKE_CAPS_TOGGLE_START, "START", 0, "Start", ""},
+ {GP_STROKE_CAPS_TOGGLE_END, "END", 0, "End", ""},
+ {GP_STROKE_CAPS_TOGGLE_DEFAULT, "TOGGLE", 0, "Default", "Set as default rounded"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Set Caps Mode";
+ ot->idname = "GPENCIL_OT_stroke_caps_set";
+ ot->description = "Change Stroke caps mode (rounded or flat)";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_caps_set_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", toggle_type, GP_STROKE_CAPS_TOGGLE_BOTH, "Type", "");
}
/* ******************* Stroke join ************************** */
@@ -2938,1523 +2957,1524 @@ void GPENCIL_OT_stroke_caps_set(wmOperatorType *ot)
/* Helper: flip stroke */
static void gpencil_flip_stroke(bGPDstroke *gps)
{
- int end = gps->totpoints - 1;
-
- for (int i = 0; i < gps->totpoints / 2; i++) {
- bGPDspoint *point, *point2;
- bGPDspoint pt;
-
- /* save first point */
- point = &gps->points[i];
- pt.x = point->x;
- pt.y = point->y;
- pt.z = point->z;
- pt.flag = point->flag;
- pt.pressure = point->pressure;
- pt.strength = point->strength;
- pt.time = point->time;
-
- /* replace first point with last point */
- point2 = &gps->points[end];
- point->x = point2->x;
- point->y = point2->y;
- point->z = point2->z;
- point->flag = point2->flag;
- point->pressure = point2->pressure;
- point->strength = point2->strength;
- point->time = point2->time;
-
- /* replace last point with first saved before */
- point = &gps->points[end];
- point->x = pt.x;
- point->y = pt.y;
- point->z = pt.z;
- point->flag = pt.flag;
- point->pressure = pt.pressure;
- point->strength = pt.strength;
- point->time = pt.time;
-
- end--;
- }
+ int end = gps->totpoints - 1;
+
+ for (int i = 0; i < gps->totpoints / 2; i++) {
+ bGPDspoint *point, *point2;
+ bGPDspoint pt;
+
+ /* save first point */
+ point = &gps->points[i];
+ pt.x = point->x;
+ pt.y = point->y;
+ pt.z = point->z;
+ pt.flag = point->flag;
+ pt.pressure = point->pressure;
+ pt.strength = point->strength;
+ pt.time = point->time;
+
+ /* replace first point with last point */
+ point2 = &gps->points[end];
+ point->x = point2->x;
+ point->y = point2->y;
+ point->z = point2->z;
+ point->flag = point2->flag;
+ point->pressure = point2->pressure;
+ point->strength = point2->strength;
+ point->time = point2->time;
+
+ /* replace last point with first saved before */
+ point = &gps->points[end];
+ point->x = pt.x;
+ point->y = pt.y;
+ point->z = pt.z;
+ point->flag = pt.flag;
+ point->pressure = pt.pressure;
+ point->strength = pt.strength;
+ point->time = pt.time;
+
+ end--;
+ }
}
/* Helper: copy point between strokes */
-static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, int idx, float delta[3],
- float pressure, float strength, float deltatime)
+static void gpencil_stroke_copy_point(bGPDstroke *gps,
+ bGPDspoint *point,
+ int idx,
+ float delta[3],
+ float pressure,
+ float strength,
+ float deltatime)
{
- bGPDspoint *newpoint;
-
- gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
- if (gps->dvert != NULL) {
- gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
- }
- gps->totpoints++;
- newpoint = &gps->points[gps->totpoints - 1];
-
- newpoint->x = point->x * delta[0];
- newpoint->y = point->y * delta[1];
- newpoint->z = point->z * delta[2];
- newpoint->flag = point->flag;
- newpoint->pressure = pressure;
- newpoint->strength = strength;
- newpoint->time = point->time + deltatime;
-
- if (gps->dvert != NULL) {
- MDeformVert *dvert = &gps->dvert[idx];
- MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1];
-
- newdvert->totweight = dvert->totweight;
- newdvert->dw = MEM_dupallocN(dvert->dw);
- }
+ bGPDspoint *newpoint;
+
+ gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
+ }
+ gps->totpoints++;
+ newpoint = &gps->points[gps->totpoints - 1];
+
+ newpoint->x = point->x * delta[0];
+ newpoint->y = point->y * delta[1];
+ newpoint->z = point->z * delta[2];
+ newpoint->flag = point->flag;
+ newpoint->pressure = pressure;
+ newpoint->strength = strength;
+ newpoint->time = point->time + deltatime;
+
+ if (gps->dvert != NULL) {
+ MDeformVert *dvert = &gps->dvert[idx];
+ MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1];
+
+ newdvert->totweight = dvert->totweight;
+ newdvert->dw = MEM_dupallocN(dvert->dw);
+ }
}
/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */
-static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, const bool leave_gaps)
+static void gpencil_stroke_join_strokes(bGPDstroke *gps_a,
+ bGPDstroke *gps_b,
+ const bool leave_gaps)
{
- bGPDspoint point;
- bGPDspoint *pt;
- int i;
- float delta[3] = {1.0f, 1.0f, 1.0f};
- float deltatime = 0.0f;
-
- /* sanity checks */
- if (ELEM(NULL, gps_a, gps_b))
- return;
-
- if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0))
- return;
-
- /* define start and end points of each stroke */
- float sa[3], sb[3], ea[3], eb[3];
- pt = &gps_a->points[0];
- copy_v3_v3(sa, &pt->x);
-
- pt = &gps_a->points[gps_a->totpoints - 1];
- copy_v3_v3(ea, &pt->x);
-
- pt = &gps_b->points[0];
- copy_v3_v3(sb, &pt->x);
-
- pt = &gps_b->points[gps_b->totpoints - 1];
- copy_v3_v3(eb, &pt->x);
-
- /* review if need flip stroke B */
- float ea_sb = len_squared_v3v3(ea, sb);
- float ea_eb = len_squared_v3v3(ea, eb);
- /* flip if distance to end point is shorter */
- if (ea_eb < ea_sb) {
- gpencil_flip_stroke(gps_b);
- }
-
- /* don't visibly link the first and last points? */
- if (leave_gaps) {
- /* 1st: add one tail point to start invisible area */
- point = gps_a->points[gps_a->totpoints - 1];
- deltatime = point.time;
- gpencil_stroke_copy_point(gps_a, &point, gps_a->totpoints - 1, delta, 0.0f, 0.0f, 0.0f);
-
- /* 2nd: add one head point to finish invisible area */
- point = gps_b->points[0];
- gpencil_stroke_copy_point(gps_a, &point, 0, delta, 0.0f, 0.0f, deltatime);
- }
-
- /* 3rd: add all points */
- for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
- /* check if still room in buffer */
- if (gps_a->totpoints <= GP_STROKE_BUFFER_MAX - 2) {
- gpencil_stroke_copy_point(gps_a, pt, i, delta, pt->pressure, pt->strength, deltatime);
- }
- }
+ bGPDspoint point;
+ bGPDspoint *pt;
+ int i;
+ float delta[3] = {1.0f, 1.0f, 1.0f};
+ float deltatime = 0.0f;
+
+ /* sanity checks */
+ if (ELEM(NULL, gps_a, gps_b))
+ return;
+
+ if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0))
+ return;
+
+ /* define start and end points of each stroke */
+ float sa[3], sb[3], ea[3], eb[3];
+ pt = &gps_a->points[0];
+ copy_v3_v3(sa, &pt->x);
+
+ pt = &gps_a->points[gps_a->totpoints - 1];
+ copy_v3_v3(ea, &pt->x);
+
+ pt = &gps_b->points[0];
+ copy_v3_v3(sb, &pt->x);
+
+ pt = &gps_b->points[gps_b->totpoints - 1];
+ copy_v3_v3(eb, &pt->x);
+
+ /* review if need flip stroke B */
+ float ea_sb = len_squared_v3v3(ea, sb);
+ float ea_eb = len_squared_v3v3(ea, eb);
+ /* flip if distance to end point is shorter */
+ if (ea_eb < ea_sb) {
+ gpencil_flip_stroke(gps_b);
+ }
+
+ /* don't visibly link the first and last points? */
+ if (leave_gaps) {
+ /* 1st: add one tail point to start invisible area */
+ point = gps_a->points[gps_a->totpoints - 1];
+ deltatime = point.time;
+ gpencil_stroke_copy_point(gps_a, &point, gps_a->totpoints - 1, delta, 0.0f, 0.0f, 0.0f);
+
+ /* 2nd: add one head point to finish invisible area */
+ point = gps_b->points[0];
+ gpencil_stroke_copy_point(gps_a, &point, 0, delta, 0.0f, 0.0f, deltatime);
+ }
+
+ /* 3rd: add all points */
+ for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
+ /* check if still room in buffer */
+ if (gps_a->totpoints <= GP_STROKE_BUFFER_MAX - 2) {
+ gpencil_stroke_copy_point(gps_a, pt, i, delta, pt->pressure, pt->strength, deltatime);
+ }
+ }
}
static int gp_stroke_join_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *activegpl = BKE_gpencil_layer_getactive(gpd);
- bGPDstroke *gps, *gpsn;
- Object *ob = CTX_data_active_object(C);
-
- bGPDframe *gpf_a = NULL;
- bGPDstroke *stroke_a = NULL;
- bGPDstroke *stroke_b = NULL;
- bGPDstroke *new_stroke = NULL;
-
- const int type = RNA_enum_get(op->ptr, "type");
- const bool leave_gaps = RNA_boolean_get(op->ptr, "leave_gaps");
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- if (activegpl->flag & GP_LAYER_LOCKED)
- return OPERATOR_CANCELLED;
-
- BLI_assert(ELEM(type, GP_STROKE_JOIN, GP_STROKE_JOINCOPY));
-
-
- /* read all selected strokes */
- bool first = false;
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL)
- continue;
-
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
- continue;
- }
-
- /* to join strokes, cyclic must be disabled */
- gps->flag &= ~GP_STROKE_CYCLIC;
-
- /* saves first frame and stroke */
- if (!first) {
- first = true;
- gpf_a = gpf;
- stroke_a = gps;
- }
- else {
- stroke_b = gps;
-
- /* create a new stroke if was not created before (only created if something to join) */
- if (new_stroke == NULL) {
- new_stroke = MEM_dupallocN(stroke_a);
- new_stroke->points = MEM_dupallocN(stroke_a->points);
- if (stroke_a->dvert != NULL) {
- new_stroke->dvert = MEM_dupallocN(stroke_a->dvert);
- BKE_gpencil_stroke_weights_duplicate(stroke_a, new_stroke);
- }
- new_stroke->triangles = NULL;
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* if new, set current color */
- if (type == GP_STROKE_JOINCOPY) {
- new_stroke->mat_nr = stroke_a->mat_nr;
- }
- }
-
- /* join new_stroke and stroke B. New stroke will contain all the previous data */
- gpencil_stroke_join_strokes(new_stroke, stroke_b, leave_gaps);
-
- /* if join only, delete old strokes */
- if (type == GP_STROKE_JOIN) {
- if (stroke_a) {
- BLI_insertlinkbefore(&gpf_a->strokes, stroke_a, new_stroke);
- BLI_remlink(&gpf->strokes, stroke_a);
- BKE_gpencil_free_stroke(stroke_a);
- stroke_a = NULL;
- }
- if (stroke_b) {
- BLI_remlink(&gpf->strokes, stroke_b);
- BKE_gpencil_free_stroke(stroke_b);
- stroke_b = NULL;
- }
- }
- }
- }
- }
- }
- CTX_DATA_END;
-
- /* add new stroke if was not added before */
- if (type == GP_STROKE_JOINCOPY) {
- if (new_stroke) {
- /* Add a new frame if needed */
- if (activegpl->actframe == NULL)
- activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum);
-
- BLI_addtail(&activegpl->actframe->strokes, new_stroke);
- }
- }
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *activegpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDstroke *gps, *gpsn;
+ Object *ob = CTX_data_active_object(C);
+
+ bGPDframe *gpf_a = NULL;
+ bGPDstroke *stroke_a = NULL;
+ bGPDstroke *stroke_b = NULL;
+ bGPDstroke *new_stroke = NULL;
+
+ const int type = RNA_enum_get(op->ptr, "type");
+ const bool leave_gaps = RNA_boolean_get(op->ptr, "leave_gaps");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ if (activegpl->flag & GP_LAYER_LOCKED)
+ return OPERATOR_CANCELLED;
+
+ BLI_assert(ELEM(type, GP_STROKE_JOIN, GP_STROKE_JOINCOPY));
+
+ /* read all selected strokes */
+ bool first = false;
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL)
+ continue;
+
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+
+ /* to join strokes, cyclic must be disabled */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+
+ /* saves first frame and stroke */
+ if (!first) {
+ first = true;
+ gpf_a = gpf;
+ stroke_a = gps;
+ }
+ else {
+ stroke_b = gps;
+
+ /* create a new stroke if was not created before (only created if something to join) */
+ if (new_stroke == NULL) {
+ new_stroke = MEM_dupallocN(stroke_a);
+ new_stroke->points = MEM_dupallocN(stroke_a->points);
+ if (stroke_a->dvert != NULL) {
+ new_stroke->dvert = MEM_dupallocN(stroke_a->dvert);
+ BKE_gpencil_stroke_weights_duplicate(stroke_a, new_stroke);
+ }
+ new_stroke->triangles = NULL;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* if new, set current color */
+ if (type == GP_STROKE_JOINCOPY) {
+ new_stroke->mat_nr = stroke_a->mat_nr;
+ }
+ }
+
+ /* join new_stroke and stroke B. New stroke will contain all the previous data */
+ gpencil_stroke_join_strokes(new_stroke, stroke_b, leave_gaps);
+
+ /* if join only, delete old strokes */
+ if (type == GP_STROKE_JOIN) {
+ if (stroke_a) {
+ BLI_insertlinkbefore(&gpf_a->strokes, stroke_a, new_stroke);
+ BLI_remlink(&gpf->strokes, stroke_a);
+ BKE_gpencil_free_stroke(stroke_a);
+ stroke_a = NULL;
+ }
+ if (stroke_b) {
+ BLI_remlink(&gpf->strokes, stroke_b);
+ BKE_gpencil_free_stroke(stroke_b);
+ stroke_b = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* add new stroke if was not added before */
+ if (type == GP_STROKE_JOINCOPY) {
+ if (new_stroke) {
+ /* Add a new frame if needed */
+ if (activegpl->actframe == NULL)
+ activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum);
+
+ BLI_addtail(&activegpl->actframe->strokes, new_stroke);
+ }
+ }
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_join(wmOperatorType *ot)
{
- static const EnumPropertyItem join_type[] = {
- {GP_STROKE_JOIN, "JOIN", 0, "Join", ""},
- {GP_STROKE_JOINCOPY, "JOINCOPY", 0, "Join and Copy", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Join Strokes";
- ot->idname = "GPENCIL_OT_stroke_join";
- ot->description = "Join selected strokes (optionally as new stroke)";
-
- /* api callbacks */
- ot->exec = gp_stroke_join_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", "");
- RNA_def_boolean(ot->srna, "leave_gaps", false, "Leave Gaps", "Leave gaps between joined strokes instead of linking them");
+ static const EnumPropertyItem join_type[] = {
+ {GP_STROKE_JOIN, "JOIN", 0, "Join", ""},
+ {GP_STROKE_JOINCOPY, "JOINCOPY", 0, "Join and Copy", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Join Strokes";
+ ot->idname = "GPENCIL_OT_stroke_join";
+ ot->description = "Join selected strokes (optionally as new stroke)";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_join_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", "");
+ RNA_def_boolean(ot->srna,
+ "leave_gaps",
+ false,
+ "Leave Gaps",
+ "Leave gaps between joined strokes instead of linking them");
}
/* ******************* Stroke flip ************************** */
static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- Object *ob = CTX_data_active_object(C);
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- /* read all selected strokes */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL)
- continue;
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
- continue;
- }
-
- /* flip stroke */
- gpencil_flip_stroke(gps);
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* read all selected strokes */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+
+ /* flip stroke */
+ gpencil_flip_stroke(gps);
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Flip Stroke";
- ot->idname = "GPENCIL_OT_stroke_flip";
- ot->description = "Change direction of the points of the selected strokes";
+ /* identifiers */
+ ot->name = "Flip Stroke";
+ ot->idname = "GPENCIL_OT_stroke_flip";
+ ot->description = "Change direction of the points of the selected strokes";
- /* api callbacks */
- ot->exec = gp_stroke_flip_exec;
- ot->poll = gp_active_layer_poll;
+ /* api callbacks */
+ ot->exec = gp_stroke_flip_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ***************** Reproject Strokes ********************** */
typedef enum eGP_ReprojectModes {
- /* Axis */
- GP_REPROJECT_FRONT = 0,
- GP_REPROJECT_SIDE,
- GP_REPROJECT_TOP,
- /* On same plane, parallel to viewplane */
- GP_REPROJECT_VIEW,
- /* Reprojected on to the scene geometry */
- GP_REPROJECT_SURFACE,
- /* Reprojected on 3D cursor orientation */
- GP_REPROJECT_CURSOR,
+ /* Axis */
+ GP_REPROJECT_FRONT = 0,
+ GP_REPROJECT_SIDE,
+ GP_REPROJECT_TOP,
+ /* On same plane, parallel to viewplane */
+ GP_REPROJECT_VIEW,
+ /* Reprojected on to the scene geometry */
+ GP_REPROJECT_SURFACE,
+ /* Reprojected on 3D cursor orientation */
+ GP_REPROJECT_CURSOR,
} eGP_ReprojectModes;
static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *ob = CTX_data_active_object(C);
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = ar->regiondata;
-
- GP_SpaceConversion gsc = {NULL};
- eGP_ReprojectModes mode = RNA_enum_get(op->ptr, "type");
-
- float origin[3];
-
- /* init space conversion stuff */
- gp_point_conversion_init(C, &gsc);
-
- /* init autodist for geometry projection */
- if (mode == GP_REPROJECT_SURFACE) {
- view3d_region_operator_needs_opengl(CTX_wm_window(C), gsc.ar);
- ED_view3d_autodist_init(depsgraph, gsc.ar, CTX_wm_view3d(C), 0);
- }
-
- // TODO: For deforming geometry workflow, create new frames?
-
- /* Go through each editable + selected stroke, adjusting each of its points one by one... */
- GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
- float inverse_diff_mat[4][4];
-
- /* Compute inverse matrix for unapplying parenting once instead of doing per-point */
- /* TODO: add this bit to the iteration macro? */
- invert_m4_m4(inverse_diff_mat, gpstroke_iter.diff_mat);
-
- /* Adjust each point */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- float xy[2];
-
- /* 3D to Screenspace */
- /* Note: We can't use gp_point_to_xy() here because that uses ints for the screenspace
- * coordinates, resulting in lost precision, which in turn causes stairstepping
- * artifacts in the final points.
- */
- bGPDspoint pt2;
- gp_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2);
- gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
-
- /* Project stroke in one axis */
- if (ELEM(mode, GP_REPROJECT_FRONT, GP_REPROJECT_SIDE,
- GP_REPROJECT_TOP, GP_REPROJECT_CURSOR))
- {
- if (mode != GP_REPROJECT_CURSOR) {
- ED_gp_get_drawing_reference(
- scene, ob, gpl,
- ts->gpencil_v3d_align, origin);
- }
- else {
- copy_v3_v3(origin, scene->cursor.location);
- }
-
- int axis = 0;
- switch (mode) {
- case GP_REPROJECT_FRONT:
- {
- axis = 1;
- break;
- }
- case GP_REPROJECT_SIDE:
- {
- axis = 0;
- break;
- }
- case GP_REPROJECT_TOP:
- {
- axis = 2;
- break;
- }
- case GP_REPROJECT_CURSOR:
- {
- axis = 3;
- break;
- }
- default:
- {
- axis = 1;
- break;
- }
- }
-
- ED_gp_project_point_to_plane(
- scene, ob, rv3d, origin,
- axis, &pt2);
-
- copy_v3_v3(&pt->x, &pt2.x);
-
- /* apply parent again */
- gp_apply_parent_point(depsgraph, ob, gpd, gpl, pt);
- }
- /* Project screenspace back to 3D space (from current perspective)
- * so that all points have been treated the same way
- */
- else if (mode == GP_REPROJECT_VIEW) {
- /* Planar - All on same plane parallel to the viewplane */
- gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
- }
- else {
- /* Geometry - Snap to surfaces of visible geometry */
- /* XXX: There will be precision loss (possible stairstep artifacts)
- * from this conversion to satisfy the API's */
- const int screen_co[2] = {(int)xy[0], (int)xy[1]};
-
- int depth_margin = 0; // XXX: 4 for strokes, 0 for normal
- float depth;
-
- /* XXX: The proper procedure computes the depths into an array,
- * to have smooth transitions when all else fails... */
- if (ED_view3d_autodist_depth(gsc.ar, screen_co, depth_margin, &depth)) {
- ED_view3d_autodist_simple(gsc.ar, screen_co, &pt->x, 0, &depth);
- }
- else {
- /* Default to planar */
- gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
- }
- }
-
- /* Unapply parent corrections */
- if (!ELEM(mode, GP_REPROJECT_FRONT, GP_REPROJECT_SIDE, GP_REPROJECT_TOP)) {
- mul_m4_v3(inverse_diff_mat, &pt->x);
- }
- }
- }
- }
- GP_EDITABLE_STROKES_END(gpstroke_iter);
-
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = CTX_data_active_object(C);
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ GP_SpaceConversion gsc = {NULL};
+ eGP_ReprojectModes mode = RNA_enum_get(op->ptr, "type");
+
+ float origin[3];
+
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
+
+ /* init autodist for geometry projection */
+ if (mode == GP_REPROJECT_SURFACE) {
+ view3d_region_operator_needs_opengl(CTX_wm_window(C), gsc.ar);
+ ED_view3d_autodist_init(depsgraph, gsc.ar, CTX_wm_view3d(C), 0);
+ }
+
+ // TODO: For deforming geometry workflow, create new frames?
+
+ /* Go through each editable + selected stroke, adjusting each of its points one by one... */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+ float inverse_diff_mat[4][4];
+
+ /* Compute inverse matrix for unapplying parenting once instead of doing per-point */
+ /* TODO: add this bit to the iteration macro? */
+ invert_m4_m4(inverse_diff_mat, gpstroke_iter.diff_mat);
+
+ /* Adjust each point */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float xy[2];
+
+ /* 3D to Screenspace */
+ /* Note: We can't use gp_point_to_xy() here because that uses ints for the screenspace
+ * coordinates, resulting in lost precision, which in turn causes stairstepping
+ * artifacts in the final points.
+ */
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2);
+ gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
+
+ /* Project stroke in one axis */
+ if (ELEM(mode,
+ GP_REPROJECT_FRONT,
+ GP_REPROJECT_SIDE,
+ GP_REPROJECT_TOP,
+ GP_REPROJECT_CURSOR)) {
+ if (mode != GP_REPROJECT_CURSOR) {
+ ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
+ }
+ else {
+ copy_v3_v3(origin, scene->cursor.location);
+ }
+
+ int axis = 0;
+ switch (mode) {
+ case GP_REPROJECT_FRONT: {
+ axis = 1;
+ break;
+ }
+ case GP_REPROJECT_SIDE: {
+ axis = 0;
+ break;
+ }
+ case GP_REPROJECT_TOP: {
+ axis = 2;
+ break;
+ }
+ case GP_REPROJECT_CURSOR: {
+ axis = 3;
+ break;
+ }
+ default: {
+ axis = 1;
+ break;
+ }
+ }
+
+ ED_gp_project_point_to_plane(scene, ob, rv3d, origin, axis, &pt2);
+
+ copy_v3_v3(&pt->x, &pt2.x);
+
+ /* apply parent again */
+ gp_apply_parent_point(depsgraph, ob, gpd, gpl, pt);
+ }
+ /* Project screenspace back to 3D space (from current perspective)
+ * so that all points have been treated the same way
+ */
+ else if (mode == GP_REPROJECT_VIEW) {
+ /* Planar - All on same plane parallel to the viewplane */
+ gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
+ }
+ else {
+ /* Geometry - Snap to surfaces of visible geometry */
+ /* XXX: There will be precision loss (possible stairstep artifacts)
+ * from this conversion to satisfy the API's */
+ const int screen_co[2] = {(int)xy[0], (int)xy[1]};
+
+ int depth_margin = 0; // XXX: 4 for strokes, 0 for normal
+ float depth;
+
+ /* XXX: The proper procedure computes the depths into an array,
+ * to have smooth transitions when all else fails... */
+ if (ED_view3d_autodist_depth(gsc.ar, screen_co, depth_margin, &depth)) {
+ ED_view3d_autodist_simple(gsc.ar, screen_co, &pt->x, 0, &depth);
+ }
+ else {
+ /* Default to planar */
+ gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
+ }
+ }
+
+ /* Unapply parent corrections */
+ if (!ELEM(mode, GP_REPROJECT_FRONT, GP_REPROJECT_SIDE, GP_REPROJECT_TOP)) {
+ mul_m4_v3(inverse_diff_mat, &pt->x);
+ }
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_reproject(wmOperatorType *ot)
{
- static const EnumPropertyItem reproject_type[] = {
- {GP_REPROJECT_FRONT, "FRONT", 0, "Front",
- "Reproject the strokes using the X-Z plane"},
- {GP_REPROJECT_SIDE, "SIDE", 0, "Side",
- "Reproject the strokes using the Y-Z plane"},
- {GP_REPROJECT_TOP, "TOP", 0, "Top",
- "Reproject the strokes using the X-Y plane"},
- {GP_REPROJECT_VIEW, "VIEW", 0, "View",
- "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint "
- "using 'Cursor' Stroke Placement"},
- {GP_REPROJECT_SURFACE, "SURFACE", 0, "Surface",
- "Reproject the strokes on to the scene geometry, as if drawn using 'Surface' placement"},
- {GP_REPROJECT_CURSOR, "CURSOR", 0, "Cursor",
- "Reproject the strokes using the orienation of 3D cursor"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Reproject Strokes";
- ot->idname = "GPENCIL_OT_reproject";
- ot->description = "Reproject the selected strokes from the current viewpoint as if they had been newly drawn "
- "(e.g. to fix problems from accidental 3D cursor movement or accidental viewport changes, "
- "or for matching deforming geometry)";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = gp_strokes_reproject_exec;
- ot->poll = gp_strokes_edit3d_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", reproject_type, GP_REPROJECT_VIEW, "Projection Type", "");
+ static const EnumPropertyItem reproject_type[] = {
+ {GP_REPROJECT_FRONT, "FRONT", 0, "Front", "Reproject the strokes using the X-Z plane"},
+ {GP_REPROJECT_SIDE, "SIDE", 0, "Side", "Reproject the strokes using the Y-Z plane"},
+ {GP_REPROJECT_TOP, "TOP", 0, "Top", "Reproject the strokes using the X-Y plane"},
+ {GP_REPROJECT_VIEW,
+ "VIEW",
+ 0,
+ "View",
+ "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint "
+ "using 'Cursor' Stroke Placement"},
+ {GP_REPROJECT_SURFACE,
+ "SURFACE",
+ 0,
+ "Surface",
+ "Reproject the strokes on to the scene geometry, as if drawn using 'Surface' placement"},
+ {GP_REPROJECT_CURSOR,
+ "CURSOR",
+ 0,
+ "Cursor",
+ "Reproject the strokes using the orienation of 3D cursor"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Reproject Strokes";
+ ot->idname = "GPENCIL_OT_reproject";
+ ot->description =
+ "Reproject the selected strokes from the current viewpoint as if they had been newly drawn "
+ "(e.g. to fix problems from accidental 3D cursor movement or accidental viewport changes, "
+ "or for matching deforming geometry)";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gp_strokes_reproject_exec;
+ ot->poll = gp_strokes_edit3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
+
+ /* properties */
+ ot->prop = RNA_def_enum(
+ ot->srna, "type", reproject_type, GP_REPROJECT_VIEW, "Projection Type", "");
}
/* ******************* Stroke subdivide ************************** */
/* helper to smooth */
static void gp_smooth_stroke(bContext *C, wmOperator *op)
{
- const int repeat = RNA_int_get(op->ptr, "repeat");
- float factor = RNA_float_get(op->ptr, "factor");
- const bool only_selected = RNA_boolean_get(op->ptr, "only_selected");
- const bool smooth_position = RNA_boolean_get(op->ptr, "smooth_position");
- const bool smooth_thickness = RNA_boolean_get(op->ptr, "smooth_thickness");
- const bool smooth_strength = RNA_boolean_get(op->ptr, "smooth_strength");
- const bool smooth_uv = RNA_boolean_get(op->ptr, "smooth_uv");
-
- if (factor == 0.0f) {
- return;
- }
-
- GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
- if (gps->flag & GP_STROKE_SELECT) {
- for (int r = 0; r < repeat; r++) {
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- if ((only_selected) && ((pt->flag & GP_SPOINT_SELECT) == 0)) {
- continue;
- }
-
- /* perform smoothing */
- if (smooth_position) {
- BKE_gpencil_smooth_stroke(gps, i, factor);
- }
- if (smooth_strength) {
- BKE_gpencil_smooth_stroke_strength(gps, i, factor);
- }
- if (smooth_thickness) {
- /* thickness need to repeat process several times */
- for (int r2 = 0; r2 < r * 10; r2++) {
- BKE_gpencil_smooth_stroke_thickness(gps, i, factor);
- }
- }
- if (smooth_uv) {
- BKE_gpencil_smooth_stroke_uv(gps, i, factor);
- }
- }
- }
- }
- }
- GP_EDITABLE_STROKES_END(gpstroke_iter);
+ const int repeat = RNA_int_get(op->ptr, "repeat");
+ float factor = RNA_float_get(op->ptr, "factor");
+ const bool only_selected = RNA_boolean_get(op->ptr, "only_selected");
+ const bool smooth_position = RNA_boolean_get(op->ptr, "smooth_position");
+ const bool smooth_thickness = RNA_boolean_get(op->ptr, "smooth_thickness");
+ const bool smooth_strength = RNA_boolean_get(op->ptr, "smooth_strength");
+ const bool smooth_uv = RNA_boolean_get(op->ptr, "smooth_uv");
+
+ if (factor == 0.0f) {
+ return;
+ }
+
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ for (int r = 0; r < repeat; r++) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ if ((only_selected) && ((pt->flag & GP_SPOINT_SELECT) == 0)) {
+ continue;
+ }
+
+ /* perform smoothing */
+ if (smooth_position) {
+ BKE_gpencil_smooth_stroke(gps, i, factor);
+ }
+ if (smooth_strength) {
+ BKE_gpencil_smooth_stroke_strength(gps, i, factor);
+ }
+ if (smooth_thickness) {
+ /* thickness need to repeat process several times */
+ for (int r2 = 0; r2 < r * 10; r2++) {
+ BKE_gpencil_smooth_stroke_thickness(gps, i, factor);
+ }
+ }
+ if (smooth_uv) {
+ BKE_gpencil_smooth_stroke_uv(gps, i, factor);
+ }
+ }
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
}
/* helper: Count how many points need to be inserted */
static int gp_count_subdivision_cuts(bGPDstroke *gps)
{
- bGPDspoint *pt;
- int i;
- int totnewpoints = 0;
- for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- if (i + 1 < gps->totpoints) {
- if (gps->points[i + 1].flag & GP_SPOINT_SELECT) {
- totnewpoints++;
- }
- }
- }
- }
-
- return totnewpoints;
+ bGPDspoint *pt;
+ int i;
+ int totnewpoints = 0;
+ for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (i + 1 < gps->totpoints) {
+ if (gps->points[i + 1].flag & GP_SPOINT_SELECT) {
+ totnewpoints++;
+ }
+ }
+ }
+ }
+
+ return totnewpoints;
}
static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDspoint *temp_points;
- const int cuts = RNA_int_get(op->ptr, "number_cuts");
-
- int totnewpoints, oldtotpoints;
- int i2;
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- /* Go through each editable + selected stroke */
- GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
- if (gps->flag & GP_STROKE_SELECT) {
- /* loop as many times as cuts */
- for (int s = 0; s < cuts; s++) {
- totnewpoints = gp_count_subdivision_cuts(gps);
- if (totnewpoints == 0) {
- continue;
- }
- /* duplicate points in a temp area */
- temp_points = MEM_dupallocN(gps->points);
- oldtotpoints = gps->totpoints;
-
- MDeformVert *temp_dverts = NULL;
- MDeformVert *dvert_final = NULL;
- MDeformVert *dvert = NULL;
- MDeformVert *dvert_next = NULL;
- if (gps->dvert != NULL) {
- temp_dverts = MEM_dupallocN(gps->dvert);
- }
-
- /* resize the points arrays */
- gps->totpoints += totnewpoints;
- gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
- if (gps->dvert != NULL) {
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
- }
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* loop and interpolate */
- i2 = 0;
- for (int i = 0; i < oldtotpoints; i++) {
- bGPDspoint *pt = &temp_points[i];
- bGPDspoint *pt_final = &gps->points[i2];
-
- /* copy current point */
- copy_v3_v3(&pt_final->x, &pt->x);
- pt_final->pressure = pt->pressure;
- pt_final->strength = pt->strength;
- pt_final->time = pt->time;
- pt_final->flag = pt->flag;
-
- if (gps->dvert != NULL) {
- dvert = &temp_dverts[i];
- dvert_final = &gps->dvert[i2];
- dvert_final->totweight = dvert->totweight;
- dvert_final->dw = dvert->dw;
- }
- i2++;
-
- /* if next point is selected add a half way point */
- if (pt->flag & GP_SPOINT_SELECT) {
- if (i + 1 < oldtotpoints) {
- if (temp_points[i + 1].flag & GP_SPOINT_SELECT) {
- pt_final = &gps->points[i2];
- if (gps->dvert != NULL) {
- dvert_final = &gps->dvert[i2];
- }
- /* Interpolate all values */
- bGPDspoint *next = &temp_points[i + 1];
- interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
- pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
- pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
- CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- pt_final->time = interpf(pt->time, next->time, 0.5f);
- pt_final->flag |= GP_SPOINT_SELECT;
-
- /* interpolate weights */
- if (gps->dvert != NULL) {
- dvert = &temp_dverts[i];
- dvert_next = &temp_dverts[i + 1];
- dvert_final = &gps->dvert[i2];
-
- dvert_final->totweight = dvert->totweight;
- dvert_final->dw = MEM_dupallocN(dvert->dw);
-
- /* interpolate weight values */
- for (int d = 0; d < dvert->totweight; d++) {
- MDeformWeight *dw_a = &dvert->dw[d];
- if (dvert_next->totweight > d) {
- MDeformWeight *dw_b = &dvert_next->dw[d];
- MDeformWeight *dw_final = &dvert_final->dw[d];
- dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f);
- }
- }
- }
-
- i2++;
- }
- }
- }
- }
- /* free temp memory */
- MEM_SAFE_FREE(temp_points);
- MEM_SAFE_FREE(temp_dverts);
- }
-
- /* triangles cache needs to be recalculated */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
- }
- }
- GP_EDITABLE_STROKES_END(gpstroke_iter);
-
- /* smooth stroke */
- gp_smooth_stroke(C, op);
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDspoint *temp_points;
+ const int cuts = RNA_int_get(op->ptr, "number_cuts");
+
+ int totnewpoints, oldtotpoints;
+ int i2;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* Go through each editable + selected stroke */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* loop as many times as cuts */
+ for (int s = 0; s < cuts; s++) {
+ totnewpoints = gp_count_subdivision_cuts(gps);
+ if (totnewpoints == 0) {
+ continue;
+ }
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+
+ MDeformVert *temp_dverts = NULL;
+ MDeformVert *dvert_final = NULL;
+ MDeformVert *dvert = NULL;
+ MDeformVert *dvert_next = NULL;
+ if (gps->dvert != NULL) {
+ temp_dverts = MEM_dupallocN(gps->dvert);
+ }
+
+ /* resize the points arrays */
+ gps->totpoints += totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ }
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* loop and interpolate */
+ i2 = 0;
+ for (int i = 0; i < oldtotpoints; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ /* copy current point */
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+
+ if (gps->dvert != NULL) {
+ dvert = &temp_dverts[i];
+ dvert_final = &gps->dvert[i2];
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = dvert->dw;
+ }
+ i2++;
+
+ /* if next point is selected add a half way point */
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (i + 1 < oldtotpoints) {
+ if (temp_points[i + 1].flag & GP_SPOINT_SELECT) {
+ pt_final = &gps->points[i2];
+ if (gps->dvert != NULL) {
+ dvert_final = &gps->dvert[i2];
+ }
+ /* Interpolate all values */
+ bGPDspoint *next = &temp_points[i + 1];
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
+ pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
+ CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt_final->time = interpf(pt->time, next->time, 0.5f);
+ pt_final->flag |= GP_SPOINT_SELECT;
+
+ /* interpolate weights */
+ if (gps->dvert != NULL) {
+ dvert = &temp_dverts[i];
+ dvert_next = &temp_dverts[i + 1];
+ dvert_final = &gps->dvert[i2];
+
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = MEM_dupallocN(dvert->dw);
+
+ /* interpolate weight values */
+ for (int d = 0; d < dvert->totweight; d++) {
+ MDeformWeight *dw_a = &dvert->dw[d];
+ if (dvert_next->totweight > d) {
+ MDeformWeight *dw_b = &dvert_next->dw[d];
+ MDeformWeight *dw_final = &dvert_final->dw[d];
+ dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f);
+ }
+ }
+ }
+
+ i2++;
+ }
+ }
+ }
+ }
+ /* free temp memory */
+ MEM_SAFE_FREE(temp_points);
+ MEM_SAFE_FREE(temp_dverts);
+ }
+
+ /* triangles cache needs to be recalculated */
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* smooth stroke */
+ gp_smooth_stroke(C, op);
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Subdivide Stroke";
- ot->idname = "GPENCIL_OT_stroke_subdivide";
- ot->description = "Subdivide between continuous selected points of the stroke adding a point half way between them";
-
- /* api callbacks */
- ot->exec = gp_stroke_subdivide_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, 5);
- /* avoid re-using last var because it can cause _very_ high value and annoy users */
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- /* Smooth parameters */
- RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, 2.0f, "Smooth", "", 0.0f, 2.0f);
- prop = RNA_def_int(ot->srna, "repeat", 1, 1, 10, "Repeat", "", 1, 5);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_boolean(
- ot->srna, "only_selected", true, "Selected Points",
- "Smooth only selected points in the stroke");
- RNA_def_boolean(ot->srna, "smooth_position", true, "Position", "");
- RNA_def_boolean(ot->srna, "smooth_thickness", true, "Thickness", "");
- RNA_def_boolean(ot->srna, "smooth_strength", false, "Strength", "");
- RNA_def_boolean(ot->srna, "smooth_uv", false, "UV", "");
-
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Subdivide Stroke";
+ ot->idname = "GPENCIL_OT_stroke_subdivide";
+ ot->description =
+ "Subdivide between continuous selected points of the stroke adding a point half way between "
+ "them";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_subdivide_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, 5);
+ /* avoid re-using last var because it can cause _very_ high value and annoy users */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ /* Smooth parameters */
+ RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, 2.0f, "Smooth", "", 0.0f, 2.0f);
+ prop = RNA_def_int(ot->srna, "repeat", 1, 1, 10, "Repeat", "", 1, 5);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_boolean(ot->srna,
+ "only_selected",
+ true,
+ "Selected Points",
+ "Smooth only selected points in the stroke");
+ RNA_def_boolean(ot->srna, "smooth_position", true, "Position", "");
+ RNA_def_boolean(ot->srna, "smooth_thickness", true, "Thickness", "");
+ RNA_def_boolean(ot->srna, "smooth_strength", false, "Strength", "");
+ RNA_def_boolean(ot->srna, "smooth_uv", false, "UV", "");
}
/* ** simplify stroke *** */
static int gp_stroke_simplify_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- float factor = RNA_float_get(op->ptr, "factor");
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- /* Go through each editable + selected stroke */
- GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
- if (gps->flag & GP_STROKE_SELECT) {
- /* simplify stroke using Ramer-Douglas-Peucker algorithm */
- BKE_gpencil_simplify_stroke(gps, factor);
- }
- }
- GP_EDITABLE_STROKES_END(gpstroke_iter);
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ float factor = RNA_float_get(op->ptr, "factor");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* Go through each editable + selected stroke */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* simplify stroke using Ramer-Douglas-Peucker algorithm */
+ BKE_gpencil_simplify_stroke(gps, factor);
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_simplify(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ PropertyRNA *prop;
- /* identifiers */
- ot->name = "Simplify Stroke";
- ot->idname = "GPENCIL_OT_stroke_simplify";
- ot->description = "Simplify selected stroked reducing number of points";
+ /* identifiers */
+ ot->name = "Simplify Stroke";
+ ot->idname = "GPENCIL_OT_stroke_simplify";
+ ot->description = "Simplify selected stroked reducing number of points";
- /* api callbacks */
- ot->exec = gp_stroke_simplify_exec;
- ot->poll = gp_active_layer_poll;
+ /* api callbacks */
+ ot->exec = gp_stroke_simplify_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- prop = RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, 100.0f, "Factor", "", 0.0f, 100.0f);
- /* avoid re-using last var */
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ /* properties */
+ prop = RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, 100.0f, "Factor", "", 0.0f, 100.0f);
+ /* avoid re-using last var */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ** simplify stroke using fixed algorithm *** */
static int gp_stroke_simplify_fixed_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- int steps = RNA_int_get(op->ptr, "step");
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- /* Go through each editable + selected stroke */
- GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
- if (gps->flag & GP_STROKE_SELECT) {
- for (int i = 0; i < steps; i++) {
- BKE_gpencil_simplify_fixed(gps);
- }
- }
- }
- GP_EDITABLE_STROKES_END(gpstroke_iter);
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ int steps = RNA_int_get(op->ptr, "step");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* Go through each editable + selected stroke */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ for (int i = 0; i < steps; i++) {
+ BKE_gpencil_simplify_fixed(gps);
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_simplify_fixed(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Simplify Fixed Stroke";
- ot->idname = "GPENCIL_OT_stroke_simplify_fixed";
- ot->description = "Simplify selected stroked reducing number of points using fixed algorithm";
+ PropertyRNA *prop;
- /* api callbacks */
- ot->exec = gp_stroke_simplify_fixed_exec;
- ot->poll = gp_active_layer_poll;
+ /* identifiers */
+ ot->name = "Simplify Fixed Stroke";
+ ot->idname = "GPENCIL_OT_stroke_simplify_fixed";
+ ot->description = "Simplify selected stroked reducing number of points using fixed algorithm";
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* api callbacks */
+ ot->exec = gp_stroke_simplify_fixed_exec;
+ ot->poll = gp_active_layer_poll;
- /* properties */
- prop = RNA_def_int(ot->srna, "step", 1, 1, 100, "Steps", "Number of simplify steps", 1, 10);
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* avoid re-using last var */
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ /* properties */
+ prop = RNA_def_int(ot->srna, "step", 1, 1, 100, "Steps", "Number of simplify steps", 1, 10);
+ /* avoid re-using last var */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ******************* Stroke trim ************************** */
static int gp_stroke_trim_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- /* Go through each editable + selected stroke */
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- bGPDstroke *gps, *gpsn;
-
- if (gpf == NULL)
- continue;
-
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- if (gps->flag & GP_STROKE_SELECT) {
- BKE_gpencil_trim_stroke(gps);
- }
- }
- /* if not multiedit, exit loop*/
- if (!is_multiedit) {
- break;
- }
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* Go through each editable + selected stroke */
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL)
+ continue;
+
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ if (gps->flag & GP_STROKE_SELECT) {
+ BKE_gpencil_trim_stroke(gps);
+ }
+ }
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_trim(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Trim Stroke";
- ot->idname = "GPENCIL_OT_stroke_trim";
- ot->description = "Trim selected stroke to first loop or intersection";
+ /* identifiers */
+ ot->name = "Trim Stroke";
+ ot->idname = "GPENCIL_OT_stroke_trim";
+ ot->description = "Trim selected stroke to first loop or intersection";
- /* api callbacks */
- ot->exec = gp_stroke_trim_exec;
- ot->poll = gp_active_layer_poll;
+ /* api callbacks */
+ ot->exec = gp_stroke_trim_exec;
+ ot->poll = gp_active_layer_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ***************** Separate Strokes ********************** */
typedef enum eGP_SeparateModes {
- /* Points */
- GP_SEPARATE_POINT = 0,
- /* Selected Strokes */
- GP_SEPARATE_STROKE,
- /* Current Layer */
- GP_SEPARATE_LAYER,
+ /* Points */
+ GP_SEPARATE_POINT = 0,
+ /* Selected Strokes */
+ GP_SEPARATE_STROKE,
+ /* Current Layer */
+ GP_SEPARATE_LAYER,
} eGP_SeparateModes;
static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
{
- Base *base_new;
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base_old = CTX_data_active_base(C);
- bGPdata *gpd_src = ED_gpencil_data_get_active(C);
- Object *ob = CTX_data_active_object(C);
-
- Object *ob_dst = NULL;
- bGPdata *gpd_dst = NULL;
- bGPDlayer *gpl_dst = NULL;
- bGPDframe *gpf_dst = NULL;
- bGPDspoint *pt;
- Material *ma = NULL;
- int i, idx;
-
- eGP_SeparateModes mode = RNA_enum_get(op->ptr, "mode");
-
- /* sanity checks */
- if (ELEM(NULL, gpd_src)) {
- return OPERATOR_CANCELLED;
- }
-
- if ((mode == GP_SEPARATE_LAYER) && (BLI_listbase_count(&gpd_src->layers) == 1)) {
- BKE_report(op->reports, RPT_ERROR, "Cannot separate an object with one layer only");
- return OPERATOR_CANCELLED;
- }
-
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_src);
-
- /* create a new object */
- base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, 0);
- ob_dst = base_new->object;
- ob_dst->mode = OB_MODE_OBJECT;
- /* create new grease pencil datablock */
- gpd_dst = BKE_gpencil_data_addnew(bmain, gpd_src->id.name + 2);
- ob_dst->data = (bGPdata *)gpd_dst;
-
- /* loop old datablock and separate parts */
- if ((mode == GP_SEPARATE_POINT) || (mode == GP_SEPARATE_STROKE)) {
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- gpl_dst = NULL;
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- bGPDstroke *gps, *gpsn;
-
- if (gpf == NULL) {
- continue;
- }
-
- gpf_dst = NULL;
-
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
- continue;
- }
- /* separate selected strokes */
- if (gps->flag & GP_STROKE_SELECT) {
- /* add layer if not created before */
- if (gpl_dst == NULL) {
- gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl->info, false);
- }
-
- /* add frame if not created before */
- if (gpf_dst == NULL) {
- gpf_dst = BKE_gpencil_layer_getframe(gpl_dst, gpf->framenum, GP_GETFRAME_ADD_NEW);
- }
-
- /* add duplicate materials */
- ma = give_current_material(ob, gps->mat_nr + 1); /* XXX same material can be in multiple slots */
- idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma);
-
- /* selected points mode */
- if (mode == GP_SEPARATE_POINT) {
- /* make copy of source stroke */
- bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
-
- /* reasign material */
- gps_dst->mat_nr = idx;
-
- /* link to destination frame */
- BLI_addtail(&gpf_dst->strokes, gps_dst);
-
- /* Invert selection status of all points in destination stroke */
- for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
- pt->flag ^= GP_SPOINT_SELECT;
- }
-
- /* delete selected points from destination stroke */
- gp_stroke_delete_tagged_points(gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, 0);
-
- /* delete selected points from origin stroke */
- gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false, 0);
- }
- /* selected strokes mode */
- else if (mode == GP_SEPARATE_STROKE) {
- /* deselect old stroke */
- gps->flag &= ~GP_STROKE_SELECT;
- /* unlink from source frame */
- BLI_remlink(&gpf->strokes, gps);
- gps->prev = gps->next = NULL;
- /* relink to destination frame */
- BLI_addtail(&gpf_dst->strokes, gps);
- /* reasign material */
- gps->mat_nr = idx;
- }
- }
- }
- }
-
- /* if not multiedit, exit loop*/
- if (!is_multiedit) {
- break;
- }
- }
- }
- CTX_DATA_END;
- }
- else if (mode == GP_SEPARATE_LAYER) {
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- if (gpl) {
- /* try to set a new active layer in source datablock */
- if (gpl->prev) {
- BKE_gpencil_layer_setactive(gpd_src, gpl->prev);
- }
- else if (gpl->next) {
- BKE_gpencil_layer_setactive(gpd_src, gpl->next);
- }
- /* unlink from source datablock */
- BLI_remlink(&gpd_src->layers, gpl);
- gpl->prev = gpl->next = NULL;
- /* relink to destination datablock */
- BLI_addtail(&gpd_dst->layers, gpl);
-
- /* add duplicate materials */
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- ma = give_current_material(ob, gps->mat_nr + 1);
- gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma);
- }
- }
- }
- }
-
- DEG_id_tag_update(&gpd_src->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- DEG_id_tag_update(&gpd_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-
- DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ Base *base_new;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Base *base_old = CTX_data_active_base(C);
+ bGPdata *gpd_src = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+
+ Object *ob_dst = NULL;
+ bGPdata *gpd_dst = NULL;
+ bGPDlayer *gpl_dst = NULL;
+ bGPDframe *gpf_dst = NULL;
+ bGPDspoint *pt;
+ Material *ma = NULL;
+ int i, idx;
+
+ eGP_SeparateModes mode = RNA_enum_get(op->ptr, "mode");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd_src)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if ((mode == GP_SEPARATE_LAYER) && (BLI_listbase_count(&gpd_src->layers) == 1)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot separate an object with one layer only");
+ return OPERATOR_CANCELLED;
+ }
+
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_src);
+
+ /* create a new object */
+ base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, 0);
+ ob_dst = base_new->object;
+ ob_dst->mode = OB_MODE_OBJECT;
+ /* create new grease pencil datablock */
+ gpd_dst = BKE_gpencil_data_addnew(bmain, gpd_src->id.name + 2);
+ ob_dst->data = (bGPdata *)gpd_dst;
+
+ /* loop old datablock and separate parts */
+ if ((mode == GP_SEPARATE_POINT) || (mode == GP_SEPARATE_STROKE)) {
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ gpl_dst = NULL;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL) {
+ continue;
+ }
+
+ gpf_dst = NULL;
+
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ /* separate selected strokes */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* add layer if not created before */
+ if (gpl_dst == NULL) {
+ gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl->info, false);
+ }
+
+ /* add frame if not created before */
+ if (gpf_dst == NULL) {
+ gpf_dst = BKE_gpencil_layer_getframe(gpl_dst, gpf->framenum, GP_GETFRAME_ADD_NEW);
+ }
+
+ /* add duplicate materials */
+ ma = give_current_material(
+ ob, gps->mat_nr + 1); /* XXX same material can be in multiple slots */
+ idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma);
+
+ /* selected points mode */
+ if (mode == GP_SEPARATE_POINT) {
+ /* make copy of source stroke */
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
+
+ /* reasign material */
+ gps_dst->mat_nr = idx;
+
+ /* link to destination frame */
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+
+ /* Invert selection status of all points in destination stroke */
+ for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
+ pt->flag ^= GP_SPOINT_SELECT;
+ }
+
+ /* delete selected points from destination stroke */
+ gp_stroke_delete_tagged_points(gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, 0);
+
+ /* delete selected points from origin stroke */
+ gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false, 0);
+ }
+ /* selected strokes mode */
+ else if (mode == GP_SEPARATE_STROKE) {
+ /* deselect old stroke */
+ gps->flag &= ~GP_STROKE_SELECT;
+ /* unlink from source frame */
+ BLI_remlink(&gpf->strokes, gps);
+ gps->prev = gps->next = NULL;
+ /* relink to destination frame */
+ BLI_addtail(&gpf_dst->strokes, gps);
+ /* reasign material */
+ gps->mat_nr = idx;
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+ }
+ else if (mode == GP_SEPARATE_LAYER) {
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ if (gpl) {
+ /* try to set a new active layer in source datablock */
+ if (gpl->prev) {
+ BKE_gpencil_layer_setactive(gpd_src, gpl->prev);
+ }
+ else if (gpl->next) {
+ BKE_gpencil_layer_setactive(gpd_src, gpl->next);
+ }
+ /* unlink from source datablock */
+ BLI_remlink(&gpd_src->layers, gpl);
+ gpl->prev = gpl->next = NULL;
+ /* relink to destination datablock */
+ BLI_addtail(&gpd_dst->layers, gpl);
+
+ /* add duplicate materials */
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ ma = give_current_material(ob, gps->mat_nr + 1);
+ gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma);
+ }
+ }
+ }
+ }
+
+ DEG_id_tag_update(&gpd_src->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&gpd_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_separate(wmOperatorType *ot)
{
- static const EnumPropertyItem separate_type[] = {
- {GP_SEPARATE_POINT, "POINT", 0, "Selected Points", "Separate the selected points"},
- {GP_SEPARATE_STROKE, "STROKE", 0, "Selected Strokes", "Separate the selected strokes"},
- {GP_SEPARATE_LAYER, "LAYER", 0, "Active Layer", "Separate the strokes of the current layer"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Separate Strokes";
- ot->idname = "GPENCIL_OT_stroke_separate";
- ot->description = "Separate the selected strokes or layer in a new grease pencil object";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = gp_stroke_separate_exec;
- ot->poll = gp_strokes_edit3d_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "mode", separate_type, GP_SEPARATE_POINT, "Mode", "");
+ static const EnumPropertyItem separate_type[] = {
+ {GP_SEPARATE_POINT, "POINT", 0, "Selected Points", "Separate the selected points"},
+ {GP_SEPARATE_STROKE, "STROKE", 0, "Selected Strokes", "Separate the selected strokes"},
+ {GP_SEPARATE_LAYER, "LAYER", 0, "Active Layer", "Separate the strokes of the current layer"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Separate Strokes";
+ ot->idname = "GPENCIL_OT_stroke_separate";
+ ot->description = "Separate the selected strokes or layer in a new grease pencil object";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gp_stroke_separate_exec;
+ ot->poll = gp_strokes_edit3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "mode", separate_type, GP_SEPARATE_POINT, "Mode", "");
}
/* ***************** Split Strokes ********************** */
static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDspoint *pt;
- int i;
-
- /* sanity checks */
- if (ELEM(NULL, gpd)) {
- return OPERATOR_CANCELLED;
- }
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
-
- /* loop strokes and split parts */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- bGPDstroke *gps, *gpsn;
-
- if (gpf == NULL) {
- continue;
- }
-
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
- continue;
- }
- /* split selected strokes */
- if (gps->flag & GP_STROKE_SELECT) {
- /* make copy of source stroke */
- bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
-
- /* link to same frame */
- BLI_addtail(&gpf->strokes, gps_dst);
-
- /* invert selection status of all points in destination stroke */
- for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
- pt->flag ^= GP_SPOINT_SELECT;
- }
-
- /* delete selected points from destination stroke */
- gp_stroke_delete_tagged_points(gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, 0);
-
- /* delete selected points from origin stroke */
- gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false, 0);
- }
- }
- /* select again tagged points */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- bGPDspoint *ptn = gps->points;
- for (int i2 = 0; i2 < gps->totpoints; i2++, ptn++) {
- if (ptn->flag & GP_SPOINT_TAG) {
- ptn->flag |= GP_SPOINT_SELECT;
- ptn->flag &= ~GP_SPOINT_TAG;
- }
- }
- }
- }
-
- /* if not multiedit, exit loop*/
- if (!is_multiedit) {
- break;
- }
- }
- }
- CTX_DATA_END;
-
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDspoint *pt;
+ int i;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
+ /* loop strokes and split parts */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL) {
+ continue;
+ }
+
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ /* split selected strokes */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* make copy of source stroke */
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
+
+ /* link to same frame */
+ BLI_addtail(&gpf->strokes, gps_dst);
+
+ /* invert selection status of all points in destination stroke */
+ for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
+ pt->flag ^= GP_SPOINT_SELECT;
+ }
+
+ /* delete selected points from destination stroke */
+ gp_stroke_delete_tagged_points(gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, 0);
+
+ /* delete selected points from origin stroke */
+ gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false, 0);
+ }
+ }
+ /* select again tagged points */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *ptn = gps->points;
+ for (int i2 = 0; i2 < gps->totpoints; i2++, ptn++) {
+ if (ptn->flag & GP_SPOINT_TAG) {
+ ptn->flag |= GP_SPOINT_SELECT;
+ ptn->flag &= ~GP_SPOINT_TAG;
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_split(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Split Strokes";
- ot->idname = "GPENCIL_OT_stroke_split";
- ot->description = "Split selected points as new stroke on same frame";
+ /* identifiers */
+ ot->name = "Split Strokes";
+ ot->idname = "GPENCIL_OT_stroke_split";
+ ot->description = "Split selected points as new stroke on same frame";
- /* callbacks */
- ot->exec = gp_stroke_split_exec;
- ot->poll = gp_strokes_edit3d_poll;
+ /* callbacks */
+ ot->exec = gp_stroke_split_exec;
+ ot->poll = gp_strokes_edit3d_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int gp_stroke_smooth_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
- gp_smooth_stroke(C, op);
+ gp_smooth_stroke(C, op);
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_smooth(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Smooth Stroke";
- ot->idname = "GPENCIL_OT_stroke_smooth";
- ot->description = "Smooth selected strokes";
-
- /* api callbacks */
- ot->exec = gp_stroke_smooth_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- prop = RNA_def_int(ot->srna, "repeat", 1, 1, 10, "Repeat", "", 1, 5);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 2.0f, "Factor", "", 0.0f, 2.0f);
- RNA_def_boolean(
- ot->srna, "only_selected", true, "Selected Points",
- "Smooth only selected points in the stroke");
- RNA_def_boolean(ot->srna, "smooth_position", true, "Position", "");
- RNA_def_boolean(ot->srna, "smooth_thickness", true, "Thickness", "");
- RNA_def_boolean(ot->srna, "smooth_strength", false, "Strength", "");
- RNA_def_boolean(ot->srna, "smooth_uv", false, "UV", "");
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Smooth Stroke";
+ ot->idname = "GPENCIL_OT_stroke_smooth";
+ ot->description = "Smooth selected strokes";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_smooth_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_int(ot->srna, "repeat", 1, 1, 10, "Repeat", "", 1, 5);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 2.0f, "Factor", "", 0.0f, 2.0f);
+ RNA_def_boolean(ot->srna,
+ "only_selected",
+ true,
+ "Selected Points",
+ "Smooth only selected points in the stroke");
+ RNA_def_boolean(ot->srna, "smooth_position", true, "Position", "");
+ RNA_def_boolean(ot->srna, "smooth_thickness", true, "Thickness", "");
+ RNA_def_boolean(ot->srna, "smooth_strength", false, "Strength", "");
+ RNA_def_boolean(ot->srna, "smooth_uv", false, "UV", "");
}
/* smart stroke cutter for trimming stroke ends */
struct GP_SelectLassoUserData {
- rcti rect;
- const int(*mcords)[2];
- int mcords_len;
+ rcti rect;
+ const int (*mcords)[2];
+ int mcords_len;
};
-static bool gpencil_test_lasso(
- bGPDstroke *gps, bGPDspoint *pt,
- const GP_SpaceConversion *gsc, const float diff_mat[4][4],
- void *user_data)
+static bool gpencil_test_lasso(bGPDstroke *gps,
+ bGPDspoint *pt,
+ const GP_SpaceConversion *gsc,
+ const float diff_mat[4][4],
+ void *user_data)
{
- const struct GP_SelectLassoUserData *data = user_data;
- bGPDspoint pt2;
- int x0, y0;
- gp_point_to_parent_space(pt, diff_mat, &pt2);
- gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
- /* test if in lasso */
- return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) &&
- BLI_rcti_isect_pt(&data->rect, x0, y0) &&
- BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX));
+ const struct GP_SelectLassoUserData *data = user_data;
+ bGPDspoint pt2;
+ int x0, y0;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
+ /* test if in lasso */
+ return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) &&
+ BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX));
}
-typedef bool(*GPencilTestFn)(
- bGPDstroke *gps, bGPDspoint *pt,
- const GP_SpaceConversion *gsc, const float diff_mat[4][4], void *user_data);
+typedef bool (*GPencilTestFn)(bGPDstroke *gps,
+ bGPDspoint *pt,
+ const GP_SpaceConversion *gsc,
+ const float diff_mat[4][4],
+ void *user_data);
static void gpencil_cutter_dissolve(bGPDlayer *hit_layer, bGPDstroke *hit_stroke)
{
- bGPDspoint *pt = NULL;
- bGPDspoint *pt1 = NULL;
- int i;
-
- bGPDstroke *gpsn = hit_stroke->next;
-
- int totselect = 0;
- for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- totselect++;
- }
- }
-
- /* if all points selected delete or only 2 points and 1 selected */
- if (((totselect == 1) && (hit_stroke->totpoints == 2)) ||
- (hit_stroke->totpoints == totselect))
- {
- BLI_remlink(&hit_layer->actframe->strokes, hit_stroke);
- BKE_gpencil_free_stroke(hit_stroke);
- hit_stroke = NULL;
- }
-
- /* if very small distance delete */
- if ((hit_stroke) && (hit_stroke->totpoints == 2)) {
- pt = &hit_stroke->points[0];
- pt1 = &hit_stroke->points[1];
- if (len_v3v3(&pt->x, &pt1->x) < 0.001f) {
- BLI_remlink(&hit_layer->actframe->strokes, hit_stroke);
- BKE_gpencil_free_stroke(hit_stroke);
- hit_stroke = NULL;
- }
- }
-
- if (hit_stroke) {
- /* tag and dissolve (untag new points) */
- for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- pt->flag &= ~GP_SPOINT_SELECT;
- pt->flag |= GP_SPOINT_TAG;
- }
- else if (pt->flag & GP_SPOINT_TAG) {
- pt->flag &= ~GP_SPOINT_TAG;
- }
- }
- gp_stroke_delete_tagged_points(
- hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1);
- }
+ bGPDspoint *pt = NULL;
+ bGPDspoint *pt1 = NULL;
+ int i;
+
+ bGPDstroke *gpsn = hit_stroke->next;
+
+ int totselect = 0;
+ for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ totselect++;
+ }
+ }
+
+ /* if all points selected delete or only 2 points and 1 selected */
+ if (((totselect == 1) && (hit_stroke->totpoints == 2)) || (hit_stroke->totpoints == totselect)) {
+ BLI_remlink(&hit_layer->actframe->strokes, hit_stroke);
+ BKE_gpencil_free_stroke(hit_stroke);
+ hit_stroke = NULL;
+ }
+
+ /* if very small distance delete */
+ if ((hit_stroke) && (hit_stroke->totpoints == 2)) {
+ pt = &hit_stroke->points[0];
+ pt1 = &hit_stroke->points[1];
+ if (len_v3v3(&pt->x, &pt1->x) < 0.001f) {
+ BLI_remlink(&hit_layer->actframe->strokes, hit_stroke);
+ BKE_gpencil_free_stroke(hit_stroke);
+ hit_stroke = NULL;
+ }
+ }
+
+ if (hit_stroke) {
+ /* tag and dissolve (untag new points) */
+ for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ pt->flag |= GP_SPOINT_TAG;
+ }
+ else if (pt->flag & GP_SPOINT_TAG) {
+ pt->flag &= ~GP_SPOINT_TAG;
+ }
+ }
+ gp_stroke_delete_tagged_points(hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1);
+ }
}
-static int gpencil_cutter_lasso_select(
- bContext *C, wmOperator *op,
- GPencilTestFn is_inside_fn, void *user_data)
+static int gpencil_cutter_lasso_select(bContext *C,
+ wmOperator *op,
+ GPencilTestFn is_inside_fn,
+ void *user_data)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- ScrArea *sa = CTX_wm_area(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- const float scale = ts->gp_sculpt.isect_threshold;
-
- bGPDspoint *pt;
- int i;
- GP_SpaceConversion gsc = { NULL };
-
- bool changed = false;
-
- /* sanity checks */
- if (sa == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active area");
- return OPERATOR_CANCELLED;
- }
-
- /* init space conversion stuff */
- gp_point_conversion_init(C, &gsc);
-
- /* deselect all strokes first */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
-
- gps->flag &= ~GP_STROKE_SELECT;
- }
- CTX_DATA_END;
-
- /* select points */
- GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
- int tot_inside = 0;
- const int oldtot = gps->totpoints;
- for (i = 0; i < gps->totpoints; i++) {
- pt = &gps->points[i];
- if ((pt->flag & GP_SPOINT_SELECT) || (pt->flag & GP_SPOINT_TAG)) {
- continue;
- }
- /* convert point coords to screenspace */
- const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
- if (is_inside) {
- tot_inside++;
- changed = true;
- pt->flag |= GP_SPOINT_SELECT;
- gps->flag |= GP_STROKE_SELECT;
- float r_hita[3], r_hitb[3];
- if (gps->totpoints > 1) {
- ED_gpencil_select_stroke_segment(
- gpl, gps, pt, true, true, scale, r_hita, r_hitb);
- }
- /* avoid infinite loops */
- if (gps->totpoints > oldtot) {
- break;
- }
- }
- }
- /* if mark all points inside lasso set to remove all stroke */
- if ((tot_inside == oldtot) ||
- ((tot_inside == 1) && (oldtot == 2)))
- {
- for (i = 0; i < gps->totpoints; i++) {
- pt = &gps->points[i];
- pt->flag |= GP_SPOINT_SELECT;
- }
- }
- }
- GP_EDITABLE_STROKES_END(gpstroke_iter);
-
- /* dissolve selected points */
- bGPDstroke *gpsn;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL) {
- continue;
- }
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
- if (gps->flag & GP_STROKE_SELECT) {
- gpencil_cutter_dissolve(gpl, gps);
- }
- }
- }
-
- /* updates */
- if (changed) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- }
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ const float scale = ts->gp_sculpt.isect_threshold;
+
+ bGPDspoint *pt;
+ int i;
+ GP_SpaceConversion gsc = {NULL};
+
+ bool changed = false;
+
+ /* sanity checks */
+ if (sa == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active area");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
+
+ /* deselect all strokes first */
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ CTX_DATA_END;
+
+ /* select points */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ int tot_inside = 0;
+ const int oldtot = gps->totpoints;
+ for (i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ if ((pt->flag & GP_SPOINT_SELECT) || (pt->flag & GP_SPOINT_TAG)) {
+ continue;
+ }
+ /* convert point coords to screenspace */
+ const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
+ if (is_inside) {
+ tot_inside++;
+ changed = true;
+ pt->flag |= GP_SPOINT_SELECT;
+ gps->flag |= GP_STROKE_SELECT;
+ float r_hita[3], r_hitb[3];
+ if (gps->totpoints > 1) {
+ ED_gpencil_select_stroke_segment(gpl, gps, pt, true, true, scale, r_hita, r_hitb);
+ }
+ /* avoid infinite loops */
+ if (gps->totpoints > oldtot) {
+ break;
+ }
+ }
+ }
+ /* if mark all points inside lasso set to remove all stroke */
+ if ((tot_inside == oldtot) || ((tot_inside == 1) && (oldtot == 2))) {
+ for (i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* dissolve selected points */
+ bGPDstroke *gpsn;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL) {
+ continue;
+ }
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ if (gps->flag & GP_STROKE_SELECT) {
+ gpencil_cutter_dissolve(gpl, gps);
+ }
+ }
+ }
+
+ /* updates */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ }
+
+ return OPERATOR_FINISHED;
}
static bool gpencil_cutter_poll(bContext *C)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
- if (GPENCIL_PAINT_MODE(gpd)) {
- if (gpd->layers.first)
- return true;
- }
+ if (GPENCIL_PAINT_MODE(gpd)) {
+ if (gpd->layers.first)
+ return true;
+ }
- return false;
+ return false;
}
static int gpencil_cutter_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
- /* sanity checks */
- if (sa == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active area");
- return OPERATOR_CANCELLED;
- }
+ ScrArea *sa = CTX_wm_area(C);
+ /* sanity checks */
+ if (sa == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active area");
+ return OPERATOR_CANCELLED;
+ }
- struct GP_SelectLassoUserData data = { 0 };
- data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len);
+ struct GP_SelectLassoUserData data = {0};
+ data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len);
- /* Sanity check. */
- if (data.mcords == NULL) {
- return OPERATOR_PASS_THROUGH;
- }
+ /* Sanity check. */
+ if (data.mcords == NULL) {
+ return OPERATOR_PASS_THROUGH;
+ }
- /* Compute boundbox of lasso (for faster testing later). */
- BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
+ /* Compute boundbox of lasso (for faster testing later). */
+ BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
- gpencil_cutter_lasso_select(C, op, gpencil_test_lasso, &data);
+ gpencil_cutter_lasso_select(C, op, gpencil_test_lasso, &data);
- MEM_freeN((void *)data.mcords);
+ MEM_freeN((void *)data.mcords);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_cutter(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Stroke Cutter";
- ot->description = "Select section and cut";
- ot->idname = "GPENCIL_OT_stroke_cutter";
-
- /* callbacks */
- ot->invoke = WM_gesture_lasso_invoke;
- ot->modal = WM_gesture_lasso_modal;
- ot->exec = gpencil_cutter_exec;
- ot->poll = gpencil_cutter_poll;
- ot->cancel = WM_gesture_lasso_cancel;
-
- /* flag */
- ot->flag = OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
-
- /* properties */
- WM_operator_properties_gesture_lasso(ot);
+ /* identifiers */
+ ot->name = "Stroke Cutter";
+ ot->description = "Select section and cut";
+ ot->idname = "GPENCIL_OT_stroke_cutter";
+
+ /* callbacks */
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = gpencil_cutter_exec;
+ ot->poll = gpencil_cutter_poll;
+ ot->cancel = WM_gesture_lasso_cancel;
+
+ /* flag */
+ ot->flag = OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
+
+ /* properties */
+ WM_operator_properties_gesture_lasso(ot);
}
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 76d15557055..8d3137ed3db 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -79,373 +79,393 @@
#define LEAK_HORZ 0
#define LEAK_VERT 1
-
- /* Temporary fill operation data (op->customdata) */
+/* Temporary fill operation data (op->customdata) */
typedef struct tGPDfill {
- bContext *C;
- struct Main *bmain;
- struct Depsgraph *depsgraph;
- /** window where painting originated */
- struct wmWindow *win;
- /** current scene from context */
- struct Scene *scene;
- /** current active gp object */
- struct Object *ob;
- /** area where painting originated */
- struct ScrArea *sa;
- /** region where painting originated */
- struct RegionView3D *rv3d;
- /** view3 where painting originated */
- struct View3D *v3d;
- /** region where painting originated */
- struct ARegion *ar;
- /** current GP datablock */
- struct bGPdata *gpd;
- /** current material */
- struct Material *mat;
- /** layer */
- struct bGPDlayer *gpl;
- /** frame */
- struct bGPDframe *gpf;
-
- /** flags */
- short flag;
- /** avoid too fast events */
- short oldkey;
- /** send to back stroke */
- bool on_back;
-
- /** mouse fill center position */
- int center[2];
- /** windows width */
- int sizex;
- /** window height */
- int sizey;
- /** lock to viewport axis */
- int lock_axis;
-
- /** number of pixel to consider the leak is too small (x 2) */
- short fill_leak;
- /** factor for transparency */
- float fill_threshold;
- /** number of simplify steps */
- int fill_simplylvl;
- /** boundary limits drawing mode */
- int fill_draw_mode;
- /* scaling factor */
- short fill_factor;
-
- /** number of elements currently in cache */
- short sbuffer_size;
- /** temporary points */
- void *sbuffer;
- /** depth array for reproject */
- float *depth_arr;
-
- /** temp image */
- Image *ima;
- /** temp points data */
- BLI_Stack *stack;
- /** handle for drawing strokes while operator is running 3d stuff */
- void *draw_handle_3d;
-
- /* tmp size x */
- int bwinx;
- /* tmp size y */
- int bwiny;
- rcti brect;
+ bContext *C;
+ struct Main *bmain;
+ struct Depsgraph *depsgraph;
+ /** window where painting originated */
+ struct wmWindow *win;
+ /** current scene from context */
+ struct Scene *scene;
+ /** current active gp object */
+ struct Object *ob;
+ /** area where painting originated */
+ struct ScrArea *sa;
+ /** region where painting originated */
+ struct RegionView3D *rv3d;
+ /** view3 where painting originated */
+ struct View3D *v3d;
+ /** region where painting originated */
+ struct ARegion *ar;
+ /** current GP datablock */
+ struct bGPdata *gpd;
+ /** current material */
+ struct Material *mat;
+ /** layer */
+ struct bGPDlayer *gpl;
+ /** frame */
+ struct bGPDframe *gpf;
+
+ /** flags */
+ short flag;
+ /** avoid too fast events */
+ short oldkey;
+ /** send to back stroke */
+ bool on_back;
+
+ /** mouse fill center position */
+ int center[2];
+ /** windows width */
+ int sizex;
+ /** window height */
+ int sizey;
+ /** lock to viewport axis */
+ int lock_axis;
+
+ /** number of pixel to consider the leak is too small (x 2) */
+ short fill_leak;
+ /** factor for transparency */
+ float fill_threshold;
+ /** number of simplify steps */
+ int fill_simplylvl;
+ /** boundary limits drawing mode */
+ int fill_draw_mode;
+ /* scaling factor */
+ short fill_factor;
+
+ /** number of elements currently in cache */
+ short sbuffer_size;
+ /** temporary points */
+ void *sbuffer;
+ /** depth array for reproject */
+ float *depth_arr;
+
+ /** temp image */
+ Image *ima;
+ /** temp points data */
+ BLI_Stack *stack;
+ /** handle for drawing strokes while operator is running 3d stuff */
+ void *draw_handle_3d;
+
+ /* tmp size x */
+ int bwinx;
+ /* tmp size y */
+ int bwiny;
+ rcti brect;
} tGPDfill;
-
/* draw a given stroke using same thickness and color for all points */
-static void gp_draw_basic_stroke(
- tGPDfill *tgpf, bGPDstroke *gps, const float diff_mat[4][4],
- const bool cyclic, const float ink[4], const int flag, const float thershold)
+static void gp_draw_basic_stroke(tGPDfill *tgpf,
+ bGPDstroke *gps,
+ const float diff_mat[4][4],
+ const bool cyclic,
+ const float ink[4],
+ const int flag,
+ const float thershold)
{
- bGPDspoint *points = gps->points;
-
- Material *ma = tgpf->mat;
- MaterialGPencilStyle *gp_style = ma->gp_style;
-
- int totpoints = gps->totpoints;
- float fpt[3];
- float col[4];
-
- copy_v4_v4(col, ink);
-
- /* if cyclic needs more vertex */
- int cyclic_add = (cyclic) ? 1 : 0;
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
-
- /* draw stroke curve */
- GPU_line_width(1.0f);
- immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
- const bGPDspoint *pt = points;
-
- for (int i = 0; i < totpoints; i++, pt++) {
-
- if (flag & GP_BRUSH_FILL_HIDE) {
- float alpha = gp_style->stroke_rgba[3] * pt->strength;
- CLAMP(alpha, 0.0f, 1.0f);
- col[3] = alpha <= thershold ? 0.0f : 1.0f;
- }
- else {
- col[3] = 1.0f;
- }
- /* set point */
- immAttr4fv(color, col);
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- immVertex3fv(pos, fpt);
- }
-
- if (cyclic && totpoints > 2) {
- /* draw line to first point to complete the cycle */
- immAttr4fv(color, col);
- mul_v3_m4v3(fpt, diff_mat, &points->x);
- immVertex3fv(pos, fpt);
- }
-
- immEnd();
- immUnbindProgram();
+ bGPDspoint *points = gps->points;
+
+ Material *ma = tgpf->mat;
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+
+ int totpoints = gps->totpoints;
+ float fpt[3];
+ float col[4];
+
+ copy_v4_v4(col, ink);
+
+ /* if cyclic needs more vertex */
+ int cyclic_add = (cyclic) ? 1 : 0;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ /* draw stroke curve */
+ GPU_line_width(1.0f);
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
+ const bGPDspoint *pt = points;
+
+ for (int i = 0; i < totpoints; i++, pt++) {
+
+ if (flag & GP_BRUSH_FILL_HIDE) {
+ float alpha = gp_style->stroke_rgba[3] * pt->strength;
+ CLAMP(alpha, 0.0f, 1.0f);
+ col[3] = alpha <= thershold ? 0.0f : 1.0f;
+ }
+ else {
+ col[3] = 1.0f;
+ }
+ /* set point */
+ immAttr4fv(color, col);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ immVertex3fv(pos, fpt);
+ }
+
+ if (cyclic && totpoints > 2) {
+ /* draw line to first point to complete the cycle */
+ immAttr4fv(color, col);
+ mul_v3_m4v3(fpt, diff_mat, &points->x);
+ immVertex3fv(pos, fpt);
+ }
+
+ immEnd();
+ immUnbindProgram();
}
/* loop all layers */
static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4])
{
- /* duplicated: etempFlags */
- enum {
- GP_DRAWFILLS_NOSTATUS = (1 << 0), /* don't draw status info */
- GP_DRAWFILLS_ONLY3D = (1 << 1), /* only draw 3d-strokes */
- };
-
- Object *ob = tgpf->ob;
- bGPdata *gpd = tgpf->gpd;
- int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
-
- tGPDdraw tgpw;
- tgpw.rv3d = tgpf->rv3d;
- tgpw.depsgraph = tgpf->depsgraph;
- tgpw.ob = ob;
- tgpw.gpd = gpd;
- tgpw.offsx = 0;
- tgpw.offsy = 0;
- tgpw.winx = tgpf->ar->winx;
- tgpw.winy = tgpf->ar->winy;
- tgpw.dflag = 0;
- tgpw.disable_fill = 1;
- tgpw.dflag |= (GP_DRAWFILLS_ONLY3D | GP_DRAWFILLS_NOSTATUS);
-
- GPU_blend(true);
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* calculate parent position */
- ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, tgpw.diff_mat);
-
- /* do not draw layer if hidden */
- if (gpl->flag & GP_LAYER_HIDE)
- continue;
-
- /* if active layer and no keyframe, create a new one */
- if (gpl == tgpf->gpl) {
- if ((gpl->actframe == NULL) || (gpl->actframe->framenum != cfra_eval)) {
- BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
- }
- }
-
- /* get frame to draw */
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
- if (gpf == NULL)
- continue;
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* check if stroke can be drawn */
- if ((gps->points == NULL) || (gps->totpoints < 2)) {
- continue;
- }
- /* check if the color is visible */
- MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
- if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) {
- continue;
- }
-
- tgpw.gps = gps;
- tgpw.gpl = gpl;
- tgpw.gpf = gpf;
- tgpw.t_gpf = gpf;
-
- /* reduce thickness to avoid gaps */
- tgpw.is_fill_stroke = (tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ? false : true ;
- tgpw.lthick = gpl->line_change;
- tgpw.opacity = 1.0;
- copy_v4_v4(tgpw.tintcolor, ink);
- tgpw.onion = true;
- tgpw.custonion = true;
-
- bool textured_stroke = (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE);
-
- /* normal strokes */
- if (((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
- (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) &&
- !textured_stroke)
- {
- ED_gp_draw_fill(&tgpw);
- }
-
- /* 3D Lines with basic shapes and invisible lines */
- if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ||
- (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH) ||
- textured_stroke)
- {
- gp_draw_basic_stroke(
- tgpf, gps, tgpw.diff_mat, gps->flag & GP_STROKE_CYCLIC, ink,
- tgpf->flag, tgpf->fill_threshold);
- }
- }
- }
-
- GPU_blend(false);
+ /* duplicated: etempFlags */
+ enum {
+ GP_DRAWFILLS_NOSTATUS = (1 << 0), /* don't draw status info */
+ GP_DRAWFILLS_ONLY3D = (1 << 1), /* only draw 3d-strokes */
+ };
+
+ Object *ob = tgpf->ob;
+ bGPdata *gpd = tgpf->gpd;
+ int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
+
+ tGPDdraw tgpw;
+ tgpw.rv3d = tgpf->rv3d;
+ tgpw.depsgraph = tgpf->depsgraph;
+ tgpw.ob = ob;
+ tgpw.gpd = gpd;
+ tgpw.offsx = 0;
+ tgpw.offsy = 0;
+ tgpw.winx = tgpf->ar->winx;
+ tgpw.winy = tgpf->ar->winy;
+ tgpw.dflag = 0;
+ tgpw.disable_fill = 1;
+ tgpw.dflag |= (GP_DRAWFILLS_ONLY3D | GP_DRAWFILLS_NOSTATUS);
+
+ GPU_blend(true);
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* calculate parent position */
+ ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, tgpw.diff_mat);
+
+ /* do not draw layer if hidden */
+ if (gpl->flag & GP_LAYER_HIDE)
+ continue;
+
+ /* if active layer and no keyframe, create a new one */
+ if (gpl == tgpf->gpl) {
+ if ((gpl->actframe == NULL) || (gpl->actframe->framenum != cfra_eval)) {
+ BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
+ }
+ }
+
+ /* get frame to draw */
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* check if stroke can be drawn */
+ if ((gps->points == NULL) || (gps->totpoints < 2)) {
+ continue;
+ }
+ /* check if the color is visible */
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) {
+ continue;
+ }
+
+ tgpw.gps = gps;
+ tgpw.gpl = gpl;
+ tgpw.gpf = gpf;
+ tgpw.t_gpf = gpf;
+
+ /* reduce thickness to avoid gaps */
+ tgpw.is_fill_stroke = (tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ? false : true;
+ tgpw.lthick = gpl->line_change;
+ tgpw.opacity = 1.0;
+ copy_v4_v4(tgpw.tintcolor, ink);
+ tgpw.onion = true;
+ tgpw.custonion = true;
+
+ bool textured_stroke = (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE);
+
+ /* normal strokes */
+ if (((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
+ (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) &&
+ !textured_stroke) {
+ ED_gp_draw_fill(&tgpw);
+ }
+
+ /* 3D Lines with basic shapes and invisible lines */
+ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ||
+ (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH) || textured_stroke) {
+ gp_draw_basic_stroke(tgpf,
+ gps,
+ tgpw.diff_mat,
+ gps->flag & GP_STROKE_CYCLIC,
+ ink,
+ tgpf->flag,
+ tgpf->fill_threshold);
+ }
+ }
+ }
+
+ GPU_blend(false);
}
/* draw strokes in offscreen buffer */
static bool gp_render_offscreen(tGPDfill *tgpf)
{
- bool is_ortho = false;
- float winmat[4][4];
-
- if (!tgpf->gpd) {
- return false;
- }
-
- /* set temporary new size */
- tgpf->bwinx = tgpf->ar->winx;
- tgpf->bwiny = tgpf->ar->winy;
- tgpf->brect = tgpf->ar->winrct;
-
- /* resize ar */
- tgpf->ar->winrct.xmin = 0;
- tgpf->ar->winrct.ymin = 0;
- tgpf->ar->winrct.xmax = (int)tgpf->ar->winx * tgpf->fill_factor;
- tgpf->ar->winrct.ymax = (int)tgpf->ar->winy * tgpf->fill_factor;
- tgpf->ar->winx = (short)abs(tgpf->ar->winrct.xmax - tgpf->ar->winrct.xmin);
- tgpf->ar->winy = (short)abs(tgpf->ar->winrct.ymax - tgpf->ar->winrct.ymin);
-
- /* save new size */
- tgpf->sizex = (int)tgpf->ar->winx;
- tgpf->sizey = (int)tgpf->ar->winy;
-
- /* adjust center */
- float center[2];
- center[0] = (float)tgpf->center[0] * ((float)tgpf->ar->winx / (float)tgpf->bwinx);
- center[1] = (float)tgpf->center[1] * ((float)tgpf->ar->winy / (float)tgpf->bwiny);
- round_v2i_v2fl(tgpf->center, center);
-
- char err_out[256] = "unknown";
- GPUOffScreen *offscreen = GPU_offscreen_create(tgpf->sizex, tgpf->sizey, 0, true, false, err_out);
- if (offscreen == NULL) {
- printf("GPencil - Fill - Unable to create fill buffer\n");
- return false;
- }
-
- GPU_offscreen_bind(offscreen, true);
- uint flag = IB_rect | IB_rectfloat;
- ImBuf *ibuf = IMB_allocImBuf(tgpf->sizex, tgpf->sizey, 32, flag);
-
- rctf viewplane;
- float clip_start, clip_end;
-
- is_ortho = ED_view3d_viewplane_get(
- tgpf->depsgraph, tgpf->v3d, tgpf->rv3d, tgpf->sizex, tgpf->sizey,
- &viewplane, &clip_start, &clip_end, NULL);
- if (is_ortho) {
- orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clip_end, clip_end);
- }
- else {
- perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clip_start, clip_end);
- }
-
- GPU_matrix_push_projection();
- GPU_matrix_identity_set();
- GPU_matrix_push();
- GPU_matrix_identity_set();
-
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- ED_view3d_update_viewmat(
- tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar,
- NULL, winmat, NULL);
- /* set for opengl */
- GPU_matrix_projection_set(tgpf->rv3d->winmat);
- GPU_matrix_set(tgpf->rv3d->viewmat);
-
- /* draw strokes */
- float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
- gp_draw_datablock(tgpf, ink);
-
- GPU_matrix_pop_projection();
- GPU_matrix_pop();
-
- /* create a image to see result of template */
- if (ibuf->rect_float) {
- GPU_offscreen_read_pixels(offscreen, GL_FLOAT, ibuf->rect_float);
- }
- else if (ibuf->rect) {
- GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, ibuf->rect);
- }
- if (ibuf->rect_float && ibuf->rect) {
- IMB_rect_from_float(ibuf);
- }
-
- tgpf->ima = BKE_image_add_from_imbuf(tgpf->bmain, ibuf, "GP_fill");
- tgpf->ima->id.tag |= LIB_TAG_DOIT;
-
- BKE_image_release_ibuf(tgpf->ima, ibuf, NULL);
-
- /* switch back to window-system-provided framebuffer */
- GPU_offscreen_unbind(offscreen, true);
- GPU_offscreen_free(offscreen);
-
- return true;
+ bool is_ortho = false;
+ float winmat[4][4];
+
+ if (!tgpf->gpd) {
+ return false;
+ }
+
+ /* set temporary new size */
+ tgpf->bwinx = tgpf->ar->winx;
+ tgpf->bwiny = tgpf->ar->winy;
+ tgpf->brect = tgpf->ar->winrct;
+
+ /* resize ar */
+ tgpf->ar->winrct.xmin = 0;
+ tgpf->ar->winrct.ymin = 0;
+ tgpf->ar->winrct.xmax = (int)tgpf->ar->winx * tgpf->fill_factor;
+ tgpf->ar->winrct.ymax = (int)tgpf->ar->winy * tgpf->fill_factor;
+ tgpf->ar->winx = (short)abs(tgpf->ar->winrct.xmax - tgpf->ar->winrct.xmin);
+ tgpf->ar->winy = (short)abs(tgpf->ar->winrct.ymax - tgpf->ar->winrct.ymin);
+
+ /* save new size */
+ tgpf->sizex = (int)tgpf->ar->winx;
+ tgpf->sizey = (int)tgpf->ar->winy;
+
+ /* adjust center */
+ float center[2];
+ center[0] = (float)tgpf->center[0] * ((float)tgpf->ar->winx / (float)tgpf->bwinx);
+ center[1] = (float)tgpf->center[1] * ((float)tgpf->ar->winy / (float)tgpf->bwiny);
+ round_v2i_v2fl(tgpf->center, center);
+
+ char err_out[256] = "unknown";
+ GPUOffScreen *offscreen = GPU_offscreen_create(
+ tgpf->sizex, tgpf->sizey, 0, true, false, err_out);
+ if (offscreen == NULL) {
+ printf("GPencil - Fill - Unable to create fill buffer\n");
+ return false;
+ }
+
+ GPU_offscreen_bind(offscreen, true);
+ uint flag = IB_rect | IB_rectfloat;
+ ImBuf *ibuf = IMB_allocImBuf(tgpf->sizex, tgpf->sizey, 32, flag);
+
+ rctf viewplane;
+ float clip_start, clip_end;
+
+ is_ortho = ED_view3d_viewplane_get(tgpf->depsgraph,
+ tgpf->v3d,
+ tgpf->rv3d,
+ tgpf->sizex,
+ tgpf->sizey,
+ &viewplane,
+ &clip_start,
+ &clip_end,
+ NULL);
+ if (is_ortho) {
+ orthographic_m4(winmat,
+ viewplane.xmin,
+ viewplane.xmax,
+ viewplane.ymin,
+ viewplane.ymax,
+ -clip_end,
+ clip_end);
+ }
+ else {
+ perspective_m4(winmat,
+ viewplane.xmin,
+ viewplane.xmax,
+ viewplane.ymin,
+ viewplane.ymax,
+ clip_start,
+ clip_end);
+ }
+
+ GPU_matrix_push_projection();
+ GPU_matrix_identity_set();
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ ED_view3d_update_viewmat(tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar, NULL, winmat, NULL);
+ /* set for opengl */
+ GPU_matrix_projection_set(tgpf->rv3d->winmat);
+ GPU_matrix_set(tgpf->rv3d->viewmat);
+
+ /* draw strokes */
+ float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ gp_draw_datablock(tgpf, ink);
+
+ GPU_matrix_pop_projection();
+ GPU_matrix_pop();
+
+ /* create a image to see result of template */
+ if (ibuf->rect_float) {
+ GPU_offscreen_read_pixels(offscreen, GL_FLOAT, ibuf->rect_float);
+ }
+ else if (ibuf->rect) {
+ GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, ibuf->rect);
+ }
+ if (ibuf->rect_float && ibuf->rect) {
+ IMB_rect_from_float(ibuf);
+ }
+
+ tgpf->ima = BKE_image_add_from_imbuf(tgpf->bmain, ibuf, "GP_fill");
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
+
+ BKE_image_release_ibuf(tgpf->ima, ibuf, NULL);
+
+ /* switch back to window-system-provided framebuffer */
+ GPU_offscreen_unbind(offscreen, true);
+ GPU_offscreen_free(offscreen);
+
+ return true;
}
/* return pixel data (rgba) at index */
static void get_pixel(const ImBuf *ibuf, const int idx, float r_col[4])
{
- if (ibuf->rect_float) {
- const float *frgba = &ibuf->rect_float[idx * 4];
- copy_v4_v4(r_col, frgba);
- }
- else {
- /* XXX: This case probably doesn't happen, as we only write to the float buffer,
- * but we get compiler warnings about uninitialised vars otherwise
- */
- BLI_assert(!"gpencil_fill.c - get_pixel() non-float case is used!");
- zero_v4(r_col);
- }
+ if (ibuf->rect_float) {
+ const float *frgba = &ibuf->rect_float[idx * 4];
+ copy_v4_v4(r_col, frgba);
+ }
+ else {
+ /* XXX: This case probably doesn't happen, as we only write to the float buffer,
+ * but we get compiler warnings about uninitialised vars otherwise
+ */
+ BLI_assert(!"gpencil_fill.c - get_pixel() non-float case is used!");
+ zero_v4(r_col);
+ }
}
/* set pixel data (rgba) at index */
static void set_pixel(ImBuf *ibuf, int idx, const float col[4])
{
- //BLI_assert(idx <= ibuf->x * ibuf->y);
- if (ibuf->rect) {
- uint *rrect = &ibuf->rect[idx];
- uchar ccol[4];
-
- rgba_float_to_uchar(ccol, col);
- *rrect = *((uint *)ccol);
- }
-
- if (ibuf->rect_float) {
- float *rrectf = &ibuf->rect_float[idx * 4];
- copy_v4_v4(rrectf, col);
- }
+ //BLI_assert(idx <= ibuf->x * ibuf->y);
+ if (ibuf->rect) {
+ uint *rrect = &ibuf->rect[idx];
+ uchar ccol[4];
+
+ rgba_float_to_uchar(ccol, col);
+ *rrect = *((uint *)ccol);
+ }
+
+ if (ibuf->rect_float) {
+ float *rrectf = &ibuf->rect_float[idx * 4];
+ copy_v4_v4(rrectf, col);
+ }
}
/* check if the size of the leak is narrow to determine if the stroke is closed
@@ -460,96 +480,96 @@ static void set_pixel(ImBuf *ibuf, int idx, const float col[4])
*/
static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index, int type)
{
- float rgba[4];
- int i;
- int pt;
- bool t_a = false;
- bool t_b = false;
-
- /* Horizontal leak (check vertical pixels)
- * X
- * X
- * xB7
- * X
- * X
- */
- if (type == LEAK_HORZ) {
- /* pixels on top */
- for (i = 1; i <= limit; i++) {
- pt = index + (ibuf->x * i);
- if (pt <= maxpixel) {
- get_pixel(ibuf, pt, rgba);
- if (rgba[0] == 1.0f) {
- t_a = true;
- break;
- }
- }
- else {
- /* edge of image*/
- t_a = true;
- break;
- }
- }
- /* pixels on bottom */
- for (i = 1; i <= limit; i++) {
- pt = index - (ibuf->x * i);
- if (pt >= 0) {
- get_pixel(ibuf, pt, rgba);
- if (rgba[0] == 1.0f) {
- t_b = true;
- break;
- }
- }
- else {
- /* edge of image*/
- t_b = true;
- break;
- }
- }
- }
-
- /* Vertical leak (check horizontal pixels)
- *
- * XXXxB7XX
- */
- if (type == LEAK_VERT) {
- /* get pixel range of the row */
- int row = index / ibuf->x;
- int lowpix = row * ibuf->x;
- int higpix = lowpix + ibuf->x - 1;
-
- /* pixels to right */
- for (i = 0; i < limit; i++) {
- pt = index - (limit - i);
- if (pt >= lowpix) {
- get_pixel(ibuf, pt, rgba);
- if (rgba[0] == 1.0f) {
- t_a = true;
- break;
- }
- }
- else {
- t_a = true; /* edge of image*/
- break;
- }
- }
- /* pixels to left */
- for (i = 0; i < limit; i++) {
- pt = index + (limit - i);
- if (pt <= higpix) {
- get_pixel(ibuf, pt, rgba);
- if (rgba[0] == 1.0f) {
- t_b = true;
- break;
- }
- }
- else {
- t_b = true; /* edge of image */
- break;
- }
- }
- }
- return (bool)(t_a && t_b);
+ float rgba[4];
+ int i;
+ int pt;
+ bool t_a = false;
+ bool t_b = false;
+
+ /* Horizontal leak (check vertical pixels)
+ * X
+ * X
+ * xB7
+ * X
+ * X
+ */
+ if (type == LEAK_HORZ) {
+ /* pixels on top */
+ for (i = 1; i <= limit; i++) {
+ pt = index + (ibuf->x * i);
+ if (pt <= maxpixel) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_a = true;
+ break;
+ }
+ }
+ else {
+ /* edge of image*/
+ t_a = true;
+ break;
+ }
+ }
+ /* pixels on bottom */
+ for (i = 1; i <= limit; i++) {
+ pt = index - (ibuf->x * i);
+ if (pt >= 0) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_b = true;
+ break;
+ }
+ }
+ else {
+ /* edge of image*/
+ t_b = true;
+ break;
+ }
+ }
+ }
+
+ /* Vertical leak (check horizontal pixels)
+ *
+ * XXXxB7XX
+ */
+ if (type == LEAK_VERT) {
+ /* get pixel range of the row */
+ int row = index / ibuf->x;
+ int lowpix = row * ibuf->x;
+ int higpix = lowpix + ibuf->x - 1;
+
+ /* pixels to right */
+ for (i = 0; i < limit; i++) {
+ pt = index - (limit - i);
+ if (pt >= lowpix) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_a = true;
+ break;
+ }
+ }
+ else {
+ t_a = true; /* edge of image*/
+ break;
+ }
+ }
+ /* pixels to left */
+ for (i = 0; i < limit; i++) {
+ pt = index + (limit - i);
+ if (pt <= higpix) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_b = true;
+ break;
+ }
+ }
+ else {
+ t_b = true; /* edge of image */
+ break;
+ }
+ }
+ }
+ return (bool)(t_a && t_b);
}
/* Boundary fill inside strokes
@@ -560,122 +580,122 @@ static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index
*/
static void gpencil_boundaryfill_area(tGPDfill *tgpf)
{
- ImBuf *ibuf;
- float rgba[4];
- void *lock;
- const float fill_col[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
- ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
- const int maxpixel = (ibuf->x * ibuf->y) - 1;
-
- BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
-
- /* calculate index of the seed point using the position of the mouse */
- int index = (tgpf->sizex * tgpf->center[1]) + tgpf->center[0];
- if ((index >= 0) && (index <= maxpixel)) {
- BLI_stack_push(stack, &index);
- }
-
- /* the fill use a stack to save the pixel list instead of the common recursive
- * 4-contact point method.
- * The problem with recursive calls is that for big fill areas, we can get max limit
- * of recursive calls and STACK_OVERFLOW error.
- *
- * The 4-contact point analyze the pixels to the left, right, bottom and top
- * -----------
- * | X |
- * | XoX |
- * | X |
- * -----------
- */
- while (!BLI_stack_is_empty(stack)) {
- int v;
-
- BLI_stack_pop(stack, &v);
-
- get_pixel(ibuf, v, rgba);
-
- if (true) { /* Was: 'rgba' */
- /* check if no border(red) or already filled color(green) */
- if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) {
- /* fill current pixel with green */
- set_pixel(ibuf, v, fill_col);
-
- /* add contact pixels */
- /* pixel left */
- if (v - 1 >= 0) {
- index = v - 1;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
- BLI_stack_push(stack, &index);
- }
- }
- /* pixel right */
- if (v + 1 <= maxpixel) {
- index = v + 1;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
- BLI_stack_push(stack, &index);
- }
- }
- /* pixel top */
- if (v + ibuf->x <= maxpixel) {
- index = v + ibuf->x;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
- BLI_stack_push(stack, &index);
- }
- }
- /* pixel bottom */
- if (v - ibuf->x >= 0) {
- index = v - ibuf->x;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
- BLI_stack_push(stack, &index);
- }
- }
- }
- }
- }
-
- /* release ibuf */
- if (ibuf) {
- BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
- }
-
- tgpf->ima->id.tag |= LIB_TAG_DOIT;
- /* free temp stack data */
- BLI_stack_free(stack);
+ ImBuf *ibuf;
+ float rgba[4];
+ void *lock;
+ const float fill_col[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ const int maxpixel = (ibuf->x * ibuf->y) - 1;
+
+ BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
+
+ /* calculate index of the seed point using the position of the mouse */
+ int index = (tgpf->sizex * tgpf->center[1]) + tgpf->center[0];
+ if ((index >= 0) && (index <= maxpixel)) {
+ BLI_stack_push(stack, &index);
+ }
+
+ /* the fill use a stack to save the pixel list instead of the common recursive
+ * 4-contact point method.
+ * The problem with recursive calls is that for big fill areas, we can get max limit
+ * of recursive calls and STACK_OVERFLOW error.
+ *
+ * The 4-contact point analyze the pixels to the left, right, bottom and top
+ * -----------
+ * | X |
+ * | XoX |
+ * | X |
+ * -----------
+ */
+ while (!BLI_stack_is_empty(stack)) {
+ int v;
+
+ BLI_stack_pop(stack, &v);
+
+ get_pixel(ibuf, v, rgba);
+
+ if (true) { /* Was: 'rgba' */
+ /* check if no border(red) or already filled color(green) */
+ if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) {
+ /* fill current pixel with green */
+ set_pixel(ibuf, v, fill_col);
+
+ /* add contact pixels */
+ /* pixel left */
+ if (v - 1 >= 0) {
+ index = v - 1;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel right */
+ if (v + 1 <= maxpixel) {
+ index = v + 1;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel top */
+ if (v + ibuf->x <= maxpixel) {
+ index = v + ibuf->x;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel bottom */
+ if (v - ibuf->x >= 0) {
+ index = v - ibuf->x;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ }
+ }
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
+
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
+ /* free temp stack data */
+ BLI_stack_free(stack);
}
/* clean external border of image to avoid infinite loops */
static void gpencil_clean_borders(tGPDfill *tgpf)
{
- ImBuf *ibuf;
- void *lock;
- const float fill_col[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
- ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
- int idx;
- int pixel = 0;
-
- /* horizontal lines */
- for (idx = 0; idx < ibuf->x; idx++) {
- /* bottom line */
- set_pixel(ibuf, idx, fill_col);
- /* top line */
- pixel = idx + (ibuf->x * (ibuf->y - 1));
- set_pixel(ibuf, pixel, fill_col);
- }
- /* vertical lines */
- for (idx = 0; idx < ibuf->y; idx++) {
- /* left line */
- set_pixel(ibuf, ibuf->x * idx, fill_col);
- /* right line */
- pixel = ibuf->x * idx + (ibuf->x - 1);
- set_pixel(ibuf, pixel, fill_col);
- }
-
- /* release ibuf */
- if (ibuf) {
- BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
- }
-
- tgpf->ima->id.tag |= LIB_TAG_DOIT;
+ ImBuf *ibuf;
+ void *lock;
+ const float fill_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ int idx;
+ int pixel = 0;
+
+ /* horizontal lines */
+ for (idx = 0; idx < ibuf->x; idx++) {
+ /* bottom line */
+ set_pixel(ibuf, idx, fill_col);
+ /* top line */
+ pixel = idx + (ibuf->x * (ibuf->y - 1));
+ set_pixel(ibuf, pixel, fill_col);
+ }
+ /* vertical lines */
+ for (idx = 0; idx < ibuf->y; idx++) {
+ /* left line */
+ set_pixel(ibuf, ibuf->x * idx, fill_col);
+ /* right line */
+ pixel = ibuf->x * idx + (ibuf->x - 1);
+ set_pixel(ibuf, pixel, fill_col);
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
+
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
}
/* Naive dilate
@@ -691,96 +711,96 @@ static void gpencil_clean_borders(tGPDfill *tgpf)
*/
static void dilate(ImBuf *ibuf)
{
- BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
- const float green[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
- const int maxpixel = (ibuf->x * ibuf->y) - 1;
- /* detect pixels and expand into red areas */
- for (int v = maxpixel; v != 0; v--) {
- float color[4];
- int index;
- int tp = 0;
- int bm = 0;
- int lt = 0;
- int rt = 0;
- get_pixel(ibuf, v, color);
- if (color[1] == 1.0f) {
- /* pixel left */
- if (v - 1 >= 0) {
- index = v - 1;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- lt = index;
- }
- }
- /* pixel right */
- if (v + 1 <= maxpixel) {
- index = v + 1;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- rt = index;
- }
- }
- /* pixel top */
- if (v + ibuf->x <= maxpixel) {
- index = v + ibuf->x;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- tp = index;
- }
- }
- /* pixel bottom */
- if (v - ibuf->x >= 0) {
- index = v - ibuf->x;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- bm = index;
- }
- }
- /* pixel top-left */
- if (tp && lt) {
- index = tp - 1;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- }
- }
- /* pixel top-right */
- if (tp && rt) {
- index = tp + 1;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- }
- }
- /* pixel bottom-left */
- if (bm && lt) {
- index = bm - 1;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- }
- }
- /* pixel bottom-right */
- if (bm && rt) {
- index = bm + 1;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- }
- }
- }
- }
- /* set dilated pixels */
- while (!BLI_stack_is_empty(stack)) {
- int v;
- BLI_stack_pop(stack, &v);
- set_pixel(ibuf, v, green);
- }
- BLI_stack_free(stack);
+ BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
+ const float green[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ const int maxpixel = (ibuf->x * ibuf->y) - 1;
+ /* detect pixels and expand into red areas */
+ for (int v = maxpixel; v != 0; v--) {
+ float color[4];
+ int index;
+ int tp = 0;
+ int bm = 0;
+ int lt = 0;
+ int rt = 0;
+ get_pixel(ibuf, v, color);
+ if (color[1] == 1.0f) {
+ /* pixel left */
+ if (v - 1 >= 0) {
+ index = v - 1;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ lt = index;
+ }
+ }
+ /* pixel right */
+ if (v + 1 <= maxpixel) {
+ index = v + 1;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ rt = index;
+ }
+ }
+ /* pixel top */
+ if (v + ibuf->x <= maxpixel) {
+ index = v + ibuf->x;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ tp = index;
+ }
+ }
+ /* pixel bottom */
+ if (v - ibuf->x >= 0) {
+ index = v - ibuf->x;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ bm = index;
+ }
+ }
+ /* pixel top-left */
+ if (tp && lt) {
+ index = tp - 1;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel top-right */
+ if (tp && rt) {
+ index = tp + 1;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel bottom-left */
+ if (bm && lt) {
+ index = bm - 1;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel bottom-right */
+ if (bm && rt) {
+ index = bm + 1;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ }
+ }
+ /* set dilated pixels */
+ while (!BLI_stack_is_empty(stack)) {
+ int v;
+ BLI_stack_pop(stack, &v);
+ set_pixel(ibuf, v, green);
+ }
+ BLI_stack_free(stack);
}
/* Get the outline points of a shape using Moore Neighborhood algorithm
@@ -790,331 +810,325 @@ static void dilate(ImBuf *ibuf)
*/
static void gpencil_get_outline_points(tGPDfill *tgpf)
{
- ImBuf *ibuf;
- float rgba[4];
- void *lock;
- int v[2];
- int boundary_co[2];
- int start_co[2];
- int backtracked_co[2];
- int current_check_co[2];
- int prev_check_co[2];
- int backtracked_offset[1][2] = {{0, 0}};
- // bool boundary_found = false;
- bool start_found = false;
- const int NEIGHBOR_COUNT = 8;
-
- const int offset[8][2] = {
- {-1, -1},
- {0, -1},
- {1, -1},
- {1, 0},
- {1, 1},
- {0, 1},
- {-1, 1},
- {-1, 0},
- };
-
- tgpf->stack = BLI_stack_new(sizeof(int[2]), __func__);
-
- ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
- int imagesize = ibuf->x * ibuf->y;
-
- /* dilate */
- dilate(ibuf);
-
- /* find the initial point to start outline analysis */
- for (int idx = imagesize - 1; idx != 0; idx--) {
- get_pixel(ibuf, idx, rgba);
- if (rgba[1] == 1.0f) {
- boundary_co[0] = idx % ibuf->x;
- boundary_co[1] = idx / ibuf->x;
- copy_v2_v2_int(start_co, boundary_co);
- backtracked_co[0] = (idx - 1) % ibuf->x;
- backtracked_co[1] = (idx - 1) / ibuf->x;
- backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
- backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
- copy_v2_v2_int(prev_check_co, start_co);
-
- BLI_stack_push(tgpf->stack, &boundary_co);
- start_found = true;
- break;
- }
- }
-
- while (start_found) {
- int cur_back_offset = -1;
- for (int i = 0; i < NEIGHBOR_COUNT; i++) {
- if (backtracked_offset[0][0] == offset[i][0] &&
- backtracked_offset[0][1] == offset[i][1])
- {
- /* Finding the bracktracked pixel offset index */
- cur_back_offset = i;
- break;
- }
- }
-
- int loop = 0;
- while (loop < (NEIGHBOR_COUNT - 1) && cur_back_offset != -1) {
- int offset_idx = (cur_back_offset + 1) % NEIGHBOR_COUNT;
- current_check_co[0] = boundary_co[0] + offset[offset_idx][0];
- current_check_co[1] = boundary_co[1] + offset[offset_idx][1];
-
- int image_idx = ibuf->x * current_check_co[1] + current_check_co[0];
- get_pixel(ibuf, image_idx, rgba);
-
- /* find next boundary pixel */
- if (rgba[1] == 1.0f) {
- copy_v2_v2_int(boundary_co, current_check_co);
- copy_v2_v2_int(backtracked_co, prev_check_co);
- backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
- backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
-
- BLI_stack_push(tgpf->stack, &boundary_co);
-
- break;
- }
- copy_v2_v2_int(prev_check_co, current_check_co);
- cur_back_offset++;
- loop++;
- }
- /* current pixel is equal to starting pixel */
- if (boundary_co[0] == start_co[0] &&
- boundary_co[1] == start_co[1])
- {
- BLI_stack_pop(tgpf->stack, &v);
- // boundary_found = true;
- break;
- }
- }
-
- /* release ibuf */
- if (ibuf) {
- BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
- }
+ ImBuf *ibuf;
+ float rgba[4];
+ void *lock;
+ int v[2];
+ int boundary_co[2];
+ int start_co[2];
+ int backtracked_co[2];
+ int current_check_co[2];
+ int prev_check_co[2];
+ int backtracked_offset[1][2] = {{0, 0}};
+ // bool boundary_found = false;
+ bool start_found = false;
+ const int NEIGHBOR_COUNT = 8;
+
+ const int offset[8][2] = {
+ {-1, -1},
+ {0, -1},
+ {1, -1},
+ {1, 0},
+ {1, 1},
+ {0, 1},
+ {-1, 1},
+ {-1, 0},
+ };
+
+ tgpf->stack = BLI_stack_new(sizeof(int[2]), __func__);
+
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ int imagesize = ibuf->x * ibuf->y;
+
+ /* dilate */
+ dilate(ibuf);
+
+ /* find the initial point to start outline analysis */
+ for (int idx = imagesize - 1; idx != 0; idx--) {
+ get_pixel(ibuf, idx, rgba);
+ if (rgba[1] == 1.0f) {
+ boundary_co[0] = idx % ibuf->x;
+ boundary_co[1] = idx / ibuf->x;
+ copy_v2_v2_int(start_co, boundary_co);
+ backtracked_co[0] = (idx - 1) % ibuf->x;
+ backtracked_co[1] = (idx - 1) / ibuf->x;
+ backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
+ backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
+ copy_v2_v2_int(prev_check_co, start_co);
+
+ BLI_stack_push(tgpf->stack, &boundary_co);
+ start_found = true;
+ break;
+ }
+ }
+
+ while (start_found) {
+ int cur_back_offset = -1;
+ for (int i = 0; i < NEIGHBOR_COUNT; i++) {
+ if (backtracked_offset[0][0] == offset[i][0] && backtracked_offset[0][1] == offset[i][1]) {
+ /* Finding the bracktracked pixel offset index */
+ cur_back_offset = i;
+ break;
+ }
+ }
+
+ int loop = 0;
+ while (loop < (NEIGHBOR_COUNT - 1) && cur_back_offset != -1) {
+ int offset_idx = (cur_back_offset + 1) % NEIGHBOR_COUNT;
+ current_check_co[0] = boundary_co[0] + offset[offset_idx][0];
+ current_check_co[1] = boundary_co[1] + offset[offset_idx][1];
+
+ int image_idx = ibuf->x * current_check_co[1] + current_check_co[0];
+ get_pixel(ibuf, image_idx, rgba);
+
+ /* find next boundary pixel */
+ if (rgba[1] == 1.0f) {
+ copy_v2_v2_int(boundary_co, current_check_co);
+ copy_v2_v2_int(backtracked_co, prev_check_co);
+ backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
+ backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
+
+ BLI_stack_push(tgpf->stack, &boundary_co);
+
+ break;
+ }
+ copy_v2_v2_int(prev_check_co, current_check_co);
+ cur_back_offset++;
+ loop++;
+ }
+ /* current pixel is equal to starting pixel */
+ if (boundary_co[0] == start_co[0] && boundary_co[1] == start_co[1]) {
+ BLI_stack_pop(tgpf->stack, &v);
+ // boundary_found = true;
+ break;
+ }
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
}
/* get z-depth array to reproject on surface */
static void gpencil_get_depth_array(tGPDfill *tgpf)
{
- tGPspoint *ptc;
- ToolSettings *ts = tgpf->scene->toolsettings;
- int totpoints = tgpf->sbuffer_size;
- int i = 0;
-
- if (totpoints == 0) {
- return;
- }
-
- /* for surface sketching, need to set the right OpenGL context stuff so that
- * the conversions will project the values correctly...
- */
- if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) {
- /* need to restore the original projection settings before packing up */
- view3d_region_operator_needs_opengl(tgpf->win, tgpf->ar);
- ED_view3d_autodist_init(tgpf->depsgraph, tgpf->ar, tgpf->v3d, 0);
-
- /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
- int depth_margin = 0;
-
- /* get an array of depths, far depths are blended */
- int mval_prev[2] = { 0 };
- int interp_depth = 0;
- int found_depth = 0;
-
- tgpf->depth_arr = MEM_mallocN(sizeof(float) * totpoints, "depth_points");
-
- for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) {
-
- int mval_i[2];
- round_v2i_v2fl(mval_i, &ptc->x);
-
- if ((ED_view3d_autodist_depth(
- tgpf->ar, mval_i, depth_margin, tgpf->depth_arr + i) == 0) &&
- (i && (ED_view3d_autodist_depth_seg(
- tgpf->ar, mval_i, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0)))
- {
- interp_depth = true;
- }
- else {
- found_depth = true;
- }
-
- copy_v2_v2_int(mval_prev, mval_i);
- }
-
- if (found_depth == false) {
- /* eeh... not much we can do.. :/, ignore depth in this case */
- for (i = totpoints - 1; i >= 0; i--)
- tgpf->depth_arr[i] = 0.9999f;
- }
- else {
- if (interp_depth) {
- interp_sparse_array(tgpf->depth_arr, totpoints, FLT_MAX);
- }
- }
- }
+ tGPspoint *ptc;
+ ToolSettings *ts = tgpf->scene->toolsettings;
+ int totpoints = tgpf->sbuffer_size;
+ int i = 0;
+
+ if (totpoints == 0) {
+ return;
+ }
+
+ /* for surface sketching, need to set the right OpenGL context stuff so that
+ * the conversions will project the values correctly...
+ */
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) {
+ /* need to restore the original projection settings before packing up */
+ view3d_region_operator_needs_opengl(tgpf->win, tgpf->ar);
+ ED_view3d_autodist_init(tgpf->depsgraph, tgpf->ar, tgpf->v3d, 0);
+
+ /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
+ int depth_margin = 0;
+
+ /* get an array of depths, far depths are blended */
+ int mval_prev[2] = {0};
+ int interp_depth = 0;
+ int found_depth = 0;
+
+ tgpf->depth_arr = MEM_mallocN(sizeof(float) * totpoints, "depth_points");
+
+ for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) {
+
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, &ptc->x);
+
+ if ((ED_view3d_autodist_depth(tgpf->ar, mval_i, depth_margin, tgpf->depth_arr + i) == 0) &&
+ (i && (ED_view3d_autodist_depth_seg(
+ tgpf->ar, mval_i, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0))) {
+ interp_depth = true;
+ }
+ else {
+ found_depth = true;
+ }
+
+ copy_v2_v2_int(mval_prev, mval_i);
+ }
+
+ if (found_depth == false) {
+ /* eeh... not much we can do.. :/, ignore depth in this case */
+ for (i = totpoints - 1; i >= 0; i--)
+ tgpf->depth_arr[i] = 0.9999f;
+ }
+ else {
+ if (interp_depth) {
+ interp_sparse_array(tgpf->depth_arr, totpoints, FLT_MAX);
+ }
+ }
+ }
}
/* create array of points using stack as source */
static void gpencil_points_from_stack(tGPDfill *tgpf)
{
- tGPspoint *point2D;
- int totpoints = BLI_stack_count(tgpf->stack);
- if (totpoints == 0) {
- return;
- }
-
- tgpf->sbuffer_size = (short)totpoints;
- tgpf->sbuffer = MEM_callocN(sizeof(tGPspoint) * totpoints, __func__);
-
- point2D = tgpf->sbuffer;
- while (!BLI_stack_is_empty(tgpf->stack)) {
- int v[2];
- BLI_stack_pop(tgpf->stack, &v);
- copy_v2fl_v2i(&point2D->x, v);
- /* shift points to center of pixel */
- add_v2_fl(&point2D->x, 0.5f);
- point2D->pressure = 1.0f;
- point2D->strength = 1.0f;
- point2D->time = 0.0f;
- point2D++;
- }
+ tGPspoint *point2D;
+ int totpoints = BLI_stack_count(tgpf->stack);
+ if (totpoints == 0) {
+ return;
+ }
+
+ tgpf->sbuffer_size = (short)totpoints;
+ tgpf->sbuffer = MEM_callocN(sizeof(tGPspoint) * totpoints, __func__);
+
+ point2D = tgpf->sbuffer;
+ while (!BLI_stack_is_empty(tgpf->stack)) {
+ int v[2];
+ BLI_stack_pop(tgpf->stack, &v);
+ copy_v2fl_v2i(&point2D->x, v);
+ /* shift points to center of pixel */
+ add_v2_fl(&point2D->x, 0.5f);
+ point2D->pressure = 1.0f;
+ point2D->strength = 1.0f;
+ point2D->time = 0.0f;
+ point2D++;
+ }
}
/* create a grease pencil stroke using points in buffer */
static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
{
- const int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
-
- ToolSettings *ts = tgpf->scene->toolsettings;
- const char *align_flag = &ts->gpencil_v3d_align;
- const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
- const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
- (tgpf->rv3d->persp == RV3D_CAMOB) && (!is_depth);
- Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
- if (brush == NULL) {
- return;
- }
-
- bGPDspoint *pt;
- MDeformVert *dvert = NULL;
- tGPspoint *point2D;
-
- if (tgpf->sbuffer_size == 0) {
- return;
- }
-
- /* get frame or create a new one */
- tgpf->gpf = BKE_gpencil_layer_getframe(tgpf->gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
-
- /* create new stroke */
- bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
- gps->thickness = brush->size;
- gps->gradient_f = brush->gpencil_settings->gradient_f;
- copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
- gps->inittime = 0.0f;
-
- /* the polygon must be closed, so enabled cyclic */
- gps->flag |= GP_STROKE_CYCLIC;
- gps->flag |= GP_STROKE_3DSPACE;
-
- gps->mat_nr = BKE_gpencil_object_material_ensure(tgpf->bmain, tgpf->ob, tgpf->mat);
-
- /* allocate memory for storage points */
- gps->totpoints = tgpf->sbuffer_size;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * tgpf->sbuffer_size, "gp_stroke_points");
-
- /* initialize triangle memory to dummy data */
- gps->tot_triangles = 0;
- gps->triangles = NULL;
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* add stroke to frame */
- if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)) {
- BLI_addhead(&tgpf->gpf->strokes, gps);
- }
- else {
- BLI_addtail(&tgpf->gpf->strokes, gps);
- }
-
- /* add points */
- pt = gps->points;
- point2D = (tGPspoint *)tgpf->sbuffer;
-
- const int def_nr = tgpf->ob->actdef - 1;
- const bool have_weight = (bool)BLI_findlink(&tgpf->ob->defbase, def_nr);
-
- if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
- BKE_gpencil_dvert_ensure(gps);
- dvert = gps->dvert;
- }
-
- for (int i = 0; i < tgpf->sbuffer_size && point2D; i++, point2D++, pt++) {
- /* convert screen-coordinates to 3D coordinates */
- gp_stroke_convertcoords_tpoint(
- tgpf->scene, tgpf->ar, tgpf->ob,
- tgpf->gpl, point2D,
- tgpf->depth_arr ? tgpf->depth_arr + i : NULL,
- &pt->x);
-
- pt->pressure = 1.0f;
- pt->strength = 1.0f;
- pt->time = 0.0f;
-
- if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
- MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
- if (dw) {
- dw->weight = ts->vgroup_weight;
- }
-
- dvert++;
- }
- else {
- if (dvert != NULL) {
- dvert->totweight = 0;
- dvert->dw = NULL;
- dvert++;
- }
- }
- }
-
- /* smooth stroke */
- float reduce = 0.0f;
- float smoothfac = 1.0f;
- for (int r = 0; r < 1; r++) {
- for (int i = 0; i < gps->totpoints; i++) {
- BKE_gpencil_smooth_stroke(gps, i, smoothfac - reduce);
- }
- reduce += 0.25f; // reduce the factor
- }
-
- /* if axis locked, reproject to plane locked */
- if ((tgpf->lock_axis > GP_LOCKAXIS_VIEW) && ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) {
- float origin[3];
- ED_gp_get_drawing_reference(
- tgpf->scene, tgpf->ob, tgpf->gpl,
- ts->gpencil_v3d_align, origin);
- ED_gp_project_stroke_to_plane(
- tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin,
- tgpf->lock_axis - 1);
- }
-
- /* if parented change position relative to parent object */
- for (int a = 0; a < tgpf->sbuffer_size; a++) {
- pt = &gps->points[a];
- gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpd, tgpf->gpl, pt);
- }
-
- /* if camera view, reproject flat to view to avoid perspective effect */
- if (is_camera) {
- ED_gpencil_project_stroke_to_view(tgpf->C, tgpf->gpl, gps);
- }
-
- /* simplify stroke */
- for (int b = 0; b < tgpf->fill_simplylvl; b++) {
- BKE_gpencil_simplify_fixed(gps);
- }
+ const int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
+
+ ToolSettings *ts = tgpf->scene->toolsettings;
+ const char *align_flag = &ts->gpencil_v3d_align;
+ const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
+ const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
+ (tgpf->rv3d->persp == RV3D_CAMOB) && (!is_depth);
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+ if (brush == NULL) {
+ return;
+ }
+
+ bGPDspoint *pt;
+ MDeformVert *dvert = NULL;
+ tGPspoint *point2D;
+
+ if (tgpf->sbuffer_size == 0) {
+ return;
+ }
+
+ /* get frame or create a new one */
+ tgpf->gpf = BKE_gpencil_layer_getframe(tgpf->gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
+
+ /* create new stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
+ gps->thickness = brush->size;
+ gps->gradient_f = brush->gpencil_settings->gradient_f;
+ copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
+ gps->inittime = 0.0f;
+
+ /* the polygon must be closed, so enabled cyclic */
+ gps->flag |= GP_STROKE_CYCLIC;
+ gps->flag |= GP_STROKE_3DSPACE;
+
+ gps->mat_nr = BKE_gpencil_object_material_ensure(tgpf->bmain, tgpf->ob, tgpf->mat);
+
+ /* allocate memory for storage points */
+ gps->totpoints = tgpf->sbuffer_size;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * tgpf->sbuffer_size, "gp_stroke_points");
+
+ /* initialize triangle memory to dummy data */
+ gps->tot_triangles = 0;
+ gps->triangles = NULL;
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* add stroke to frame */
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)) {
+ BLI_addhead(&tgpf->gpf->strokes, gps);
+ }
+ else {
+ BLI_addtail(&tgpf->gpf->strokes, gps);
+ }
+
+ /* add points */
+ pt = gps->points;
+ point2D = (tGPspoint *)tgpf->sbuffer;
+
+ const int def_nr = tgpf->ob->actdef - 1;
+ const bool have_weight = (bool)BLI_findlink(&tgpf->ob->defbase, def_nr);
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ dvert = gps->dvert;
+ }
+
+ for (int i = 0; i < tgpf->sbuffer_size && point2D; i++, point2D++, pt++) {
+ /* convert screen-coordinates to 3D coordinates */
+ gp_stroke_convertcoords_tpoint(tgpf->scene,
+ tgpf->ar,
+ tgpf->ob,
+ tgpf->gpl,
+ point2D,
+ tgpf->depth_arr ? tgpf->depth_arr + i : NULL,
+ &pt->x);
+
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ pt->time = 0.0f;
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+
+ dvert++;
+ }
+ else {
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ dvert++;
+ }
+ }
+ }
+
+ /* smooth stroke */
+ float reduce = 0.0f;
+ float smoothfac = 1.0f;
+ for (int r = 0; r < 1; r++) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ BKE_gpencil_smooth_stroke(gps, i, smoothfac - reduce);
+ }
+ reduce += 0.25f; // reduce the factor
+ }
+
+ /* if axis locked, reproject to plane locked */
+ if ((tgpf->lock_axis > GP_LOCKAXIS_VIEW) &&
+ ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) {
+ float origin[3];
+ ED_gp_get_drawing_reference(tgpf->scene, tgpf->ob, tgpf->gpl, ts->gpencil_v3d_align, origin);
+ ED_gp_project_stroke_to_plane(
+ tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin, tgpf->lock_axis - 1);
+ }
+
+ /* if parented change position relative to parent object */
+ for (int a = 0; a < tgpf->sbuffer_size; a++) {
+ pt = &gps->points[a];
+ gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpd, tgpf->gpl, pt);
+ }
+
+ /* if camera view, reproject flat to view to avoid perspective effect */
+ if (is_camera) {
+ ED_gpencil_project_stroke_to_view(tgpf->C, tgpf->gpl, gps);
+ }
+
+ /* simplify stroke */
+ for (int b = 0; b < tgpf->fill_simplylvl; b++) {
+ BKE_gpencil_simplify_fixed(gps);
+ }
}
/* ----------------------- */
@@ -1122,357 +1136,356 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
/* Helper: Draw status message while the user is running the operator */
static void gpencil_fill_status_indicators(bContext *C, tGPDfill *UNUSED(tgpf))
{
- const char *status_str = IFACE_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back");
- ED_workspace_status_text(C, status_str);
+ const char *status_str = IFACE_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back");
+ ED_workspace_status_text(C, status_str);
}
/* draw boundary lines to see fill limits */
static void gpencil_draw_boundary_lines(const bContext *UNUSED(C), tGPDfill *tgpf)
{
- if (!tgpf->gpd) {
- return;
- }
- const float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
- gp_draw_datablock(tgpf, ink);
+ if (!tgpf->gpd) {
+ return;
+ }
+ const float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ gp_draw_datablock(tgpf, ink);
}
/* Drawing callback for modal operator in 3d mode */
static void gpencil_fill_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg)
{
- tGPDfill *tgpf = (tGPDfill *)arg;
- /* draw only in the region that originated operator. This is required for multiwindow */
- ARegion *ar = CTX_wm_region(C);
- if (ar != tgpf->ar) {
- return;
- }
-
- gpencil_draw_boundary_lines(C, tgpf);
+ tGPDfill *tgpf = (tGPDfill *)arg;
+ /* draw only in the region that originated operator. This is required for multiwindow */
+ ARegion *ar = CTX_wm_region(C);
+ if (ar != tgpf->ar) {
+ return;
+ }
+
+ gpencil_draw_boundary_lines(C, tgpf);
}
/* check if context is suitable for filling */
static bool gpencil_fill_poll(bContext *C)
{
- Object *obact = CTX_data_active_object(C);
-
- if (ED_operator_regionactive(C)) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa->spacetype == SPACE_VIEW3D) {
- if ((obact == NULL) ||
- (obact->type != OB_GPENCIL) ||
- (obact->mode != OB_MODE_PAINT_GPENCIL))
- {
- return false;
- }
-
- return true;
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Active region not valid for filling operator");
- return false;
- }
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Active region not set");
- return false;
- }
+ Object *obact = CTX_data_active_object(C);
+
+ if (ED_operator_regionactive(C)) {
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa->spacetype == SPACE_VIEW3D) {
+ if ((obact == NULL) || (obact->type != OB_GPENCIL) ||
+ (obact->mode != OB_MODE_PAINT_GPENCIL)) {
+ return false;
+ }
+
+ return true;
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not valid for filling operator");
+ return false;
+ }
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ return false;
+ }
}
/* Allocate memory and initialize values */
static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op))
{
- tGPDfill *tgpf = MEM_callocN(sizeof(tGPDfill), "GPencil Fill Data");
-
- /* define initial values */
- ToolSettings *ts = CTX_data_tool_settings(C);
- bGPdata *gpd = CTX_data_gpencil_data(C);
- Main *bmain = CTX_data_main(C);
-
- /* set current scene and window info */
- tgpf->C = C;
- tgpf->bmain = CTX_data_main(C);
- tgpf->scene = CTX_data_scene(C);
- tgpf->ob = CTX_data_active_object(C);
- tgpf->sa = CTX_wm_area(C);
- tgpf->ar = CTX_wm_region(C);
- tgpf->rv3d = tgpf->ar->regiondata;
- tgpf->v3d = tgpf->sa->spacedata.first;
- tgpf->depsgraph = CTX_data_depsgraph(C);
- tgpf->win = CTX_wm_window(C);
-
- /* set GP datablock */
- tgpf->gpd = gpd;
- tgpf->gpl = BKE_gpencil_layer_getactive(gpd);
- if (tgpf->gpl == NULL) {
- tgpf->gpl = BKE_gpencil_layer_addnew(tgpf->gpd, DATA_("GP_Layer"), true);
- }
- tgpf->lock_axis = ts->gp_sculpt.lock_axis;
-
- tgpf->oldkey = -1;
- tgpf->sbuffer_size = 0;
- tgpf->sbuffer = NULL;
- tgpf->depth_arr = NULL;
-
- /* save filling parameters */
- Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
- tgpf->flag = brush->gpencil_settings->flag;
- tgpf->fill_leak = brush->gpencil_settings->fill_leak;
- tgpf->fill_threshold = brush->gpencil_settings->fill_threshold;
- tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl;
- tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode;
- tgpf->fill_factor = (short)max_ii(1, min_ii((int)brush->gpencil_settings->fill_factor, 8));
-
- int totcol = tgpf->ob->totcol;
-
- /* get color info */
- Material *ma = BKE_gpencil_object_material_ensure_from_active_input_brush(bmain, tgpf->ob, brush);
-
- tgpf->mat = ma;
-
- /* check whether the material was newly added */
- if (totcol != tgpf->ob->totcol) {
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
- }
-
- /* init undo */
- gpencil_undo_init(tgpf->gpd);
-
- /* return context data for running operator */
- return tgpf;
+ tGPDfill *tgpf = MEM_callocN(sizeof(tGPDfill), "GPencil Fill Data");
+
+ /* define initial values */
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Main *bmain = CTX_data_main(C);
+
+ /* set current scene and window info */
+ tgpf->C = C;
+ tgpf->bmain = CTX_data_main(C);
+ tgpf->scene = CTX_data_scene(C);
+ tgpf->ob = CTX_data_active_object(C);
+ tgpf->sa = CTX_wm_area(C);
+ tgpf->ar = CTX_wm_region(C);
+ tgpf->rv3d = tgpf->ar->regiondata;
+ tgpf->v3d = tgpf->sa->spacedata.first;
+ tgpf->depsgraph = CTX_data_depsgraph(C);
+ tgpf->win = CTX_wm_window(C);
+
+ /* set GP datablock */
+ tgpf->gpd = gpd;
+ tgpf->gpl = BKE_gpencil_layer_getactive(gpd);
+ if (tgpf->gpl == NULL) {
+ tgpf->gpl = BKE_gpencil_layer_addnew(tgpf->gpd, DATA_("GP_Layer"), true);
+ }
+ tgpf->lock_axis = ts->gp_sculpt.lock_axis;
+
+ tgpf->oldkey = -1;
+ tgpf->sbuffer_size = 0;
+ tgpf->sbuffer = NULL;
+ tgpf->depth_arr = NULL;
+
+ /* save filling parameters */
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+ tgpf->flag = brush->gpencil_settings->flag;
+ tgpf->fill_leak = brush->gpencil_settings->fill_leak;
+ tgpf->fill_threshold = brush->gpencil_settings->fill_threshold;
+ tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl;
+ tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode;
+ tgpf->fill_factor = (short)max_ii(1, min_ii((int)brush->gpencil_settings->fill_factor, 8));
+
+ int totcol = tgpf->ob->totcol;
+
+ /* get color info */
+ Material *ma = BKE_gpencil_object_material_ensure_from_active_input_brush(
+ bmain, tgpf->ob, brush);
+
+ tgpf->mat = ma;
+
+ /* check whether the material was newly added */
+ if (totcol != tgpf->ob->totcol) {
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
+ }
+
+ /* init undo */
+ gpencil_undo_init(tgpf->gpd);
+
+ /* return context data for running operator */
+ return tgpf;
}
/* end operator */
static void gpencil_fill_exit(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_active_object(C);
-
- /* clear undo stack */
- gpencil_undo_finish();
-
- /* restore cursor to indicate end of fill */
- WM_cursor_modal_restore(CTX_wm_window(C));
-
- tGPDfill *tgpf = op->customdata;
-
- /* don't assume that operator data exists at all */
- if (tgpf) {
- /* clear status message area */
- ED_workspace_status_text(C, NULL);
-
- MEM_SAFE_FREE(tgpf->sbuffer);
- MEM_SAFE_FREE(tgpf->depth_arr);
-
- /* remove drawing handler */
- if (tgpf->draw_handle_3d) {
- ED_region_draw_cb_exit(tgpf->ar->type, tgpf->draw_handle_3d);
- }
-
- /* delete temp image */
- if (tgpf->ima) {
- for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
- if (ima == tgpf->ima) {
- BLI_remlink(&bmain->images, ima);
- BKE_image_free(tgpf->ima);
- MEM_SAFE_FREE(tgpf->ima);
- break;
- }
- }
- }
-
- /* finally, free memory used by temp data */
- MEM_freeN(tgpf);
- }
-
- /* clear pointer */
- op->customdata = NULL;
-
- /* drawing batch cache is dirty now */
- if ((ob) && (ob->type == OB_GPENCIL) && (ob->data)) {
- bGPdata *gpd2 = ob->data;
- DEG_id_tag_update(&gpd2->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- gpd2->flag |= GP_DATA_CACHE_IS_DIRTY;
- }
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* clear undo stack */
+ gpencil_undo_finish();
+
+ /* restore cursor to indicate end of fill */
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ tGPDfill *tgpf = op->customdata;
+
+ /* don't assume that operator data exists at all */
+ if (tgpf) {
+ /* clear status message area */
+ ED_workspace_status_text(C, NULL);
+
+ MEM_SAFE_FREE(tgpf->sbuffer);
+ MEM_SAFE_FREE(tgpf->depth_arr);
+
+ /* remove drawing handler */
+ if (tgpf->draw_handle_3d) {
+ ED_region_draw_cb_exit(tgpf->ar->type, tgpf->draw_handle_3d);
+ }
+
+ /* delete temp image */
+ if (tgpf->ima) {
+ for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
+ if (ima == tgpf->ima) {
+ BLI_remlink(&bmain->images, ima);
+ BKE_image_free(tgpf->ima);
+ MEM_SAFE_FREE(tgpf->ima);
+ break;
+ }
+ }
+ }
+
+ /* finally, free memory used by temp data */
+ MEM_freeN(tgpf);
+ }
+
+ /* clear pointer */
+ op->customdata = NULL;
+
+ /* drawing batch cache is dirty now */
+ if ((ob) && (ob->type == OB_GPENCIL) && (ob->data)) {
+ bGPdata *gpd2 = ob->data;
+ DEG_id_tag_update(&gpd2->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ gpd2->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
}
static void gpencil_fill_cancel(bContext *C, wmOperator *op)
{
- /* this is just a wrapper around exit() */
- gpencil_fill_exit(C, op);
+ /* this is just a wrapper around exit() */
+ gpencil_fill_exit(C, op);
}
/* Init: Allocate memory and set init values */
static int gpencil_fill_init(bContext *C, wmOperator *op)
{
- tGPDfill *tgpf;
- /* cannot paint in locked layer */
- bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- if ((gpl) && (gpl->flag & GP_LAYER_LOCKED)) {
- return 0;
- }
-
- /* check context */
- tgpf = op->customdata = gp_session_init_fill(C, op);
- if (tgpf == NULL) {
- /* something wasn't set correctly in context */
- gpencil_fill_exit(C, op);
- return 0;
- }
-
- /* everything is now setup ok */
- return 1;
+ tGPDfill *tgpf;
+ /* cannot paint in locked layer */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ if ((gpl) && (gpl->flag & GP_LAYER_LOCKED)) {
+ return 0;
+ }
+
+ /* check context */
+ tgpf = op->customdata = gp_session_init_fill(C, op);
+ if (tgpf == NULL) {
+ /* something wasn't set correctly in context */
+ gpencil_fill_exit(C, op);
+ return 0;
+ }
+
+ /* everything is now setup ok */
+ return 1;
}
/* start of interactive part of operator */
static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- tGPDfill *tgpf = NULL;
+ tGPDfill *tgpf = NULL;
- /* try to initialize context data needed */
- if (!gpencil_fill_init(C, op)) {
- gpencil_fill_exit(C, op);
- if (op->customdata)
- MEM_freeN(op->customdata);
- return OPERATOR_CANCELLED;
- }
- else {
- tgpf = op->customdata;
- }
+ /* try to initialize context data needed */
+ if (!gpencil_fill_init(C, op)) {
+ gpencil_fill_exit(C, op);
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ tgpf = op->customdata;
+ }
- /* Enable custom drawing handlers to show help lines */
- if (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) {
- tgpf->draw_handle_3d = ED_region_draw_cb_activate(tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW);
- }
+ /* Enable custom drawing handlers to show help lines */
+ if (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) {
+ tgpf->draw_handle_3d = ED_region_draw_cb_activate(
+ tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW);
+ }
- WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR);
- gpencil_fill_status_indicators(C, tgpf);
+ gpencil_fill_status_indicators(C, tgpf);
- DEG_id_tag_update(&tgpf->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ DEG_id_tag_update(&tgpf->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
- /* add a modal handler for this operator*/
- WM_event_add_modal_handler(C, op);
+ /* add a modal handler for this operator*/
+ WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
/* events handling during interactive part of operator */
static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGPDfill *tgpf = op->customdata;
-
- int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through */
-
- switch (event->type) {
- case ESCKEY:
- case RIGHTMOUSE:
- estate = OPERATOR_CANCELLED;
- break;
- case LEFTMOUSE:
- tgpf->on_back = RNA_boolean_get(op->ptr, "on_back");
- /* first time the event is not enabled to show help lines */
- if ((tgpf->oldkey != -1) || ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) == 0)) {
- ARegion *ar = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y);
- if (ar) {
- bool in_bounds = false;
-
- /* Perform bounds check */
- in_bounds = BLI_rcti_isect_pt(&ar->winrct, event->x, event->y);
-
- if ((in_bounds) && (ar->regiontype == RGN_TYPE_WINDOW)) {
- /* TODO GPXX: Verify the mouse click is right for any window size */
- tgpf->center[0] = event->mval[0];
- tgpf->center[1] = event->mval[1];
-
- /* render screen to temp image */
- if ( gp_render_offscreen(tgpf) ) {
-
- /* apply boundary fill */
- gpencil_boundaryfill_area(tgpf);
-
- /* clean borders to avoid infinite loops */
- gpencil_clean_borders(tgpf);
-
- /* analyze outline */
- gpencil_get_outline_points(tgpf);
-
- /* create array of points from stack */
- gpencil_points_from_stack(tgpf);
-
- /* create z-depth array for reproject */
- gpencil_get_depth_array(tgpf);
-
- /* create stroke and reproject */
- gpencil_stroke_from_buffer(tgpf);
-
- }
-
- /* restore size */
- tgpf->ar->winx = (short)tgpf->bwinx;
- tgpf->ar->winy = (short)tgpf->bwiny;
- tgpf->ar->winrct = tgpf->brect;
-
- /* free temp stack data */
- if (tgpf->stack) {
- BLI_stack_free(tgpf->stack);
- }
-
- /* push undo data */
- gpencil_undo_push(tgpf->gpd);
-
- estate = OPERATOR_FINISHED;
- }
- else {
- estate = OPERATOR_CANCELLED;
- }
- }
- else {
- estate = OPERATOR_CANCELLED;
- }
- }
- tgpf->oldkey = event->type;
- break;
- }
- /* process last operations before exiting */
- switch (estate) {
- case OPERATOR_FINISHED:
- gpencil_fill_exit(C, op);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
- break;
-
- case OPERATOR_CANCELLED:
- gpencil_fill_exit(C, op);
- break;
-
- case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
- break;
- }
-
- /* return status code */
- return estate;
+ tGPDfill *tgpf = op->customdata;
+
+ int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through */
+
+ switch (event->type) {
+ case ESCKEY:
+ case RIGHTMOUSE:
+ estate = OPERATOR_CANCELLED;
+ break;
+ case LEFTMOUSE:
+ tgpf->on_back = RNA_boolean_get(op->ptr, "on_back");
+ /* first time the event is not enabled to show help lines */
+ if ((tgpf->oldkey != -1) || ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) == 0)) {
+ ARegion *ar = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y);
+ if (ar) {
+ bool in_bounds = false;
+
+ /* Perform bounds check */
+ in_bounds = BLI_rcti_isect_pt(&ar->winrct, event->x, event->y);
+
+ if ((in_bounds) && (ar->regiontype == RGN_TYPE_WINDOW)) {
+ /* TODO GPXX: Verify the mouse click is right for any window size */
+ tgpf->center[0] = event->mval[0];
+ tgpf->center[1] = event->mval[1];
+
+ /* render screen to temp image */
+ if (gp_render_offscreen(tgpf)) {
+
+ /* apply boundary fill */
+ gpencil_boundaryfill_area(tgpf);
+
+ /* clean borders to avoid infinite loops */
+ gpencil_clean_borders(tgpf);
+
+ /* analyze outline */
+ gpencil_get_outline_points(tgpf);
+
+ /* create array of points from stack */
+ gpencil_points_from_stack(tgpf);
+
+ /* create z-depth array for reproject */
+ gpencil_get_depth_array(tgpf);
+
+ /* create stroke and reproject */
+ gpencil_stroke_from_buffer(tgpf);
+ }
+
+ /* restore size */
+ tgpf->ar->winx = (short)tgpf->bwinx;
+ tgpf->ar->winy = (short)tgpf->bwiny;
+ tgpf->ar->winrct = tgpf->brect;
+
+ /* free temp stack data */
+ if (tgpf->stack) {
+ BLI_stack_free(tgpf->stack);
+ }
+
+ /* push undo data */
+ gpencil_undo_push(tgpf->gpd);
+
+ estate = OPERATOR_FINISHED;
+ }
+ else {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ else {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ tgpf->oldkey = event->type;
+ break;
+ }
+ /* process last operations before exiting */
+ switch (estate) {
+ case OPERATOR_FINISHED:
+ gpencil_fill_exit(C, op);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ break;
+
+ case OPERATOR_CANCELLED:
+ gpencil_fill_exit(C, op);
+ break;
+
+ case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
+ break;
+ }
+
+ /* return status code */
+ return estate;
}
void GPENCIL_OT_fill(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ PropertyRNA *prop;
- /* identifiers */
- ot->name = "Grease Pencil Fill";
- ot->idname = "GPENCIL_OT_fill";
- ot->description = "Fill with color the shape formed by strokes";
+ /* identifiers */
+ ot->name = "Grease Pencil Fill";
+ ot->idname = "GPENCIL_OT_fill";
+ ot->description = "Fill with color the shape formed by strokes";
- /* api callbacks */
- ot->invoke = gpencil_fill_invoke;
- ot->modal = gpencil_fill_modal;
- ot->poll = gpencil_fill_poll;
- ot->cancel = gpencil_fill_cancel;
+ /* api callbacks */
+ ot->invoke = gpencil_fill_invoke;
+ ot->modal = gpencil_fill_modal;
+ ot->poll = gpencil_fill_poll;
+ ot->cancel = gpencil_fill_cancel;
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
- prop = RNA_def_boolean(ot->srna, "on_back", false, "Draw On Back", "Send new stroke to Back");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "on_back", false, "Draw On Back", "Send new stroke to Back");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 3742ca92551..c8d2547ad51 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -24,12 +24,10 @@
#ifndef __GPENCIL_INTERN_H__
#define __GPENCIL_INTERN_H__
-
#include "DNA_vec_types.h"
#include "ED_numinput.h"
-
/* internal exports only */
struct Material;
struct bGPDspoint;
@@ -53,7 +51,6 @@ struct EnumPropertyItem;
struct PointerRNA;
struct PropertyRNA;
-
/* ***************************************************** */
/* Modal Operator Geometry Preview
*
@@ -73,172 +70,171 @@ struct PropertyRNA;
/* Temporary draw data (no draw manager mode) */
typedef struct tGPDdraw {
- struct RegionView3D *rv3d; /* region to draw */
- struct Depsgraph *depsgraph; /* depsgraph */
- struct Object *ob; /* GP object */
- struct bGPdata *gpd; /* current GP datablock */
- struct bGPDlayer *gpl; /* layer */
- struct bGPDframe *gpf; /* frame */
- struct bGPDframe *t_gpf; /* temporal frame */
- struct bGPDstroke *gps; /* stroke */
- int disable_fill; /* disable fill */
- int offsx; /* windows offset x */
- int offsy; /* windows offset y */
- int winx; /* windows width */
- int winy; /* windows height */
- int dflag; /* flags datablock */
- short lthick; /* layer thickness */
- float opacity; /* opacity */
- float tintcolor[4]; /* tint color */
- bool onion; /* onion flag */
- bool custonion; /* use custom onion colors */
- bool is_fill_stroke; /* use fill tool */
- float diff_mat[4][4]; /* matrix */
+ struct RegionView3D *rv3d; /* region to draw */
+ struct Depsgraph *depsgraph; /* depsgraph */
+ struct Object *ob; /* GP object */
+ struct bGPdata *gpd; /* current GP datablock */
+ struct bGPDlayer *gpl; /* layer */
+ struct bGPDframe *gpf; /* frame */
+ struct bGPDframe *t_gpf; /* temporal frame */
+ struct bGPDstroke *gps; /* stroke */
+ int disable_fill; /* disable fill */
+ int offsx; /* windows offset x */
+ int offsy; /* windows offset y */
+ int winx; /* windows width */
+ int winy; /* windows height */
+ int dflag; /* flags datablock */
+ short lthick; /* layer thickness */
+ float opacity; /* opacity */
+ float tintcolor[4]; /* tint color */
+ bool onion; /* onion flag */
+ bool custonion; /* use custom onion colors */
+ bool is_fill_stroke; /* use fill tool */
+ float diff_mat[4][4]; /* matrix */
} tGPDdraw;
-
/* Temporary interpolate operation data */
typedef struct tGPDinterpolate_layer {
- struct tGPDinterpolate_layer *next, *prev;
-
- /** layer */
- struct bGPDlayer *gpl;
- /** frame before current frame (interpolate-from) */
- struct bGPDframe *prevFrame;
- /** frame after current frame (interpolate-to) */
- struct bGPDframe *nextFrame;
- /** interpolated frame */
- struct bGPDframe *interFrame;
- /** interpolate factor */
- float factor;
+ struct tGPDinterpolate_layer *next, *prev;
+
+ /** layer */
+ struct bGPDlayer *gpl;
+ /** frame before current frame (interpolate-from) */
+ struct bGPDframe *prevFrame;
+ /** frame after current frame (interpolate-to) */
+ struct bGPDframe *nextFrame;
+ /** interpolated frame */
+ struct bGPDframe *interFrame;
+ /** interpolate factor */
+ float factor;
} tGPDinterpolate_layer;
typedef struct tGPDinterpolate {
- /** current scene from context */
- struct Scene *scene;
- /** area where painting originated */
- struct ScrArea *sa;
- /** region where painting originated */
- struct ARegion *ar;
- /** current GP datablock */
- struct bGPdata *gpd;
- /** current material */
- struct Material *mat;
-
- /** current frame number */
- int cframe;
- /** (tGPDinterpolate_layer) layers to be interpolated */
- ListBase ilayers;
- /** value for determining the displacement influence */
- float shift;
- /** initial interpolation factor for active layer */
- float init_factor;
- /** shift low limit (-100%) */
- float low_limit;
- /** shift upper limit (200%) */
- float high_limit;
- /** flag from toolsettings */
- int flag;
-
- NumInput num; /* numeric input */
- /** handle for drawing strokes while operator is running 3d stuff */
- void *draw_handle_3d;
- /** handle for drawing strokes while operator is running screen stuff */
- void *draw_handle_screen;
+ /** current scene from context */
+ struct Scene *scene;
+ /** area where painting originated */
+ struct ScrArea *sa;
+ /** region where painting originated */
+ struct ARegion *ar;
+ /** current GP datablock */
+ struct bGPdata *gpd;
+ /** current material */
+ struct Material *mat;
+
+ /** current frame number */
+ int cframe;
+ /** (tGPDinterpolate_layer) layers to be interpolated */
+ ListBase ilayers;
+ /** value for determining the displacement influence */
+ float shift;
+ /** initial interpolation factor for active layer */
+ float init_factor;
+ /** shift low limit (-100%) */
+ float low_limit;
+ /** shift upper limit (200%) */
+ float high_limit;
+ /** flag from toolsettings */
+ int flag;
+
+ NumInput num; /* numeric input */
+ /** handle for drawing strokes while operator is running 3d stuff */
+ void *draw_handle_3d;
+ /** handle for drawing strokes while operator is running screen stuff */
+ void *draw_handle_screen;
} tGPDinterpolate;
-
/* Temporary primitive operation data */
typedef struct tGPDprimitive {
- /** main database pointer */
- struct Main *bmain;
- struct Depsgraph *depsgraph;
- /** window where painting originated */
- struct wmWindow *win;
- /** current scene from context */
- struct Scene *scene;
- /** current active gp object */
- struct Object *ob;
- /** area where painting originated */
- struct ScrArea *sa;
- /** region where painting originated */
- struct RegionView3D *rv3d;
- /** view3d where painting originated */
- struct View3D *v3d;
- /** region where painting originated */
- struct ARegion *ar;
- /** current GP datablock */
- struct bGPdata *gpd;
- /** current material */
- struct Material *mat;
- /** current brush */
- struct Brush *brush;
-
- /** current frame number */
- int cframe;
- /** layer */
- struct bGPDlayer *gpl;
- /** frame */
- struct bGPDframe *gpf;
- /** type of primitive */
- int type;
- /** original type of primitive */
- int orign_type;
- /** type of primitive is a curve */
- bool curve;
- /** brush size */
- int brush_size;
- /** brush strength */
- float brush_strength;
- /** flip option */
- short flip;
- /** array of data-points for stroke */
- tGPspoint *points;
- /** number of edges allocated */
- int point_count;
- /** stored number of polygon edges */
- int tot_stored_edges;
- /** number of polygon edges */
- int tot_edges;
- /** move distance */
- float move[2];
- /** initial box corner */
- float origin[2];
- /** first box corner */
- float start[2];
- /** last box corner */
- float end[2];
- /** midpoint box corner */
- float midpoint[2];
- /** first control point */
- float cp1[2];
- /** second control point */
- float cp2[2];
- /** flag to determine control point is selected */
- int sel_cp;
- /** flag to determine operations in progress */
- int flag;
- /** recorded mouse-position */
- float mval[2];
- /** previous recorded mouse-position */
- float mvalo[2];
-
- /** lock to viewport axis */
- int lock_axis;
- struct RNG *rng;
-
- /** numeric input */
- NumInput num;
-
- /** size in pixels for uv calculation */
- float totpixlen;
+ /** main database pointer */
+ struct Main *bmain;
+ struct Depsgraph *depsgraph;
+ /** window where painting originated */
+ struct wmWindow *win;
+ /** current scene from context */
+ struct Scene *scene;
+ /** current active gp object */
+ struct Object *ob;
+ /** area where painting originated */
+ struct ScrArea *sa;
+ /** region where painting originated */
+ struct RegionView3D *rv3d;
+ /** view3d where painting originated */
+ struct View3D *v3d;
+ /** region where painting originated */
+ struct ARegion *ar;
+ /** current GP datablock */
+ struct bGPdata *gpd;
+ /** current material */
+ struct Material *mat;
+ /** current brush */
+ struct Brush *brush;
+
+ /** current frame number */
+ int cframe;
+ /** layer */
+ struct bGPDlayer *gpl;
+ /** frame */
+ struct bGPDframe *gpf;
+ /** type of primitive */
+ int type;
+ /** original type of primitive */
+ int orign_type;
+ /** type of primitive is a curve */
+ bool curve;
+ /** brush size */
+ int brush_size;
+ /** brush strength */
+ float brush_strength;
+ /** flip option */
+ short flip;
+ /** array of data-points for stroke */
+ tGPspoint *points;
+ /** number of edges allocated */
+ int point_count;
+ /** stored number of polygon edges */
+ int tot_stored_edges;
+ /** number of polygon edges */
+ int tot_edges;
+ /** move distance */
+ float move[2];
+ /** initial box corner */
+ float origin[2];
+ /** first box corner */
+ float start[2];
+ /** last box corner */
+ float end[2];
+ /** midpoint box corner */
+ float midpoint[2];
+ /** first control point */
+ float cp1[2];
+ /** second control point */
+ float cp2[2];
+ /** flag to determine control point is selected */
+ int sel_cp;
+ /** flag to determine operations in progress */
+ int flag;
+ /** recorded mouse-position */
+ float mval[2];
+ /** previous recorded mouse-position */
+ float mvalo[2];
+
+ /** lock to viewport axis */
+ int lock_axis;
+ struct RNG *rng;
+
+ /** numeric input */
+ NumInput num;
+
+ /** size in pixels for uv calculation */
+ float totpixlen;
} tGPDprimitive;
-
/* Modal Operator Drawing Callbacks ------------------------ */
-void ED_gp_draw_interpolation(const struct bContext *C, struct tGPDinterpolate *tgpi, const int type);
+void ED_gp_draw_interpolation(const struct bContext *C,
+ struct tGPDinterpolate *tgpi,
+ const int type);
void ED_gp_draw_fill(struct tGPDdraw *tgpw);
/* ***************************************************** */
@@ -248,55 +244,74 @@ void ED_gp_draw_fill(struct tGPDdraw *tgpw);
/* gpencil_utils.c */
typedef struct GP_SpaceConversion {
- struct Scene *scene;
- struct Object *ob;
- struct bGPdata *gpd;
- struct bGPDlayer *gpl;
+ struct Scene *scene;
+ struct Object *ob;
+ struct bGPdata *gpd;
+ struct bGPDlayer *gpl;
- struct ScrArea *sa;
- struct ARegion *ar;
- struct View2D *v2d;
+ struct ScrArea *sa;
+ struct ARegion *ar;
+ struct View2D *v2d;
- rctf *subrect; /* for using the camera rect within the 3d view */
- rctf subrect_data;
+ rctf *subrect; /* for using the camera rect within the 3d view */
+ rctf subrect_data;
- float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */
+ float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */
} GP_SpaceConversion;
bool gp_stroke_inside_circle(
- const float mval[2], const float UNUSED(mvalo[2]),
- int rad, int x0, int y0, int x1, int y1);
+ const float mval[2], const float UNUSED(mvalo[2]), int rad, int x0, int y0, int x1, int y1);
void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
-void gp_point_to_xy(
- const GP_SpaceConversion *gsc, const struct bGPDstroke *gps, const struct bGPDspoint *pt,
- int *r_x, int *r_y);
+void gp_point_to_xy(const GP_SpaceConversion *gsc,
+ const struct bGPDstroke *gps,
+ const struct bGPDspoint *pt,
+ int *r_x,
+ int *r_y);
-void gp_point_to_xy_fl(
- const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt,
- float *r_x, float *r_y);
+void gp_point_to_xy_fl(const GP_SpaceConversion *gsc,
+ const bGPDstroke *gps,
+ const bGPDspoint *pt,
+ float *r_x,
+ float *r_y);
void gp_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4], bGPDspoint *r_pt);
/**
* Change points position relative to parent object
*/
-void gp_apply_parent(struct Depsgraph *depsgraph, struct Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps);
+void gp_apply_parent(struct Depsgraph *depsgraph,
+ struct Object *obact,
+ bGPdata *gpd,
+ bGPDlayer *gpl,
+ bGPDstroke *gps);
/**
* Change point position relative to parent object
*/
-void gp_apply_parent_point(struct Depsgraph *depsgraph, struct Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDspoint *pt);
-
-void gp_point_3d_to_xy(const GP_SpaceConversion *gsc, const short flag, const float pt[3], float xy[2]);
-
-bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc, struct Scene *scene, const float screen_co[2], float r_out[3]);
+void gp_apply_parent_point(struct Depsgraph *depsgraph,
+ struct Object *obact,
+ bGPdata *gpd,
+ bGPDlayer *gpl,
+ bGPDspoint *pt);
+
+void gp_point_3d_to_xy(const GP_SpaceConversion *gsc,
+ const short flag,
+ const float pt[3],
+ float xy[2]);
+
+bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc,
+ struct Scene *scene,
+ const float screen_co[2],
+ float r_out[3]);
/* helper to convert 2d to 3d */
-void gp_stroke_convertcoords_tpoint(
- struct Scene *scene, struct ARegion *ar,
- struct Object *ob,
- bGPDlayer *gpl, const struct tGPspoint *point2D,
- float *depth, float out[3]);
+void gp_stroke_convertcoords_tpoint(struct Scene *scene,
+ struct ARegion *ar,
+ struct Object *ob,
+ bGPDlayer *gpl,
+ const struct tGPspoint *point2D,
+ float *depth,
+ float out[3]);
/* Poll Callbacks ------------------------------------ */
/* gpencil_utils.c */
@@ -316,9 +331,12 @@ struct GHash *gp_copybuf_validate_colormap(struct bContext *C);
/* Stroke Editing ------------------------------------ */
-void gp_stroke_delete_tagged_points(
- bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke,
- int tag_flags, bool select, int limit);
+void gp_stroke_delete_tagged_points(bGPDframe *gpf,
+ bGPDstroke *gps,
+ bGPDstroke *next_stroke,
+ int tag_flags,
+ bool select,
+ int limit);
int gp_delete_selected_point_wrap(bContext *C);
void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide);
@@ -326,12 +344,14 @@ void gp_randomize_stroke(bGPDstroke *gps, Brush *brush, struct RNG *rng);
/* Layers Enums -------------------------------------- */
-const struct EnumPropertyItem *ED_gpencil_layers_enum_itemf(
- struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
- bool *r_free);
-const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(
- struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
- bool *r_free);
+const struct EnumPropertyItem *ED_gpencil_layers_enum_itemf(struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ bool *r_free);
+const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ bool *r_free);
/* ***************************************************** */
/* Operator Defines */
@@ -340,7 +360,6 @@ const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(
void GPENCIL_OT_annotate(struct wmOperatorType *ot);
-
/* drawing ---------- */
void GPENCIL_OT_draw(struct wmOperatorType *ot);
@@ -352,15 +371,15 @@ void GPENCIL_OT_guide_rotate(struct wmOperatorType *ot);
/* Paint Modes for operator */
typedef enum eGPencil_PaintModes {
- GP_PAINTMODE_DRAW = 0,
- GP_PAINTMODE_ERASER,
- GP_PAINTMODE_DRAW_STRAIGHT,
- GP_PAINTMODE_DRAW_POLY,
- GP_PAINTMODE_SET_CP,
+ GP_PAINTMODE_DRAW = 0,
+ GP_PAINTMODE_ERASER,
+ GP_PAINTMODE_DRAW_STRAIGHT,
+ GP_PAINTMODE_DRAW_POLY,
+ GP_PAINTMODE_SET_CP,
} eGPencil_PaintModes;
/* maximum sizes of gp-session buffer */
-#define GP_STROKE_BUFFER_MAX 5000
+#define GP_STROKE_BUFFER_MAX 5000
/* stroke editing ----- */
@@ -436,21 +455,21 @@ void GPENCIL_OT_frame_clean_loose(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
enum {
- GP_STROKE_JOIN = -1,
- GP_STROKE_JOINCOPY = 1,
+ GP_STROKE_JOIN = -1,
+ GP_STROKE_JOINCOPY = 1,
};
enum {
- GP_STROKE_BOX = -1,
- GP_STROKE_LINE = 1,
- GP_STROKE_CIRCLE = 2,
- GP_STROKE_ARC = 3,
- GP_STROKE_CURVE = 4,
+ GP_STROKE_BOX = -1,
+ GP_STROKE_LINE = 1,
+ GP_STROKE_CIRCLE = 2,
+ GP_STROKE_ARC = 3,
+ GP_STROKE_CURVE = 4,
};
enum {
- GP_MERGE_STROKE = -1,
- GP_MERGE_POINT = 1,
+ GP_MERGE_STROKE = -1,
+ GP_MERGE_POINT = 1,
};
void GPENCIL_OT_stroke_arrange(struct wmOperatorType *ot);
@@ -520,20 +539,20 @@ void GPENCIL_OT_generate_weights(struct wmOperatorType *ot);
/* XXX - TODO: replace this with the modern bAnimListElem... */
/* This struct defines a structure used for quick access */
typedef struct bActListElem {
- struct bActListElem *next, *prev;
+ struct bActListElem *next, *prev;
- void *data; /* source data this elem represents */
- int type; /* one of the ACTTYPE_* values */
- int flag; /* copy of elem's flags for quick access */
- int index; /* copy of adrcode where applicable */
+ void *data; /* source data this elem represents */
+ int type; /* one of the ACTTYPE_* values */
+ int flag; /* copy of elem's flags for quick access */
+ int index; /* copy of adrcode where applicable */
- void *key_data; /* motion data - ipo or ipo-curve */
- short datatype; /* type of motion data to expect */
+ void *key_data; /* motion data - ipo or ipo-curve */
+ short datatype; /* type of motion data to expect */
- struct bActionGroup *grp; /* action group that owns the channel */
+ struct bActionGroup *grp; /* action group that owns the channel */
- void *owner; /* will either be an action channel or fake ipo-channel (for keys) */
- short ownertype; /* type of owner */
+ void *owner; /* will either be an action channel or fake ipo-channel (for keys) */
+ short ownertype; /* type of owner */
} bActListElem;
/* ****************************************************** */
@@ -541,29 +560,29 @@ typedef struct bActListElem {
/* filtering flags - under what circumstances should a channel be added */
typedef enum ACTFILTER_FLAGS {
- ACTFILTER_VISIBLE = (1 << 0), /* should channels be visible */
- ACTFILTER_SEL = (1 << 1), /* should channels be selected */
- ACTFILTER_FOREDIT = (1 << 2), /* does editable status matter */
- ACTFILTER_CHANNELS = (1 << 3), /* do we only care that it is a channel */
- ACTFILTER_IPOKEYS = (1 << 4), /* only channels referencing ipo's */
- ACTFILTER_ONLYICU = (1 << 5), /* only reference ipo-curves */
- ACTFILTER_FORDRAWING = (1 << 6), /* make list for interface drawing */
- ACTFILTER_ACTGROUPED = (1 << 7), /* belongs to the active group */
+ ACTFILTER_VISIBLE = (1 << 0), /* should channels be visible */
+ ACTFILTER_SEL = (1 << 1), /* should channels be selected */
+ ACTFILTER_FOREDIT = (1 << 2), /* does editable status matter */
+ ACTFILTER_CHANNELS = (1 << 3), /* do we only care that it is a channel */
+ ACTFILTER_IPOKEYS = (1 << 4), /* only channels referencing ipo's */
+ ACTFILTER_ONLYICU = (1 << 5), /* only reference ipo-curves */
+ ACTFILTER_FORDRAWING = (1 << 6), /* make list for interface drawing */
+ ACTFILTER_ACTGROUPED = (1 << 7), /* belongs to the active group */
} ACTFILTER_FLAGS;
/* Action Editor - Main Data types */
typedef enum ACTCONT_TYPES {
- ACTCONT_NONE = 0,
- ACTCONT_ACTION,
- ACTCONT_SHAPEKEY,
- ACTCONT_GPENCIL,
+ ACTCONT_NONE = 0,
+ ACTCONT_ACTION,
+ ACTCONT_SHAPEKEY,
+ ACTCONT_GPENCIL,
} ACTCONT_TYPES;
/* ****************************************************** */
/* Stroke Iteration Utilities */
struct GP_EditableStrokes_Iter {
- float diff_mat[4][4];
+ float diff_mat[4][4];
};
/**
@@ -576,42 +595,42 @@ struct GP_EditableStrokes_Iter {
* \param gps: The identifier to use for current stroke being processed.
* Choose a suitable value to avoid name clashes.
*/
-#define GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps) \
-{ \
- struct GP_EditableStrokes_Iter gpstroke_iter = {{{0}}}; \
- Depsgraph *depsgraph_ = CTX_data_depsgraph(C); \
- Object *obact_ = CTX_data_active_object(C); \
- bGPdata *gpd_ = CTX_data_gpencil_data(C); \
- const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) \
- { \
- bGPDframe *init_gpf_ = gpl->actframe; \
- if (is_multiedit_) { \
- init_gpf_ = gpl->frames.first; \
- } \
- for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
- if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
- ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \
- /* loop over strokes */ \
- for (bGPDstroke *gps = gpf_->strokes.first; gps; gps = gps->next) { \
- /* skip strokes that are invalid for current view */ \
- if (ED_gpencil_stroke_can_use(C, gps) == false) \
- continue; \
- /* check if the color is editable */ \
- if (ED_gpencil_stroke_color_use(obact_, gpl, gps) == false) \
- continue; \
- /* ... Do Stuff With Strokes ... */
-
-#define GP_EDITABLE_STROKES_END(gpstroke_iter) \
- } \
- } \
- if (!is_multiedit_) { \
- break; \
- } \
- } \
- } \
- CTX_DATA_END; \
-} (void)0
+#define GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps) \
+ { \
+ struct GP_EditableStrokes_Iter gpstroke_iter = {{{0}}}; \
+ Depsgraph *depsgraph_ = CTX_data_depsgraph(C); \
+ Object *obact_ = CTX_data_active_object(C); \
+ bGPdata *gpd_ = CTX_data_gpencil_data(C); \
+ const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { \
+ bGPDframe *init_gpf_ = gpl->actframe; \
+ if (is_multiedit_) { \
+ init_gpf_ = gpl->frames.first; \
+ } \
+ for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
+ if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
+ ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \
+ /* loop over strokes */ \
+ for (bGPDstroke *gps = gpf_->strokes.first; gps; gps = gps->next) { \
+ /* skip strokes that are invalid for current view */ \
+ if (ED_gpencil_stroke_can_use(C, gps) == false) \
+ continue; \
+ /* check if the color is editable */ \
+ if (ED_gpencil_stroke_color_use(obact_, gpl, gps) == false) \
+ continue; \
+ /* ... Do Stuff With Strokes ... */
+
+#define GP_EDITABLE_STROKES_END(gpstroke_iter) \
+ } \
+ } \
+ if (!is_multiedit_) { \
+ break; \
+ } \
+ } \
+ } \
+ CTX_DATA_END; \
+ } \
+ (void)0
/* ****************************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 7be157b5d84..5c9b9416330 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -22,7 +22,6 @@
* \ingroup edgpencil
*/
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -82,46 +81,48 @@
/* Poll callback for interpolation operators */
static bool gpencil_view3d_poll(bContext *C)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- /* only 3D view */
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype != SPACE_VIEW3D) {
- return 0;
- }
+ /* only 3D view */
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype != SPACE_VIEW3D) {
+ return 0;
+ }
- /* need data to interpolate */
- if (ELEM(NULL, gpd, gpl)) {
- return 0;
- }
+ /* need data to interpolate */
+ if (ELEM(NULL, gpd, gpl)) {
+ return 0;
+ }
- return 1;
+ return 1;
}
/* Perform interpolation */
-static void gp_interpolate_update_points(
- const bGPDstroke *gps_from, const bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor)
+static void gp_interpolate_update_points(const bGPDstroke *gps_from,
+ const bGPDstroke *gps_to,
+ bGPDstroke *new_stroke,
+ float factor)
{
- /* update points */
- for (int i = 0; i < new_stroke->totpoints; i++) {
- const bGPDspoint *prev = &gps_from->points[i];
- const bGPDspoint *next = &gps_to->points[i];
- bGPDspoint *pt = &new_stroke->points[i];
-
- /* Interpolate all values */
- interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor);
- pt->pressure = interpf(prev->pressure, next->pressure, 1.0f - factor);
- pt->strength = interpf(prev->strength, next->strength, 1.0f - factor);
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
-
- /* GPXX interpolate dverts */
+ /* update points */
+ for (int i = 0; i < new_stroke->totpoints; i++) {
+ const bGPDspoint *prev = &gps_from->points[i];
+ const bGPDspoint *next = &gps_to->points[i];
+ bGPDspoint *pt = &new_stroke->points[i];
+
+ /* Interpolate all values */
+ interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor);
+ pt->pressure = interpf(prev->pressure, next->pressure, 1.0f - factor);
+ pt->strength = interpf(prev->strength, next->strength, 1.0f - factor);
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+
+ /* GPXX interpolate dverts */
#if 0
- MDeformVert *dvert = &new_stroke->dvert[i];
- dvert->totweight = 0;
- dvert->dw = NULL;
+ MDeformVert *dvert = &new_stroke->dvert[i];
+ dvert->totweight = 0;
+ dvert->dw = NULL;
#endif
- }
+ }
}
/* ****************** Interpolate Interactive *********************** */
@@ -129,212 +130,223 @@ static void gp_interpolate_update_points(
/* Helper: Update all strokes interpolated */
static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
{
- bGPdata *gpd = tgpi->gpd;
- tGPDinterpolate_layer *tgpil;
- const float shift = tgpi->shift;
-
- for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
- bGPDstroke *new_stroke;
- const float factor = tgpil->factor + shift;
-
- for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) {
- bGPDstroke *gps_from, *gps_to;
- int stroke_idx;
-
- if (new_stroke->totpoints == 0) {
- continue;
- }
-
- /* get strokes to interpolate */
- stroke_idx = BLI_findindex(&tgpil->interFrame->strokes, new_stroke);
-
- gps_from = BLI_findlink(&tgpil->prevFrame->strokes, stroke_idx);
- gps_to = BLI_findlink(&tgpil->nextFrame->strokes, stroke_idx);
-
- /* update points position */
- if ((gps_from) && (gps_to)) {
- gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
- }
- }
- }
-
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ bGPdata *gpd = tgpi->gpd;
+ tGPDinterpolate_layer *tgpil;
+ const float shift = tgpi->shift;
+
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ bGPDstroke *new_stroke;
+ const float factor = tgpil->factor + shift;
+
+ for (new_stroke = tgpil->interFrame->strokes.first; new_stroke;
+ new_stroke = new_stroke->next) {
+ bGPDstroke *gps_from, *gps_to;
+ int stroke_idx;
+
+ if (new_stroke->totpoints == 0) {
+ continue;
+ }
+
+ /* get strokes to interpolate */
+ stroke_idx = BLI_findindex(&tgpil->interFrame->strokes, new_stroke);
+
+ gps_from = BLI_findlink(&tgpil->prevFrame->strokes, stroke_idx);
+ gps_to = BLI_findlink(&tgpil->nextFrame->strokes, stroke_idx);
+
+ /* update points position */
+ if ((gps_from) && (gps_to)) {
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
+ }
+ }
+ }
+
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
}
/* Helper: Verify valid strokes for interpolation */
static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd)
{
- Object *ob = CTX_data_active_object(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag;
-
- /* get layers */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* all layers or only active */
- if (!(flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && !(gpl->flag & GP_LAYER_ACTIVE)) {
- continue;
- }
- /* only editable and visible layers are considered */
- if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
- continue;
- }
-
- /* read strokes */
- for (bGPDstroke *gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) {
- bGPDstroke *gps_to;
- int fFrame;
-
- /* only selected */
- if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
- continue;
- }
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) {
- continue;
- }
-
- /* get final stroke to interpolate */
- fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from);
- gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame);
- if (gps_to == NULL) {
- continue;
- }
-
- return true;
- }
- }
- return false;
+ Object *ob = CTX_data_active_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag;
+
+ /* get layers */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* all layers or only active */
+ if (!(flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && !(gpl->flag & GP_LAYER_ACTIVE)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+
+ /* read strokes */
+ for (bGPDstroke *gps_from = gpl->actframe->strokes.first; gps_from;
+ gps_from = gps_from->next) {
+ bGPDstroke *gps_to;
+ int fFrame;
+
+ /* only selected */
+ if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) &&
+ ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ continue;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) {
+ continue;
+ }
+
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from);
+ gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame);
+ if (gps_to == NULL) {
+ continue;
+ }
+
+ return true;
+ }
+ }
+ return false;
}
/* Helper: Create internal strokes interpolated */
static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
{
- bGPdata *gpd = tgpi->gpd;
- bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
- bGPDframe *actframe = active_gpl->actframe;
- Object *ob = CTX_data_active_object(C);
-
- /* save initial factor for active layer to define shift limits */
- tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) / (actframe->next->framenum - actframe->framenum + 1);
-
- /* limits are 100% below 0 and 100% over the 100% */
- tgpi->low_limit = -1.0f - tgpi->init_factor;
- tgpi->high_limit = 2.0f - tgpi->init_factor;
-
- /* set layers */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- tGPDinterpolate_layer *tgpil;
-
- /* all layers or only active */
- if (!(tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && (gpl != active_gpl)) {
- continue;
- }
- /* only editable and visible layers are considered */
- if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
- continue;
- }
-
- /* create temp data for each layer */
- tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
-
- tgpil->gpl = gpl;
- tgpil->prevFrame = gpl->actframe;
- tgpil->nextFrame = gpl->actframe->next;
-
- BLI_addtail(&tgpi->ilayers, tgpil);
-
- /* create a new temporary frame */
- tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe");
- tgpil->interFrame->framenum = tgpi->cframe;
-
- /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */
- tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) / (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1);
-
- /* create new strokes data with interpolated points reading original stroke */
- for (bGPDstroke *gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
- bGPDstroke *gps_to;
- int fFrame;
-
- bGPDstroke *new_stroke = NULL;
- bool valid = true;
-
-
- /* only selected */
- if ((tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
- valid = false;
- }
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
- valid = false;
- }
-
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, tgpil->gpl, gps_from) == false) {
- valid = false;
- }
-
- /* get final stroke to interpolate */
- fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from);
- gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame);
- if (gps_to == NULL) {
- valid = false;
- }
-
- /* create new stroke */
- new_stroke = BKE_gpencil_stroke_duplicate(gps_from);
-
- if (valid) {
- /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
- if (gps_from->totpoints > gps_to->totpoints) {
- new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
- if (new_stroke->dvert != NULL) {
- new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert) * gps_to->totpoints);
- }
- new_stroke->totpoints = gps_to->totpoints;
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
- }
- /* update points position */
- gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
- }
- else {
- /* need an empty stroke to keep index correct for lookup, but resize to smallest size */
- new_stroke->totpoints = 0;
- new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points));
- if (new_stroke->dvert != NULL) {
- new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert));
- }
- new_stroke->tot_triangles = 0;
- new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles));
- new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
- }
-
- /* add to strokes */
- BLI_addtail(&tgpil->interFrame->strokes, new_stroke);
- }
- }
+ bGPdata *gpd = tgpi->gpd;
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDframe *actframe = active_gpl->actframe;
+ Object *ob = CTX_data_active_object(C);
+
+ /* save initial factor for active layer to define shift limits */
+ tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) /
+ (actframe->next->framenum - actframe->framenum + 1);
+
+ /* limits are 100% below 0 and 100% over the 100% */
+ tgpi->low_limit = -1.0f - tgpi->init_factor;
+ tgpi->high_limit = 2.0f - tgpi->init_factor;
+
+ /* set layers */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ tGPDinterpolate_layer *tgpil;
+
+ /* all layers or only active */
+ if (!(tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && (gpl != active_gpl)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+
+ /* create temp data for each layer */
+ tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
+
+ tgpil->gpl = gpl;
+ tgpil->prevFrame = gpl->actframe;
+ tgpil->nextFrame = gpl->actframe->next;
+
+ BLI_addtail(&tgpi->ilayers, tgpil);
+
+ /* create a new temporary frame */
+ tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe");
+ tgpil->interFrame->framenum = tgpi->cframe;
+
+ /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */
+ tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) /
+ (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1);
+
+ /* create new strokes data with interpolated points reading original stroke */
+ for (bGPDstroke *gps_from = tgpil->prevFrame->strokes.first; gps_from;
+ gps_from = gps_from->next) {
+ bGPDstroke *gps_to;
+ int fFrame;
+
+ bGPDstroke *new_stroke = NULL;
+ bool valid = true;
+
+ /* only selected */
+ if ((tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) &&
+ ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ valid = false;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ valid = false;
+ }
+
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, tgpil->gpl, gps_from) == false) {
+ valid = false;
+ }
+
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from);
+ gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame);
+ if (gps_to == NULL) {
+ valid = false;
+ }
+
+ /* create new stroke */
+ new_stroke = BKE_gpencil_stroke_duplicate(gps_from);
+
+ if (valid) {
+ /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
+ if (gps_from->totpoints > gps_to->totpoints) {
+ new_stroke->points = MEM_recallocN(new_stroke->points,
+ sizeof(*new_stroke->points) * gps_to->totpoints);
+ if (new_stroke->dvert != NULL) {
+ new_stroke->dvert = MEM_recallocN(new_stroke->dvert,
+ sizeof(*new_stroke->dvert) * gps_to->totpoints);
+ }
+ new_stroke->totpoints = gps_to->totpoints;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
+ }
+ /* update points position */
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
+ }
+ else {
+ /* need an empty stroke to keep index correct for lookup, but resize to smallest size */
+ new_stroke->totpoints = 0;
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points));
+ if (new_stroke->dvert != NULL) {
+ new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert));
+ }
+ new_stroke->tot_triangles = 0;
+ new_stroke->triangles = MEM_recallocN(new_stroke->triangles,
+ sizeof(*new_stroke->triangles));
+ new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
+ }
+
+ /* add to strokes */
+ BLI_addtail(&tgpil->interFrame->strokes, new_stroke);
+ }
+ }
}
/* ----------------------- */
/* Drawing Callbacks */
/* Drawing callback for modal operator in screen mode */
-static void gpencil_interpolate_draw_screen(const struct bContext *C, ARegion *UNUSED(ar), void *arg)
+static void gpencil_interpolate_draw_screen(const struct bContext *C,
+ ARegion *UNUSED(ar),
+ void *arg)
{
- tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
- ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_PIXEL);
+ tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
+ ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_PIXEL);
}
/* Drawing callback for modal operator in 3d mode */
static void gpencil_interpolate_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg)
{
- tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
- ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_VIEW);
+ tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
+ ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_VIEW);
}
/* ----------------------- */
@@ -344,52 +356,57 @@ static void gpencil_interpolate_draw_3d(const bContext *C, ARegion *UNUSED(ar),
*/
static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event)
{
- float mid = (float)(tgpi->ar->winx - tgpi->ar->winrct.xmin) / 2.0f;
- float mpos = event->x - tgpi->ar->winrct.xmin;
-
- if (mpos >= mid) {
- tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid;
- }
- else {
- tgpi->shift = tgpi->low_limit - ((mpos * tgpi->low_limit) / mid);
- }
-
- CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
- RNA_float_set(op->ptr, "shift", tgpi->shift);
+ float mid = (float)(tgpi->ar->winx - tgpi->ar->winrct.xmin) / 2.0f;
+ float mpos = event->x - tgpi->ar->winrct.xmin;
+
+ if (mpos >= mid) {
+ tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid;
+ }
+ else {
+ tgpi->shift = tgpi->low_limit - ((mpos * tgpi->low_limit) / mid);
+ }
+
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
}
/* Helper: Draw status message while the user is running the operator */
static void gpencil_interpolate_status_indicators(bContext *C, tGPDinterpolate *p)
{
- Scene *scene = p->scene;
- char status_str[UI_MAX_DRAW_STR];
- char msg_str[UI_MAX_DRAW_STR];
-
- BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: "), UI_MAX_DRAW_STR);
-
- if (hasNumInput(&p->num)) {
- char str_offs[NUM_STR_REP_LEN];
-
- outputNumInput(&p->num, str_offs, &scene->unit);
- BLI_snprintf(status_str, sizeof(status_str), "%s%s", msg_str, str_offs);
- }
- else {
- BLI_snprintf(status_str, sizeof(status_str), "%s%d %%", msg_str, (int)((p->init_factor + p->shift) * 100.0f));
- }
-
- ED_area_status_text(p->sa, status_str);
- ED_workspace_status_text(C, IFACE_("ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"));
+ Scene *scene = p->scene;
+ char status_str[UI_MAX_DRAW_STR];
+ char msg_str[UI_MAX_DRAW_STR];
+
+ BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: "), UI_MAX_DRAW_STR);
+
+ if (hasNumInput(&p->num)) {
+ char str_offs[NUM_STR_REP_LEN];
+
+ outputNumInput(&p->num, str_offs, &scene->unit);
+ BLI_snprintf(status_str, sizeof(status_str), "%s%s", msg_str, str_offs);
+ }
+ else {
+ BLI_snprintf(status_str,
+ sizeof(status_str),
+ "%s%d %%",
+ msg_str,
+ (int)((p->init_factor + p->shift) * 100.0f));
+ }
+
+ ED_area_status_text(p->sa, status_str);
+ ED_workspace_status_text(
+ C, IFACE_("ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"));
}
/* Update screen and stroke */
static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
{
- /* update shift indicator in header */
- gpencil_interpolate_status_indicators(C, tgpi);
- /* apply... */
- tgpi->shift = RNA_float_get(op->ptr, "shift");
- /* update points position */
- gp_interpolate_update_strokes(C, tgpi);
+ /* update shift indicator in header */
+ gpencil_interpolate_status_indicators(C, tgpi);
+ /* apply... */
+ tgpi->shift = RNA_float_get(op->ptr, "shift");
+ /* update points position */
+ gp_interpolate_update_strokes(C, tgpi);
}
/* ----------------------- */
@@ -397,93 +414,93 @@ static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpol
/* Exit and free memory */
static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
{
- tGPDinterpolate *tgpi = op->customdata;
- tGPDinterpolate_layer *tgpil;
- bGPdata *gpd = tgpi->gpd;
-
- /* don't assume that operator data exists at all */
- if (tgpi) {
- /* remove drawing handler */
- if (tgpi->draw_handle_screen) {
- ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_screen);
- }
- if (tgpi->draw_handle_3d) {
- ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d);
- }
-
- /* clear status message area */
- ED_area_status_text(tgpi->sa, NULL);
- ED_workspace_status_text(C, NULL);
-
- /* finally, free memory used by temp data */
- for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
- BKE_gpencil_free_strokes(tgpil->interFrame);
- MEM_freeN(tgpil->interFrame);
- }
-
- BLI_freelistN(&tgpi->ilayers);
- MEM_freeN(tgpi);
- }
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
-
- /* clear pointer */
- op->customdata = NULL;
+ tGPDinterpolate *tgpi = op->customdata;
+ tGPDinterpolate_layer *tgpil;
+ bGPdata *gpd = tgpi->gpd;
+
+ /* don't assume that operator data exists at all */
+ if (tgpi) {
+ /* remove drawing handler */
+ if (tgpi->draw_handle_screen) {
+ ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_screen);
+ }
+ if (tgpi->draw_handle_3d) {
+ ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d);
+ }
+
+ /* clear status message area */
+ ED_area_status_text(tgpi->sa, NULL);
+ ED_workspace_status_text(C, NULL);
+
+ /* finally, free memory used by temp data */
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ BKE_gpencil_free_strokes(tgpil->interFrame);
+ MEM_freeN(tgpil->interFrame);
+ }
+
+ BLI_freelistN(&tgpi->ilayers);
+ MEM_freeN(tgpi);
+ }
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* clear pointer */
+ op->customdata = NULL;
}
/* Init new temporary interpolation data */
static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- bGPdata *gpd = CTX_data_gpencil_data(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
- /* set current scene and window */
- tgpi->scene = CTX_data_scene(C);
- tgpi->sa = CTX_wm_area(C);
- tgpi->ar = CTX_wm_region(C);
- tgpi->flag = ts->gp_interpolate.flag;
+ /* set current scene and window */
+ tgpi->scene = CTX_data_scene(C);
+ tgpi->sa = CTX_wm_area(C);
+ tgpi->ar = CTX_wm_region(C);
+ tgpi->flag = ts->gp_interpolate.flag;
- /* set current frame number */
- tgpi->cframe = tgpi->scene->r.cfra;
+ /* set current frame number */
+ tgpi->cframe = tgpi->scene->r.cfra;
- /* set GP datablock */
- tgpi->gpd = gpd;
+ /* set GP datablock */
+ tgpi->gpd = gpd;
- /* set interpolation weight */
- tgpi->shift = RNA_float_get(op->ptr, "shift");
- /* set layers */
- gp_interpolate_set_points(C, tgpi);
+ /* set interpolation weight */
+ tgpi->shift = RNA_float_get(op->ptr, "shift");
+ /* set layers */
+ gp_interpolate_set_points(C, tgpi);
- return 1;
+ return 1;
}
/* Allocate memory and initialize values */
static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op)
{
- tGPDinterpolate *tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data");
+ tGPDinterpolate *tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data");
- /* define initial values */
- gp_interpolate_set_init_values(C, op, tgpi);
+ /* define initial values */
+ gp_interpolate_set_init_values(C, op, tgpi);
- /* return context data for running operator */
- return tgpi;
+ /* return context data for running operator */
+ return tgpi;
}
/* Init interpolation: Allocate memory and set init values */
static int gpencil_interpolate_init(bContext *C, wmOperator *op)
{
- tGPDinterpolate *tgpi;
-
- /* check context */
- tgpi = op->customdata = gp_session_init_interpolation(C, op);
- if (tgpi == NULL) {
- /* something wasn't set correctly in context */
- gpencil_interpolate_exit(C, op);
- return 0;
- }
-
- /* everything is now setup ok */
- return 1;
+ tGPDinterpolate *tgpi;
+
+ /* check context */
+ tgpi = op->customdata = gp_session_init_interpolation(C, op);
+ if (tgpi == NULL) {
+ /* something wasn't set correctly in context */
+ gpencil_interpolate_exit(C, op);
+ return 0;
+ }
+
+ /* everything is now setup ok */
+ return 1;
}
/* ----------------------- */
@@ -491,219 +508,230 @@ static int gpencil_interpolate_init(bContext *C, wmOperator *op)
/* Invoke handler: Initialize the operator */
static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- wmWindow *win = CTX_wm_window(C);
- bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
- bGPDframe *actframe = gpl->actframe;
- tGPDinterpolate *tgpi = NULL;
-
- /* cannot interpolate if not between 2 frames */
- if (ELEM(NULL, actframe, actframe->next)) {
- BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer");
- return OPERATOR_CANCELLED;
- }
-
- /* cannot interpolate in extremes */
- if (ELEM(cfra_eval, actframe->framenum, actframe->next->framenum)) {
- BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames");
- return OPERATOR_CANCELLED;
- }
-
- /* need editable strokes */
- if (!gp_interpolate_check_todo(C, gpd)) {
- BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable strokes");
- return OPERATOR_CANCELLED;
- }
-
- /* try to initialize context data needed */
- if (!gpencil_interpolate_init(C, op)) {
- if (op->customdata)
- MEM_freeN(op->customdata);
- return OPERATOR_CANCELLED;
- }
- else {
- tgpi = op->customdata;
- }
-
- /* Enable custom drawing handlers
- * It needs 2 handlers because strokes can in 3d space and screen space
- * and each handler use different coord system
- */
- tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, tgpi, REGION_DRAW_POST_PIXEL);
- tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW);
-
- /* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
-
- /* update shift indicator in header */
- gpencil_interpolate_status_indicators(C, tgpi);
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
-
- /* add a modal handler for this operator */
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
+ wmWindow *win = CTX_wm_window(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+ bGPDframe *actframe = gpl->actframe;
+ tGPDinterpolate *tgpi = NULL;
+
+ /* cannot interpolate if not between 2 frames */
+ if (ELEM(NULL, actframe, actframe->next)) {
+ BKE_report(
+ op->reports,
+ RPT_ERROR,
+ "Cannot find a pair of grease pencil frames to interpolate between in active layer");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* cannot interpolate in extremes */
+ if (ELEM(cfra_eval, actframe->framenum, actframe->next->framenum)) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Cannot interpolate as current frame already has existing grease pencil frames");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* need editable strokes */
+ if (!gp_interpolate_check_todo(C, gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable strokes");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* try to initialize context data needed */
+ if (!gpencil_interpolate_init(C, op)) {
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ tgpi = op->customdata;
+ }
+
+ /* Enable custom drawing handlers
+ * It needs 2 handlers because strokes can in 3d space and screen space
+ * and each handler use different coord system
+ */
+ tgpi->draw_handle_screen = ED_region_draw_cb_activate(
+ tgpi->ar->type, gpencil_interpolate_draw_screen, tgpi, REGION_DRAW_POST_PIXEL);
+ tgpi->draw_handle_3d = ED_region_draw_cb_activate(
+ tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW);
+
+ /* set cursor to indicate modal */
+ WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+
+ /* update shift indicator in header */
+ gpencil_interpolate_status_indicators(C, tgpi);
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* add a modal handler for this operator */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
}
/* Modal handler: Events handling during interactive part */
static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGPDinterpolate *tgpi = op->customdata;
- wmWindow *win = CTX_wm_window(C);
- bGPDframe *gpf_dst;
- bGPDstroke *gps_src, *gps_dst;
- tGPDinterpolate_layer *tgpil;
- const bool has_numinput = hasNumInput(&tgpi->num);
-
- switch (event->type) {
- case LEFTMOUSE: /* confirm */
- case RETKEY:
- {
- /* return to normal cursor and header status */
- ED_area_status_text(tgpi->sa, NULL);
- ED_workspace_status_text(C, NULL);
- WM_cursor_modal_restore(win);
-
- /* insert keyframes as required... */
- for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
- gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
- gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN;
-
- /* copy strokes */
- BLI_listbase_clear(&gpf_dst->strokes);
- for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) {
- if (gps_src->totpoints == 0) {
- continue;
- }
-
- /* make copy of source stroke, then adjust pointer to points too */
- gps_dst = MEM_dupallocN(gps_src);
- gps_dst->points = MEM_dupallocN(gps_src->points);
- if (gps_src->dvert != NULL) {
- gps_dst->dvert = MEM_dupallocN(gps_src->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
- }
- gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
- gps_dst->flag |= GP_STROKE_RECALC_GEOMETRY;
- BLI_addtail(&gpf_dst->strokes, gps_dst);
- }
- }
-
- /* clean up temp data */
- gpencil_interpolate_exit(C, op);
-
- /* done! */
- return OPERATOR_FINISHED;
- }
-
- case ESCKEY: /* cancel */
- case RIGHTMOUSE:
- {
- /* return to normal cursor and header status */
- ED_area_status_text(tgpi->sa, NULL);
- ED_workspace_status_text(C, NULL);
- WM_cursor_modal_restore(win);
-
- /* clean up temp data */
- gpencil_interpolate_exit(C, op);
-
- /* canceled! */
- return OPERATOR_CANCELLED;
- }
-
- case WHEELUPMOUSE:
- {
- tgpi->shift = tgpi->shift + 0.01f;
- CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
- RNA_float_set(op->ptr, "shift", tgpi->shift);
-
- /* update screen */
- gpencil_interpolate_update(C, op, tgpi);
- break;
- }
- case WHEELDOWNMOUSE:
- {
- tgpi->shift = tgpi->shift - 0.01f;
- CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
- RNA_float_set(op->ptr, "shift", tgpi->shift);
-
- /* update screen */
- gpencil_interpolate_update(C, op, tgpi);
- break;
- }
- case MOUSEMOVE: /* calculate new position */
- {
- /* only handle mousemove if not doing numinput */
- if (has_numinput == false) {
- /* update shift based on position of mouse */
- gpencil_mouse_update_shift(tgpi, op, event);
-
- /* update screen */
- gpencil_interpolate_update(C, op, tgpi);
- }
- break;
- }
- default:
- {
- if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
- const float factor = tgpi->init_factor;
- float value;
-
- /* Grab shift from numeric input, and store this new value (the user see an int) */
- value = (factor + tgpi->shift) * 100.0f;
- applyNumInput(&tgpi->num, &value);
- tgpi->shift = value / 100.0f;
-
- /* recalculate the shift to get the right value in the frame scale */
- tgpi->shift = tgpi->shift - factor;
-
- CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
- RNA_float_set(op->ptr, "shift", tgpi->shift);
-
- /* update screen */
- gpencil_interpolate_update(C, op, tgpi);
-
- break;
- }
- else {
- /* unhandled event - allow to pass through */
- return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
- }
- }
- }
-
- /* still running... */
- return OPERATOR_RUNNING_MODAL;
+ tGPDinterpolate *tgpi = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+ bGPDframe *gpf_dst;
+ bGPDstroke *gps_src, *gps_dst;
+ tGPDinterpolate_layer *tgpil;
+ const bool has_numinput = hasNumInput(&tgpi->num);
+
+ switch (event->type) {
+ case LEFTMOUSE: /* confirm */
+ case RETKEY: {
+ /* return to normal cursor and header status */
+ ED_area_status_text(tgpi->sa, NULL);
+ ED_workspace_status_text(C, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* insert keyframes as required... */
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
+ gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN;
+
+ /* copy strokes */
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) {
+ if (gps_src->totpoints == 0) {
+ continue;
+ }
+
+ /* make copy of source stroke, then adjust pointer to points too */
+ gps_dst = MEM_dupallocN(gps_src);
+ gps_dst->points = MEM_dupallocN(gps_src->points);
+ if (gps_src->dvert != NULL) {
+ gps_dst->dvert = MEM_dupallocN(gps_src->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
+ }
+ gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
+ gps_dst->flag |= GP_STROKE_RECALC_GEOMETRY;
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+ }
+ }
+
+ /* clean up temp data */
+ gpencil_interpolate_exit(C, op);
+
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+
+ case ESCKEY: /* cancel */
+ case RIGHTMOUSE: {
+ /* return to normal cursor and header status */
+ ED_area_status_text(tgpi->sa, NULL);
+ ED_workspace_status_text(C, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* clean up temp data */
+ gpencil_interpolate_exit(C, op);
+
+ /* canceled! */
+ return OPERATOR_CANCELLED;
+ }
+
+ case WHEELUPMOUSE: {
+ tgpi->shift = tgpi->shift + 0.01f;
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ break;
+ }
+ case WHEELDOWNMOUSE: {
+ tgpi->shift = tgpi->shift - 0.01f;
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ break;
+ }
+ case MOUSEMOVE: /* calculate new position */
+ {
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* update shift based on position of mouse */
+ gpencil_mouse_update_shift(tgpi, op, event);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ }
+ break;
+ }
+ default: {
+ if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
+ const float factor = tgpi->init_factor;
+ float value;
+
+ /* Grab shift from numeric input, and store this new value (the user see an int) */
+ value = (factor + tgpi->shift) * 100.0f;
+ applyNumInput(&tgpi->num, &value);
+ tgpi->shift = value / 100.0f;
+
+ /* recalculate the shift to get the right value in the frame scale */
+ tgpi->shift = tgpi->shift - factor;
+
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+
+ break;
+ }
+ else {
+ /* unhandled event - allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
+ }
+ }
+
+ /* still running... */
+ return OPERATOR_RUNNING_MODAL;
}
/* Cancel handler */
static void gpencil_interpolate_cancel(bContext *C, wmOperator *op)
{
- /* this is just a wrapper around exit() */
- gpencil_interpolate_exit(C, op);
+ /* this is just a wrapper around exit() */
+ gpencil_interpolate_exit(C, op);
}
void GPENCIL_OT_interpolate(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Grease Pencil Interpolation";
- ot->idname = "GPENCIL_OT_interpolate";
- ot->description = "Interpolate grease pencil strokes between frames";
-
- /* callbacks */
- ot->invoke = gpencil_interpolate_invoke;
- ot->modal = gpencil_interpolate_modal;
- ot->cancel = gpencil_interpolate_cancel;
- ot->poll = gpencil_view3d_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* properties */
- RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Bias factor for which frame has more influence on the interpolated strokes", -0.9f, 0.9f);
+ /* identifiers */
+ ot->name = "Grease Pencil Interpolation";
+ ot->idname = "GPENCIL_OT_interpolate";
+ ot->description = "Interpolate grease pencil strokes between frames";
+
+ /* callbacks */
+ ot->invoke = gpencil_interpolate_invoke;
+ ot->modal = gpencil_interpolate_modal;
+ ot->cancel = gpencil_interpolate_cancel;
+ ot->poll = gpencil_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ RNA_def_float_percentage(
+ ot->srna,
+ "shift",
+ 0.0f,
+ -1.0f,
+ 1.0f,
+ "Shift",
+ "Bias factor for which frame has more influence on the interpolated strokes",
+ -0.9f,
+ 0.9f);
}
/* ****************** Interpolate Sequence *********************** */
@@ -711,464 +739,473 @@ void GPENCIL_OT_interpolate(wmOperatorType *ot)
/* Helper: Perform easing equation calculations for GP interpolation operator */
static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_settings, float time)
{
- const float begin = 0.0f;
- const float change = 1.0f;
- const float duration = 1.0f;
-
- const float back = ipo_settings->back;
- const float amplitude = ipo_settings->amplitude;
- const float period = ipo_settings->period;
-
- eBezTriple_Easing easing = ipo_settings->easing;
- float result = time;
-
- switch (ipo_settings->type) {
- case GP_IPO_BACK:
- switch (easing) {
- case BEZT_IPO_EASE_IN:
- result = BLI_easing_back_ease_in(time, begin, change, duration, back);
- break;
- case BEZT_IPO_EASE_OUT:
- result = BLI_easing_back_ease_out(time, begin, change, duration, back);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- result = BLI_easing_back_ease_in_out(time, begin, change, duration, back);
- break;
-
- default: /* default/auto: same as ease out */
- result = BLI_easing_back_ease_out(time, begin, change, duration, back);
- break;
- }
- break;
-
- case GP_IPO_BOUNCE:
- switch (easing) {
- case BEZT_IPO_EASE_IN:
- result = BLI_easing_bounce_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- result = BLI_easing_bounce_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- result = BLI_easing_bounce_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease out */
- result = BLI_easing_bounce_ease_out(time, begin, change, duration);
- break;
- }
- break;
-
- case GP_IPO_CIRC:
- switch (easing) {
- case BEZT_IPO_EASE_IN:
- result = BLI_easing_circ_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- result = BLI_easing_circ_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- result = BLI_easing_circ_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- result = BLI_easing_circ_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case GP_IPO_CUBIC:
- switch (easing) {
- case BEZT_IPO_EASE_IN:
- result = BLI_easing_cubic_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- result = BLI_easing_cubic_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- result = BLI_easing_cubic_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- result = BLI_easing_cubic_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case GP_IPO_ELASTIC:
- switch (easing) {
- case BEZT_IPO_EASE_IN:
- result = BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
- break;
- case BEZT_IPO_EASE_OUT:
- result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- result = BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period);
- break;
-
- default: /* default/auto: same as ease out */
- result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
- break;
- }
- break;
-
- case GP_IPO_EXPO:
- switch (easing) {
- case BEZT_IPO_EASE_IN:
- result = BLI_easing_expo_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- result = BLI_easing_expo_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- result = BLI_easing_expo_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- result = BLI_easing_expo_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case GP_IPO_QUAD:
- switch (easing) {
- case BEZT_IPO_EASE_IN:
- result = BLI_easing_quad_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- result = BLI_easing_quad_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- result = BLI_easing_quad_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- result = BLI_easing_quad_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case GP_IPO_QUART:
- switch (easing) {
- case BEZT_IPO_EASE_IN:
- result = BLI_easing_quart_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- result = BLI_easing_quart_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- result = BLI_easing_quart_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- result = BLI_easing_quart_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case GP_IPO_QUINT:
- switch (easing) {
- case BEZT_IPO_EASE_IN:
- result = BLI_easing_quint_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- result = BLI_easing_quint_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- result = BLI_easing_quint_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- result = BLI_easing_quint_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case GP_IPO_SINE:
- switch (easing) {
- case BEZT_IPO_EASE_IN:
- result = BLI_easing_sine_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- result = BLI_easing_sine_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- result = BLI_easing_sine_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- result = BLI_easing_sine_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- default:
- printf("%s: Unknown interpolation type - %d\n", __func__, ipo_settings->type);
- break;
- }
-
- return result;
+ const float begin = 0.0f;
+ const float change = 1.0f;
+ const float duration = 1.0f;
+
+ const float back = ipo_settings->back;
+ const float amplitude = ipo_settings->amplitude;
+ const float period = ipo_settings->period;
+
+ eBezTriple_Easing easing = ipo_settings->easing;
+ float result = time;
+
+ switch (ipo_settings->type) {
+ case GP_IPO_BACK:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_back_ease_in(time, begin, change, duration, back);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_back_ease_out(time, begin, change, duration, back);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_back_ease_in_out(time, begin, change, duration, back);
+ break;
+
+ default: /* default/auto: same as ease out */
+ result = BLI_easing_back_ease_out(time, begin, change, duration, back);
+ break;
+ }
+ break;
+
+ case GP_IPO_BOUNCE:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_bounce_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_bounce_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_bounce_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease out */
+ result = BLI_easing_bounce_ease_out(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_CIRC:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_circ_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_circ_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_circ_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_circ_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_CUBIC:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_cubic_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_cubic_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_cubic_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_cubic_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_ELASTIC:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_elastic_ease_in_out(
+ time, begin, change, duration, amplitude, period);
+ break;
+
+ default: /* default/auto: same as ease out */
+ result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
+ break;
+ }
+ break;
+
+ case GP_IPO_EXPO:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_expo_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_expo_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_expo_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_expo_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_QUAD:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_quad_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_quad_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_quad_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_quad_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_QUART:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_quart_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_quart_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_quart_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_quart_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_QUINT:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_quint_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_quint_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_quint_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_quint_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_SINE:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_sine_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_sine_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_sine_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_sine_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ default:
+ printf("%s: Unknown interpolation type - %d\n", __func__, ipo_settings->type);
+ break;
+ }
+
+ return result;
}
static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
- bGPDframe *actframe = active_gpl->actframe;
-
- Object *ob = CTX_data_active_object(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
-
- GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate;
- eGP_Interpolate_SettingsFlag flag = ipo_settings->flag;
-
- /* cannot interpolate if not between 2 frames */
- if (ELEM(NULL, actframe, actframe->next)) {
- BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer");
- return OPERATOR_CANCELLED;
- }
- /* cannot interpolate in extremes */
- if (ELEM(cfra_eval, actframe->framenum, actframe->next->framenum)) {
- BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames");
- return OPERATOR_CANCELLED;
- }
-
- /* loop all layer to check if need interpolation */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- bGPDframe *prevFrame, *nextFrame;
- bGPDstroke *gps_from, *gps_to;
- int cframe, fFrame;
-
- /* all layers or only active */
- if (((flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
- continue;
- }
- /* only editable and visible layers are considered */
- if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
- continue;
- }
-
- /* store extremes */
- prevFrame = gpl->actframe;
- nextFrame = gpl->actframe->next;
-
- /* Loop over intermediary frames and create the interpolation */
- for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) {
- bGPDframe *interFrame = NULL;
- float factor;
-
- /* get interpolation factor */
- factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1);
-
- if (ipo_settings->type == GP_IPO_CURVEMAP) {
- /* custom curvemap */
- if (ipo_settings->custom_ipo) {
- factor = curvemapping_evaluateF(ipo_settings->custom_ipo, 0, factor);
- }
- else {
- BKE_report(op->reports, RPT_ERROR, "Custom interpolation curve does not exist");
- }
- }
- else if (ipo_settings->type >= GP_IPO_BACK) {
- /* easing equation... */
- factor = gp_interpolate_seq_easing_calc(ipo_settings, factor);
- }
-
- /* create new strokes data with interpolated points reading original stroke */
- for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
- bGPDstroke *new_stroke = NULL;
-
- /* only selected */
- if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
- continue;
- }
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) {
- continue;
- }
-
- /* get final stroke to interpolate */
- fFrame = BLI_findindex(&prevFrame->strokes, gps_from);
- gps_to = BLI_findlink(&nextFrame->strokes, fFrame);
- if (gps_to == NULL) {
- continue;
- }
-
- /* create a new frame if needed */
- if (interFrame == NULL) {
- interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW);
- interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN;
- }
-
- /* create new stroke */
- new_stroke = BKE_gpencil_stroke_duplicate(gps_from);
-
- /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
- if (gps_from->totpoints > gps_to->totpoints) {
- /* free weights of removed points */
- if (gps_from->dvert != NULL) {
- BKE_defvert_array_free_elems(gps_from->dvert + gps_to->totpoints, gps_from->totpoints - gps_to->totpoints);
- }
-
- new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
-
- if (new_stroke->dvert != NULL) {
- new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert) * gps_to->totpoints);
- }
- new_stroke->totpoints = gps_to->totpoints;
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
- }
-
- /* update points position */
- gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
-
- /* add to strokes */
- BLI_addtail(&interFrame->strokes, new_stroke);
- }
- }
- }
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDframe *actframe = active_gpl->actframe;
+
+ Object *ob = CTX_data_active_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate;
+ eGP_Interpolate_SettingsFlag flag = ipo_settings->flag;
+
+ /* cannot interpolate if not between 2 frames */
+ if (ELEM(NULL, actframe, actframe->next)) {
+ BKE_report(
+ op->reports,
+ RPT_ERROR,
+ "Cannot find a pair of grease pencil frames to interpolate between in active layer");
+ return OPERATOR_CANCELLED;
+ }
+ /* cannot interpolate in extremes */
+ if (ELEM(cfra_eval, actframe->framenum, actframe->next->framenum)) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Cannot interpolate as current frame already has existing grease pencil frames");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* loop all layer to check if need interpolation */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *prevFrame, *nextFrame;
+ bGPDstroke *gps_from, *gps_to;
+ int cframe, fFrame;
+
+ /* all layers or only active */
+ if (((flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+
+ /* store extremes */
+ prevFrame = gpl->actframe;
+ nextFrame = gpl->actframe->next;
+
+ /* Loop over intermediary frames and create the interpolation */
+ for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) {
+ bGPDframe *interFrame = NULL;
+ float factor;
+
+ /* get interpolation factor */
+ factor = (float)(cframe - prevFrame->framenum) /
+ (nextFrame->framenum - prevFrame->framenum + 1);
+
+ if (ipo_settings->type == GP_IPO_CURVEMAP) {
+ /* custom curvemap */
+ if (ipo_settings->custom_ipo) {
+ factor = curvemapping_evaluateF(ipo_settings->custom_ipo, 0, factor);
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Custom interpolation curve does not exist");
+ }
+ }
+ else if (ipo_settings->type >= GP_IPO_BACK) {
+ /* easing equation... */
+ factor = gp_interpolate_seq_easing_calc(ipo_settings, factor);
+ }
+
+ /* create new strokes data with interpolated points reading original stroke */
+ for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
+ bGPDstroke *new_stroke = NULL;
+
+ /* only selected */
+ if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) &&
+ ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ continue;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) {
+ continue;
+ }
+
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&prevFrame->strokes, gps_from);
+ gps_to = BLI_findlink(&nextFrame->strokes, fFrame);
+ if (gps_to == NULL) {
+ continue;
+ }
+
+ /* create a new frame if needed */
+ if (interFrame == NULL) {
+ interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW);
+ interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN;
+ }
+
+ /* create new stroke */
+ new_stroke = BKE_gpencil_stroke_duplicate(gps_from);
+
+ /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
+ if (gps_from->totpoints > gps_to->totpoints) {
+ /* free weights of removed points */
+ if (gps_from->dvert != NULL) {
+ BKE_defvert_array_free_elems(gps_from->dvert + gps_to->totpoints,
+ gps_from->totpoints - gps_to->totpoints);
+ }
+
+ new_stroke->points = MEM_recallocN(new_stroke->points,
+ sizeof(*new_stroke->points) * gps_to->totpoints);
+
+ if (new_stroke->dvert != NULL) {
+ new_stroke->dvert = MEM_recallocN(new_stroke->dvert,
+ sizeof(*new_stroke->dvert) * gps_to->totpoints);
+ }
+ new_stroke->totpoints = gps_to->totpoints;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
+ }
+
+ /* update points position */
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
+
+ /* add to strokes */
+ BLI_addtail(&interFrame->strokes, new_stroke);
+ }
+ }
+ }
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Interpolate Sequence";
- ot->idname = "GPENCIL_OT_interpolate_sequence";
- ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames";
+ /* identifiers */
+ ot->name = "Interpolate Sequence";
+ ot->idname = "GPENCIL_OT_interpolate_sequence";
+ ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames";
- /* api callbacks */
- ot->exec = gpencil_interpolate_seq_exec;
- ot->poll = gpencil_view3d_poll;
+ /* api callbacks */
+ ot->exec = gpencil_interpolate_seq_exec;
+ ot->poll = gpencil_view3d_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ******************** Remove Breakdowns ************************ */
static bool gpencil_interpolate_reverse_poll(bContext *C)
{
- if (!gpencil_view3d_poll(C)) {
- return 0;
- }
+ if (!gpencil_view3d_poll(C)) {
+ return 0;
+ }
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- /* need to be on a breakdown frame */
- if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN)) {
- CTX_wm_operator_poll_msg_set(C, "Expected current frame to be a breakdown");
- return 0;
- }
+ /* need to be on a breakdown frame */
+ if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN)) {
+ CTX_wm_operator_poll_msg_set(C, "Expected current frame to be a breakdown");
+ return 0;
+ }
- return 1;
+ return 1;
}
static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
-
- /* Go through each layer, deleting the breakdowns around the current frame,
- * but only if there is a keyframe nearby to stop at
- */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *start_key = NULL;
- bGPDframe *end_key = NULL;
- bGPDframe *gpf, *gpfn;
-
- /* Only continue if we're currently on a breakdown keyframe */
- if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN))
- continue;
-
- /* Search left for "start_key" (i.e. the first breakdown to remove) */
- gpf = gpl->actframe;
- while (gpf) {
- if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
- /* A breakdown... keep going left */
- start_key = gpf;
- gpf = gpf->prev;
- }
- else {
- /* Not a breakdown (may be a key, or an extreme,
- * or something else that wasn't generated)... stop */
- break;
- }
- }
-
- /* Search right for "end_key" (i.e. the last breakdown to remove) */
- gpf = gpl->actframe;
- while (gpf) {
- if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
- /* A breakdown... keep going right */
- end_key = gpf;
- gpf = gpf->next;
- }
- else {
- /* Not a breakdown... stop */
- break;
- }
- }
-
- /* Did we find anything? */
- /* NOTE: We should only proceed if there's something before/after these extents...
- * Otherwise, there's just an extent of breakdowns with no keys to interpolate between
- */
- if ((start_key && end_key) &&
- ELEM(NULL, start_key->prev, end_key->next) == false)
- {
- /* Set actframe to the key before start_key, since the keys have been removed now */
- gpl->actframe = start_key->prev;
-
- /* Free each frame we're removing (except the last one) */
- for (gpf = start_key; gpf && gpf != end_key; gpf = gpfn) {
- gpfn = gpf->next;
-
- /* free strokes and their associated memory */
- BKE_gpencil_free_strokes(gpf);
- BLI_freelinkN(&gpl->frames, gpf);
- }
-
- /* Now free the last one... */
- BKE_gpencil_free_strokes(end_key);
- BLI_freelinkN(&gpl->frames, end_key);
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ /* Go through each layer, deleting the breakdowns around the current frame,
+ * but only if there is a keyframe nearby to stop at
+ */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *start_key = NULL;
+ bGPDframe *end_key = NULL;
+ bGPDframe *gpf, *gpfn;
+
+ /* Only continue if we're currently on a breakdown keyframe */
+ if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN))
+ continue;
+
+ /* Search left for "start_key" (i.e. the first breakdown to remove) */
+ gpf = gpl->actframe;
+ while (gpf) {
+ if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
+ /* A breakdown... keep going left */
+ start_key = gpf;
+ gpf = gpf->prev;
+ }
+ else {
+ /* Not a breakdown (may be a key, or an extreme,
+ * or something else that wasn't generated)... stop */
+ break;
+ }
+ }
+
+ /* Search right for "end_key" (i.e. the last breakdown to remove) */
+ gpf = gpl->actframe;
+ while (gpf) {
+ if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
+ /* A breakdown... keep going right */
+ end_key = gpf;
+ gpf = gpf->next;
+ }
+ else {
+ /* Not a breakdown... stop */
+ break;
+ }
+ }
+
+ /* Did we find anything? */
+ /* NOTE: We should only proceed if there's something before/after these extents...
+ * Otherwise, there's just an extent of breakdowns with no keys to interpolate between
+ */
+ if ((start_key && end_key) && ELEM(NULL, start_key->prev, end_key->next) == false) {
+ /* Set actframe to the key before start_key, since the keys have been removed now */
+ gpl->actframe = start_key->prev;
+
+ /* Free each frame we're removing (except the last one) */
+ for (gpf = start_key; gpf && gpf != end_key; gpf = gpfn) {
+ gpfn = gpf->next;
+
+ /* free strokes and their associated memory */
+ BKE_gpencil_free_strokes(gpf);
+ BLI_freelinkN(&gpl->frames, gpf);
+ }
+
+ /* Now free the last one... */
+ BKE_gpencil_free_strokes(end_key);
+ BLI_freelinkN(&gpl->frames, end_key);
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_interpolate_reverse(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Remove Breakdowns";
- ot->idname = "GPENCIL_OT_interpolate_reverse";
- ot->description = "Remove breakdown frames generated by interpolating between two Grease Pencil frames";
-
- /* callbacks */
- ot->exec = gpencil_interpolate_reverse_exec;
- ot->poll = gpencil_interpolate_reverse_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Remove Breakdowns";
+ ot->idname = "GPENCIL_OT_interpolate_reverse";
+ ot->description =
+ "Remove breakdown frames generated by interpolating between two Grease Pencil frames";
+
+ /* callbacks */
+ ot->exec = gpencil_interpolate_reverse_exec;
+ ot->poll = gpencil_interpolate_reverse_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* *************************************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c
index 10bf45a9e2f..48c761919e5 100644
--- a/source/blender/editors/gpencil/gpencil_merge.c
+++ b/source/blender/editors/gpencil/gpencil_merge.c
@@ -54,144 +54,144 @@
#include "gpencil_intern.h"
typedef struct tGPencilPointCache {
- float factor; /* value to sort */
- bGPDstroke *gps;
- float x, y, z;
- float pressure;
- float strength;
+ float factor; /* value to sort */
+ bGPDstroke *gps;
+ float x, y, z;
+ float pressure;
+ float strength;
} tGPencilPointCache;
/* helper function to sort points */
static int gpencil_sort_points(const void *a1, const void *a2)
{
- const tGPencilPointCache *ps1 = a1, *ps2 = a2;
+ const tGPencilPointCache *ps1 = a1, *ps2 = a2;
- if (ps1->factor < ps2->factor) return -1;
- else if (ps1->factor > ps2->factor) return 1;
+ if (ps1->factor < ps2->factor)
+ return -1;
+ else if (ps1->factor > ps2->factor)
+ return 1;
- return 0;
+ return 0;
}
-static void gpencil_insert_points_to_stroke(
- bGPDstroke *gps, tGPencilPointCache *points_array, int totpoints)
+static void gpencil_insert_points_to_stroke(bGPDstroke *gps,
+ tGPencilPointCache *points_array,
+ int totpoints)
{
- tGPencilPointCache *point_elem = NULL;
-
- for (int i = 0; i < totpoints; i++) {
- point_elem = &points_array[i];
- bGPDspoint *pt_dst = &gps->points[i];
-
- copy_v3_v3(&pt_dst->x, &point_elem->x);
- pt_dst->pressure = point_elem->pressure;
- pt_dst->strength = point_elem->strength;
- pt_dst->uv_fac = 1.0f;
- pt_dst->uv_rot = 0;
- pt_dst->flag |= GP_SPOINT_SELECT;
- }
-
+ tGPencilPointCache *point_elem = NULL;
+
+ for (int i = 0; i < totpoints; i++) {
+ point_elem = &points_array[i];
+ bGPDspoint *pt_dst = &gps->points[i];
+
+ copy_v3_v3(&pt_dst->x, &point_elem->x);
+ pt_dst->pressure = point_elem->pressure;
+ pt_dst->strength = point_elem->strength;
+ pt_dst->uv_fac = 1.0f;
+ pt_dst->uv_rot = 0;
+ pt_dst->flag |= GP_SPOINT_SELECT;
+ }
}
static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpoints)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *ob = CTX_data_active_object(C);
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
-
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
-
- const bool back = RNA_boolean_get(op->ptr, "back");
- const bool additive = RNA_boolean_get(op->ptr, "additive");
- const bool cyclic = RNA_boolean_get(op->ptr, "cyclic");
-
- Paint *paint = &ts->gp_paint->paint;
- /* if not exist, create a new one */
- if (paint->brush == NULL) {
- /* create new brushes */
- BKE_brush_gpencil_presets(C);
- }
- Brush *brush = paint->brush;
-
- /* frame */
- short add_frame_mode;
- if (additive) {
- add_frame_mode = GP_GETFRAME_ADD_COPY;
- }
- else {
- add_frame_mode = GP_GETFRAME_ADD_NEW;
- }
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, add_frame_mode);
-
- /* stroke */
- bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- gps->totpoints = totpoints;
- gps->inittime = 0.0f;
- gps->thickness = brush->size;
- gps->gradient_f = brush->gpencil_settings->gradient_f;
- copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
- gps->flag |= GP_STROKE_SELECT;
- gps->flag |= GP_STROKE_3DSPACE;
- gps->mat_nr = ob->actcol - 1;
-
- /* allocate memory for points */
- gps->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, "gp_stroke_points");
- /* initialize triangle memory to dummy data */
- gps->tot_triangles = 0;
- gps->triangles = NULL;
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- if (cyclic) {
- gps->flag |= GP_STROKE_CYCLIC;
- }
-
- /* add new stroke to frame */
- if (back) {
- BLI_addhead(&gpf->strokes, gps);
- }
- else {
- BLI_addtail(&gpf->strokes, gps);
- }
-
- return gps;
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = CTX_data_active_object(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ const bool back = RNA_boolean_get(op->ptr, "back");
+ const bool additive = RNA_boolean_get(op->ptr, "additive");
+ const bool cyclic = RNA_boolean_get(op->ptr, "cyclic");
+
+ Paint *paint = &ts->gp_paint->paint;
+ /* if not exist, create a new one */
+ if (paint->brush == NULL) {
+ /* create new brushes */
+ BKE_brush_gpencil_presets(C);
+ }
+ Brush *brush = paint->brush;
+
+ /* frame */
+ short add_frame_mode;
+ if (additive) {
+ add_frame_mode = GP_GETFRAME_ADD_COPY;
+ }
+ else {
+ add_frame_mode = GP_GETFRAME_ADD_NEW;
+ }
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, add_frame_mode);
+
+ /* stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
+ gps->totpoints = totpoints;
+ gps->inittime = 0.0f;
+ gps->thickness = brush->size;
+ gps->gradient_f = brush->gpencil_settings->gradient_f;
+ copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
+ gps->flag |= GP_STROKE_SELECT;
+ gps->flag |= GP_STROKE_3DSPACE;
+ gps->mat_nr = ob->actcol - 1;
+
+ /* allocate memory for points */
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, "gp_stroke_points");
+ /* initialize triangle memory to dummy data */
+ gps->tot_triangles = 0;
+ gps->triangles = NULL;
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ if (cyclic) {
+ gps->flag |= GP_STROKE_CYCLIC;
+ }
+
+ /* add new stroke to frame */
+ if (back) {
+ BLI_addhead(&gpf->strokes, gps);
+ }
+ else {
+ BLI_addtail(&gpf->strokes, gps);
+ }
+
+ return gps;
}
static void gpencil_get_elements_len(bContext *C, int *totstrokes, int *totpoints)
{
- bGPDspoint *pt;
- int i;
-
- /* count number of strokes and selected points */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- if (gps->flag & GP_STROKE_SELECT) {
- *totstrokes += 1;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- *totpoints += 1;
- }
- }
- }
- }
- CTX_DATA_END;
+ bGPDspoint *pt;
+ int i;
+
+ /* count number of strokes and selected points */
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ *totstrokes += 1;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ *totpoints += 1;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
}
static void gpencil_dissolve_points(bContext *C)
{
- bGPDstroke *gps, *gpsn;
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL) {
- continue;
- }
-
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
- gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_TAG, false, 0);
- }
- }
- CTX_DATA_END;
+ bGPDstroke *gps, *gpsn;
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL) {
+ continue;
+ }
+
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_TAG, false, 0);
+ }
+ }
+ CTX_DATA_END;
}
/* Calc a factor of each selected point and fill an array with all the data.
@@ -201,367 +201,368 @@ static void gpencil_dissolve_points(bContext *C)
*
* All the data is saved to be sorted and used later.
*/
-static void gpencil_calc_points_factor(
- bContext *C, const int mode, int totpoints,
- const bool clear_point, const bool clear_stroke,
- tGPencilPointCache *src_array)
+static void gpencil_calc_points_factor(bContext *C,
+ const int mode,
+ int totpoints,
+ const bool clear_point,
+ const bool clear_stroke,
+ tGPencilPointCache *src_array)
{
- bGPDspoint *pt;
- int i;
- int idx = 0;
-
- /* create selected point array an fill it */
- bGPDstroke **gps_array = MEM_callocN(sizeof(bGPDstroke *) * totpoints, __func__);
- bGPDspoint *pt_array = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__);
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL) {
- continue;
- }
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- if (gps->flag & GP_STROKE_SELECT) {
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (clear_stroke) {
- pt->flag |= GP_SPOINT_TAG;
- }
- else {
- pt->flag &= ~GP_SPOINT_TAG;
- }
-
- if (pt->flag & GP_SPOINT_SELECT) {
- bGPDspoint *pt2 = &pt_array[idx];
- copy_v3_v3(&pt2->x, &pt->x);
- pt2->pressure = pt->pressure;
- pt2->strength = pt->strength;
- pt->flag &= ~GP_SPOINT_SELECT;
- if (clear_point) {
- pt->flag |= GP_SPOINT_TAG;
- }
-
- /* save stroke */
- gps_array[idx] = gps;
-
- idx++;
- }
- }
- gps->flag &= ~GP_STROKE_SELECT;
- }
- }
- }
- CTX_DATA_END;
-
- /* project in 2d plane */
- int direction = 0;
- float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, "GP Stroke temp 2d points");
- BKE_gpencil_stroke_2d_flat(pt_array, totpoints, points2d, &direction);
-
- /* calc center */
- float center[2] = { 0.0f, 0.0f };
- for (i = 0; i < totpoints; i++) {
- center[0] += points2d[i][0];
- center[1] += points2d[i][1];
- }
- mul_v2_fl(center, 1.0f / totpoints);
-
- /* calc angle and distance to center for each point */
- const float axis[2] = { 1.0f, 0.0f };
- float v1[3];
- for (i = 0; i < totpoints; i++) {
- float ln = len_v2v2(center, points2d[i]);
- sub_v2_v2v2(v1, points2d[i], center);
- float angle = angle_signed_v2v2(axis, v1);
- if (angle < 0.0f) {
- angle = fabsf(angle);
- }
- else {
- angle = (M_PI * 2.0) - angle;
- }
- tGPencilPointCache *sort_pt = &src_array[i];
- bGPDspoint *pt2 = &pt_array[i];
-
- copy_v3_v3(&sort_pt->x, &pt2->x);
- sort_pt->pressure = pt2->pressure;
- sort_pt->strength = pt2->strength;
-
- sort_pt->gps = gps_array[i];
-
- if (mode == GP_MERGE_STROKE) {
- sort_pt->factor = angle;
- }
- else {
- sort_pt->factor = (angle * 100000.0f) + ln;
- }
- }
- MEM_SAFE_FREE(points2d);
- MEM_SAFE_FREE(gps_array);
- MEM_SAFE_FREE(pt_array);
+ bGPDspoint *pt;
+ int i;
+ int idx = 0;
+
+ /* create selected point array an fill it */
+ bGPDstroke **gps_array = MEM_callocN(sizeof(bGPDstroke *) * totpoints, __func__);
+ bGPDspoint *pt_array = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__);
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL) {
+ continue;
+ }
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (clear_stroke) {
+ pt->flag |= GP_SPOINT_TAG;
+ }
+ else {
+ pt->flag &= ~GP_SPOINT_TAG;
+ }
+
+ if (pt->flag & GP_SPOINT_SELECT) {
+ bGPDspoint *pt2 = &pt_array[idx];
+ copy_v3_v3(&pt2->x, &pt->x);
+ pt2->pressure = pt->pressure;
+ pt2->strength = pt->strength;
+ pt->flag &= ~GP_SPOINT_SELECT;
+ if (clear_point) {
+ pt->flag |= GP_SPOINT_TAG;
+ }
+
+ /* save stroke */
+ gps_array[idx] = gps;
+
+ idx++;
+ }
+ }
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* project in 2d plane */
+ int direction = 0;
+ float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, "GP Stroke temp 2d points");
+ BKE_gpencil_stroke_2d_flat(pt_array, totpoints, points2d, &direction);
+
+ /* calc center */
+ float center[2] = {0.0f, 0.0f};
+ for (i = 0; i < totpoints; i++) {
+ center[0] += points2d[i][0];
+ center[1] += points2d[i][1];
+ }
+ mul_v2_fl(center, 1.0f / totpoints);
+
+ /* calc angle and distance to center for each point */
+ const float axis[2] = {1.0f, 0.0f};
+ float v1[3];
+ for (i = 0; i < totpoints; i++) {
+ float ln = len_v2v2(center, points2d[i]);
+ sub_v2_v2v2(v1, points2d[i], center);
+ float angle = angle_signed_v2v2(axis, v1);
+ if (angle < 0.0f) {
+ angle = fabsf(angle);
+ }
+ else {
+ angle = (M_PI * 2.0) - angle;
+ }
+ tGPencilPointCache *sort_pt = &src_array[i];
+ bGPDspoint *pt2 = &pt_array[i];
+
+ copy_v3_v3(&sort_pt->x, &pt2->x);
+ sort_pt->pressure = pt2->pressure;
+ sort_pt->strength = pt2->strength;
+
+ sort_pt->gps = gps_array[i];
+
+ if (mode == GP_MERGE_STROKE) {
+ sort_pt->factor = angle;
+ }
+ else {
+ sort_pt->factor = (angle * 100000.0f) + ln;
+ }
+ }
+ MEM_SAFE_FREE(points2d);
+ MEM_SAFE_FREE(gps_array);
+ MEM_SAFE_FREE(pt_array);
}
/* insert a group of points in destination array */
-static int gpencil_insert_to_array(
- tGPencilPointCache *src_array, tGPencilPointCache *dst_array, int totpoints,
- bGPDstroke *gps_filter, bool reverse, int last)
+static int gpencil_insert_to_array(tGPencilPointCache *src_array,
+ tGPencilPointCache *dst_array,
+ int totpoints,
+ bGPDstroke *gps_filter,
+ bool reverse,
+ int last)
{
- tGPencilPointCache *src_elem = NULL;
- tGPencilPointCache *dst_elem = NULL;
- int idx = 0;
-
- for (int i = 0; i < totpoints; i++) {
- if (!reverse) {
- idx = i;
- }
- else {
- idx = totpoints - i - 1;
- }
- src_elem = &src_array[idx];
- /* check if all points or only a stroke */
- if ((gps_filter != NULL) && (gps_filter != src_elem->gps)) {
- continue;
- }
-
- dst_elem = &dst_array[last];
- last++;
-
- copy_v3_v3(&dst_elem->x, &src_elem->x);
- dst_elem->gps = src_elem->gps;
- dst_elem->pressure = src_elem->pressure;
- dst_elem->strength = src_elem->strength;
- dst_elem->factor = src_elem->factor;
- }
-
- return last;
+ tGPencilPointCache *src_elem = NULL;
+ tGPencilPointCache *dst_elem = NULL;
+ int idx = 0;
+
+ for (int i = 0; i < totpoints; i++) {
+ if (!reverse) {
+ idx = i;
+ }
+ else {
+ idx = totpoints - i - 1;
+ }
+ src_elem = &src_array[idx];
+ /* check if all points or only a stroke */
+ if ((gps_filter != NULL) && (gps_filter != src_elem->gps)) {
+ continue;
+ }
+
+ dst_elem = &dst_array[last];
+ last++;
+
+ copy_v3_v3(&dst_elem->x, &src_elem->x);
+ dst_elem->gps = src_elem->gps;
+ dst_elem->pressure = src_elem->pressure;
+ dst_elem->strength = src_elem->strength;
+ dst_elem->factor = src_elem->factor;
+ }
+
+ return last;
}
/* get first and last point location */
static void gpencil_get_extremes(
- tGPencilPointCache *src_array, int totpoints,
- bGPDstroke *gps_filter, float *start, float *end)
+ tGPencilPointCache *src_array, int totpoints, bGPDstroke *gps_filter, float *start, float *end)
{
- tGPencilPointCache *array_pt = NULL;
- int i;
-
- /* find first point */
- for (i = 0; i < totpoints; i++) {
- array_pt = &src_array[i];
- if (gps_filter == array_pt->gps) {
- copy_v3_v3(start, &array_pt->x);
- break;
- }
- }
- /* find last point */
- for (i = totpoints - 1; i >= 0; i--) {
- array_pt = &src_array[i];
- if (gps_filter == array_pt->gps) {
- copy_v3_v3(end, &array_pt->x);
- break;
- }
- }
+ tGPencilPointCache *array_pt = NULL;
+ int i;
+
+ /* find first point */
+ for (i = 0; i < totpoints; i++) {
+ array_pt = &src_array[i];
+ if (gps_filter == array_pt->gps) {
+ copy_v3_v3(start, &array_pt->x);
+ break;
+ }
+ }
+ /* find last point */
+ for (i = totpoints - 1; i >= 0; i--) {
+ array_pt = &src_array[i];
+ if (gps_filter == array_pt->gps) {
+ copy_v3_v3(end, &array_pt->x);
+ break;
+ }
+ }
}
-static int gpencil_analyze_strokes(
- tGPencilPointCache *src_array, int totstrokes, int totpoints,
- tGPencilPointCache *dst_array)
+static int gpencil_analyze_strokes(tGPencilPointCache *src_array,
+ int totstrokes,
+ int totpoints,
+ tGPencilPointCache *dst_array)
{
- int i;
- int last = 0;
- GHash *all_strokes = BLI_ghash_ptr_new(__func__);
- /* add first stroke to array */
- tGPencilPointCache *sort_pt = &src_array[0];
- bGPDstroke *gps = sort_pt->gps;
- last = gpencil_insert_to_array(src_array, dst_array, totpoints, gps, false, last);
- float start[3];
- float end[3];
- float end_prv[3];
- gpencil_get_extremes(src_array, totpoints, gps, start, end);
- copy_v3_v3(end_prv, end);
- BLI_ghash_insert(all_strokes, sort_pt->gps, sort_pt->gps);
-
- /* look for near stroke */
- bool loop = (bool)(totstrokes > 1);
- while (loop) {
- bGPDstroke *gps_next = NULL;
- GHash *strokes = BLI_ghash_ptr_new(__func__);
- float dist_start = 0.0f;
- float dist_end = 0.0f;
- float dist = FLT_MAX;
- bool reverse = false;
-
- for (i = 0; i < totpoints; i++) {
- sort_pt = &src_array[i];
- /* avoid dups */
- if (BLI_ghash_haskey(all_strokes, sort_pt->gps)) {
- continue;
- }
- if (!BLI_ghash_haskey(strokes, sort_pt->gps)) {
- gpencil_get_extremes(src_array, totpoints, sort_pt->gps, start, end);
- /* distances to previous end */
- dist_start = len_v3v3(end_prv, start);
- dist_end = len_v3v3(end_prv, end);
-
- if (dist > dist_start) {
- gps_next = sort_pt->gps;
- dist = dist_start;
- reverse = false;
- }
- if (dist > dist_end) {
- gps_next = sort_pt->gps;
- dist = dist_end;
- reverse = true;
- }
- BLI_ghash_insert(strokes, sort_pt->gps, sort_pt->gps);
- }
- }
- BLI_ghash_free(strokes, NULL, NULL);
-
- /* add the stroke to array */
- if (gps->next != NULL) {
- BLI_ghash_insert(all_strokes, gps_next, gps_next);
- last = gpencil_insert_to_array(src_array, dst_array, totpoints, gps_next, reverse, last);
- /* replace last end */
- sort_pt = &dst_array[last - 1];
- copy_v3_v3(end_prv, &sort_pt->x);
- }
-
- /* loop exit */
- if (last >= totpoints) {
- loop = false;
- }
- }
-
- BLI_ghash_free(all_strokes, NULL, NULL);
- return last;
+ int i;
+ int last = 0;
+ GHash *all_strokes = BLI_ghash_ptr_new(__func__);
+ /* add first stroke to array */
+ tGPencilPointCache *sort_pt = &src_array[0];
+ bGPDstroke *gps = sort_pt->gps;
+ last = gpencil_insert_to_array(src_array, dst_array, totpoints, gps, false, last);
+ float start[3];
+ float end[3];
+ float end_prv[3];
+ gpencil_get_extremes(src_array, totpoints, gps, start, end);
+ copy_v3_v3(end_prv, end);
+ BLI_ghash_insert(all_strokes, sort_pt->gps, sort_pt->gps);
+
+ /* look for near stroke */
+ bool loop = (bool)(totstrokes > 1);
+ while (loop) {
+ bGPDstroke *gps_next = NULL;
+ GHash *strokes = BLI_ghash_ptr_new(__func__);
+ float dist_start = 0.0f;
+ float dist_end = 0.0f;
+ float dist = FLT_MAX;
+ bool reverse = false;
+
+ for (i = 0; i < totpoints; i++) {
+ sort_pt = &src_array[i];
+ /* avoid dups */
+ if (BLI_ghash_haskey(all_strokes, sort_pt->gps)) {
+ continue;
+ }
+ if (!BLI_ghash_haskey(strokes, sort_pt->gps)) {
+ gpencil_get_extremes(src_array, totpoints, sort_pt->gps, start, end);
+ /* distances to previous end */
+ dist_start = len_v3v3(end_prv, start);
+ dist_end = len_v3v3(end_prv, end);
+
+ if (dist > dist_start) {
+ gps_next = sort_pt->gps;
+ dist = dist_start;
+ reverse = false;
+ }
+ if (dist > dist_end) {
+ gps_next = sort_pt->gps;
+ dist = dist_end;
+ reverse = true;
+ }
+ BLI_ghash_insert(strokes, sort_pt->gps, sort_pt->gps);
+ }
+ }
+ BLI_ghash_free(strokes, NULL, NULL);
+
+ /* add the stroke to array */
+ if (gps->next != NULL) {
+ BLI_ghash_insert(all_strokes, gps_next, gps_next);
+ last = gpencil_insert_to_array(src_array, dst_array, totpoints, gps_next, reverse, last);
+ /* replace last end */
+ sort_pt = &dst_array[last - 1];
+ copy_v3_v3(end_prv, &sort_pt->x);
+ }
+
+ /* loop exit */
+ if (last >= totpoints) {
+ loop = false;
+ }
+ }
+
+ BLI_ghash_free(all_strokes, NULL, NULL);
+ return last;
}
static bool gp_strokes_merge_poll(bContext *C)
{
- /* only supported with grease pencil objects */
- Object *ob = CTX_data_active_object(C);
- if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
- return false;
- }
-
- /* check material */
- Material *ma = NULL;
- ma = give_current_material(ob, ob->actcol);
- if ((ma == NULL) || (ma->gp_style == NULL)) {
- return false;
- }
-
- /* check hidden or locked materials */
- MaterialGPencilStyle *gp_style = ma->gp_style;
- if ((gp_style->flag & GP_STYLE_COLOR_HIDE) ||
- (gp_style->flag & GP_STYLE_COLOR_LOCKED))
- {
- return false;
- }
-
- /* check layer */
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- if ((gpl == NULL) ||
- (gpl->flag & GP_LAYER_LOCKED) ||
- (gpl->flag & GP_LAYER_HIDE))
- {
- return false;
- }
-
- /* NOTE: this is a bit slower, but is the most accurate... */
- return (CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0) && ED_operator_view3d_active(C);
+ /* only supported with grease pencil objects */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ /* check material */
+ Material *ma = NULL;
+ ma = give_current_material(ob, ob->actcol);
+ if ((ma == NULL) || (ma->gp_style == NULL)) {
+ return false;
+ }
+
+ /* check hidden or locked materials */
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ if ((gp_style->flag & GP_STYLE_COLOR_HIDE) || (gp_style->flag & GP_STYLE_COLOR_LOCKED)) {
+ return false;
+ }
+
+ /* check layer */
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ if ((gpl == NULL) || (gpl->flag & GP_LAYER_LOCKED) || (gpl->flag & GP_LAYER_HIDE)) {
+ return false;
+ }
+
+ /* NOTE: this is a bit slower, but is the most accurate... */
+ return (CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0) && ED_operator_view3d_active(C);
}
static int gp_stroke_merge_exec(bContext *C, wmOperator *op)
{
- const int mode = RNA_enum_get(op->ptr, "mode");
- const bool clear_point = RNA_boolean_get(op->ptr, "clear_point");
- const bool clear_stroke = RNA_boolean_get(op->ptr, "clear_stroke");
-
- Object *ob = CTX_data_active_object(C);
- /* sanity checks */
- if (!ob || ob->type != OB_GPENCIL) {
- return OPERATOR_CANCELLED;
- }
-
- bGPdata *gpd = (bGPdata *)ob->data;
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- if (gpl == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- int totstrokes = 0;
- int totpoints = 0;
-
- /* count number of strokes and selected points */
- gpencil_get_elements_len(C, &totstrokes, &totpoints);
-
- if (totpoints == 0) {
- return OPERATOR_CANCELLED;
- }
-
- /* calc factor of each point and fill an array with all data */
- tGPencilPointCache *sorted_array = NULL;
- tGPencilPointCache *original_array = MEM_callocN(sizeof(tGPencilPointCache) * totpoints, __func__);
- gpencil_calc_points_factor(C, mode, totpoints, clear_point, clear_stroke, original_array);
-
- /* for strokes analyze strokes and load sorted array */
- if (mode == GP_MERGE_STROKE) {
- sorted_array = MEM_callocN(sizeof(tGPencilPointCache) * totpoints, __func__);
- totpoints = gpencil_analyze_strokes(original_array, totstrokes, totpoints, sorted_array);
- }
- else {
- /* make a copy to sort */
- sorted_array = MEM_dupallocN(original_array);
- /* sort by factor around center */
- qsort(sorted_array, totpoints, sizeof(tGPencilPointCache), gpencil_sort_points);
- }
-
- /* prepare the new stroke */
- bGPDstroke *gps = gpencil_prepare_stroke(C, op, totpoints);
-
- /* copy original points to final stroke */
- gpencil_insert_points_to_stroke(gps, sorted_array, totpoints);
-
- /* dissolve all tagged points */
- if ((clear_point) || (clear_stroke)) {
- gpencil_dissolve_points(C);
- }
-
- /* free memory */
- MEM_SAFE_FREE(original_array);
- MEM_SAFE_FREE(sorted_array);
-
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ const bool clear_point = RNA_boolean_get(op->ptr, "clear_point");
+ const bool clear_stroke = RNA_boolean_get(op->ptr, "clear_stroke");
+
+ Object *ob = CTX_data_active_object(C);
+ /* sanity checks */
+ if (!ob || ob->type != OB_GPENCIL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ if (gpl == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int totstrokes = 0;
+ int totpoints = 0;
+
+ /* count number of strokes and selected points */
+ gpencil_get_elements_len(C, &totstrokes, &totpoints);
+
+ if (totpoints == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* calc factor of each point and fill an array with all data */
+ tGPencilPointCache *sorted_array = NULL;
+ tGPencilPointCache *original_array = MEM_callocN(sizeof(tGPencilPointCache) * totpoints,
+ __func__);
+ gpencil_calc_points_factor(C, mode, totpoints, clear_point, clear_stroke, original_array);
+
+ /* for strokes analyze strokes and load sorted array */
+ if (mode == GP_MERGE_STROKE) {
+ sorted_array = MEM_callocN(sizeof(tGPencilPointCache) * totpoints, __func__);
+ totpoints = gpencil_analyze_strokes(original_array, totstrokes, totpoints, sorted_array);
+ }
+ else {
+ /* make a copy to sort */
+ sorted_array = MEM_dupallocN(original_array);
+ /* sort by factor around center */
+ qsort(sorted_array, totpoints, sizeof(tGPencilPointCache), gpencil_sort_points);
+ }
+
+ /* prepare the new stroke */
+ bGPDstroke *gps = gpencil_prepare_stroke(C, op, totpoints);
+
+ /* copy original points to final stroke */
+ gpencil_insert_points_to_stroke(gps, sorted_array, totpoints);
+
+ /* dissolve all tagged points */
+ if ((clear_point) || (clear_stroke)) {
+ gpencil_dissolve_points(C);
+ }
+
+ /* free memory */
+ MEM_SAFE_FREE(original_array);
+ MEM_SAFE_FREE(sorted_array);
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_merge(wmOperatorType *ot)
{
- static const EnumPropertyItem mode_type[] = {
- {GP_MERGE_STROKE, "STROKE", 0, "Stroke", ""},
- {GP_MERGE_POINT, "POINT", 0, "Point", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Merge Strokes";
- ot->idname = "GPENCIL_OT_stroke_merge";
- ot->description = "Create a new stroke with the selected stroke points";
-
- /* api callbacks */
- ot->exec = gp_stroke_merge_exec;
- ot->poll = gp_strokes_merge_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "mode", mode_type, GP_MERGE_STROKE, "Mode", "");
- RNA_def_boolean(ot->srna, "back", 0, "Draw on Back", "Draw new stroke below all previous strokes");
- RNA_def_boolean(ot->srna, "additive", 0, "Additive Drawing", "Add to previous drawing");
- RNA_def_boolean(ot->srna, "cyclic", 0, "Cyclic", "Close new stroke");
- RNA_def_boolean(ot->srna, "clear_point", 0, "Dissolve Points", "Dissolve old selected points");
- RNA_def_boolean(ot->srna, "clear_stroke", 0, "Delete Strokes", "Delete old selected strokes");
+ static const EnumPropertyItem mode_type[] = {
+ {GP_MERGE_STROKE, "STROKE", 0, "Stroke", ""},
+ {GP_MERGE_POINT, "POINT", 0, "Point", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Merge Strokes";
+ ot->idname = "GPENCIL_OT_stroke_merge";
+ ot->description = "Create a new stroke with the selected stroke points";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_merge_exec;
+ ot->poll = gp_strokes_merge_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "mode", mode_type, GP_MERGE_STROKE, "Mode", "");
+ RNA_def_boolean(
+ ot->srna, "back", 0, "Draw on Back", "Draw new stroke below all previous strokes");
+ RNA_def_boolean(ot->srna, "additive", 0, "Additive Drawing", "Add to previous drawing");
+ RNA_def_boolean(ot->srna, "cyclic", 0, "Cyclic", "Close new stroke");
+ RNA_def_boolean(ot->srna, "clear_point", 0, "Dissolve Points", "Dissolve old selected points");
+ RNA_def_boolean(ot->srna, "clear_stroke", 0, "Delete Strokes", "Delete old selected strokes");
}
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 779094c21ea..fce8fa79217 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -21,7 +21,6 @@
* \ingroup edgpencil
*/
-
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
@@ -58,7 +57,7 @@
/* Generic Drawing Keymap - Annotations */
static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
{
- WM_keymap_ensure(keyconf, "Grease Pencil", 0, 0);
+ WM_keymap_ensure(keyconf, "Grease Pencil", 0, 0);
}
/* ==================== */
@@ -66,317 +65,316 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
/* Poll callback for stroke editing mode */
static bool gp_stroke_editmode_poll(bContext *C)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- return (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE));
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ return (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE));
}
/* Poll callback for stroke painting mode */
static bool gp_stroke_paintmode_poll(bContext *C)
{
- /* TODO: limit this to mode, but review 2D editors */
- bGPdata *gpd = CTX_data_gpencil_data(C);
- return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE));
+ /* TODO: limit this to mode, but review 2D editors */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE));
}
static bool gp_stroke_paintmode_poll_with_tool(bContext *C, const char gpencil_tool)
{
- /* TODO: limit this to mode, but review 2D editors */
- bGPdata *gpd = CTX_data_gpencil_data(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
- return ((gpd) && (gpd->flag & GP_DATA_STROKE_PAINTMODE) &&
- (brush && brush->gpencil_settings) &&
- WM_toolsystem_active_tool_is_brush(C) &&
- (brush->gpencil_tool == gpencil_tool));
+ /* TODO: limit this to mode, but review 2D editors */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+ return ((gpd) && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush && brush->gpencil_settings) &&
+ WM_toolsystem_active_tool_is_brush(C) && (brush->gpencil_tool == gpencil_tool));
}
/* Poll callback for stroke painting (draw brush) */
static bool gp_stroke_paintmode_draw_poll(bContext *C)
{
- return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_DRAW);
+ return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_DRAW);
}
/* Poll callback for stroke painting (erase brush) */
static bool gp_stroke_paintmode_erase_poll(bContext *C)
{
- return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_ERASE);
+ return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_ERASE);
}
/* Poll callback for stroke painting (fill) */
static bool gp_stroke_paintmode_fill_poll(bContext *C)
{
- return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_FILL);
+ return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_FILL);
}
/* Poll callback for stroke sculpting mode */
static bool gp_stroke_sculptmode_poll(bContext *C)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- Object *ob = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
-
- /* if not gpencil object and not view3d, need sculpt keys if edit mode */
- if (sa->spacetype != SPACE_VIEW3D) {
- return ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
- }
- else {
- /* weight paint is a submode of sculpt */
- if ((ob) && (ob->type == OB_GPENCIL)) {
- return GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd);
- }
- }
-
- return 0;
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Object *ob = CTX_data_active_object(C);
+ ScrArea *sa = CTX_wm_area(C);
+
+ /* if not gpencil object and not view3d, need sculpt keys if edit mode */
+ if (sa->spacetype != SPACE_VIEW3D) {
+ return ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
+ }
+ else {
+ /* weight paint is a submode of sculpt */
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd);
+ }
+ }
+
+ return 0;
}
/* Poll callback for stroke weight paint mode */
static bool gp_stroke_weightmode_poll(bContext *C)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Object *ob = CTX_data_active_object(C);
- if ((ob) && (ob->type == OB_GPENCIL)) {
- return (gpd && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE));
- }
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return (gpd && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE));
+ }
- return 0;
+ return 0;
}
/* Stroke Editing Keymap - Only when editmode is enabled */
static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0);
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0);
- /* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */
- keymap->poll = gp_stroke_editmode_poll;
+ /* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */
+ keymap->poll = gp_stroke_editmode_poll;
}
/* keys for draw with a drawing brush (no fill) */
static void ed_keymap_gpencil_painting_draw(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Draw brush)", 0, 0);
- keymap->poll = gp_stroke_paintmode_draw_poll;
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Draw brush)", 0, 0);
+ keymap->poll = gp_stroke_paintmode_draw_poll;
}
/* keys for draw with a eraser brush (erase) */
static void ed_keymap_gpencil_painting_erase(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Erase)", 0, 0);
- keymap->poll = gp_stroke_paintmode_erase_poll;
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Erase)", 0, 0);
+ keymap->poll = gp_stroke_paintmode_erase_poll;
}
/* keys for draw with a fill brush */
static void ed_keymap_gpencil_painting_fill(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Fill)", 0, 0);
- keymap->poll = gp_stroke_paintmode_fill_poll;
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Fill)", 0, 0);
+ keymap->poll = gp_stroke_paintmode_fill_poll;
}
/* Stroke Painting Keymap - Only when paintmode is enabled */
static void ed_keymap_gpencil_painting(wmKeyConfig *keyconf)
{
- /* set poll callback - so that this keymap only gets enabled when stroke paintmode is enabled */
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint Mode", 0, 0);
- keymap->poll = gp_stroke_paintmode_poll;
+ /* set poll callback - so that this keymap only gets enabled when stroke paintmode is enabled */
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint Mode", 0, 0);
+ keymap->poll = gp_stroke_paintmode_poll;
}
/* Stroke Sculpting Keymap - Only when sculptmode is enabled */
static void ed_keymap_gpencil_sculpting(wmKeyConfig *keyconf)
{
- /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt Mode", 0, 0);
- keymap->poll = gp_stroke_sculptmode_poll;
+ /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt Mode", 0, 0);
+ keymap->poll = gp_stroke_sculptmode_poll;
}
/* Stroke Weight Paint Keymap - Only when weight is enabled */
static void ed_keymap_gpencil_weightpainting(wmKeyConfig *keyconf)
{
- /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight Mode", 0, 0);
- keymap->poll = gp_stroke_weightmode_poll;
+ /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight Mode", 0, 0);
+ keymap->poll = gp_stroke_weightmode_poll;
}
/* ==================== */
void ED_keymap_gpencil(wmKeyConfig *keyconf)
{
- ed_keymap_gpencil_general(keyconf);
- ed_keymap_gpencil_editing(keyconf);
- ed_keymap_gpencil_painting(keyconf);
- ed_keymap_gpencil_painting_draw(keyconf);
- ed_keymap_gpencil_painting_erase(keyconf);
- ed_keymap_gpencil_painting_fill(keyconf);
- ed_keymap_gpencil_sculpting(keyconf);
- ed_keymap_gpencil_weightpainting(keyconf);
+ ed_keymap_gpencil_general(keyconf);
+ ed_keymap_gpencil_editing(keyconf);
+ ed_keymap_gpencil_painting(keyconf);
+ ed_keymap_gpencil_painting_draw(keyconf);
+ ed_keymap_gpencil_painting_erase(keyconf);
+ ed_keymap_gpencil_painting_fill(keyconf);
+ ed_keymap_gpencil_sculpting(keyconf);
+ ed_keymap_gpencil_weightpainting(keyconf);
}
/* ****************************************** */
void ED_operatortypes_gpencil(void)
{
- /* Annotations -------------------- */
-
- WM_operatortype_append(GPENCIL_OT_annotate);
-
- /* Drawing ----------------------- */
-
- WM_operatortype_append(GPENCIL_OT_draw);
- WM_operatortype_append(GPENCIL_OT_fill);
-
- /* Guides ----------------------- */
-
- WM_operatortype_append(GPENCIL_OT_guide_rotate);
-
- /* Editing (Strokes) ------------ */
-
- WM_operatortype_append(GPENCIL_OT_editmode_toggle);
- WM_operatortype_append(GPENCIL_OT_selectmode_toggle);
- WM_operatortype_append(GPENCIL_OT_paintmode_toggle);
- WM_operatortype_append(GPENCIL_OT_sculptmode_toggle);
- WM_operatortype_append(GPENCIL_OT_weightmode_toggle);
- WM_operatortype_append(GPENCIL_OT_selection_opacity_toggle);
-
- WM_operatortype_append(GPENCIL_OT_select);
- WM_operatortype_append(GPENCIL_OT_select_all);
- WM_operatortype_append(GPENCIL_OT_select_circle);
- WM_operatortype_append(GPENCIL_OT_select_box);
- WM_operatortype_append(GPENCIL_OT_select_lasso);
-
- WM_operatortype_append(GPENCIL_OT_select_linked);
- WM_operatortype_append(GPENCIL_OT_select_grouped);
- WM_operatortype_append(GPENCIL_OT_select_more);
- WM_operatortype_append(GPENCIL_OT_select_less);
- WM_operatortype_append(GPENCIL_OT_select_first);
- WM_operatortype_append(GPENCIL_OT_select_last);
- WM_operatortype_append(GPENCIL_OT_select_alternate);
-
- WM_operatortype_append(GPENCIL_OT_duplicate);
- WM_operatortype_append(GPENCIL_OT_delete);
- WM_operatortype_append(GPENCIL_OT_dissolve);
- WM_operatortype_append(GPENCIL_OT_copy);
- WM_operatortype_append(GPENCIL_OT_paste);
- WM_operatortype_append(GPENCIL_OT_extrude);
-
- WM_operatortype_append(GPENCIL_OT_move_to_layer);
- WM_operatortype_append(GPENCIL_OT_layer_change);
-
- WM_operatortype_append(GPENCIL_OT_snap_to_grid);
- WM_operatortype_append(GPENCIL_OT_snap_to_cursor);
- WM_operatortype_append(GPENCIL_OT_snap_cursor_to_selected);
-
- WM_operatortype_append(GPENCIL_OT_reproject);
-
- WM_operatortype_append(GPENCIL_OT_sculpt_paint);
-
- /* Editing (Buttons) ------------ */
-
- WM_operatortype_append(GPENCIL_OT_data_add);
- WM_operatortype_append(GPENCIL_OT_data_unlink);
-
- WM_operatortype_append(GPENCIL_OT_layer_add);
- WM_operatortype_append(GPENCIL_OT_layer_remove);
- WM_operatortype_append(GPENCIL_OT_layer_move);
- WM_operatortype_append(GPENCIL_OT_layer_duplicate);
- WM_operatortype_append(GPENCIL_OT_layer_duplicate_object);
-
- WM_operatortype_append(GPENCIL_OT_hide);
- WM_operatortype_append(GPENCIL_OT_reveal);
- WM_operatortype_append(GPENCIL_OT_lock_all);
- WM_operatortype_append(GPENCIL_OT_unlock_all);
- WM_operatortype_append(GPENCIL_OT_layer_isolate);
- WM_operatortype_append(GPENCIL_OT_layer_merge);
-
- WM_operatortype_append(GPENCIL_OT_blank_frame_add);
-
- WM_operatortype_append(GPENCIL_OT_active_frame_delete);
- WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
- WM_operatortype_append(GPENCIL_OT_frame_duplicate);
- WM_operatortype_append(GPENCIL_OT_frame_clean_fill);
- WM_operatortype_append(GPENCIL_OT_frame_clean_loose);
-
- WM_operatortype_append(GPENCIL_OT_convert);
-
- WM_operatortype_append(GPENCIL_OT_stroke_arrange);
- WM_operatortype_append(GPENCIL_OT_stroke_change_color);
- WM_operatortype_append(GPENCIL_OT_stroke_lock_color);
- WM_operatortype_append(GPENCIL_OT_stroke_apply_thickness);
- WM_operatortype_append(GPENCIL_OT_stroke_cyclical_set);
- WM_operatortype_append(GPENCIL_OT_stroke_caps_set);
- WM_operatortype_append(GPENCIL_OT_stroke_join);
- WM_operatortype_append(GPENCIL_OT_stroke_flip);
- WM_operatortype_append(GPENCIL_OT_stroke_subdivide);
- WM_operatortype_append(GPENCIL_OT_stroke_simplify);
- WM_operatortype_append(GPENCIL_OT_stroke_simplify_fixed);
- WM_operatortype_append(GPENCIL_OT_stroke_separate);
- WM_operatortype_append(GPENCIL_OT_stroke_split);
- WM_operatortype_append(GPENCIL_OT_stroke_smooth);
- WM_operatortype_append(GPENCIL_OT_stroke_merge);
- WM_operatortype_append(GPENCIL_OT_stroke_cutter);
- WM_operatortype_append(GPENCIL_OT_stroke_trim);
-
- WM_operatortype_append(GPENCIL_OT_brush_presets_create);
-
- /* vertex groups */
- WM_operatortype_append(GPENCIL_OT_vertex_group_assign);
- WM_operatortype_append(GPENCIL_OT_vertex_group_remove_from);
- WM_operatortype_append(GPENCIL_OT_vertex_group_select);
- WM_operatortype_append(GPENCIL_OT_vertex_group_deselect);
- WM_operatortype_append(GPENCIL_OT_vertex_group_invert);
- WM_operatortype_append(GPENCIL_OT_vertex_group_smooth);
- WM_operatortype_append(GPENCIL_OT_vertex_group_normalize);
- WM_operatortype_append(GPENCIL_OT_vertex_group_normalize_all);
-
- /* color handle */
- WM_operatortype_append(GPENCIL_OT_lock_layer);
- WM_operatortype_append(GPENCIL_OT_color_isolate);
- WM_operatortype_append(GPENCIL_OT_color_hide);
- WM_operatortype_append(GPENCIL_OT_color_reveal);
- WM_operatortype_append(GPENCIL_OT_color_lock_all);
- WM_operatortype_append(GPENCIL_OT_color_unlock_all);
- WM_operatortype_append(GPENCIL_OT_color_select);
-
- /* Editing (Time) --------------- */
-
- /* Interpolation */
- WM_operatortype_append(GPENCIL_OT_interpolate);
- WM_operatortype_append(GPENCIL_OT_interpolate_sequence);
- WM_operatortype_append(GPENCIL_OT_interpolate_reverse);
-
- /* Primitives */
- WM_operatortype_append(GPENCIL_OT_primitive);
-
- /* convert old 2.7 files to 2.8 */
- WM_operatortype_append(GPENCIL_OT_convert_old_files);
-
- /* armatures */
- WM_operatortype_append(GPENCIL_OT_generate_weights);
+ /* Annotations -------------------- */
+
+ WM_operatortype_append(GPENCIL_OT_annotate);
+
+ /* Drawing ----------------------- */
+
+ WM_operatortype_append(GPENCIL_OT_draw);
+ WM_operatortype_append(GPENCIL_OT_fill);
+
+ /* Guides ----------------------- */
+
+ WM_operatortype_append(GPENCIL_OT_guide_rotate);
+
+ /* Editing (Strokes) ------------ */
+
+ WM_operatortype_append(GPENCIL_OT_editmode_toggle);
+ WM_operatortype_append(GPENCIL_OT_selectmode_toggle);
+ WM_operatortype_append(GPENCIL_OT_paintmode_toggle);
+ WM_operatortype_append(GPENCIL_OT_sculptmode_toggle);
+ WM_operatortype_append(GPENCIL_OT_weightmode_toggle);
+ WM_operatortype_append(GPENCIL_OT_selection_opacity_toggle);
+
+ WM_operatortype_append(GPENCIL_OT_select);
+ WM_operatortype_append(GPENCIL_OT_select_all);
+ WM_operatortype_append(GPENCIL_OT_select_circle);
+ WM_operatortype_append(GPENCIL_OT_select_box);
+ WM_operatortype_append(GPENCIL_OT_select_lasso);
+
+ WM_operatortype_append(GPENCIL_OT_select_linked);
+ WM_operatortype_append(GPENCIL_OT_select_grouped);
+ WM_operatortype_append(GPENCIL_OT_select_more);
+ WM_operatortype_append(GPENCIL_OT_select_less);
+ WM_operatortype_append(GPENCIL_OT_select_first);
+ WM_operatortype_append(GPENCIL_OT_select_last);
+ WM_operatortype_append(GPENCIL_OT_select_alternate);
+
+ WM_operatortype_append(GPENCIL_OT_duplicate);
+ WM_operatortype_append(GPENCIL_OT_delete);
+ WM_operatortype_append(GPENCIL_OT_dissolve);
+ WM_operatortype_append(GPENCIL_OT_copy);
+ WM_operatortype_append(GPENCIL_OT_paste);
+ WM_operatortype_append(GPENCIL_OT_extrude);
+
+ WM_operatortype_append(GPENCIL_OT_move_to_layer);
+ WM_operatortype_append(GPENCIL_OT_layer_change);
+
+ WM_operatortype_append(GPENCIL_OT_snap_to_grid);
+ WM_operatortype_append(GPENCIL_OT_snap_to_cursor);
+ WM_operatortype_append(GPENCIL_OT_snap_cursor_to_selected);
+
+ WM_operatortype_append(GPENCIL_OT_reproject);
+
+ WM_operatortype_append(GPENCIL_OT_sculpt_paint);
+
+ /* Editing (Buttons) ------------ */
+
+ WM_operatortype_append(GPENCIL_OT_data_add);
+ WM_operatortype_append(GPENCIL_OT_data_unlink);
+
+ WM_operatortype_append(GPENCIL_OT_layer_add);
+ WM_operatortype_append(GPENCIL_OT_layer_remove);
+ WM_operatortype_append(GPENCIL_OT_layer_move);
+ WM_operatortype_append(GPENCIL_OT_layer_duplicate);
+ WM_operatortype_append(GPENCIL_OT_layer_duplicate_object);
+
+ WM_operatortype_append(GPENCIL_OT_hide);
+ WM_operatortype_append(GPENCIL_OT_reveal);
+ WM_operatortype_append(GPENCIL_OT_lock_all);
+ WM_operatortype_append(GPENCIL_OT_unlock_all);
+ WM_operatortype_append(GPENCIL_OT_layer_isolate);
+ WM_operatortype_append(GPENCIL_OT_layer_merge);
+
+ WM_operatortype_append(GPENCIL_OT_blank_frame_add);
+
+ WM_operatortype_append(GPENCIL_OT_active_frame_delete);
+ WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
+ WM_operatortype_append(GPENCIL_OT_frame_duplicate);
+ WM_operatortype_append(GPENCIL_OT_frame_clean_fill);
+ WM_operatortype_append(GPENCIL_OT_frame_clean_loose);
+
+ WM_operatortype_append(GPENCIL_OT_convert);
+
+ WM_operatortype_append(GPENCIL_OT_stroke_arrange);
+ WM_operatortype_append(GPENCIL_OT_stroke_change_color);
+ WM_operatortype_append(GPENCIL_OT_stroke_lock_color);
+ WM_operatortype_append(GPENCIL_OT_stroke_apply_thickness);
+ WM_operatortype_append(GPENCIL_OT_stroke_cyclical_set);
+ WM_operatortype_append(GPENCIL_OT_stroke_caps_set);
+ WM_operatortype_append(GPENCIL_OT_stroke_join);
+ WM_operatortype_append(GPENCIL_OT_stroke_flip);
+ WM_operatortype_append(GPENCIL_OT_stroke_subdivide);
+ WM_operatortype_append(GPENCIL_OT_stroke_simplify);
+ WM_operatortype_append(GPENCIL_OT_stroke_simplify_fixed);
+ WM_operatortype_append(GPENCIL_OT_stroke_separate);
+ WM_operatortype_append(GPENCIL_OT_stroke_split);
+ WM_operatortype_append(GPENCIL_OT_stroke_smooth);
+ WM_operatortype_append(GPENCIL_OT_stroke_merge);
+ WM_operatortype_append(GPENCIL_OT_stroke_cutter);
+ WM_operatortype_append(GPENCIL_OT_stroke_trim);
+
+ WM_operatortype_append(GPENCIL_OT_brush_presets_create);
+
+ /* vertex groups */
+ WM_operatortype_append(GPENCIL_OT_vertex_group_assign);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_remove_from);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_select);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_deselect);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_invert);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_smooth);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_normalize);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_normalize_all);
+
+ /* color handle */
+ WM_operatortype_append(GPENCIL_OT_lock_layer);
+ WM_operatortype_append(GPENCIL_OT_color_isolate);
+ WM_operatortype_append(GPENCIL_OT_color_hide);
+ WM_operatortype_append(GPENCIL_OT_color_reveal);
+ WM_operatortype_append(GPENCIL_OT_color_lock_all);
+ WM_operatortype_append(GPENCIL_OT_color_unlock_all);
+ WM_operatortype_append(GPENCIL_OT_color_select);
+
+ /* Editing (Time) --------------- */
+
+ /* Interpolation */
+ WM_operatortype_append(GPENCIL_OT_interpolate);
+ WM_operatortype_append(GPENCIL_OT_interpolate_sequence);
+ WM_operatortype_append(GPENCIL_OT_interpolate_reverse);
+
+ /* Primitives */
+ WM_operatortype_append(GPENCIL_OT_primitive);
+
+ /* convert old 2.7 files to 2.8 */
+ WM_operatortype_append(GPENCIL_OT_convert_old_files);
+
+ /* armatures */
+ WM_operatortype_append(GPENCIL_OT_generate_weights);
}
void ED_operatormacros_gpencil(void)
{
- wmOperatorType *ot;
- wmOperatorTypeMacro *otmacro;
-
- /* Duplicate + Move = Interactively place newly duplicated strokes */
- ot = WM_operatortype_append_macro(
- "GPENCIL_OT_duplicate_move", "Duplicate Strokes",
- "Make copies of the selected Grease Pencil strokes and move them",
- OPTYPE_UNDO | OPTYPE_REGISTER);
- WM_operatortype_macro_define(ot, "GPENCIL_OT_duplicate");
- otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
- RNA_boolean_set(otmacro->ptr, "gpencil_strokes", true);
- RNA_enum_set(otmacro->ptr, "proportional", 0);
- RNA_boolean_set(otmacro->ptr, "mirror", false);
-
- /* Extrude + Move = Interactively add new points */
- ot = WM_operatortype_append_macro(
- "GPENCIL_OT_extrude_move", "Extrude Stroke Points",
- "Extrude selected points and move them",
- OPTYPE_UNDO | OPTYPE_REGISTER);
- WM_operatortype_macro_define(ot, "GPENCIL_OT_extrude");
- otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
- RNA_boolean_set(otmacro->ptr, "gpencil_strokes", true);
- RNA_enum_set(otmacro->ptr, "proportional", 0);
- RNA_boolean_set(otmacro->ptr, "mirror", false);
+ wmOperatorType *ot;
+ wmOperatorTypeMacro *otmacro;
+
+ /* Duplicate + Move = Interactively place newly duplicated strokes */
+ ot = WM_operatortype_append_macro(
+ "GPENCIL_OT_duplicate_move",
+ "Duplicate Strokes",
+ "Make copies of the selected Grease Pencil strokes and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "GPENCIL_OT_duplicate");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "gpencil_strokes", true);
+ RNA_enum_set(otmacro->ptr, "proportional", 0);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
+
+ /* Extrude + Move = Interactively add new points */
+ ot = WM_operatortype_append_macro("GPENCIL_OT_extrude_move",
+ "Extrude Stroke Points",
+ "Extrude selected points and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "GPENCIL_OT_extrude");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "gpencil_strokes", true);
+ RNA_enum_set(otmacro->ptr, "proportional", 0);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
}
/* ****************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c
index 9fdb5a9b174..af49587f9ad 100644
--- a/source/blender/editors/gpencil/gpencil_ops_versioning.c
+++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c
@@ -22,7 +22,7 @@
* \ingroup edgpencil
*/
- /* allow to use deprecated functionality */
+/* allow to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
#include <stdio.h>
@@ -56,162 +56,161 @@
#include "gpencil_intern.h"
- /* Free all of a gp-colors */
+/* Free all of a gp-colors */
static void free_gpencil_colors(bGPDpalette *palette)
{
- /* error checking */
- if (palette == NULL) {
- return;
- }
+ /* error checking */
+ if (palette == NULL) {
+ return;
+ }
- /* free colors */
- BLI_freelistN(&palette->colors);
+ /* free colors */
+ BLI_freelistN(&palette->colors);
}
/* Free all of the gp-palettes and colors */
static void free_palettes(ListBase *list)
{
- bGPDpalette *palette_next;
-
- /* error checking */
- if (list == NULL) {
- return;
- }
-
- /* delete palettes */
- for (bGPDpalette *palette = list->first; palette; palette = palette_next) {
- palette_next = palette->next;
- /* free palette colors */
- free_gpencil_colors(palette);
-
- MEM_freeN(palette);
- }
- BLI_listbase_clear(list);
+ bGPDpalette *palette_next;
+
+ /* error checking */
+ if (list == NULL) {
+ return;
+ }
+
+ /* delete palettes */
+ for (bGPDpalette *palette = list->first; palette; palette = palette_next) {
+ palette_next = palette->next;
+ /* free palette colors */
+ free_gpencil_colors(palette);
+
+ MEM_freeN(palette);
+ }
+ BLI_listbase_clear(list);
}
/* ***************** Convert old 2.7 files to 2.8 ************************ */
static bool gpencil_convert_old_files_poll(bContext *C)
{
- Scene *scene = CTX_data_scene(C);
+ Scene *scene = CTX_data_scene(C);
- return (int) (scene->gpd != NULL);
+ return (int)(scene->gpd != NULL);
}
static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const bool is_annotation = RNA_boolean_get(op->ptr, "annotation");
- bGPdata *gpd = scene->gpd;
-
- /* Convert grease pencil scene datablock to GP object */
- if ((!is_annotation) && (view_layer != NULL)) {
- Object *ob;
- ob = BKE_object_add_for_data(bmain, view_layer, OB_GPENCIL, "GP_Scene", &scene->gpd->id, false);
- zero_v3(ob->loc);
-
- /* convert grease pencil palettes (version >= 2.78) to materials and weights */
- for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
- for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
-
- /* create material slot */
- Material *ma = BKE_gpencil_object_material_new(bmain, ob, palcolor->info, NULL);
-
- /* copy color settings */
- MaterialGPencilStyle *gp_style = ma->gp_style;
- copy_v4_v4(gp_style->stroke_rgba, palcolor->color);
- copy_v4_v4(gp_style->fill_rgba, palcolor->fill);
-
- /* set basic settings */
- gp_style->pattern_gridsize = 0.1f;
- gp_style->gradient_radius = 0.5f;
- ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f);
- ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f);
- ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
- gp_style->texture_opacity = 1.0f;
- gp_style->texture_pixsize = 100.0f;
-
- gp_style->flag |= GP_STYLE_STROKE_SHOW;
- gp_style->flag |= GP_STYLE_FILL_SHOW;
-
- /* fix strokes */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- if ((gps->colorname[0] != '\0') &&
- (STREQ(gps->colorname, palcolor->info)))
- {
- gps->mat_nr = ob->totcol - 1;
- gps->colorname[0] = '\0';
- /* weights array */
- gps->dvert = NULL;
- }
- }
- }
- }
- }
- }
-
- /* free palettes */
- free_palettes(&gpd->palettes);
-
- /* disable all GP modes */
- ED_gpencil_setup_modes(C, gpd, 0);
-
- /* set cache as dirty */
- BKE_gpencil_batch_cache_dirty_tag(ob->data);
-
- scene->gpd = NULL;
- }
-
- if (is_annotation) {
- for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
- for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- /* fix layers */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* unlock/unhide layer */
- gpl->flag &= ~GP_LAYER_LOCKED;
- gpl->flag &= ~GP_LAYER_HIDE;
- /* set opacity to 1 */
- gpl->opacity = 1.0f;
- /* disable tint */
- gpl->tintcolor[3] = 0.0f;
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- if ((gps->colorname[0] != '\0') &&
- (STREQ(gps->colorname, palcolor->info)))
- {
- /* copy color settings */
- copy_v4_v4(gpl->color, palcolor->color);
- }
- }
- }
- }
- }
- }
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool is_annotation = RNA_boolean_get(op->ptr, "annotation");
+ bGPdata *gpd = scene->gpd;
+
+ /* Convert grease pencil scene datablock to GP object */
+ if ((!is_annotation) && (view_layer != NULL)) {
+ Object *ob;
+ ob = BKE_object_add_for_data(
+ bmain, view_layer, OB_GPENCIL, "GP_Scene", &scene->gpd->id, false);
+ zero_v3(ob->loc);
+
+ /* convert grease pencil palettes (version >= 2.78) to materials and weights */
+ for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
+ for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor;
+ palcolor = palcolor->next) {
+
+ /* create material slot */
+ Material *ma = BKE_gpencil_object_material_new(bmain, ob, palcolor->info, NULL);
+
+ /* copy color settings */
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ copy_v4_v4(gp_style->stroke_rgba, palcolor->color);
+ copy_v4_v4(gp_style->fill_rgba, palcolor->fill);
+
+ /* set basic settings */
+ gp_style->pattern_gridsize = 0.1f;
+ gp_style->gradient_radius = 0.5f;
+ ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f);
+ ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f);
+ ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
+ gp_style->texture_opacity = 1.0f;
+ gp_style->texture_pixsize = 100.0f;
+
+ gp_style->flag |= GP_STYLE_STROKE_SHOW;
+ gp_style->flag |= GP_STYLE_FILL_SHOW;
+
+ /* fix strokes */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if ((gps->colorname[0] != '\0') && (STREQ(gps->colorname, palcolor->info))) {
+ gps->mat_nr = ob->totcol - 1;
+ gps->colorname[0] = '\0';
+ /* weights array */
+ gps->dvert = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* free palettes */
+ free_palettes(&gpd->palettes);
+
+ /* disable all GP modes */
+ ED_gpencil_setup_modes(C, gpd, 0);
+
+ /* set cache as dirty */
+ BKE_gpencil_batch_cache_dirty_tag(ob->data);
+
+ scene->gpd = NULL;
+ }
+
+ if (is_annotation) {
+ for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
+ for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor;
+ palcolor = palcolor->next) {
+ /* fix layers */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* unlock/unhide layer */
+ gpl->flag &= ~GP_LAYER_LOCKED;
+ gpl->flag &= ~GP_LAYER_HIDE;
+ /* set opacity to 1 */
+ gpl->opacity = 1.0f;
+ /* disable tint */
+ gpl->tintcolor[3] = 0.0f;
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if ((gps->colorname[0] != '\0') && (STREQ(gps->colorname, palcolor->info))) {
+ /* copy color settings */
+ copy_v4_v4(gpl->color, palcolor->color);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_convert_old_files(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Convert Grease Pencil";
- ot->idname = "GPENCIL_OT_convert_old_files";
- ot->description = "Convert 2.7x grease pencil files to 2.80";
+ /* identifiers */
+ ot->name = "Convert Grease Pencil";
+ ot->idname = "GPENCIL_OT_convert_old_files";
+ ot->description = "Convert 2.7x grease pencil files to 2.80";
- /* callbacks */
- ot->exec = gpencil_convert_old_files_exec;
- ot->poll = gpencil_convert_old_files_poll;
+ /* callbacks */
+ ot->exec = gpencil_convert_old_files_exec;
+ ot->poll = gpencil_convert_old_files_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- ot->prop = RNA_def_boolean(ot->srna, "annotation", 0, "Annotation", "Convert to Annotations");
+ /* props */
+ ot->prop = RNA_def_boolean(ot->srna, "annotation", 0, "Annotation", "Convert to Annotations");
}
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 8ac4d602736..bfdfe64ed54 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -69,7 +69,6 @@
#include "ED_view3d.h"
#include "ED_clip.h"
-
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_state.h"
@@ -85,153 +84,153 @@
#include "gpencil_intern.h"
- /* ******************************************* */
- /* 'Globals' and Defines */
+/* ******************************************* */
+/* 'Globals' and Defines */
- /* values for tGPsdata->status */
+/* values for tGPsdata->status */
typedef enum eGPencil_PaintStatus {
- GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
- GP_STATUS_PAINTING, /* a stroke is in progress */
- GP_STATUS_ERROR, /* something wasn't correctly set up */
- GP_STATUS_DONE, /* painting done */
+ GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
+ GP_STATUS_PAINTING, /* a stroke is in progress */
+ GP_STATUS_ERROR, /* something wasn't correctly set up */
+ GP_STATUS_DONE, /* painting done */
} eGPencil_PaintStatus;
/* Return flags for adding points to stroke buffer */
typedef enum eGP_StrokeAdd_Result {
- GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */
- GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */
- GP_STROKEADD_NORMAL, /* point was successfully added */
- GP_STROKEADD_FULL, /* cannot add any more points to buffer */
+ GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */
+ GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */
+ GP_STROKEADD_NORMAL, /* point was successfully added */
+ GP_STROKEADD_FULL, /* cannot add any more points to buffer */
} eGP_StrokeAdd_Result;
/* Runtime flags */
typedef enum eGPencil_PaintFlags {
- GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
- GP_PAINTFLAG_STROKEADDED = (1 << 1),
- GP_PAINTFLAG_SELECTMASK = (1 << 3),
- GP_PAINTFLAG_HARD_ERASER = (1 << 4),
- GP_PAINTFLAG_STROKE_ERASER = (1 << 5),
- GP_PAINTFLAG_REQ_VECTOR = (1 << 6),
+ GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
+ GP_PAINTFLAG_STROKEADDED = (1 << 1),
+ GP_PAINTFLAG_SELECTMASK = (1 << 3),
+ GP_PAINTFLAG_HARD_ERASER = (1 << 4),
+ GP_PAINTFLAG_STROKE_ERASER = (1 << 5),
+ GP_PAINTFLAG_REQ_VECTOR = (1 << 6),
} eGPencil_PaintFlags;
/* Temporary 'Stroke' Operation data
* "p" = op->customdata
*/
typedef struct tGPsdata {
- bContext *C;
-
- /** main database pointer. */
- Main *bmain;
- /** current scene from context. */
- Scene *scene;
- struct Depsgraph *depsgraph;
-
- /** current object. */
- Object *ob;
- /** window where painting originated. */
- wmWindow *win;
- /** area where painting originated. */
- ScrArea *sa;
- /** region where painting originated. */
- ARegion *ar;
- /** needed for GP_STROKE_2DSPACE. */
- View2D *v2d;
- /** for using the camera rect within the 3d view. */
- rctf *subrect;
- rctf subrect_data;
-
- /** settings to pass to gp_points_to_xy(). */
- GP_SpaceConversion gsc;
-
- /** pointer to owner of gp-datablock. */
- PointerRNA ownerPtr;
- /** gp-datablock layer comes from. */
- bGPdata *gpd;
- /** layer we're working on. */
- bGPDlayer *gpl;
- /** frame we're working on. */
- bGPDframe *gpf;
-
- /** projection-mode flags (toolsettings - eGPencil_Placement_Flags) */
- char *align_flag;
-
- /** current status of painting. */
- eGPencil_PaintStatus status;
- /** mode for painting. */
- eGPencil_PaintModes paintmode;
- /** flags that can get set during runtime (eGPencil_PaintFlags) */
- eGPencil_PaintFlags flags;
-
- /** radius of influence for eraser. */
- short radius;
-
- /** current mouse-position. */
- float mval[2];
- /** previous recorded mouse-position. */
- float mvalo[2];
- /** initial recorded mouse-position */
- float mvali[2];
-
- /** current stylus pressure. */
- float pressure;
- /** previous stylus pressure. */
- float opressure;
-
- /* These need to be doubles, as (at least under unix) they are in seconds since epoch,
- * float (and its 7 digits precision) is definitively not enough here!
- * double, with its 15 digits precision, ensures us millisecond precision for a few centuries at least.
- */
- /** Used when converting to path. */
- double inittime;
- /** Used when converting to path. */
- double curtime;
- /** Used when converting to path. */
- double ocurtime;
-
- /** Inverted transformation matrix applying when converting coords from screen-space
- * to region space. */
- float imat[4][4];
- float mat[4][4];
-
- /** custom color - hack for enforcing a particular color for track/mask editing. */
- float custom_color[4];
-
- /** radial cursor data for drawing eraser. */
- void *erasercursor;
-
- /* mat settings are only used for 3D view */
- /** current material */
- Material *material;
- /** current drawing brush */
- Brush *brush;
- /** default eraser brush */
- Brush *eraser;
-
- /** 1: line horizontal, 2: line vertical, other: not defined */
- short straight;
- /** lock drawing to one axis */
- int lock_axis;
- /** the stroke is no fill mode */
- bool disable_fill;
-
- RNG *rng;
-
- /** key used for invoking the operator */
- short keymodifier;
- /** shift modifier flag */
- short shift;
- /** size in pixels for uv calculation */
- float totpixlen;
-
- /* guide */
- /** guide spacing */
- float guide_spacing;
- /** half guide spacing */
- float half_spacing;
- /** origin */
- float origin[2];
-
- ReportList *reports;
+ bContext *C;
+
+ /** main database pointer. */
+ Main *bmain;
+ /** current scene from context. */
+ Scene *scene;
+ struct Depsgraph *depsgraph;
+
+ /** current object. */
+ Object *ob;
+ /** window where painting originated. */
+ wmWindow *win;
+ /** area where painting originated. */
+ ScrArea *sa;
+ /** region where painting originated. */
+ ARegion *ar;
+ /** needed for GP_STROKE_2DSPACE. */
+ View2D *v2d;
+ /** for using the camera rect within the 3d view. */
+ rctf *subrect;
+ rctf subrect_data;
+
+ /** settings to pass to gp_points_to_xy(). */
+ GP_SpaceConversion gsc;
+
+ /** pointer to owner of gp-datablock. */
+ PointerRNA ownerPtr;
+ /** gp-datablock layer comes from. */
+ bGPdata *gpd;
+ /** layer we're working on. */
+ bGPDlayer *gpl;
+ /** frame we're working on. */
+ bGPDframe *gpf;
+
+ /** projection-mode flags (toolsettings - eGPencil_Placement_Flags) */
+ char *align_flag;
+
+ /** current status of painting. */
+ eGPencil_PaintStatus status;
+ /** mode for painting. */
+ eGPencil_PaintModes paintmode;
+ /** flags that can get set during runtime (eGPencil_PaintFlags) */
+ eGPencil_PaintFlags flags;
+
+ /** radius of influence for eraser. */
+ short radius;
+
+ /** current mouse-position. */
+ float mval[2];
+ /** previous recorded mouse-position. */
+ float mvalo[2];
+ /** initial recorded mouse-position */
+ float mvali[2];
+
+ /** current stylus pressure. */
+ float pressure;
+ /** previous stylus pressure. */
+ float opressure;
+
+ /* These need to be doubles, as (at least under unix) they are in seconds since epoch,
+ * float (and its 7 digits precision) is definitively not enough here!
+ * double, with its 15 digits precision, ensures us millisecond precision for a few centuries at least.
+ */
+ /** Used when converting to path. */
+ double inittime;
+ /** Used when converting to path. */
+ double curtime;
+ /** Used when converting to path. */
+ double ocurtime;
+
+ /** Inverted transformation matrix applying when converting coords from screen-space
+ * to region space. */
+ float imat[4][4];
+ float mat[4][4];
+
+ /** custom color - hack for enforcing a particular color for track/mask editing. */
+ float custom_color[4];
+
+ /** radial cursor data for drawing eraser. */
+ void *erasercursor;
+
+ /* mat settings are only used for 3D view */
+ /** current material */
+ Material *material;
+ /** current drawing brush */
+ Brush *brush;
+ /** default eraser brush */
+ Brush *eraser;
+
+ /** 1: line horizontal, 2: line vertical, other: not defined */
+ short straight;
+ /** lock drawing to one axis */
+ int lock_axis;
+ /** the stroke is no fill mode */
+ bool disable_fill;
+
+ RNG *rng;
+
+ /** key used for invoking the operator */
+ short keymodifier;
+ /** shift modifier flag */
+ short shift;
+ /** size in pixels for uv calculation */
+ float totpixlen;
+
+ /* guide */
+ /** guide spacing */
+ float guide_spacing;
+ /** half guide spacing */
+ float half_spacing;
+ /** origin */
+ float origin[2];
+
+ ReportList *reports;
} tGPsdata;
/* ------ */
@@ -241,30 +240,30 @@ typedef struct tGPsdata {
/* Macros for accessing sensitivity thresholds... */
/* minimum number of pixels mouse should move before new point created */
-#define MIN_MANHATTEN_PX (U.gp_manhattendist)
+#define MIN_MANHATTEN_PX (U.gp_manhattendist)
/* minimum length of new segment before new point can be added */
-#define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
+#define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
static void gp_update_cache(bGPdata *gpd)
{
- if (gpd) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- }
+ if (gpd) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
}
static bool gp_stroke_added_check(tGPsdata *p)
{
- return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED);
+ return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED);
}
static void gp_stroke_added_enable(tGPsdata *p)
{
- BLI_assert(p->gpf->strokes.last != NULL);
- p->flags |= GP_PAINTFLAG_STROKEADDED;
+ BLI_assert(p->gpf->strokes.last != NULL);
+ p->flags |= GP_PAINTFLAG_STROKEADDED;
- /* drawing batch cache is dirty now */
- gp_update_cache(p->gpd);
+ /* drawing batch cache is dirty now */
+ gp_update_cache(p->gpd);
}
/* ------ */
@@ -278,49 +277,50 @@ static void gp_session_validatebuffer(tGPsdata *p);
/* check if context is suitable for drawing */
static bool gpencil_draw_poll(bContext *C)
{
- if (ED_operator_regionactive(C)) {
- ScrArea *sa = CTX_wm_area(C);
- /* 3D Viewport */
- if (sa->spacetype != SPACE_VIEW3D) {
- return false;
- }
-
- /* check if Grease Pencil isn't already running */
- if (ED_gpencil_session_active() != 0) {
- CTX_wm_operator_poll_msg_set(C, "Grease Pencil operator is already active");
- return false;
- }
-
- /* only grease pencil object type */
- Object *ob = CTX_data_active_object(C);
- if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
- return false;
- }
-
- bGPdata *gpd = (bGPdata *)ob->data;
- if (!GPENCIL_PAINT_MODE(gpd)) {
- return false;
- }
-
- ToolSettings *ts = CTX_data_scene(C)->toolsettings;
- if (!ts->gp_paint->paint.brush) {
- CTX_wm_operator_poll_msg_set(C, "Grease Pencil has no active paint tool");
- return false;
- }
-
- return true;
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Active region not set");
- return false;
- }
+ if (ED_operator_regionactive(C)) {
+ ScrArea *sa = CTX_wm_area(C);
+ /* 3D Viewport */
+ if (sa->spacetype != SPACE_VIEW3D) {
+ return false;
+ }
+
+ /* check if Grease Pencil isn't already running */
+ if (ED_gpencil_session_active() != 0) {
+ CTX_wm_operator_poll_msg_set(C, "Grease Pencil operator is already active");
+ return false;
+ }
+
+ /* only grease pencil object type */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if (!GPENCIL_PAINT_MODE(gpd)) {
+ return false;
+ }
+
+ ToolSettings *ts = CTX_data_scene(C)->toolsettings;
+ if (!ts->gp_paint->paint.brush) {
+ CTX_wm_operator_poll_msg_set(C, "Grease Pencil has no active paint tool");
+ return false;
+ }
+
+ return true;
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ return false;
+ }
}
/* check if projecting strokes into 3d-geometry in the 3D-View */
static bool gpencil_project_check(tGPsdata *p)
{
- bGPdata *gpd = p->gpd;
- return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)));
+ bGPdata *gpd = p->gpd;
+ return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) &&
+ (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)));
}
/* ******************************************* */
@@ -331,220 +331,219 @@ static bool gpencil_project_check(tGPsdata *p)
/* get the reference point for stroke-point conversions */
static void gp_get_3d_reference(tGPsdata *p, float vec[3])
{
- Object *ob = NULL;
- if (p->ownerPtr.type == &RNA_Object) {
- ob = (Object *)p->ownerPtr.data;
- }
- ED_gp_get_drawing_reference(p->scene, ob, p->gpl, *p->align_flag, vec);
+ Object *ob = NULL;
+ if (p->ownerPtr.type == &RNA_Object) {
+ ob = (Object *)p->ownerPtr.data;
+ }
+ ED_gp_get_drawing_reference(p->scene, ob, p->gpl, *p->align_flag, vec);
}
/* Stroke Editing ---------------------------- */
/* check if the current mouse position is suitable for adding a new point */
static bool gp_stroke_filtermval(tGPsdata *p, const float mval[2], float mvalo[2])
{
- Brush *brush = p->brush;
- int dx = (int)fabsf(mval[0] - mvalo[0]);
- int dy = (int)fabsf(mval[1] - mvalo[1]);
- brush->gpencil_settings->flag &= ~GP_BRUSH_STABILIZE_MOUSE_TEMP;
-
- /* if buffer is empty, just let this go through (i.e. so that dots will work) */
- if (p->gpd->runtime.sbuffer_size == 0) {
- return true;
- }
- /* if lazy mouse, check minimum distance */
- else if (GPENCIL_LAZY_MODE(brush, p->shift)) {
- brush->gpencil_settings->flag |= GP_BRUSH_STABILIZE_MOUSE_TEMP;
- if ((dx * dx + dy * dy) > (brush->smooth_stroke_radius * brush->smooth_stroke_radius)) {
- return true;
- }
- else {
- /* If the mouse is moving within the radius of the last move,
- * don't update the mouse position. This allows sharp turns. */
- copy_v2_v2(p->mval, p->mvalo);
- return false;
- }
- }
- /* check if mouse moved at least certain distance on both axes (best case)
- * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
- */
- else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX))
- return true;
-
- /* check if the distance since the last point is significant enough
- * - prevents points being added too densely
- * - distance here doesn't use sqrt to prevent slowness... we should still be safe from overflows though
- */
- else if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX)
- return true;
-
- /* mouse 'didn't move' */
- else
- return false;
+ Brush *brush = p->brush;
+ int dx = (int)fabsf(mval[0] - mvalo[0]);
+ int dy = (int)fabsf(mval[1] - mvalo[1]);
+ brush->gpencil_settings->flag &= ~GP_BRUSH_STABILIZE_MOUSE_TEMP;
+
+ /* if buffer is empty, just let this go through (i.e. so that dots will work) */
+ if (p->gpd->runtime.sbuffer_size == 0) {
+ return true;
+ }
+ /* if lazy mouse, check minimum distance */
+ else if (GPENCIL_LAZY_MODE(brush, p->shift)) {
+ brush->gpencil_settings->flag |= GP_BRUSH_STABILIZE_MOUSE_TEMP;
+ if ((dx * dx + dy * dy) > (brush->smooth_stroke_radius * brush->smooth_stroke_radius)) {
+ return true;
+ }
+ else {
+ /* If the mouse is moving within the radius of the last move,
+ * don't update the mouse position. This allows sharp turns. */
+ copy_v2_v2(p->mval, p->mvalo);
+ return false;
+ }
+ }
+ /* check if mouse moved at least certain distance on both axes (best case)
+ * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
+ */
+ else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX))
+ return true;
+
+ /* check if the distance since the last point is significant enough
+ * - prevents points being added too densely
+ * - distance here doesn't use sqrt to prevent slowness... we should still be safe from overflows though
+ */
+ else if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX)
+ return true;
+
+ /* mouse 'didn't move' */
+ else
+ return false;
}
/* reproject stroke to plane locked to axis in 3d cursor location */
static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps)
{
- bGPdata *gpd = p->gpd;
- Object *obact = (Object *)p->ownerPtr.data;
-
- float origin[3];
- RegionView3D *rv3d = p->ar->regiondata;
-
- /* verify the stroke mode is CURSOR 3d space mode */
- if ((gpd->runtime.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 drawing origin */
- gp_get_3d_reference(p, origin);
- ED_gp_project_stroke_to_plane(
- p->scene, obact, rv3d, gps,
- origin, p->lock_axis - 1);
+ bGPdata *gpd = p->gpd;
+ Object *obact = (Object *)p->ownerPtr.data;
+
+ float origin[3];
+ RegionView3D *rv3d = p->ar->regiondata;
+
+ /* verify the stroke mode is CURSOR 3d space mode */
+ if ((gpd->runtime.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 drawing origin */
+ gp_get_3d_reference(p, origin);
+ ED_gp_project_stroke_to_plane(p->scene, obact, 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 float mval[2], float out[3], float *depth)
{
- bGPdata *gpd = p->gpd;
-
- /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
- if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
-
- /* add small offset to keep stroke over the surface */
- if ((depth) &&
- (gpd->zdepth_offset > 0.0f) &&
- (*p->align_flag & GP_PROJECT_DEPTH_VIEW))
- {
- *depth *= (1.0f - gpd->zdepth_offset);
- }
-
- int mval_i[2];
- round_v2i_v2fl(mval_i, mval);
-
- if (gpencil_project_check(p) && (ED_view3d_autodist_simple(p->ar, mval_i, out, 0, depth))) {
- /* projecting onto 3D-Geometry
- * - nothing more needs to be done here, since view_autodist_simple() has already done it
- */
-
- /* verify valid zdepth, if it's wrong, the default drawing mode is used
- * and the function doesn't return now */
- if ((depth == NULL) || (*depth <= 1.0f)) {
- return;
- }
- }
-
- float mval_prj[2];
- float rvec[3], dvec[3];
- float mval_f[2];
- float zfac;
-
- /* Current method just converts each point in screen-coordinates to
- * 3D-coordinates using the 3D-cursor as reference. In general, this
- * works OK, but it could of course be improved. */
-
- gp_get_3d_reference(p, rvec);
- zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL);
-
- if (ED_view3d_project_float_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- sub_v2_v2v2(mval_f, mval_prj, mval);
- ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac);
- sub_v3_v3v3(out, rvec, dvec);
- }
- else {
- zero_v3(out);
- }
- }
+ bGPdata *gpd = p->gpd;
+
+ /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
+ if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
+
+ /* add small offset to keep stroke over the surface */
+ if ((depth) && (gpd->zdepth_offset > 0.0f) && (*p->align_flag & GP_PROJECT_DEPTH_VIEW)) {
+ *depth *= (1.0f - gpd->zdepth_offset);
+ }
+
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, mval);
+
+ if (gpencil_project_check(p) && (ED_view3d_autodist_simple(p->ar, mval_i, out, 0, depth))) {
+ /* projecting onto 3D-Geometry
+ * - nothing more needs to be done here, since view_autodist_simple() has already done it
+ */
+
+ /* verify valid zdepth, if it's wrong, the default drawing mode is used
+ * and the function doesn't return now */
+ if ((depth == NULL) || (*depth <= 1.0f)) {
+ return;
+ }
+ }
+
+ float mval_prj[2];
+ float rvec[3], dvec[3];
+ float mval_f[2];
+ float zfac;
+
+ /* Current method just converts each point in screen-coordinates to
+ * 3D-coordinates using the 3D-cursor as reference. In general, this
+ * works OK, but it could of course be improved. */
+
+ gp_get_3d_reference(p, rvec);
+ zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL);
+
+ if (ED_view3d_project_float_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
+ V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval);
+ ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(out, rvec, dvec);
+ }
+ else {
+ zero_v3(out);
+ }
+ }
}
/* apply jitter to stroke */
-static void gp_brush_jitter(
- bGPdata *gpd, Brush *brush, tGPspoint *pt, const float mval[2],
- const float pressure, float r_mval[2], RNG *rng)
+static void gp_brush_jitter(bGPdata *gpd,
+ Brush *brush,
+ tGPspoint *pt,
+ const float mval[2],
+ const float pressure,
+ float r_mval[2],
+ RNG *rng)
{
- float tmp_pressure = pressure;
- if (brush->gpencil_settings->draw_jitter > 0.0f) {
- float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_jitter, 0, pressure);
- tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
- }
- /* exponential value */
- const float exfactor = (brush->gpencil_settings->draw_jitter + 2.0f) * (brush->gpencil_settings->draw_jitter + 2.0f);
- const float fac = BLI_rng_get_float(rng) * exfactor * tmp_pressure;
- /* Jitter is applied perpendicular to the mouse movement vector (2D space) */
- float mvec[2], svec[2];
- /* mouse movement in ints -> floats */
- if (gpd->runtime.sbuffer_size > 1) {
- mvec[0] = (mval[0] - (pt - 1)->x);
- mvec[1] = (mval[1] - (pt - 1)->y);
- normalize_v2(mvec);
- }
- else {
- mvec[0] = 0.0f;
- mvec[1] = 0.0f;
- }
- /* rotate mvec by 90 degrees... */
- svec[0] = -mvec[1];
- svec[1] = mvec[0];
- /* scale the displacement by the random, and apply */
- if (BLI_rng_get_float(rng) > 0.5f) {
- mul_v2_fl(svec, -fac);
- }
- else {
- mul_v2_fl(svec, fac);
- }
-
- r_mval[0] = mval[0] + svec[0];
- r_mval[1] = mval[1] + svec[1];
-
+ float tmp_pressure = pressure;
+ if (brush->gpencil_settings->draw_jitter > 0.0f) {
+ float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_jitter, 0, pressure);
+ tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
+ }
+ /* exponential value */
+ const float exfactor = (brush->gpencil_settings->draw_jitter + 2.0f) *
+ (brush->gpencil_settings->draw_jitter + 2.0f);
+ const float fac = BLI_rng_get_float(rng) * exfactor * tmp_pressure;
+ /* Jitter is applied perpendicular to the mouse movement vector (2D space) */
+ float mvec[2], svec[2];
+ /* mouse movement in ints -> floats */
+ if (gpd->runtime.sbuffer_size > 1) {
+ mvec[0] = (mval[0] - (pt - 1)->x);
+ mvec[1] = (mval[1] - (pt - 1)->y);
+ normalize_v2(mvec);
+ }
+ else {
+ mvec[0] = 0.0f;
+ mvec[1] = 0.0f;
+ }
+ /* rotate mvec by 90 degrees... */
+ svec[0] = -mvec[1];
+ svec[1] = mvec[0];
+ /* scale the displacement by the random, and apply */
+ if (BLI_rng_get_float(rng) > 0.5f) {
+ mul_v2_fl(svec, -fac);
+ }
+ else {
+ mul_v2_fl(svec, fac);
+ }
+
+ r_mval[0] = mval[0] + svec[0];
+ r_mval[1] = mval[1] + svec[1];
}
/* apply pressure change depending of the angle of the stroke to simulate a pen with shape */
static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const float mval[2])
{
- float mvec[2];
- float sen = brush->gpencil_settings->draw_angle_factor; /* sensitivity */
- float fac;
- float mpressure;
-
- /* default angle of brush in radians */
- float angle = brush->gpencil_settings->draw_angle;
- /* angle vector of the brush with full thickness */
- float v0[2] = { cos(angle), sin(angle) };
-
- /* Apply to first point (only if there are 2 points because before no data to do it ) */
- if (gpd->runtime.sbuffer_size == 1) {
- mvec[0] = (mval[0] - (pt - 1)->x);
- mvec[1] = (mval[1] - (pt - 1)->y);
- normalize_v2(mvec);
-
- /* uses > 1.0f to get a smooth transition in first point */
- fac = 1.4f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
- (pt - 1)->pressure = (pt - 1)->pressure - (sen * fac);
-
- CLAMP((pt - 1)->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
- }
-
- /* apply from second point */
- if (gpd->runtime.sbuffer_size >= 1) {
- mvec[0] = (mval[0] - (pt - 1)->x);
- mvec[1] = (mval[1] - (pt - 1)->y);
- normalize_v2(mvec);
-
- fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
- /* interpolate with previous point for smoother transitions */
- mpressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
- pt->pressure = mpressure;
-
- CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
- }
-
+ float mvec[2];
+ float sen = brush->gpencil_settings->draw_angle_factor; /* sensitivity */
+ float fac;
+ float mpressure;
+
+ /* default angle of brush in radians */
+ float angle = brush->gpencil_settings->draw_angle;
+ /* angle vector of the brush with full thickness */
+ float v0[2] = {cos(angle), sin(angle)};
+
+ /* Apply to first point (only if there are 2 points because before no data to do it ) */
+ if (gpd->runtime.sbuffer_size == 1) {
+ mvec[0] = (mval[0] - (pt - 1)->x);
+ mvec[1] = (mval[1] - (pt - 1)->y);
+ normalize_v2(mvec);
+
+ /* uses > 1.0f to get a smooth transition in first point */
+ fac = 1.4f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
+ (pt - 1)->pressure = (pt - 1)->pressure - (sen * fac);
+
+ CLAMP((pt - 1)->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
+ }
+
+ /* apply from second point */
+ if (gpd->runtime.sbuffer_size >= 1) {
+ mvec[0] = (mval[0] - (pt - 1)->x);
+ mvec[1] = (mval[1] - (pt - 1)->y);
+ normalize_v2(mvec);
+
+ fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
+ /* interpolate with previous point for smoother transitions */
+ mpressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
+ pt->pressure = mpressure;
+
+ CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
+ }
}
/* Apply smooth to buffer while drawing
@@ -558,708 +557,712 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa
*/
static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
{
- bGPdata *gpd = p->gpd;
- short num_points = gpd->runtime.sbuffer_size;
-
- /* Do nothing if not enough points to smooth out */
- if ((num_points < 3) || (idx < 3) || (inf == 0.0f)) {
- return;
- }
-
- tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
- float steps = 4.0f;
- if (idx < 4) {
- steps--;
- }
-
- tGPspoint *pta = idx >= 4 ? &points[idx - 4] : NULL;
- tGPspoint *ptb = idx >= 3 ? &points[idx - 3] : NULL;
- tGPspoint *ptc = idx >= 2 ? &points[idx - 2] : NULL;
- tGPspoint *ptd = &points[idx - 1];
-
- float sco[2] = { 0.0f };
- float a[2], b[2], c[2], d[2];
- const float average_fac = 1.0f / steps;
-
- /* Compute smoothed coordinate by taking the ones nearby */
- if (pta) {
- copy_v2_v2(a, &pta->x);
- madd_v2_v2fl(sco, a, average_fac);
- }
- if (ptb) {
- copy_v2_v2(b, &ptb->x);
- madd_v2_v2fl(sco, b, average_fac);
- }
- if (ptc) {
- copy_v2_v2(c, &ptc->x);
- madd_v2_v2fl(sco, c, average_fac);
- }
- if (ptd) {
- copy_v2_v2(d, &ptd->x);
- madd_v2_v2fl(sco, d, average_fac);
- }
-
- /* Based on influence factor, blend between original and optimal smoothed coordinate */
- interp_v2_v2v2(c, c, sco, inf);
- copy_v2_v2(&ptc->x, c);
+ bGPdata *gpd = p->gpd;
+ short num_points = gpd->runtime.sbuffer_size;
+
+ /* Do nothing if not enough points to smooth out */
+ if ((num_points < 3) || (idx < 3) || (inf == 0.0f)) {
+ return;
+ }
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ float steps = 4.0f;
+ if (idx < 4) {
+ steps--;
+ }
+
+ tGPspoint *pta = idx >= 4 ? &points[idx - 4] : NULL;
+ tGPspoint *ptb = idx >= 3 ? &points[idx - 3] : NULL;
+ tGPspoint *ptc = idx >= 2 ? &points[idx - 2] : NULL;
+ tGPspoint *ptd = &points[idx - 1];
+
+ float sco[2] = {0.0f};
+ float a[2], b[2], c[2], d[2];
+ const float average_fac = 1.0f / steps;
+
+ /* Compute smoothed coordinate by taking the ones nearby */
+ if (pta) {
+ copy_v2_v2(a, &pta->x);
+ madd_v2_v2fl(sco, a, average_fac);
+ }
+ if (ptb) {
+ copy_v2_v2(b, &ptb->x);
+ madd_v2_v2fl(sco, b, average_fac);
+ }
+ if (ptc) {
+ copy_v2_v2(c, &ptc->x);
+ madd_v2_v2fl(sco, c, average_fac);
+ }
+ if (ptd) {
+ copy_v2_v2(d, &ptd->x);
+ madd_v2_v2fl(sco, d, average_fac);
+ }
+
+ /* Based on influence factor, blend between original and optimal smoothed coordinate */
+ interp_v2_v2v2(c, c, sco, inf);
+ copy_v2_v2(&ptc->x, c);
}
/* add current stroke-point to buffer (returns whether point was successfully added) */
-static short gp_stroke_addpoint(
- tGPsdata *p, const float mval[2], float pressure, double curtime)
+static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
{
- bGPdata *gpd = p->gpd;
- Brush *brush = p->brush;
- tGPspoint *pt;
- ToolSettings *ts = p->scene->toolsettings;
- Object *obact = (Object *)p->ownerPtr.data;
- Depsgraph *depsgraph = p->depsgraph;
- RegionView3D *rv3d = p->ar->regiondata;
- View3D *v3d = p->sa->spacedata.first;
- MaterialGPencilStyle *gp_style = p->material->gp_style;
- const int def_nr = obact->actdef - 1;
- const bool have_weight = (bool)BLI_findlink(&obact->defbase, def_nr);
-
- /* check painting mode */
- if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
- /* straight lines only - i.e. only store start and end point in buffer */
- if (gpd->runtime.sbuffer_size == 0) {
- /* first point in buffer (start point) */
- pt = (tGPspoint *)(gpd->runtime.sbuffer);
-
- /* store settings */
- copy_v2_v2(&pt->x, mval);
- /* T44932 - Pressure vals are unreliable, so ignore for now */
- pt->pressure = 1.0f;
- pt->strength = 1.0f;
- pt->time = (float)(curtime - p->inittime);
-
- /* increment buffer size */
- gpd->runtime.sbuffer_size++;
- }
- else {
- /* just reset the endpoint to the latest value
- * - assume that pointers for this are always valid...
- */
- pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
-
- /* store settings */
- copy_v2_v2(&pt->x, mval);
- /* T44932 - Pressure vals are unreliable, so ignore for now */
- pt->pressure = 1.0f;
- pt->strength = 1.0f;
- pt->time = (float)(curtime - p->inittime);
-
- /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
- gpd->runtime.sbuffer_size = 2;
- }
-
- /* can keep carrying on this way :) */
- return GP_STROKEADD_NORMAL;
- }
- else if (p->paintmode == GP_PAINTMODE_DRAW) { /* normal drawing */
- /* check if still room in buffer */
- if (gpd->runtime.sbuffer_size >= GP_STROKE_BUFFER_MAX)
- return GP_STROKEADD_OVERFLOW;
-
- /* get pointer to destination point */
- pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size);
-
- /* store settings */
- /* pressure */
- if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
- float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_sensitivity, 0, pressure);
- pt->pressure = curvef * brush->gpencil_settings->draw_sensitivity;
- }
- else {
- pt->pressure = 1.0f;
- }
-
- /* Apply jitter to position */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_jitter > 0.0f))
- {
- float r_mval[2];
- const float jitpress = (brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) ? pressure : 1.0f;
- gp_brush_jitter(gpd, brush, pt, mval, jitpress, r_mval, p->rng);
- copy_v2_v2(&pt->x, r_mval);
- }
- else {
- copy_v2_v2(&pt->x, mval);
- }
- /* apply randomness to pressure */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_random_press > 0.0f))
- {
- float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_sensitivity, 0, pressure);
- float tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
- if (BLI_rng_get_float(p->rng) > 0.5f) {
- pt->pressure -= tmp_pressure * brush->gpencil_settings->draw_random_press * BLI_rng_get_float(p->rng);
- }
- else {
- pt->pressure += tmp_pressure * brush->gpencil_settings->draw_random_press * BLI_rng_get_float(p->rng);
- }
- CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f);
- }
-
- /* apply randomness to uv texture rotation */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && (brush->gpencil_settings->uv_random > 0.0f)) {
- if (BLI_rng_get_float(p->rng) > 0.5f) {
- pt->uv_rot = (BLI_rng_get_float(p->rng) * M_PI * -1) * brush->gpencil_settings->uv_random;
- }
- else {
- pt->uv_rot = (BLI_rng_get_float(p->rng) * M_PI) * brush->gpencil_settings->uv_random;
- }
- CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
- }
- else {
- pt->uv_rot = 0.0f;
- }
-
- /* apply angle of stroke to brush size */
- if (brush->gpencil_settings->draw_angle_factor != 0.0f) {
- gp_brush_angle(gpd, brush, pt, mval);
- }
-
- /* color strength */
- if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
- float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_strength, 0, pressure);
- float tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
-
- pt->strength = tmp_pressure * brush->gpencil_settings->draw_strength;
- }
- else {
- pt->strength = brush->gpencil_settings->draw_strength;
- }
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
-
- /* apply randomness to color strength */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_random_strength > 0.0f))
- {
- if (BLI_rng_get_float(p->rng) > 0.5f) {
- pt->strength -= pt->strength * brush->gpencil_settings->draw_random_strength * BLI_rng_get_float(p->rng);
- }
- else {
- pt->strength += pt->strength * brush->gpencil_settings->draw_random_strength * BLI_rng_get_float(p->rng);
- }
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- }
-
- /* point time */
- pt->time = (float)(curtime - p->inittime);
-
- /* point uv (only 3d view) */
- if ((p->sa->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_size > 0)) {
- float pixsize = gp_style->texture_pixsize / 1000000.0f;
- tGPspoint *ptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1;
- bGPDspoint spt, spt2;
-
- /* get origin to reproject point */
- float origin[3];
- gp_get_3d_reference(p, origin);
- /* reproject current */
- ED_gpencil_tpoint_to_point(p->ar, origin, pt, &spt);
- ED_gp_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt);
-
- /* reproject previous */
- ED_gpencil_tpoint_to_point(p->ar, origin, ptb, &spt2);
- ED_gp_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt2);
- p->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize;
- pt->uv_fac = p->totpixlen;
- if ((gp_style) && (gp_style->sima)) {
- pt->uv_fac /= gp_style->sima->gen_x;
- }
- }
- else {
- p->totpixlen = 0.0f;
- pt->uv_fac = 0.0f;
- }
-
- /* increment counters */
- gpd->runtime.sbuffer_size++;
-
- /* smooth while drawing previous points with a reduction factor for previous */
- if (brush->gpencil_settings->active_smooth > 0.0f) {
- for (int s = 0; s < 3; s++) {
- gp_smooth_buffer(p, brush->gpencil_settings->active_smooth * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_size - s);
- }
- }
-
- /* check if another operation can still occur */
- if (gpd->runtime.sbuffer_size == GP_STROKE_BUFFER_MAX)
- return GP_STROKEADD_FULL;
- else
- return GP_STROKEADD_NORMAL;
- }
- else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
-
- /* enable special flag for drawing engine */
- gpd->flag |= GP_DATA_STROKE_POLYGON;
-
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- /* get pointer to destination point */
- pt = (tGPspoint *)(gpd->runtime.sbuffer);
-
- /* store settings */
- copy_v2_v2(&pt->x, mval);
- /* T44932 - Pressure vals are unreliable, so ignore for now */
- pt->pressure = 1.0f;
- pt->strength = 1.0f;
- pt->time = (float)(curtime - p->inittime);
-
- /* if there's stroke for this poly line session add (or replace last) point
- * to stroke. This allows to draw lines more interactively (see new segment
- * during mouse slide, e.g.)
- */
- if (gp_stroke_added_check(p)) {
- bGPDstroke *gps = p->gpf->strokes.last;
- bGPDspoint *pts;
- MDeformVert *dvert = NULL;
-
- /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
- if (gpd->runtime.sbuffer_size == 0) {
- gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
- if (gps->dvert != NULL) {
- gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
- }
- gps->totpoints++;
- }
-
- pts = &gps->points[gps->totpoints - 1];
- if (gps->dvert != NULL) {
- dvert = &gps->dvert[gps->totpoints - 1];
- }
- /* special case for poly lines: normally,
- * depth is needed only when creating new stroke from buffer,
- * but poly lines are converting to stroke instantly,
- * so initialize depth buffer before converting coordinates
- */
- if (gpencil_project_check(p)) {
- view3d_region_operator_needs_opengl(p->win, p->ar);
- ED_view3d_autodist_init(
- p->depsgraph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
- }
-
- /* convert screen-coordinates to appropriate coordinates (and store them) */
- gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
- /* reproject to plane (only in 3d space) */
- gp_reproject_toplane(p, gps);
- /* if parented change position relative to parent object */
- gp_apply_parent_point(depsgraph, obact, gpd, gpl, pts);
- /* copy pressure and time */
- pts->pressure = pt->pressure;
- pts->strength = pt->strength;
- pts->time = pt->time;
- pts->uv_fac = pt->uv_fac;
- pts->uv_rot = pt->uv_rot;
-
- if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
- BKE_gpencil_dvert_ensure(gps);
- MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
- if (dw) {
- dw->weight = ts->vgroup_weight;
- }
- }
- else {
- if (dvert != NULL) {
- dvert->totweight = 0;
- dvert->dw = NULL;
- }
- }
-
- /* force fill recalc */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- /* drawing batch cache is dirty now */
- gp_update_cache(p->gpd);
- }
-
- /* increment counters */
- if (gpd->runtime.sbuffer_size == 0)
- gpd->runtime.sbuffer_size++;
-
- return GP_STROKEADD_NORMAL;
- }
-
- /* return invalid state for now... */
- return GP_STROKEADD_INVALID;
+ bGPdata *gpd = p->gpd;
+ Brush *brush = p->brush;
+ tGPspoint *pt;
+ ToolSettings *ts = p->scene->toolsettings;
+ Object *obact = (Object *)p->ownerPtr.data;
+ Depsgraph *depsgraph = p->depsgraph;
+ RegionView3D *rv3d = p->ar->regiondata;
+ View3D *v3d = p->sa->spacedata.first;
+ MaterialGPencilStyle *gp_style = p->material->gp_style;
+ const int def_nr = obact->actdef - 1;
+ const bool have_weight = (bool)BLI_findlink(&obact->defbase, def_nr);
+
+ /* check painting mode */
+ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
+ /* straight lines only - i.e. only store start and end point in buffer */
+ if (gpd->runtime.sbuffer_size == 0) {
+ /* first point in buffer (start point) */
+ pt = (tGPspoint *)(gpd->runtime.sbuffer);
+
+ /* store settings */
+ copy_v2_v2(&pt->x, mval);
+ /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ pt->time = (float)(curtime - p->inittime);
+
+ /* increment buffer size */
+ gpd->runtime.sbuffer_size++;
+ }
+ else {
+ /* just reset the endpoint to the latest value
+ * - assume that pointers for this are always valid...
+ */
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
+
+ /* store settings */
+ copy_v2_v2(&pt->x, mval);
+ /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ pt->time = (float)(curtime - p->inittime);
+
+ /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
+ gpd->runtime.sbuffer_size = 2;
+ }
+
+ /* can keep carrying on this way :) */
+ return GP_STROKEADD_NORMAL;
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW) { /* normal drawing */
+ /* check if still room in buffer */
+ if (gpd->runtime.sbuffer_size >= GP_STROKE_BUFFER_MAX)
+ return GP_STROKEADD_OVERFLOW;
+
+ /* get pointer to destination point */
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size);
+
+ /* store settings */
+ /* pressure */
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
+ float curvef = curvemapping_evaluateF(
+ brush->gpencil_settings->curve_sensitivity, 0, pressure);
+ pt->pressure = curvef * brush->gpencil_settings->draw_sensitivity;
+ }
+ else {
+ pt->pressure = 1.0f;
+ }
+
+ /* Apply jitter to position */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_jitter > 0.0f)) {
+ float r_mval[2];
+ const float jitpress = (brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) ?
+ pressure :
+ 1.0f;
+ gp_brush_jitter(gpd, brush, pt, mval, jitpress, r_mval, p->rng);
+ copy_v2_v2(&pt->x, r_mval);
+ }
+ else {
+ copy_v2_v2(&pt->x, mval);
+ }
+ /* apply randomness to pressure */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_random_press > 0.0f)) {
+ float curvef = curvemapping_evaluateF(
+ brush->gpencil_settings->curve_sensitivity, 0, pressure);
+ float tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
+ if (BLI_rng_get_float(p->rng) > 0.5f) {
+ pt->pressure -= tmp_pressure * brush->gpencil_settings->draw_random_press *
+ BLI_rng_get_float(p->rng);
+ }
+ else {
+ pt->pressure += tmp_pressure * brush->gpencil_settings->draw_random_press *
+ BLI_rng_get_float(p->rng);
+ }
+ CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+
+ /* apply randomness to uv texture rotation */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->uv_random > 0.0f)) {
+ if (BLI_rng_get_float(p->rng) > 0.5f) {
+ pt->uv_rot = (BLI_rng_get_float(p->rng) * M_PI * -1) * brush->gpencil_settings->uv_random;
+ }
+ else {
+ pt->uv_rot = (BLI_rng_get_float(p->rng) * M_PI) * brush->gpencil_settings->uv_random;
+ }
+ CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
+ }
+ else {
+ pt->uv_rot = 0.0f;
+ }
+
+ /* apply angle of stroke to brush size */
+ if (brush->gpencil_settings->draw_angle_factor != 0.0f) {
+ gp_brush_angle(gpd, brush, pt, mval);
+ }
+
+ /* color strength */
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
+ float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_strength, 0, pressure);
+ float tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
+
+ pt->strength = tmp_pressure * brush->gpencil_settings->draw_strength;
+ }
+ else {
+ pt->strength = brush->gpencil_settings->draw_strength;
+ }
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+
+ /* apply randomness to color strength */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_random_strength > 0.0f)) {
+ if (BLI_rng_get_float(p->rng) > 0.5f) {
+ pt->strength -= pt->strength * brush->gpencil_settings->draw_random_strength *
+ BLI_rng_get_float(p->rng);
+ }
+ else {
+ pt->strength += pt->strength * brush->gpencil_settings->draw_random_strength *
+ BLI_rng_get_float(p->rng);
+ }
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+
+ /* point time */
+ pt->time = (float)(curtime - p->inittime);
+
+ /* point uv (only 3d view) */
+ if ((p->sa->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_size > 0)) {
+ float pixsize = gp_style->texture_pixsize / 1000000.0f;
+ tGPspoint *ptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1;
+ bGPDspoint spt, spt2;
+
+ /* get origin to reproject point */
+ float origin[3];
+ gp_get_3d_reference(p, origin);
+ /* reproject current */
+ ED_gpencil_tpoint_to_point(p->ar, origin, pt, &spt);
+ ED_gp_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt);
+
+ /* reproject previous */
+ ED_gpencil_tpoint_to_point(p->ar, origin, ptb, &spt2);
+ ED_gp_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt2);
+ p->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize;
+ pt->uv_fac = p->totpixlen;
+ if ((gp_style) && (gp_style->sima)) {
+ pt->uv_fac /= gp_style->sima->gen_x;
+ }
+ }
+ else {
+ p->totpixlen = 0.0f;
+ pt->uv_fac = 0.0f;
+ }
+
+ /* increment counters */
+ gpd->runtime.sbuffer_size++;
+
+ /* smooth while drawing previous points with a reduction factor for previous */
+ if (brush->gpencil_settings->active_smooth > 0.0f) {
+ for (int s = 0; s < 3; s++) {
+ gp_smooth_buffer(p,
+ brush->gpencil_settings->active_smooth * ((3.0f - s) / 3.0f),
+ gpd->runtime.sbuffer_size - s);
+ }
+ }
+
+ /* check if another operation can still occur */
+ if (gpd->runtime.sbuffer_size == GP_STROKE_BUFFER_MAX)
+ return GP_STROKEADD_FULL;
+ else
+ return GP_STROKEADD_NORMAL;
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+
+ /* enable special flag for drawing engine */
+ gpd->flag |= GP_DATA_STROKE_POLYGON;
+
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ /* get pointer to destination point */
+ pt = (tGPspoint *)(gpd->runtime.sbuffer);
+
+ /* store settings */
+ copy_v2_v2(&pt->x, mval);
+ /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ pt->time = (float)(curtime - p->inittime);
+
+ /* if there's stroke for this poly line session add (or replace last) point
+ * to stroke. This allows to draw lines more interactively (see new segment
+ * during mouse slide, e.g.)
+ */
+ if (gp_stroke_added_check(p)) {
+ bGPDstroke *gps = p->gpf->strokes.last;
+ bGPDspoint *pts;
+ MDeformVert *dvert = NULL;
+
+ /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
+ if (gpd->runtime.sbuffer_size == 0) {
+ gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
+ }
+ gps->totpoints++;
+ }
+
+ pts = &gps->points[gps->totpoints - 1];
+ if (gps->dvert != NULL) {
+ dvert = &gps->dvert[gps->totpoints - 1];
+ }
+ /* special case for poly lines: normally,
+ * depth is needed only when creating new stroke from buffer,
+ * but poly lines are converting to stroke instantly,
+ * so initialize depth buffer before converting coordinates
+ */
+ if (gpencil_project_check(p)) {
+ view3d_region_operator_needs_opengl(p->win, p->ar);
+ ED_view3d_autodist_init(
+ p->depsgraph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
+ }
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
+ /* reproject to plane (only in 3d space) */
+ gp_reproject_toplane(p, gps);
+ /* if parented change position relative to parent object */
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pts);
+ /* copy pressure and time */
+ pts->pressure = pt->pressure;
+ pts->strength = pt->strength;
+ pts->time = pt->time;
+ pts->uv_fac = pt->uv_fac;
+ pts->uv_rot = pt->uv_rot;
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+ }
+ else {
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ }
+ }
+
+ /* force fill recalc */
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ /* drawing batch cache is dirty now */
+ gp_update_cache(p->gpd);
+ }
+
+ /* increment counters */
+ if (gpd->runtime.sbuffer_size == 0)
+ gpd->runtime.sbuffer_size++;
+
+ return GP_STROKEADD_NORMAL;
+ }
+
+ /* return invalid state for now... */
+ return GP_STROKEADD_INVALID;
}
/* make a new stroke from the buffer data */
static void gp_stroke_newfrombuffer(tGPsdata *p)
{
- bGPdata *gpd = p->gpd;
- bGPDlayer *gpl = p->gpl;
- bGPDstroke *gps;
- bGPDspoint *pt;
- tGPspoint *ptc;
- MDeformVert *dvert = NULL;
- Brush *brush = p->brush;
- ToolSettings *ts = p->scene->toolsettings;
- Depsgraph *depsgraph = p->depsgraph;
- Object *obact = (Object *)p->ownerPtr.data;
- RegionView3D *rv3d = p->ar->regiondata;
- const int def_nr = obact->actdef - 1;
- const bool have_weight = (bool)BLI_findlink(&obact->defbase, def_nr);
- const char *align_flag = &ts->gpencil_v3d_align;
- const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
- const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
- (rv3d->persp == RV3D_CAMOB) && (!is_depth);
- int i, totelem;
-
- /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
- int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
-
- /* get total number of points to allocate space for
- * - drawing straight-lines only requires the endpoints
- */
- if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)
- totelem = (gpd->runtime.sbuffer_size >= 2) ? 2 : gpd->runtime.sbuffer_size;
- else
- totelem = gpd->runtime.sbuffer_size;
-
- /* exit with error if no valid points from this stroke */
- if (totelem == 0) {
- if (G.debug & G_DEBUG)
- printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", gpd->runtime.sbuffer_size);
- return;
- }
-
- /* special case for poly line -- for already added stroke during session
- * coordinates are getting added to stroke immediately to allow more
- * interactive behavior
- */
- if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
- /* be sure to hide any lazy cursor */
- ED_gpencil_toggle_brush_cursor(p->C, true, NULL);
-
- if (gp_stroke_added_check(p)) {
- return;
- }
- }
-
- /* allocate memory for a new stroke */
- gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
-
- /* copy appropriate settings for stroke */
- gps->totpoints = totelem;
- gps->thickness = brush->size;
- gps->gradient_f = brush->gpencil_settings->gradient_f;
- copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
- gps->flag = gpd->runtime.sbuffer_sflag;
- gps->inittime = p->inittime;
-
- /* enable recalculation flag by default (only used if hq fill) */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* allocate enough memory for a continuous array for storage points */
- const int subdivide = brush->gpencil_settings->draw_subdivide;
-
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
-
- /* initialize triangle memory to dummy data */
- gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
- /* drawing batch cache is dirty now */
- gp_update_cache(p->gpd);
- /* set pointer to first non-initialized point */
- pt = gps->points + (gps->totpoints - totelem);
- if (gps->dvert != NULL) {
- dvert = gps->dvert + (gps->totpoints - totelem);
- }
-
- /* copy points from the buffer to the stroke */
- if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
- /* straight lines only -> only endpoints */
- {
- /* first point */
- ptc = gpd->runtime.sbuffer;
-
- /* convert screen-coordinates to appropriate coordinates (and store them) */
- gp_stroke_convertcoords(p, &ptc->x, &pt->x, 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;
- pt++;
-
- if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
- BKE_gpencil_dvert_ensure(gps);
- MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
- if (dw) {
- dw->weight = ts->vgroup_weight;
- }
- dvert++;
- }
- else {
- if (dvert != NULL) {
- dvert->totweight = 0;
- dvert->dw = NULL;
- dvert++;
- }
- }
- }
-
- if (totelem == 2) {
- /* last point if applicable */
- ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_size - 1);
-
- /* convert screen-coordinates to appropriate coordinates (and store them) */
- gp_stroke_convertcoords(p, &ptc->x, &pt->x, 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;
-
- if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
- BKE_gpencil_dvert_ensure(gps);
- MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
- if (dw) {
- dw->weight = ts->vgroup_weight;
- }
- }
- else {
- if (dvert != NULL) {
- dvert->totweight = 0;
- dvert->dw = NULL;
- }
- }
- }
-
- /* reproject to plane (only in 3d space) */
- gp_reproject_toplane(p, gps);
- pt = gps->points;
- for (i = 0; i < gps->totpoints; i++, pt++) {
- /* if parented change position relative to parent object */
- gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
- }
-
- /* if camera view, reproject flat to view to avoid perspective effect */
- if (is_camera) {
- ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps);
- }
- }
- else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
- /* first point */
- ptc = gpd->runtime.sbuffer;
-
- /* convert screen-coordinates to appropriate coordinates (and store them) */
- gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
- /* reproject to plane (only in 3d space) */
- gp_reproject_toplane(p, gps);
- /* if parented change position relative to parent object */
- gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
- /* if camera view, reproject flat to view to avoid perspective effect */
- if (is_camera) {
- ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps);
- }
- /* copy pressure and time */
- pt->pressure = ptc->pressure;
- pt->strength = ptc->strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- pt->time = ptc->time;
-
- if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
- BKE_gpencil_dvert_ensure(gps);
- MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
- if (dw) {
- dw->weight = ts->vgroup_weight;
- }
- }
- else {
- if (dvert != NULL) {
- dvert->totweight = 0;
- dvert->dw = NULL;
- }
- }
-
- }
- else {
- float *depth_arr = NULL;
-
- /* get an array of depths, far depths are blended */
- if (gpencil_project_check(p)) {
- int mval_i[2], mval_prev[2] = { 0 };
- int interp_depth = 0;
- int found_depth = 0;
-
- depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_size, "depth_points");
-
- for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size; i++, ptc++, pt++) {
-
- round_v2i_v2fl(mval_i, &ptc->x);
-
- if ((ED_view3d_autodist_depth(p->ar, mval_i, depth_margin, depth_arr + i) == 0) &&
- (i && (ED_view3d_autodist_depth_seg(p->ar, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
- {
- interp_depth = true;
- }
- else {
- found_depth = true;
- }
-
- copy_v2_v2_int(mval_prev, mval_i);
- }
-
- if (found_depth == false) {
- /* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
- for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--)
- depth_arr[i] = 0.9999f;
- }
- else {
- if ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) ||
- (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_FIRST))
- {
- int first_valid = 0;
- int last_valid = 0;
-
- /* find first valid contact point */
- for (i = 0; i < gpd->runtime.sbuffer_size; i++) {
- if (depth_arr[i] != FLT_MAX)
- break;
- }
- first_valid = i;
-
- /* find last valid contact point */
- if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_FIRST) {
- last_valid = first_valid;
- }
- else {
- for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--) {
- if (depth_arr[i] != FLT_MAX)
- break;
- }
- last_valid = i;
- }
- /* invalidate any other point, to interpolate between
- * first and last contact in an imaginary line between them */
- for (i = 0; i < gpd->runtime.sbuffer_size; i++) {
- if ((i != first_valid) && (i != last_valid)) {
- depth_arr[i] = FLT_MAX;
- }
- }
- interp_depth = true;
- }
-
- if (interp_depth) {
- interp_sparse_array(depth_arr, gpd->runtime.sbuffer_size, FLT_MAX);
- }
- }
- }
-
- pt = gps->points;
- dvert = gps->dvert;
-
- /* convert all points (normal behavior) */
- for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.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;
- pt->uv_fac = ptc->uv_fac;
- pt->uv_rot = ptc->uv_rot;
-
- if (dvert != NULL) {
- dvert->totweight = 0;
- dvert->dw = NULL;
- dvert++;
- }
- }
-
- /* subdivide and smooth the stroke */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && (subdivide > 0)) {
- gp_subdivide_stroke(gps, subdivide);
- }
- /* apply randomness to stroke */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_random_sub > 0.0f))
- {
- gp_randomize_stroke(gps, brush, p->rng);
- }
-
- /* 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->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
- (brush->gpencil_settings->draw_smoothfac > 0.0f))
- {
- float reduce = 0.0f;
- for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) {
- for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_smooth_stroke(gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
- BKE_gpencil_smooth_stroke_strength(gps, i, brush->gpencil_settings->draw_smoothfac);
- }
- reduce += 0.25f; // reduce the factor
- }
- }
- /* smooth thickness */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
- (brush->gpencil_settings->thick_smoothfac > 0.0f))
- {
- for (int r = 0; r < brush->gpencil_settings->thick_smoothlvl * 2; r++) {
- for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_smooth_stroke_thickness(gps, i, brush->gpencil_settings->thick_smoothfac);
- }
- }
- }
-
- /* reproject to plane (only in 3d space) */
- gp_reproject_toplane(p, gps);
- /* change position relative to parent object */
- gp_apply_parent(depsgraph, obact, gpd, gpl, gps);
- /* if camera view, reproject flat to view to avoid perspective effect */
- if (is_camera) {
- ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps);
- }
-
- if (depth_arr)
- MEM_freeN(depth_arr);
- }
-
- /* Save material index */
- gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(p->ob, p->brush);
-
- /* calculate UVs along the stroke */
- ED_gpencil_calc_stroke_uv(obact, gps);
-
- /* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke is added on listbase head
- * because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist
- * when drawing the background
- */
- if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode != GP_PAINTMODE_DRAW_POLY)) {
- BLI_addhead(&p->gpf->strokes, gps);
- }
- else {
- BLI_addtail(&p->gpf->strokes, gps);
- }
- /* add weights */
- if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
- BKE_gpencil_dvert_ensure(gps);
- for (i = 0; i < gps->totpoints; i++) {
- MDeformVert *ve = &gps->dvert[i];
- MDeformWeight *dw = defvert_verify_index(ve, def_nr);
- if (dw) {
- dw->weight = ts->vgroup_weight;
- }
- }
- }
-
- /* post process stroke */
- if ((p->brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
- p->brush->gpencil_settings->flag & GP_BRUSH_TRIM_STROKE)
- {
- BKE_gpencil_trim_stroke(gps);
- }
-
- gp_stroke_added_enable(p);
+ bGPdata *gpd = p->gpd;
+ bGPDlayer *gpl = p->gpl;
+ bGPDstroke *gps;
+ bGPDspoint *pt;
+ tGPspoint *ptc;
+ MDeformVert *dvert = NULL;
+ Brush *brush = p->brush;
+ ToolSettings *ts = p->scene->toolsettings;
+ Depsgraph *depsgraph = p->depsgraph;
+ Object *obact = (Object *)p->ownerPtr.data;
+ RegionView3D *rv3d = p->ar->regiondata;
+ const int def_nr = obact->actdef - 1;
+ const bool have_weight = (bool)BLI_findlink(&obact->defbase, def_nr);
+ const char *align_flag = &ts->gpencil_v3d_align;
+ const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
+ const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) && (rv3d->persp == RV3D_CAMOB) &&
+ (!is_depth);
+ int i, totelem;
+
+ /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
+ int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
+
+ /* get total number of points to allocate space for
+ * - drawing straight-lines only requires the endpoints
+ */
+ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)
+ totelem = (gpd->runtime.sbuffer_size >= 2) ? 2 : gpd->runtime.sbuffer_size;
+ else
+ totelem = gpd->runtime.sbuffer_size;
+
+ /* exit with error if no valid points from this stroke */
+ if (totelem == 0) {
+ if (G.debug & G_DEBUG)
+ printf("Error: No valid points in stroke buffer to convert (tot=%d)\n",
+ gpd->runtime.sbuffer_size);
+ return;
+ }
+
+ /* special case for poly line -- for already added stroke during session
+ * coordinates are getting added to stroke immediately to allow more
+ * interactive behavior
+ */
+ if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+ /* be sure to hide any lazy cursor */
+ ED_gpencil_toggle_brush_cursor(p->C, true, NULL);
+
+ if (gp_stroke_added_check(p)) {
+ return;
+ }
+ }
+
+ /* allocate memory for a new stroke */
+ gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
+
+ /* copy appropriate settings for stroke */
+ gps->totpoints = totelem;
+ gps->thickness = brush->size;
+ gps->gradient_f = brush->gpencil_settings->gradient_f;
+ copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
+ gps->flag = gpd->runtime.sbuffer_sflag;
+ gps->inittime = p->inittime;
+
+ /* enable recalculation flag by default (only used if hq fill) */
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* allocate enough memory for a continuous array for storage points */
+ const int subdivide = brush->gpencil_settings->draw_subdivide;
+
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+
+ /* initialize triangle memory to dummy data */
+ gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
+ /* drawing batch cache is dirty now */
+ gp_update_cache(p->gpd);
+ /* set pointer to first non-initialized point */
+ pt = gps->points + (gps->totpoints - totelem);
+ if (gps->dvert != NULL) {
+ dvert = gps->dvert + (gps->totpoints - totelem);
+ }
+
+ /* copy points from the buffer to the stroke */
+ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
+ /* straight lines only -> only endpoints */
+ {
+ /* first point */
+ ptc = gpd->runtime.sbuffer;
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, 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;
+ pt++;
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+ dvert++;
+ }
+ else {
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ dvert++;
+ }
+ }
+ }
+
+ if (totelem == 2) {
+ /* last point if applicable */
+ ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_size - 1);
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, 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;
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+ }
+ else {
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ }
+ }
+ }
+
+ /* reproject to plane (only in 3d space) */
+ gp_reproject_toplane(p, gps);
+ pt = gps->points;
+ for (i = 0; i < gps->totpoints; i++, pt++) {
+ /* if parented change position relative to parent object */
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
+ }
+
+ /* if camera view, reproject flat to view to avoid perspective effect */
+ if (is_camera) {
+ ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps);
+ }
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+ /* first point */
+ ptc = gpd->runtime.sbuffer;
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ /* reproject to plane (only in 3d space) */
+ gp_reproject_toplane(p, gps);
+ /* if parented change position relative to parent object */
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
+ /* if camera view, reproject flat to view to avoid perspective effect */
+ if (is_camera) {
+ ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps);
+ }
+ /* copy pressure and time */
+ pt->pressure = ptc->pressure;
+ pt->strength = ptc->strength;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt->time = ptc->time;
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+ }
+ else {
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ }
+ }
+ }
+ else {
+ float *depth_arr = NULL;
+
+ /* get an array of depths, far depths are blended */
+ if (gpencil_project_check(p)) {
+ int mval_i[2], mval_prev[2] = {0};
+ int interp_depth = 0;
+ int found_depth = 0;
+
+ depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_size, "depth_points");
+
+ for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size; i++, ptc++, pt++) {
+
+ round_v2i_v2fl(mval_i, &ptc->x);
+
+ if ((ED_view3d_autodist_depth(p->ar, mval_i, depth_margin, depth_arr + i) == 0) &&
+ (i && (ED_view3d_autodist_depth_seg(
+ p->ar, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
+ interp_depth = true;
+ }
+ else {
+ found_depth = true;
+ }
+
+ copy_v2_v2_int(mval_prev, mval_i);
+ }
+
+ if (found_depth == false) {
+ /* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
+ for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--)
+ depth_arr[i] = 0.9999f;
+ }
+ else {
+ if ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) ||
+ (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_FIRST)) {
+ int first_valid = 0;
+ int last_valid = 0;
+
+ /* find first valid contact point */
+ for (i = 0; i < gpd->runtime.sbuffer_size; i++) {
+ if (depth_arr[i] != FLT_MAX)
+ break;
+ }
+ first_valid = i;
+
+ /* find last valid contact point */
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_FIRST) {
+ last_valid = first_valid;
+ }
+ else {
+ for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--) {
+ if (depth_arr[i] != FLT_MAX)
+ break;
+ }
+ last_valid = i;
+ }
+ /* invalidate any other point, to interpolate between
+ * first and last contact in an imaginary line between them */
+ for (i = 0; i < gpd->runtime.sbuffer_size; i++) {
+ if ((i != first_valid) && (i != last_valid)) {
+ depth_arr[i] = FLT_MAX;
+ }
+ }
+ interp_depth = true;
+ }
+
+ if (interp_depth) {
+ interp_sparse_array(depth_arr, gpd->runtime.sbuffer_size, FLT_MAX);
+ }
+ }
+ }
+
+ pt = gps->points;
+ dvert = gps->dvert;
+
+ /* convert all points (normal behavior) */
+ for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.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;
+ pt->uv_fac = ptc->uv_fac;
+ pt->uv_rot = ptc->uv_rot;
+
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ dvert++;
+ }
+ }
+
+ /* subdivide and smooth the stroke */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && (subdivide > 0)) {
+ gp_subdivide_stroke(gps, subdivide);
+ }
+ /* apply randomness to stroke */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_random_sub > 0.0f)) {
+ gp_randomize_stroke(gps, brush, p->rng);
+ }
+
+ /* 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->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
+ (brush->gpencil_settings->draw_smoothfac > 0.0f)) {
+ float reduce = 0.0f;
+ for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) {
+ for (i = 0; i < gps->totpoints - 1; i++) {
+ BKE_gpencil_smooth_stroke(gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
+ BKE_gpencil_smooth_stroke_strength(gps, i, brush->gpencil_settings->draw_smoothfac);
+ }
+ reduce += 0.25f; // reduce the factor
+ }
+ }
+ /* smooth thickness */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
+ (brush->gpencil_settings->thick_smoothfac > 0.0f)) {
+ for (int r = 0; r < brush->gpencil_settings->thick_smoothlvl * 2; r++) {
+ for (i = 0; i < gps->totpoints - 1; i++) {
+ BKE_gpencil_smooth_stroke_thickness(gps, i, brush->gpencil_settings->thick_smoothfac);
+ }
+ }
+ }
+
+ /* reproject to plane (only in 3d space) */
+ gp_reproject_toplane(p, gps);
+ /* change position relative to parent object */
+ gp_apply_parent(depsgraph, obact, gpd, gpl, gps);
+ /* if camera view, reproject flat to view to avoid perspective effect */
+ if (is_camera) {
+ ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps);
+ }
+
+ if (depth_arr)
+ MEM_freeN(depth_arr);
+ }
+
+ /* Save material index */
+ gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(p->ob, p->brush);
+
+ /* calculate UVs along the stroke */
+ ED_gpencil_calc_stroke_uv(obact, gps);
+
+ /* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke is added on listbase head
+ * because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist
+ * when drawing the background
+ */
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) &&
+ (p->paintmode != GP_PAINTMODE_DRAW_POLY)) {
+ BLI_addhead(&p->gpf->strokes, gps);
+ }
+ else {
+ BLI_addtail(&p->gpf->strokes, gps);
+ }
+ /* add weights */
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ for (i = 0; i < gps->totpoints; i++) {
+ MDeformVert *ve = &gps->dvert[i];
+ MDeformWeight *dw = defvert_verify_index(ve, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+ }
+ }
+
+ /* post process stroke */
+ if ((p->brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
+ p->brush->gpencil_settings->flag & GP_BRUSH_TRIM_STROKE) {
+ BKE_gpencil_trim_stroke(gps);
+ }
+
+ gp_stroke_added_enable(p);
}
/* --- 'Eraser' for 'Paint' Tool ------ */
@@ -1267,97 +1270,102 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* which which point is infront (result should only be used for comparison) */
static float view3d_point_depth(const RegionView3D *rv3d, const float co[3])
{
- if (rv3d->is_persp) {
- return ED_view3d_calc_zfac(rv3d, co, NULL);
- }
- else {
- return -dot_v3v3(rv3d->viewinv[2], co);
- }
+ if (rv3d->is_persp) {
+ return ED_view3d_calc_zfac(rv3d, co, NULL);
+ }
+ else {
+ return -dot_v3v3(rv3d->viewinv[2], co);
+ }
}
/* only erase stroke points that are visible */
-static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y)
+static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
+ const bGPDspoint *pt,
+ const int x,
+ const int y)
{
- Object *obact = (Object *)p->ownerPtr.data;
- Brush *brush = p->brush;
- Brush *eraser = p->eraser;
- BrushGpencilSettings *gp_settings = NULL;
-
- if (brush->gpencil_tool == GPAINT_TOOL_ERASE) {
- gp_settings = brush->gpencil_settings;
- }
- else if ((eraser != NULL) & (eraser->gpencil_tool == GPAINT_TOOL_ERASE)) {
- gp_settings = eraser->gpencil_settings;
- }
-
- if ((gp_settings != NULL) && (p->sa->spacetype == SPACE_VIEW3D) &&
- (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER))
- {
- RegionView3D *rv3d = p->ar->regiondata;
- bGPDlayer *gpl = p->gpl;
-
- const int mval_i[2] = {x, y};
- float mval_3d[3];
- float fpt[3];
-
- float diff_mat[4][4];
- /* calculate difference matrix if parent object */
- ED_gpencil_parent_location(p->depsgraph, obact, p->gpd, gpl, diff_mat);
-
- if (ED_view3d_autodist_simple(p->ar, mval_i, mval_3d, 0, NULL)) {
- const float depth_mval = view3d_point_depth(rv3d, mval_3d);
-
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- const float depth_pt = view3d_point_depth(rv3d, fpt);
-
- if (depth_pt > depth_mval) {
- return true;
- }
- }
- }
- return false;
+ Object *obact = (Object *)p->ownerPtr.data;
+ Brush *brush = p->brush;
+ Brush *eraser = p->eraser;
+ BrushGpencilSettings *gp_settings = NULL;
+
+ if (brush->gpencil_tool == GPAINT_TOOL_ERASE) {
+ gp_settings = brush->gpencil_settings;
+ }
+ else if ((eraser != NULL) & (eraser->gpencil_tool == GPAINT_TOOL_ERASE)) {
+ gp_settings = eraser->gpencil_settings;
+ }
+
+ if ((gp_settings != NULL) && (p->sa->spacetype == SPACE_VIEW3D) &&
+ (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
+ RegionView3D *rv3d = p->ar->regiondata;
+ bGPDlayer *gpl = p->gpl;
+
+ const int mval_i[2] = {x, y};
+ float mval_3d[3];
+ float fpt[3];
+
+ float diff_mat[4][4];
+ /* calculate difference matrix if parent object */
+ ED_gpencil_parent_location(p->depsgraph, obact, p->gpd, gpl, diff_mat);
+
+ if (ED_view3d_autodist_simple(p->ar, mval_i, mval_3d, 0, NULL)) {
+ const float depth_mval = view3d_point_depth(rv3d, mval_3d);
+
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ const float depth_pt = view3d_point_depth(rv3d, fpt);
+
+ if (depth_pt > depth_mval) {
+ return true;
+ }
+ }
+ }
+ return false;
}
/* apply a falloff effect to brush strength, based on distance */
-static float gp_stroke_eraser_calc_influence(tGPsdata *p, const float mval[2], const int radius, const int co[2])
+static float gp_stroke_eraser_calc_influence(tGPsdata *p,
+ const float mval[2],
+ const int radius,
+ const int co[2])
{
- Brush *brush = p->brush;
- /* Linear Falloff... */
- int mval_i[2];
- round_v2i_v2fl(mval_i, mval);
- float distance = (float)len_v2v2_int(mval_i, co);
- float fac;
-
- CLAMP(distance, 0.0f, (float)radius);
- fac = 1.0f - (distance / (float)radius);
-
- /* apply strength factor */
- fac *= brush->gpencil_settings->draw_strength;
-
- /* Control this further using pen pressure */
- if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
- fac *= p->pressure;
- }
- /* Return influence factor computed here */
- return fac;
+ Brush *brush = p->brush;
+ /* Linear Falloff... */
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, mval);
+ float distance = (float)len_v2v2_int(mval_i, co);
+ float fac;
+
+ CLAMP(distance, 0.0f, (float)radius);
+ fac = 1.0f - (distance / (float)radius);
+
+ /* apply strength factor */
+ fac *= brush->gpencil_settings->draw_strength;
+
+ /* Control this further using pen pressure */
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
+ fac *= p->pressure;
+ }
+ /* Return influence factor computed here */
+ return fac;
}
/* helper to free a stroke */
static void gp_free_stroke(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps)
{
- if (gps->points) {
- MEM_freeN(gps->points);
- }
-
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
-
- if (gps->triangles)
- MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
- gp_update_cache(gpd);
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ gp_update_cache(gpd);
}
/**
@@ -1367,322 +1375,324 @@ static void gp_free_stroke(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps)
*/
static void gp_stroke_soft_refine(bGPDstroke *gps)
{
- bGPDspoint *pt = NULL;
- bGPDspoint *pt2 = NULL;
- int i;
-
- /* check if enough points*/
- if (gps->totpoints < 3) {
- return;
- }
-
- /* loop all points to untag any point that next is not tagged */
- pt = gps->points;
- for (i = 1; i < gps->totpoints - 1; i++, pt++) {
- if (pt->flag & GP_SPOINT_TAG) {
- pt2 = &gps->points[i + 1];
- if ((pt2->flag & GP_SPOINT_TAG) == 0) {
- pt->flag &= ~GP_SPOINT_TAG;
- }
- }
- }
-
- /* loop reverse all points to untag any point that previous is not tagged */
- pt = &gps->points[gps->totpoints - 1];
- for (i = gps->totpoints - 1; i > 0; i--, pt--) {
- if (pt->flag & GP_SPOINT_TAG) {
- pt2 = &gps->points[i - 1];
- if ((pt2->flag & GP_SPOINT_TAG) == 0) {
- pt->flag &= ~GP_SPOINT_TAG;
- }
- }
- }
+ bGPDspoint *pt = NULL;
+ bGPDspoint *pt2 = NULL;
+ int i;
+
+ /* check if enough points*/
+ if (gps->totpoints < 3) {
+ return;
+ }
+
+ /* loop all points to untag any point that next is not tagged */
+ pt = gps->points;
+ for (i = 1; i < gps->totpoints - 1; i++, pt++) {
+ if (pt->flag & GP_SPOINT_TAG) {
+ pt2 = &gps->points[i + 1];
+ if ((pt2->flag & GP_SPOINT_TAG) == 0) {
+ pt->flag &= ~GP_SPOINT_TAG;
+ }
+ }
+ }
+
+ /* loop reverse all points to untag any point that previous is not tagged */
+ pt = &gps->points[gps->totpoints - 1];
+ for (i = gps->totpoints - 1; i > 0; i--, pt--) {
+ if (pt->flag & GP_SPOINT_TAG) {
+ pt2 = &gps->points[i - 1];
+ if ((pt2->flag & GP_SPOINT_TAG) == 0) {
+ pt->flag &= ~GP_SPOINT_TAG;
+ }
+ }
+ }
}
/* eraser tool - evaluation per stroke */
/* TODO: this could really do with some optimization (KD-Tree/BVH?) */
static void gp_stroke_eraser_dostroke(tGPsdata *p,
- bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
- const float mval[2], const float mvalo[2],
- const int radius, const rcti *rect)
+ bGPDlayer *gpl,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ const float mval[2],
+ const float mvalo[2],
+ const int radius,
+ const rcti *rect)
{
- Depsgraph *depsgraph = p->depsgraph;
- Object *obact = (Object *)p->ownerPtr.data;
- Brush *eraser = p->eraser;
- bGPDspoint *pt0, *pt1, *pt2;
- int pc0[2] = {0};
- int pc1[2] = {0};
- int pc2[2] = {0};
- int i;
- float diff_mat[4][4];
- int mval_i[2];
- round_v2i_v2fl(mval_i, mval);
-
- /* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, obact, p->gpd, gpl, diff_mat);
-
- if (gps->totpoints == 0) {
- /* just free stroke */
- gp_free_stroke(p->gpd, gpf, gps);
- }
- else if (gps->totpoints == 1) {
- /* only process if it hasn't been masked out... */
- if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
- bGPDspoint pt_temp;
- gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
- gp_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
- /* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
- /* only check if point is inside */
- if (len_v2v2_int(mval_i, pc1) <= radius) {
- /* free stroke */
- gp_free_stroke(p->gpd, gpf, gps);
- }
- }
- }
- }
- else if ((p->flags & GP_PAINTFLAG_STROKE_ERASER) || (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_STROKE)) {
- for (i = 0; (i + 1) < gps->totpoints; i++) {
-
- /* only process if it hasn't been masked out... */
- if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
- continue;
-
- /* get points to work with */
- pt1 = gps->points + i;
- bGPDspoint npt;
- gp_point_to_parent_space(pt1, diff_mat, &npt);
- gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
-
- /* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
- /* only check if point is inside */
- if (len_v2v2_int(mval_i, pc1) <= radius) {
- /* free stroke */
- gp_free_stroke(p->gpd, gpf, gps);
- return;
- }
- }
- }
- }
- else {
- /* Pressure threshold at which stroke should be culled */
- const float cull_thresh = 0.005f;
-
- /* Amount to decrease the pressure of each point with each stroke */
- const float strength = 0.1f;
-
- /* Perform culling? */
- bool do_cull = false;
-
- /* Clear Tags
- *
- * Note: It's better this way, as we are sure that
- * we don't miss anything, though things will be
- * slightly slower as a result
- */
- for (i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- pt->flag &= ~GP_SPOINT_TAG;
- }
-
- /* First Pass: Loop over the points in the stroke
- * 1) Thin out parts of the stroke under the brush
- * 2) Tag "too thin" parts for removal (in second pass)
- */
- for (i = 0; (i + 1) < gps->totpoints; i++) {
- /* get points to work with */
- pt0 = i > 0 ? gps->points + i - 1 : NULL;
- pt1 = gps->points + i;
- pt2 = gps->points + i + 1;
-
- /* only process if it hasn't been masked out... */
- if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
- continue;
-
- bGPDspoint npt;
- if (pt0) {
- gp_point_to_parent_space(pt0, diff_mat, &npt);
- gp_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]);
- }
- else {
- /* avoid null values */
- copy_v2_v2_int(pc0, pc1);
- }
-
- gp_point_to_parent_space(pt1, diff_mat, &npt);
- gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
-
- gp_point_to_parent_space(pt2, diff_mat, &npt);
- gp_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
-
- /* Check that point segment of the boundbox of the eraser stroke */
- if (((!ELEM(V2D_IS_CLIPPED, pc0[0], pc0[1])) && BLI_rcti_isect_pt(rect, pc0[0], pc0[1])) ||
- ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
- ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1])))
- {
- /* Check if point segment of stroke had anything to do with
- * eraser region (either within stroke painted, or on its lines)
- * - this assumes that linewidth is irrelevant
- */
- if (gp_stroke_inside_circle(mval, mvalo, radius, pc0[0], pc0[1], pc2[0], pc2[1])) {
- if ((gp_stroke_eraser_is_occluded(p, pt0, pc0[0], pc0[1]) == false) ||
- (gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
- (gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false))
- {
- /* Point is affected: */
- /* Adjust thickness
- * - Influence of eraser falls off with distance from the middle of the eraser
- * - Second point gets less influence, as it might get hit again in the next segment
- */
-
- /* Adjust strength if the eraser is soft */
- if (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_SOFT) {
- float f_strength = eraser->gpencil_settings->era_strength_f / 100.0f;
- float f_thickness = eraser->gpencil_settings->era_thickness_f / 100.0f;
- float influence = 0.0f;
-
- if (pt0) {
- influence = gp_stroke_eraser_calc_influence(p, mval, radius, pc0);
- pt0->strength -= influence * strength * f_strength * 0.5f;
- CLAMP_MIN(pt0->strength, 0.0f);
- pt0->pressure -= influence * strength * f_thickness * 0.5f;
- }
-
- influence = gp_stroke_eraser_calc_influence(p, mval, radius, pc1);
- pt1->strength -= influence * strength * f_strength;
- CLAMP_MIN(pt1->strength, 0.0f);
- pt1->pressure -= influence * strength * f_thickness;
-
- influence = gp_stroke_eraser_calc_influence(p, mval, radius, pc2);
- pt2->strength -= influence * strength * f_strength * 0.5f;
- CLAMP_MIN(pt2->strength, 0.0f);
- pt2->pressure -= influence * strength * f_thickness * 0.5f;
-
- /* if invisible, delete point */
- if ((pt0) &&
- ((pt0->strength <= GPENCIL_ALPHA_OPACITY_THRESH) ||
- (pt0->pressure < cull_thresh)))
- {
- pt0->flag |= GP_SPOINT_TAG;
- do_cull = true;
- }
- if ((pt1->strength <= GPENCIL_ALPHA_OPACITY_THRESH) || (pt1->pressure < cull_thresh)) {
- pt1->flag |= GP_SPOINT_TAG;
- do_cull = true;
- }
- if ((pt2->strength <= GPENCIL_ALPHA_OPACITY_THRESH) || (pt2->pressure < cull_thresh)) {
- pt2->flag |= GP_SPOINT_TAG;
- do_cull = true;
- }
- }
- else {
- pt1->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc1) * strength;
- pt2->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc2) * strength * 0.5f;
- }
-
- /* 2) Tag any point with overly low influence for removal in the next pass */
- if ((pt1->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) ||
- (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD))
- {
- pt1->flag |= GP_SPOINT_TAG;
- do_cull = true;
- }
- if ((pt2->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) ||
- (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD))
- {
- pt2->flag |= GP_SPOINT_TAG;
- do_cull = true;
- }
- }
- }
- }
- }
-
- /* Second Pass: Remove any points that are tagged */
- if (do_cull) {
- /* if soft eraser, must analyze points to be sure the stroke ends
- * don't get rounded */
- if (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_SOFT) {
- gp_stroke_soft_refine(gps);
- }
-
- gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
- }
- gp_update_cache(p->gpd);
- }
+ Depsgraph *depsgraph = p->depsgraph;
+ Object *obact = (Object *)p->ownerPtr.data;
+ Brush *eraser = p->eraser;
+ bGPDspoint *pt0, *pt1, *pt2;
+ int pc0[2] = {0};
+ int pc1[2] = {0};
+ int pc2[2] = {0};
+ int i;
+ float diff_mat[4][4];
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, mval);
+
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, p->gpd, gpl, diff_mat);
+
+ if (gps->totpoints == 0) {
+ /* just free stroke */
+ gp_free_stroke(p->gpd, gpf, gps);
+ }
+ else if (gps->totpoints == 1) {
+ /* only process if it hasn't been masked out... */
+ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ /* free stroke */
+ gp_free_stroke(p->gpd, gpf, gps);
+ }
+ }
+ }
+ }
+ else if ((p->flags & GP_PAINTFLAG_STROKE_ERASER) ||
+ (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_STROKE)) {
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+
+ /* only process if it hasn't been masked out... */
+ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
+ continue;
+
+ /* get points to work with */
+ pt1 = gps->points + i;
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ /* free stroke */
+ gp_free_stroke(p->gpd, gpf, gps);
+ return;
+ }
+ }
+ }
+ }
+ else {
+ /* Pressure threshold at which stroke should be culled */
+ const float cull_thresh = 0.005f;
+
+ /* Amount to decrease the pressure of each point with each stroke */
+ const float strength = 0.1f;
+
+ /* Perform culling? */
+ bool do_cull = false;
+
+ /* Clear Tags
+ *
+ * Note: It's better this way, as we are sure that
+ * we don't miss anything, though things will be
+ * slightly slower as a result
+ */
+ for (i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ pt->flag &= ~GP_SPOINT_TAG;
+ }
+
+ /* First Pass: Loop over the points in the stroke
+ * 1) Thin out parts of the stroke under the brush
+ * 2) Tag "too thin" parts for removal (in second pass)
+ */
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+ /* get points to work with */
+ pt0 = i > 0 ? gps->points + i - 1 : NULL;
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ /* only process if it hasn't been masked out... */
+ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
+ continue;
+
+ bGPDspoint npt;
+ if (pt0) {
+ gp_point_to_parent_space(pt0, diff_mat, &npt);
+ gp_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]);
+ }
+ else {
+ /* avoid null values */
+ copy_v2_v2_int(pc0, pc1);
+ }
+
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
+
+ /* Check that point segment of the boundbox of the eraser stroke */
+ if (((!ELEM(V2D_IS_CLIPPED, pc0[0], pc0[1])) && BLI_rcti_isect_pt(rect, pc0[0], pc0[1])) ||
+ ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
+ /* Check if point segment of stroke had anything to do with
+ * eraser region (either within stroke painted, or on its lines)
+ * - this assumes that linewidth is irrelevant
+ */
+ if (gp_stroke_inside_circle(mval, mvalo, radius, pc0[0], pc0[1], pc2[0], pc2[1])) {
+ if ((gp_stroke_eraser_is_occluded(p, pt0, pc0[0], pc0[1]) == false) ||
+ (gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
+ (gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) {
+ /* Point is affected: */
+ /* Adjust thickness
+ * - Influence of eraser falls off with distance from the middle of the eraser
+ * - Second point gets less influence, as it might get hit again in the next segment
+ */
+
+ /* Adjust strength if the eraser is soft */
+ if (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_SOFT) {
+ float f_strength = eraser->gpencil_settings->era_strength_f / 100.0f;
+ float f_thickness = eraser->gpencil_settings->era_thickness_f / 100.0f;
+ float influence = 0.0f;
+
+ if (pt0) {
+ influence = gp_stroke_eraser_calc_influence(p, mval, radius, pc0);
+ pt0->strength -= influence * strength * f_strength * 0.5f;
+ CLAMP_MIN(pt0->strength, 0.0f);
+ pt0->pressure -= influence * strength * f_thickness * 0.5f;
+ }
+
+ influence = gp_stroke_eraser_calc_influence(p, mval, radius, pc1);
+ pt1->strength -= influence * strength * f_strength;
+ CLAMP_MIN(pt1->strength, 0.0f);
+ pt1->pressure -= influence * strength * f_thickness;
+
+ influence = gp_stroke_eraser_calc_influence(p, mval, radius, pc2);
+ pt2->strength -= influence * strength * f_strength * 0.5f;
+ CLAMP_MIN(pt2->strength, 0.0f);
+ pt2->pressure -= influence * strength * f_thickness * 0.5f;
+
+ /* if invisible, delete point */
+ if ((pt0) && ((pt0->strength <= GPENCIL_ALPHA_OPACITY_THRESH) ||
+ (pt0->pressure < cull_thresh))) {
+ pt0->flag |= GP_SPOINT_TAG;
+ do_cull = true;
+ }
+ if ((pt1->strength <= GPENCIL_ALPHA_OPACITY_THRESH) ||
+ (pt1->pressure < cull_thresh)) {
+ pt1->flag |= GP_SPOINT_TAG;
+ do_cull = true;
+ }
+ if ((pt2->strength <= GPENCIL_ALPHA_OPACITY_THRESH) ||
+ (pt2->pressure < cull_thresh)) {
+ pt2->flag |= GP_SPOINT_TAG;
+ do_cull = true;
+ }
+ }
+ else {
+ pt1->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc1) * strength;
+ pt2->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc2) * strength *
+ 0.5f;
+ }
+
+ /* 2) Tag any point with overly low influence for removal in the next pass */
+ if ((pt1->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) ||
+ (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD)) {
+ pt1->flag |= GP_SPOINT_TAG;
+ do_cull = true;
+ }
+ if ((pt2->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) ||
+ (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD)) {
+ pt2->flag |= GP_SPOINT_TAG;
+ do_cull = true;
+ }
+ }
+ }
+ }
+ }
+
+ /* Second Pass: Remove any points that are tagged */
+ if (do_cull) {
+ /* if soft eraser, must analyze points to be sure the stroke ends
+ * don't get rounded */
+ if (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_SOFT) {
+ gp_stroke_soft_refine(gps);
+ }
+
+ gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
+ }
+ gp_update_cache(p->gpd);
+ }
}
/* erase strokes which fall under the eraser strokes */
static void gp_stroke_doeraser(tGPsdata *p)
{
- bGPDlayer *gpl;
- bGPDstroke *gps, *gpn;
- rcti rect;
- Brush *brush = p->brush;
- Brush *eraser = p->eraser;
- bool use_pressure = false;
- float press = 1.0f;
- BrushGpencilSettings *gp_settings = NULL;
-
- /* detect if use pressure in eraser */
- if (brush->gpencil_tool == GPAINT_TOOL_ERASE) {
- use_pressure = (bool)(brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE);
- gp_settings = brush->gpencil_settings;
- }
- else if ((eraser != NULL) & (eraser->gpencil_tool == GPAINT_TOOL_ERASE)) {
- use_pressure = (bool)(eraser->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE);
- gp_settings = eraser->gpencil_settings;
- }
- if (use_pressure) {
- press = p->pressure;
- CLAMP(press, 0.01f, 1.0f);
- }
- /* rect is rectangle of eraser */
- const int calc_radius = (int)p->radius * press;
- rect.xmin = p->mval[0] - calc_radius;
- rect.ymin = p->mval[1] - calc_radius;
- rect.xmax = p->mval[0] + calc_radius;
- rect.ymax = p->mval[1] + calc_radius;
-
- if (p->sa->spacetype == SPACE_VIEW3D) {
- if ((gp_settings != NULL) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
- View3D *v3d = p->sa->spacedata.first;
- view3d_region_operator_needs_opengl(p->win, p->ar);
- ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, 0);
- }
- }
-
- /* loop over all layers too, since while it's easy to restrict editing to
- * only a subset of layers, it is harder to perform the same erase operation
- * on multiple layers...
- */
- for (gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
- bGPDframe *gpf = gpl->actframe;
-
- /* only affect layer if it's editable (and visible) */
- if (gpencil_layer_is_editable(gpl) == false) {
- continue;
- }
- else if (gpf == NULL) {
- continue;
- }
-
- /* loop over strokes, checking segments for intersections */
- for (gps = gpf->strokes.first; gps; gps = gpn) {
- gpn = gps->next;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(p->ob, gpl, gps) == false) {
- continue;
- }
- /* Not all strokes in the datablock may be valid in the current editor/context
- * (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
- */
- if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
- gp_stroke_eraser_dostroke(p, gpl, gpf, gps, p->mval, p->mvalo, calc_radius, &rect);
- }
- }
- }
+ bGPDlayer *gpl;
+ bGPDstroke *gps, *gpn;
+ rcti rect;
+ Brush *brush = p->brush;
+ Brush *eraser = p->eraser;
+ bool use_pressure = false;
+ float press = 1.0f;
+ BrushGpencilSettings *gp_settings = NULL;
+
+ /* detect if use pressure in eraser */
+ if (brush->gpencil_tool == GPAINT_TOOL_ERASE) {
+ use_pressure = (bool)(brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE);
+ gp_settings = brush->gpencil_settings;
+ }
+ else if ((eraser != NULL) & (eraser->gpencil_tool == GPAINT_TOOL_ERASE)) {
+ use_pressure = (bool)(eraser->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE);
+ gp_settings = eraser->gpencil_settings;
+ }
+ if (use_pressure) {
+ press = p->pressure;
+ CLAMP(press, 0.01f, 1.0f);
+ }
+ /* rect is rectangle of eraser */
+ const int calc_radius = (int)p->radius * press;
+ rect.xmin = p->mval[0] - calc_radius;
+ rect.ymin = p->mval[1] - calc_radius;
+ rect.xmax = p->mval[0] + calc_radius;
+ rect.ymax = p->mval[1] + calc_radius;
+
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ if ((gp_settings != NULL) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
+ View3D *v3d = p->sa->spacedata.first;
+ view3d_region_operator_needs_opengl(p->win, p->ar);
+ ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, 0);
+ }
+ }
+
+ /* loop over all layers too, since while it's easy to restrict editing to
+ * only a subset of layers, it is harder to perform the same erase operation
+ * on multiple layers...
+ */
+ for (gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *gpf = gpl->actframe;
+
+ /* only affect layer if it's editable (and visible) */
+ if (gpencil_layer_is_editable(gpl) == false) {
+ continue;
+ }
+ else if (gpf == NULL) {
+ continue;
+ }
+
+ /* loop over strokes, checking segments for intersections */
+ for (gps = gpf->strokes.first; gps; gps = gpn) {
+ gpn = gps->next;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(p->ob, gpl, gps) == false) {
+ continue;
+ }
+ /* Not all strokes in the datablock may be valid in the current editor/context
+ * (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
+ */
+ if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
+ gp_stroke_eraser_dostroke(p, gpl, gpf, gps, p->mval, p->mvalo, calc_radius, &rect);
+ }
+ }
+ }
}
/* ******************************************* */
@@ -1691,563 +1701,558 @@ static void gp_stroke_doeraser(tGPsdata *p)
/* clear the session buffers (call this before AND after a paint operation) */
static void gp_session_validatebuffer(tGPsdata *p)
{
- bGPdata *gpd = p->gpd;
- Brush *brush = p->brush;
-
- /* clear memory of buffer (or allocate it if starting a new session) */
- if (gpd->runtime.sbuffer) {
- /* printf("\t\tGP - reset sbuffer\n"); */
- memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
- }
- else {
- /* printf("\t\tGP - allocate sbuffer\n"); */
- gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
- }
-
- /* reset indices */
- gpd->runtime.sbuffer_size = 0;
-
- /* reset flags */
- gpd->runtime.sbuffer_sflag = 0;
-
- /* reset region */
- gpd->runtime.ar = NULL;
-
- /* reset inittime */
- p->inittime = 0.0;
-
- /* reset lazy */
- if (brush) {
- brush->gpencil_settings->flag &= ~GP_BRUSH_STABILIZE_MOUSE_TEMP;
- }
+ bGPdata *gpd = p->gpd;
+ Brush *brush = p->brush;
+
+ /* clear memory of buffer (or allocate it if starting a new session) */
+ if (gpd->runtime.sbuffer) {
+ /* printf("\t\tGP - reset sbuffer\n"); */
+ memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
+ }
+ else {
+ /* printf("\t\tGP - allocate sbuffer\n"); */
+ gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX,
+ "gp_session_strokebuffer");
+ }
+
+ /* reset indices */
+ gpd->runtime.sbuffer_size = 0;
+
+ /* reset flags */
+ gpd->runtime.sbuffer_sflag = 0;
+
+ /* reset region */
+ gpd->runtime.ar = NULL;
+
+ /* reset inittime */
+ p->inittime = 0.0;
+
+ /* reset lazy */
+ if (brush) {
+ brush->gpencil_settings->flag &= ~GP_BRUSH_STABILIZE_MOUSE_TEMP;
+ }
}
/* helper to get default eraser and create one if no eraser brush */
static Brush *gp_get_default_eraser(Main *bmain, ToolSettings *ts)
{
- Brush *brush_dft = NULL;
- Paint *paint = &ts->gp_paint->paint;
- Brush *brush_old = paint->brush;
- for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
- if ((brush->ob_mode == OB_MODE_PAINT_GPENCIL) &&
- (brush->gpencil_tool == GPAINT_TOOL_ERASE))
- {
- /* save first eraser to use later if no default */
- if (brush_dft == NULL) {
- brush_dft = brush;
- }
- /* found default */
- if (brush->gpencil_settings->flag & GP_BRUSH_DEFAULT_ERASER) {
- return brush;
- }
- }
- }
- /* if no default, but exist eraser brush, return this and set as default */
- if (brush_dft) {
- brush_dft->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER;
- return brush_dft;
- }
- /* create a new soft eraser brush */
- else {
- brush_dft = BKE_brush_add_gpencil(bmain, ts, "Soft Eraser");
- brush_dft->size = 30.0f;
- brush_dft->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
- brush_dft->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
- brush_dft->gpencil_tool = GPAINT_TOOL_ERASE;
- brush_dft->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
-
- /* reset current brush */
- BKE_paint_brush_set(paint, brush_old);
-
- return brush_dft;
- }
+ Brush *brush_dft = NULL;
+ Paint *paint = &ts->gp_paint->paint;
+ Brush *brush_old = paint->brush;
+ for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
+ if ((brush->ob_mode == OB_MODE_PAINT_GPENCIL) && (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
+ /* save first eraser to use later if no default */
+ if (brush_dft == NULL) {
+ brush_dft = brush;
+ }
+ /* found default */
+ if (brush->gpencil_settings->flag & GP_BRUSH_DEFAULT_ERASER) {
+ return brush;
+ }
+ }
+ }
+ /* if no default, but exist eraser brush, return this and set as default */
+ if (brush_dft) {
+ brush_dft->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER;
+ return brush_dft;
+ }
+ /* create a new soft eraser brush */
+ else {
+ brush_dft = BKE_brush_add_gpencil(bmain, ts, "Soft Eraser");
+ brush_dft->size = 30.0f;
+ brush_dft->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
+ brush_dft->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
+ brush_dft->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush_dft->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
+
+ /* reset current brush */
+ BKE_paint_brush_set(paint, brush_old);
+
+ return brush_dft;
+ }
}
/* helper to set default eraser and disable others */
static void gp_set_default_eraser(Main *bmain, Brush *brush_dft)
{
- if (brush_dft == NULL) {
- return;
- }
-
- for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
- if ((brush->gpencil_settings) && (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
- if (brush == brush_dft) {
- brush->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER;
- }
- else if (brush->gpencil_settings->flag & GP_BRUSH_DEFAULT_ERASER) {
- brush->gpencil_settings->flag &= ~GP_BRUSH_DEFAULT_ERASER;
- }
- }
- }
+ if (brush_dft == NULL) {
+ return;
+ }
+
+ for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
+ if ((brush->gpencil_settings) && (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
+ if (brush == brush_dft) {
+ brush->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER;
+ }
+ else if (brush->gpencil_settings->flag & GP_BRUSH_DEFAULT_ERASER) {
+ brush->gpencil_settings->flag &= ~GP_BRUSH_DEFAULT_ERASER;
+ }
+ }
+ }
}
/* initialize a drawing brush */
static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- Paint *paint = &ts->gp_paint->paint;
- bool changed = false;
- /* if not exist, create a new one */
- if (paint->brush == NULL) {
- /* create new brushes */
- BKE_brush_gpencil_presets(C);
- changed = true;
- }
- /* be sure curves are initializated */
- curvemapping_initialize(paint->brush->gpencil_settings->curve_sensitivity);
- curvemapping_initialize(paint->brush->gpencil_settings->curve_strength);
- curvemapping_initialize(paint->brush->gpencil_settings->curve_jitter);
-
- /* assign to temp tGPsdata */
- p->brush = paint->brush;
- if (paint->brush->gpencil_tool != GPAINT_TOOL_ERASE) {
- p->eraser = gp_get_default_eraser(p->bmain, ts);
- }
- else {
- p->eraser = paint->brush;
- }
- /* set new eraser as default */
- gp_set_default_eraser(p->bmain, p->eraser);
-
- /* use radius of eraser */
- p->radius = (short)p->eraser->size;
-
- /* GPXX: Need this update to synchronize brush with draw manager.
- * Maybe this update can be removed when the new tool system
- * will be in place, but while, we need this to keep drawing working.
- */
- if (changed) {
- DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
- }
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ Paint *paint = &ts->gp_paint->paint;
+ bool changed = false;
+ /* if not exist, create a new one */
+ if (paint->brush == NULL) {
+ /* create new brushes */
+ BKE_brush_gpencil_presets(C);
+ changed = true;
+ }
+ /* be sure curves are initializated */
+ curvemapping_initialize(paint->brush->gpencil_settings->curve_sensitivity);
+ curvemapping_initialize(paint->brush->gpencil_settings->curve_strength);
+ curvemapping_initialize(paint->brush->gpencil_settings->curve_jitter);
+
+ /* assign to temp tGPsdata */
+ p->brush = paint->brush;
+ if (paint->brush->gpencil_tool != GPAINT_TOOL_ERASE) {
+ p->eraser = gp_get_default_eraser(p->bmain, ts);
+ }
+ else {
+ p->eraser = paint->brush;
+ }
+ /* set new eraser as default */
+ gp_set_default_eraser(p->bmain, p->eraser);
+
+ /* use radius of eraser */
+ p->radius = (short)p->eraser->size;
+
+ /* GPXX: Need this update to synchronize brush with draw manager.
+ * Maybe this update can be removed when the new tool system
+ * will be in place, but while, we need this to keep drawing working.
+ */
+ if (changed) {
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ }
}
-
/* initialize a paint brush and a default color if not exist */
static void gp_init_colors(tGPsdata *p)
{
- bGPdata *gpd = p->gpd;
- Brush *brush = p->brush;
-
- MaterialGPencilStyle *gp_style = NULL;
-
- /* use brush material */
- p->material = BKE_gpencil_object_material_ensure_from_active_input_brush(p->bmain, p->ob, brush);
-
- /* assign color information to temp tGPsdata */
- gp_style = p->material->gp_style;
- if (gp_style) {
-
- /* set colors */
- if (gp_style->flag & GP_STYLE_STROKE_SHOW) {
- copy_v4_v4(gpd->runtime.scolor, gp_style->stroke_rgba);
- }
- else {
- /* if no stroke, use fill */
- copy_v4_v4(gpd->runtime.scolor, gp_style->fill_rgba);
- }
- copy_v4_v4(gpd->runtime.sfill, gp_style->fill_rgba);
- /* add some alpha to make easy the filling without hide strokes */
- if (gpd->runtime.sfill[3] > 0.8f) {
- gpd->runtime.sfill[3] = 0.8f;
- }
-
- gpd->runtime.mode = (short)gp_style->mode;
- gpd->runtime.bstroke_style = gp_style->stroke_style;
- gpd->runtime.bfill_style = gp_style->fill_style;
- }
+ bGPdata *gpd = p->gpd;
+ Brush *brush = p->brush;
+
+ MaterialGPencilStyle *gp_style = NULL;
+
+ /* use brush material */
+ p->material = BKE_gpencil_object_material_ensure_from_active_input_brush(p->bmain, p->ob, brush);
+
+ /* assign color information to temp tGPsdata */
+ gp_style = p->material->gp_style;
+ if (gp_style) {
+
+ /* set colors */
+ if (gp_style->flag & GP_STYLE_STROKE_SHOW) {
+ copy_v4_v4(gpd->runtime.scolor, gp_style->stroke_rgba);
+ }
+ else {
+ /* if no stroke, use fill */
+ copy_v4_v4(gpd->runtime.scolor, gp_style->fill_rgba);
+ }
+ copy_v4_v4(gpd->runtime.sfill, gp_style->fill_rgba);
+ /* add some alpha to make easy the filling without hide strokes */
+ if (gpd->runtime.sfill[3] > 0.8f) {
+ gpd->runtime.sfill[3] = 0.8f;
+ }
+
+ gpd->runtime.mode = (short)gp_style->mode;
+ gpd->runtime.bstroke_style = gp_style->stroke_style;
+ gpd->runtime.bfill_style = gp_style->fill_style;
+ }
}
/* (re)init new painting data */
static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
{
- Main *bmain = CTX_data_main(C);
- bGPdata **gpd_ptr = NULL;
- ScrArea *curarea = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- Object *obact = CTX_data_active_object(C);
-
- /* make sure the active view (at the starting time) is a 3d-view */
- if (curarea == NULL) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: No active view for painting\n");
- return 0;
- }
-
- /* pass on current scene and window */
- p->C = C;
- p->bmain = CTX_data_main(C);
- p->scene = CTX_data_scene(C);
- p->depsgraph = CTX_data_depsgraph(C);
- p->win = CTX_wm_window(C);
- p->disable_fill = RNA_boolean_get(op->ptr, "disable_fill");
-
- unit_m4(p->imat);
- unit_m4(p->mat);
-
- switch (curarea->spacetype) {
- /* supported views first */
- case SPACE_VIEW3D:
- {
- /* View3D *v3d = curarea->spacedata.first; */
- /* RegionView3D *rv3d = ar->regiondata; */
-
- /* set current area
- * - must verify that region data is 3D-view (and not something else)
- */
- /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
- p->sa = curarea;
- p->ar = ar;
- p->align_flag = &ts->gpencil_v3d_align;
-
- if (ar->regiondata == NULL) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: 3D-View active region doesn't have any region data, so cannot be drawable\n");
- return 0;
- }
-
- if ((!obact) || (obact->type != OB_GPENCIL)) {
- View3D *v3d = p->sa->spacedata.first;
- /* if active object doesn't exist or isn't a GP Object, create one */
- const float *cur = p->scene->cursor.location;
-
- ushort local_view_bits = 0;
- if (v3d->localvd) {
- local_view_bits = v3d->local_view_uuid;
- }
- /* create new default object */
- obact = ED_gpencil_add_object(C, p->scene, cur, local_view_bits);
- }
- /* assign object after all checks to be sure we have one active */
- p->ob = obact;
-
- break;
- }
-
- /* unsupported views */
- default:
- {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: Active view not appropriate for Grease Pencil drawing\n");
- return 0;
- }
- }
-
- /* get gp-data */
- gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr);
- if ((gpd_ptr == NULL) || ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: Current context doesn't allow for any Grease Pencil data\n");
- return 0;
- }
- else {
- /* if no existing GPencil block exists, add one */
- if (*gpd_ptr == NULL)
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, "GPencil");
- p->gpd = *gpd_ptr;
- }
-
- /* clear out buffer (stored in gp-data), in case something contaminated it */
- gp_session_validatebuffer(p);
-
- /* set brush and create a new one if null */
- gp_init_drawing_brush(C, p);
-
- /* setup active color */
- if (curarea->spacetype == SPACE_VIEW3D) {
- /* region where paint was originated */
- p->gpd->runtime.ar = CTX_wm_region(C);
-
- /* NOTE: This is only done for 3D view, as Materials aren't used for
- * annotations in 2D editors
- */
- int totcol = p->ob->totcol;
-
- gp_init_colors(p);
-
- /* check whether the material was newly added */
- if (totcol != p->ob->totcol) {
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
- }
- }
-
- /* lock axis (in some modes, disable) */
- if (((*p->align_flag & GP_PROJECT_DEPTH_VIEW) == 0) &&
- ((*p->align_flag & GP_PROJECT_DEPTH_STROKE) == 0))
- {
- p->lock_axis = ts->gp_sculpt.lock_axis;
- }
- else {
- p->lock_axis = 0;
- }
-
- return 1;
+ Main *bmain = CTX_data_main(C);
+ bGPdata **gpd_ptr = NULL;
+ ScrArea *curarea = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *obact = CTX_data_active_object(C);
+
+ /* make sure the active view (at the starting time) is a 3d-view */
+ if (curarea == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: No active view for painting\n");
+ return 0;
+ }
+
+ /* pass on current scene and window */
+ p->C = C;
+ p->bmain = CTX_data_main(C);
+ p->scene = CTX_data_scene(C);
+ p->depsgraph = CTX_data_depsgraph(C);
+ p->win = CTX_wm_window(C);
+ p->disable_fill = RNA_boolean_get(op->ptr, "disable_fill");
+
+ unit_m4(p->imat);
+ unit_m4(p->mat);
+
+ switch (curarea->spacetype) {
+ /* supported views first */
+ case SPACE_VIEW3D: {
+ /* View3D *v3d = curarea->spacedata.first; */
+ /* RegionView3D *rv3d = ar->regiondata; */
+
+ /* set current area
+ * - must verify that region data is 3D-view (and not something else)
+ */
+ /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
+ p->sa = curarea;
+ p->ar = ar;
+ p->align_flag = &ts->gpencil_v3d_align;
+
+ if (ar->regiondata == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf(
+ "Error: 3D-View active region doesn't have any region data, so cannot be "
+ "drawable\n");
+ return 0;
+ }
+
+ if ((!obact) || (obact->type != OB_GPENCIL)) {
+ View3D *v3d = p->sa->spacedata.first;
+ /* if active object doesn't exist or isn't a GP Object, create one */
+ const float *cur = p->scene->cursor.location;
+
+ ushort local_view_bits = 0;
+ if (v3d->localvd) {
+ local_view_bits = v3d->local_view_uuid;
+ }
+ /* create new default object */
+ obact = ED_gpencil_add_object(C, p->scene, cur, local_view_bits);
+ }
+ /* assign object after all checks to be sure we have one active */
+ p->ob = obact;
+
+ break;
+ }
+
+ /* unsupported views */
+ default: {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: Active view not appropriate for Grease Pencil drawing\n");
+ return 0;
+ }
+ }
+
+ /* get gp-data */
+ gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr);
+ if ((gpd_ptr == NULL) || ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: Current context doesn't allow for any Grease Pencil data\n");
+ return 0;
+ }
+ else {
+ /* if no existing GPencil block exists, add one */
+ if (*gpd_ptr == NULL)
+ *gpd_ptr = BKE_gpencil_data_addnew(bmain, "GPencil");
+ p->gpd = *gpd_ptr;
+ }
+
+ /* clear out buffer (stored in gp-data), in case something contaminated it */
+ gp_session_validatebuffer(p);
+
+ /* set brush and create a new one if null */
+ gp_init_drawing_brush(C, p);
+
+ /* setup active color */
+ if (curarea->spacetype == SPACE_VIEW3D) {
+ /* region where paint was originated */
+ p->gpd->runtime.ar = CTX_wm_region(C);
+
+ /* NOTE: This is only done for 3D view, as Materials aren't used for
+ * annotations in 2D editors
+ */
+ int totcol = p->ob->totcol;
+
+ gp_init_colors(p);
+
+ /* check whether the material was newly added */
+ if (totcol != p->ob->totcol) {
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
+ }
+ }
+
+ /* lock axis (in some modes, disable) */
+ if (((*p->align_flag & GP_PROJECT_DEPTH_VIEW) == 0) &&
+ ((*p->align_flag & GP_PROJECT_DEPTH_STROKE) == 0)) {
+ p->lock_axis = ts->gp_sculpt.lock_axis;
+ }
+ else {
+ p->lock_axis = 0;
+ }
+
+ return 1;
}
/* init new painting session */
static tGPsdata *gp_session_initpaint(bContext *C, wmOperator *op)
{
- tGPsdata *p = NULL;
-
- /* Create new context data */
- p = MEM_callocN(sizeof(tGPsdata), "GPencil Drawing Data");
-
- /* Try to initialize context data
- * WARNING: This may not always succeed (e.g. using GP in an annotation-only context)
- */
- if (gp_session_initdata(C, op, p) == 0) {
- /* Invalid state - Exit
- * NOTE: It should be safe to just free the data, since failing context checks should
- * only happen when no data has been allocated.
- */
- MEM_freeN(p);
- return NULL;
- }
-
- /* Random generator, only init once. */
- uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
- rng_seed ^= POINTER_AS_UINT(p);
- p->rng = BLI_rng_new(rng_seed);
-
- /* return context data for running paint operator */
- return p;
+ tGPsdata *p = NULL;
+
+ /* Create new context data */
+ p = MEM_callocN(sizeof(tGPsdata), "GPencil Drawing Data");
+
+ /* Try to initialize context data
+ * WARNING: This may not always succeed (e.g. using GP in an annotation-only context)
+ */
+ if (gp_session_initdata(C, op, p) == 0) {
+ /* Invalid state - Exit
+ * NOTE: It should be safe to just free the data, since failing context checks should
+ * only happen when no data has been allocated.
+ */
+ MEM_freeN(p);
+ return NULL;
+ }
+
+ /* Random generator, only init once. */
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= POINTER_AS_UINT(p);
+ p->rng = BLI_rng_new(rng_seed);
+
+ /* return context data for running paint operator */
+ return p;
}
/* cleanup after a painting session */
static void gp_session_cleanup(tGPsdata *p)
{
- bGPdata *gpd = (p) ? p->gpd : NULL;
-
- /* error checking */
- if (gpd == NULL)
- return;
-
- /* free stroke buffer */
- if (gpd->runtime.sbuffer) {
- /* printf("\t\tGP - free sbuffer\n"); */
- MEM_SAFE_FREE(gpd->runtime.sbuffer);
- gpd->runtime.sbuffer = NULL;
- }
-
- /* clear flags */
- gpd->runtime.sbuffer_size = 0;
- gpd->runtime.sbuffer_sflag = 0;
- p->inittime = 0.0;
+ bGPdata *gpd = (p) ? p->gpd : NULL;
+
+ /* error checking */
+ if (gpd == NULL)
+ return;
+
+ /* free stroke buffer */
+ if (gpd->runtime.sbuffer) {
+ /* printf("\t\tGP - free sbuffer\n"); */
+ MEM_SAFE_FREE(gpd->runtime.sbuffer);
+ gpd->runtime.sbuffer = NULL;
+ }
+
+ /* clear flags */
+ gpd->runtime.sbuffer_size = 0;
+ gpd->runtime.sbuffer_sflag = 0;
+ p->inittime = 0.0;
}
static void gp_session_free(tGPsdata *p)
{
- if (p->rng != NULL) {
- BLI_rng_free(p->rng);
- }
+ if (p->rng != NULL) {
+ BLI_rng_free(p->rng);
+ }
- MEM_freeN(p);
+ MEM_freeN(p);
}
/* init new stroke */
static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Depsgraph *depsgraph)
{
- Scene *scene = p->scene;
- ToolSettings *ts = scene->toolsettings;
- int cfra_eval = (int)DEG_get_ctime(p->depsgraph);
-
- /* get active layer (or add a new one if non-existent) */
- p->gpl = BKE_gpencil_layer_getactive(p->gpd);
- if (p->gpl == NULL) {
- p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("GP_Layer"), true);
-
- if (p->custom_color[3]) {
- copy_v3_v3(p->gpl->color, p->custom_color);
- }
- }
- if ((paintmode != GP_PAINTMODE_ERASER) &&
- (p->gpl->flag & GP_LAYER_LOCKED))
- {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: Cannot paint on locked layer\n");
- return;
- }
-
- /* get active frame (add a new one if not matching frame) */
- if (paintmode == GP_PAINTMODE_ERASER) {
- /* Eraser mode:
- * 1) Add new frames to all frames that we might touch,
- * 2) Ensure that p->gpf refers to the frame used for the active layer
- * (to avoid problems with other tools which expect it to exist)
- */
- bool has_layer_to_erase = false;
-
- for (bGPDlayer *gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
- /* Skip if layer not editable */
- if (gpencil_layer_is_editable(gpl) == false)
- continue;
-
- /* Add a new frame if needed (and based off the active frame,
- * as we need some existing strokes to erase)
- *
- * Note: We don't add a new frame if there's nothing there now, so
- * -> If there are no frames at all, don't add one
- * -> If there are no strokes in that frame, don't add a new empty frame
- */
- if (gpl->actframe && gpl->actframe->strokes.first) {
- gpl->actframe = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_COPY);
- has_layer_to_erase = true;
- }
-
- /* XXX: we omit GP_FRAME_PAINT here for now,
- * as it is only really useful for doing
- * paintbuffer drawing
- */
- }
-
- /* Ensure this gets set... */
- p->gpf = p->gpl->actframe;
-
- /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
- * (though this is only available in editmode)
- */
- if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
- if (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
- p->flags |= GP_PAINTFLAG_SELECTMASK;
- }
- }
-
- if (has_layer_to_erase == false) {
- p->status = GP_STATUS_ERROR;
- return;
- }
- }
- else {
- /* Drawing Modes - Add a new frame if needed on the active layer */
- short add_frame_mode;
-
- if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
- add_frame_mode = GP_GETFRAME_ADD_COPY;
- else
- add_frame_mode = GP_GETFRAME_ADD_NEW;
-
- p->gpf = BKE_gpencil_layer_getframe(p->gpl, cfra_eval, add_frame_mode);
-
- if (p->gpf == NULL) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: No frame created (gpencil_paint_init)\n");
- return;
- }
- else {
- p->gpf->flag |= GP_FRAME_PAINT;
- }
- }
-
- /* set 'eraser' for this stroke if using eraser */
- p->paintmode = paintmode;
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER;
- }
- else {
- /* disable eraser flags - so that we can switch modes during a session */
- p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER;
- }
-
- /* set special fill stroke mode */
- if (p->disable_fill == true) {
- p->gpd->runtime.sbuffer_sflag |= GP_STROKE_NOFILL;
- /* replace stroke color with fill color */
- copy_v4_v4(p->gpd->runtime.scolor, p->gpd->runtime.sfill);
- }
-
- /* set 'initial run' flag, which is only used to denote when a new stroke is starting */
- p->flags |= GP_PAINTFLAG_FIRSTRUN;
-
- /* when drawing in the camera view, in 2D space, set the subrect */
- p->subrect = NULL;
- if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
- if (p->sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = p->sa->spacedata.first;
- RegionView3D *rv3d = p->ar->regiondata;
-
- /* for camera view set the subrect */
- if (rv3d->persp == RV3D_CAMOB) {
- /* no shift */
- ED_view3d_calc_camera_border(p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true);
- p->subrect = &p->subrect_data;
- }
- }
- }
-
- /* init stroke point space-conversion settings... */
- p->gsc.gpd = p->gpd;
- p->gsc.gpl = p->gpl;
-
- p->gsc.sa = p->sa;
- p->gsc.ar = p->ar;
- p->gsc.v2d = p->v2d;
-
- p->gsc.subrect_data = p->subrect_data;
- p->gsc.subrect = p->subrect;
-
- copy_m4_m4(p->gsc.mat, p->mat);
-
-
- /* check if points will need to be made in view-aligned space */
- if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
- switch (p->sa->spacetype) {
- case SPACE_VIEW3D:
- {
- p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
- break;
- }
- }
- }
+ Scene *scene = p->scene;
+ ToolSettings *ts = scene->toolsettings;
+ int cfra_eval = (int)DEG_get_ctime(p->depsgraph);
+
+ /* get active layer (or add a new one if non-existent) */
+ p->gpl = BKE_gpencil_layer_getactive(p->gpd);
+ if (p->gpl == NULL) {
+ p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("GP_Layer"), true);
+
+ if (p->custom_color[3]) {
+ copy_v3_v3(p->gpl->color, p->custom_color);
+ }
+ }
+ if ((paintmode != GP_PAINTMODE_ERASER) && (p->gpl->flag & GP_LAYER_LOCKED)) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: Cannot paint on locked layer\n");
+ return;
+ }
+
+ /* get active frame (add a new one if not matching frame) */
+ if (paintmode == GP_PAINTMODE_ERASER) {
+ /* Eraser mode:
+ * 1) Add new frames to all frames that we might touch,
+ * 2) Ensure that p->gpf refers to the frame used for the active layer
+ * (to avoid problems with other tools which expect it to exist)
+ */
+ bool has_layer_to_erase = false;
+
+ for (bGPDlayer *gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
+ /* Skip if layer not editable */
+ if (gpencil_layer_is_editable(gpl) == false)
+ continue;
+
+ /* Add a new frame if needed (and based off the active frame,
+ * as we need some existing strokes to erase)
+ *
+ * Note: We don't add a new frame if there's nothing there now, so
+ * -> If there are no frames at all, don't add one
+ * -> If there are no strokes in that frame, don't add a new empty frame
+ */
+ if (gpl->actframe && gpl->actframe->strokes.first) {
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_COPY);
+ has_layer_to_erase = true;
+ }
+
+ /* XXX: we omit GP_FRAME_PAINT here for now,
+ * as it is only really useful for doing
+ * paintbuffer drawing
+ */
+ }
+
+ /* Ensure this gets set... */
+ p->gpf = p->gpl->actframe;
+
+ /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
+ * (though this is only available in editmode)
+ */
+ if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ if (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
+ p->flags |= GP_PAINTFLAG_SELECTMASK;
+ }
+ }
+
+ if (has_layer_to_erase == false) {
+ p->status = GP_STATUS_ERROR;
+ return;
+ }
+ }
+ else {
+ /* Drawing Modes - Add a new frame if needed on the active layer */
+ short add_frame_mode;
+
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
+ add_frame_mode = GP_GETFRAME_ADD_COPY;
+ else
+ add_frame_mode = GP_GETFRAME_ADD_NEW;
+
+ p->gpf = BKE_gpencil_layer_getframe(p->gpl, cfra_eval, add_frame_mode);
+
+ if (p->gpf == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: No frame created (gpencil_paint_init)\n");
+ return;
+ }
+ else {
+ p->gpf->flag |= GP_FRAME_PAINT;
+ }
+ }
+
+ /* set 'eraser' for this stroke if using eraser */
+ p->paintmode = paintmode;
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER;
+ }
+ else {
+ /* disable eraser flags - so that we can switch modes during a session */
+ p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER;
+ }
+
+ /* set special fill stroke mode */
+ if (p->disable_fill == true) {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_NOFILL;
+ /* replace stroke color with fill color */
+ copy_v4_v4(p->gpd->runtime.scolor, p->gpd->runtime.sfill);
+ }
+
+ /* set 'initial run' flag, which is only used to denote when a new stroke is starting */
+ p->flags |= GP_PAINTFLAG_FIRSTRUN;
+
+ /* when drawing in the camera view, in 2D space, set the subrect */
+ p->subrect = NULL;
+ if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = p->sa->spacedata.first;
+ RegionView3D *rv3d = p->ar->regiondata;
+
+ /* for camera view set the subrect */
+ if (rv3d->persp == RV3D_CAMOB) {
+ /* no shift */
+ ED_view3d_calc_camera_border(
+ p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true);
+ p->subrect = &p->subrect_data;
+ }
+ }
+ }
+
+ /* init stroke point space-conversion settings... */
+ p->gsc.gpd = p->gpd;
+ p->gsc.gpl = p->gpl;
+
+ p->gsc.sa = p->sa;
+ p->gsc.ar = p->ar;
+ p->gsc.v2d = p->v2d;
+
+ p->gsc.subrect_data = p->subrect_data;
+ p->gsc.subrect = p->subrect;
+
+ copy_m4_m4(p->gsc.mat, p->mat);
+
+ /* check if points will need to be made in view-aligned space */
+ if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
+ switch (p->sa->spacetype) {
+ case SPACE_VIEW3D: {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
+ break;
+ }
+ }
+ }
}
/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
static void gp_paint_strokeend(tGPsdata *p)
{
- ToolSettings *ts = p->scene->toolsettings;
- /* for surface sketching, need to set the right OpenGL context stuff so that
- * the conversions will project the values correctly...
- */
- if (gpencil_project_check(p)) {
- View3D *v3d = p->sa->spacedata.first;
-
- /* need to restore the original projection settings before packing up */
- view3d_region_operator_needs_opengl(p->win, p->ar);
- ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
- }
-
- /* check if doing eraser or not */
- if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
- /* transfer stroke to frame */
- gp_stroke_newfrombuffer(p);
- }
-
- /* clean up buffer now */
- gp_session_validatebuffer(p);
+ ToolSettings *ts = p->scene->toolsettings;
+ /* for surface sketching, need to set the right OpenGL context stuff so that
+ * the conversions will project the values correctly...
+ */
+ if (gpencil_project_check(p)) {
+ View3D *v3d = p->sa->spacedata.first;
+
+ /* need to restore the original projection settings before packing up */
+ view3d_region_operator_needs_opengl(p->win, p->ar);
+ ED_view3d_autodist_init(
+ p->depsgraph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
+ }
+
+ /* check if doing eraser or not */
+ if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
+ /* transfer stroke to frame */
+ gp_stroke_newfrombuffer(p);
+ }
+
+ /* clean up buffer now */
+ gp_session_validatebuffer(p);
}
/* finish off stroke painting operation */
static void gp_paint_cleanup(tGPsdata *p)
{
- /* p->gpd==NULL happens when stroke failed to initialize,
- * for example when GP is hidden in current space (sergey)
- */
- if (p->gpd) {
- /* finish off a stroke */
- gp_paint_strokeend(p);
- }
-
- /* "unlock" frame */
- if (p->gpf)
- p->gpf->flag &= ~GP_FRAME_PAINT;
+ /* p->gpd==NULL happens when stroke failed to initialize,
+ * for example when GP is hidden in current space (sergey)
+ */
+ if (p->gpd) {
+ /* finish off a stroke */
+ gp_paint_strokeend(p);
+ }
+
+ /* "unlock" frame */
+ if (p->gpf)
+ p->gpf->flag &= ~GP_FRAME_PAINT;
}
/* ------------------------------- */
@@ -2255,265 +2260,271 @@ static void gp_paint_cleanup(tGPsdata *p)
/* Helper callback for drawing the cursor itself */
static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
{
- tGPsdata *p = (tGPsdata *)p_ptr;
+ tGPsdata *p = (tGPsdata *)p_ptr;
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- GPUVertFormat *format = immVertexFormat();
- const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ GPUVertFormat *format = immVertexFormat();
+ const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- GPU_line_smooth(true);
- GPU_blend(true);
- GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(
+ GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- immUniformColor4ub(255, 100, 100, 20);
- imm_draw_circle_fill_2d(shdr_pos, x, y, p->radius, 40);
+ immUniformColor4ub(255, 100, 100, 20);
+ imm_draw_circle_fill_2d(shdr_pos, x, y, p->radius, 40);
- immUnbindProgram();
+ immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
- immUniform1i("colors_len", 0); /* "simple" mode */
- immUniform1f("dash_width", 12.0f);
- immUniform1f("dash_factor", 0.5f);
+ immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniform1f("dash_width", 12.0f);
+ immUniform1f("dash_factor", 0.5f);
- imm_draw_circle_wire_2d(
- shdr_pos, x, y, p->radius,
- /* XXX Dashed shader gives bad results with sets of small segments currently,
- * temp hack around the issue. :( */
- max_ii(8, p->radius / 2)); /* was fixed 40 */
+ imm_draw_circle_wire_2d(
+ shdr_pos,
+ x,
+ y,
+ p->radius,
+ /* XXX Dashed shader gives bad results with sets of small segments currently,
+ * temp hack around the issue. :( */
+ max_ii(8, p->radius / 2)); /* was fixed 40 */
- immUnbindProgram();
+ immUnbindProgram();
- GPU_blend(false);
- GPU_line_smooth(false);
- }
+ GPU_blend(false);
+ GPU_line_smooth(false);
+ }
}
/* Turn brush cursor in 3D view on/off */
static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable)
{
- if (p->erasercursor && !enable) {
- /* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
- p->erasercursor = NULL;
- }
- else if (enable && !p->erasercursor) {
- ED_gpencil_toggle_brush_cursor(p->C, false, NULL);
- /* enable cursor */
- p->erasercursor = WM_paint_cursor_activate(
- CTX_wm_manager(C),
- SPACE_TYPE_ANY, RGN_TYPE_ANY,
- NULL, /* XXX */
- gpencil_draw_eraser, p);
- }
+ if (p->erasercursor && !enable) {
+ /* clear cursor */
+ WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
+ p->erasercursor = NULL;
+ }
+ else if (enable && !p->erasercursor) {
+ ED_gpencil_toggle_brush_cursor(p->C, false, NULL);
+ /* enable cursor */
+ p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ NULL, /* XXX */
+ gpencil_draw_eraser,
+ p);
+ }
}
/* Check if tablet eraser is being used (when processing events) */
static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
{
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- return (wmtab->Active == EVT_TABLET_ERASER);
- }
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+ return (wmtab->Active == EVT_TABLET_ERASER);
+ }
- return false;
+ return false;
}
/* ------------------------------- */
static void gpencil_draw_exit(bContext *C, wmOperator *op)
{
- tGPsdata *p = op->customdata;
-
- /* don't assume that operator data exists at all */
- if (p) {
- /* check size of buffer before cleanup, to determine if anything happened here */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- /* turn off radial brush cursor */
- gpencil_draw_toggle_eraser_cursor(C, p, false);
- }
-
- /* always store the new eraser size to be used again next time
- * NOTE: Do this even when not in eraser mode, as eraser may
- * have been toggled at some point.
- */
- if (p->eraser) {
- p->eraser->size = p->radius;
- }
-
- /* restore cursor to indicate end of drawing */
- if (p->sa->spacetype != SPACE_VIEW3D) {
- WM_cursor_modal_restore(CTX_wm_window(C));
- }
- else {
- /* or restore paint if 3D view */
- if ((p) && (p->paintmode == GP_PAINTMODE_ERASER)) {
- WM_cursor_modal_set(p->win, CURSOR_STD);
- }
-
- /* drawing batch cache is dirty now */
- bGPdata *gpd = CTX_data_gpencil_data(C);
- if (gpd) {
- gpd->flag &= ~GP_DATA_STROKE_POLYGON;
- gp_update_cache(gpd);
- }
- }
-
- /* clear undo stack */
- gpencil_undo_finish();
-
- /* cleanup */
- WM_cursor_modal_set(p->win, CURSOR_STD);
-
- gp_paint_cleanup(p);
- gp_session_cleanup(p);
- ED_gpencil_toggle_brush_cursor(C, true, NULL);
-
- /* finally, free the temp data */
- gp_session_free(p);
- p = NULL;
- }
-
- op->customdata = NULL;
+ tGPsdata *p = op->customdata;
+
+ /* don't assume that operator data exists at all */
+ if (p) {
+ /* check size of buffer before cleanup, to determine if anything happened here */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ /* turn off radial brush cursor */
+ gpencil_draw_toggle_eraser_cursor(C, p, false);
+ }
+
+ /* always store the new eraser size to be used again next time
+ * NOTE: Do this even when not in eraser mode, as eraser may
+ * have been toggled at some point.
+ */
+ if (p->eraser) {
+ p->eraser->size = p->radius;
+ }
+
+ /* restore cursor to indicate end of drawing */
+ if (p->sa->spacetype != SPACE_VIEW3D) {
+ WM_cursor_modal_restore(CTX_wm_window(C));
+ }
+ else {
+ /* or restore paint if 3D view */
+ if ((p) && (p->paintmode == GP_PAINTMODE_ERASER)) {
+ WM_cursor_modal_set(p->win, CURSOR_STD);
+ }
+
+ /* drawing batch cache is dirty now */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ if (gpd) {
+ gpd->flag &= ~GP_DATA_STROKE_POLYGON;
+ gp_update_cache(gpd);
+ }
+ }
+
+ /* clear undo stack */
+ gpencil_undo_finish();
+
+ /* cleanup */
+ WM_cursor_modal_set(p->win, CURSOR_STD);
+
+ gp_paint_cleanup(p);
+ gp_session_cleanup(p);
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+
+ /* finally, free the temp data */
+ gp_session_free(p);
+ p = NULL;
+ }
+
+ op->customdata = NULL;
}
static void gpencil_draw_cancel(bContext *C, wmOperator *op)
{
- /* this is just a wrapper around exit() */
- gpencil_draw_exit(C, op);
+ /* this is just a wrapper around exit() */
+ gpencil_draw_exit(C, op);
}
/* ------------------------------- */
-
static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGPsdata *p;
- eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
- ToolSettings *ts = CTX_data_tool_settings(C);
- Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
-
- /* if mode is draw and the brush is eraser, cancel */
- if (paintmode != GP_PAINTMODE_ERASER) {
- if ((brush) && (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
- return 0;
- }
- }
-
- /* check context */
- p = op->customdata = gp_session_initpaint(C, op);
- if ((p == NULL) || (p->status == GP_STATUS_ERROR)) {
- /* something wasn't set correctly in context */
- gpencil_draw_exit(C, op);
- return 0;
- }
-
- /* init painting data */
- gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C));
- if (p->status == GP_STATUS_ERROR) {
- gpencil_draw_exit(C, op);
- return 0;
- }
-
- if (event != NULL) {
- p->keymodifier = event->keymodifier;
- }
- else {
- p->keymodifier = -1;
- }
-
- p->reports = op->reports;
-
- /* everything is now setup ok */
- return 1;
+ tGPsdata *p;
+ eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+
+ /* if mode is draw and the brush is eraser, cancel */
+ if (paintmode != GP_PAINTMODE_ERASER) {
+ if ((brush) && (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
+ return 0;
+ }
+ }
+
+ /* check context */
+ p = op->customdata = gp_session_initpaint(C, op);
+ if ((p == NULL) || (p->status == GP_STATUS_ERROR)) {
+ /* something wasn't set correctly in context */
+ gpencil_draw_exit(C, op);
+ return 0;
+ }
+
+ /* init painting data */
+ gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C));
+ if (p->status == GP_STATUS_ERROR) {
+ gpencil_draw_exit(C, op);
+ return 0;
+ }
+
+ if (event != NULL) {
+ p->keymodifier = event->keymodifier;
+ }
+ else {
+ p->keymodifier = -1;
+ }
+
+ p->reports = op->reports;
+
+ /* everything is now setup ok */
+ return 1;
}
-
/* ------------------------------- */
/* ensure that the correct cursor icon is set */
static void gpencil_draw_cursor_set(tGPsdata *p)
{
- Brush *brush = p->brush;
- if ((p->paintmode == GP_PAINTMODE_ERASER) ||
- (brush->gpencil_tool == GPAINT_TOOL_ERASE))
- {
- WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
- }
- else {
- WM_cursor_modal_set(p->win, CURSOR_NONE);
- }
+ Brush *brush = p->brush;
+ if ((p->paintmode == GP_PAINTMODE_ERASER) || (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
+ WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ }
+ else {
+ WM_cursor_modal_set(p->win, CURSOR_NONE);
+ }
}
/* update UI indicators of status, including cursor and header prints */
static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
{
- /* header prints */
- switch (p->status) {
- case GP_STATUS_IDLING:
- {
- /* print status info */
- switch (p->paintmode) {
- case GP_PAINTMODE_ERASER:
- {
- ED_workspace_status_text(C, IFACE_("Grease Pencil Erase Session: Hold and drag LMB or RMB to erase | "
- "ESC/Enter to end (or click outside this area)"));
- break;
- }
- case GP_PAINTMODE_DRAW_STRAIGHT:
- {
- ED_workspace_status_text(C, IFACE_("Grease Pencil Line Session: Hold and drag LMB to draw | "
- "ESC/Enter to end (or click outside this area)"));
- break;
- }
- case GP_PAINTMODE_SET_CP:
- {
- ED_workspace_status_text(C, IFACE_("Grease Pencil Guides: LMB click and release to place reference point | "
- "Esc/RMB to cancel"));
- break;
- }
- case GP_PAINTMODE_DRAW:
- {
- GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
- if (guide->use_guide) {
- ED_workspace_status_text(C, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | "
- "M key to flip guide | O key to move reference point"));
- }
- else {
- ED_workspace_status_text(C, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw"));
- }
- break;
- }
- case GP_PAINTMODE_DRAW_POLY:
- {
- ED_workspace_status_text(C, IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | "
- "Release Shift/ESC/Enter to end (or click outside this area)"));
- break;
- }
- default: /* unhandled future cases */
- {
- ED_workspace_status_text(C, IFACE_("Grease Pencil Session: ESC/Enter to end (or click outside this area)"));
- break;
- }
- }
- break;
- }
- case GP_STATUS_ERROR:
- case GP_STATUS_DONE:
- {
- /* clear status string */
- ED_workspace_status_text(C, NULL);
- break;
- }
- case GP_STATUS_PAINTING:
- break;
- }
+ /* header prints */
+ switch (p->status) {
+ case GP_STATUS_IDLING: {
+ /* print status info */
+ switch (p->paintmode) {
+ case GP_PAINTMODE_ERASER: {
+ ED_workspace_status_text(
+ C,
+ IFACE_("Grease Pencil Erase Session: Hold and drag LMB or RMB to erase | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ }
+ case GP_PAINTMODE_DRAW_STRAIGHT: {
+ ED_workspace_status_text(
+ C,
+ IFACE_("Grease Pencil Line Session: Hold and drag LMB to draw | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ }
+ case GP_PAINTMODE_SET_CP: {
+ ED_workspace_status_text(
+ C,
+ IFACE_("Grease Pencil Guides: LMB click and release to place reference point | "
+ "Esc/RMB to cancel"));
+ break;
+ }
+ case GP_PAINTMODE_DRAW: {
+ GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
+ if (guide->use_guide) {
+ ED_workspace_status_text(
+ C,
+ IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | "
+ "M key to flip guide | O key to move reference point"));
+ }
+ else {
+ ED_workspace_status_text(
+ C, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw"));
+ }
+ break;
+ }
+ case GP_PAINTMODE_DRAW_POLY: {
+ ED_workspace_status_text(
+ C,
+ IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | "
+ "Release Shift/ESC/Enter to end (or click outside this area)"));
+ break;
+ }
+ default: /* unhandled future cases */
+ {
+ ED_workspace_status_text(
+ C, IFACE_("Grease Pencil Session: ESC/Enter to end (or click outside this area)"));
+ break;
+ }
+ }
+ break;
+ }
+ case GP_STATUS_ERROR:
+ case GP_STATUS_DONE: {
+ /* clear status string */
+ ED_workspace_status_text(C, NULL);
+ break;
+ }
+ case GP_STATUS_PAINTING:
+ break;
+ }
}
/* ------------------------------- */
@@ -2521,401 +2532,399 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
/* create a new stroke point at the point indicated by the painting context */
static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
{
- bGPdata *gpd = p->gpd;
- tGPspoint *pt = NULL;
-
- /* handle drawing/erasing -> test for erasing first */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- /* do 'live' erasing now */
- gp_stroke_doeraser(p);
-
- /* store used values */
- copy_v2_v2(p->mvalo, p->mval);
- p->opressure = p->pressure;
- }
- /* only add current point to buffer if mouse moved (even though we got an event, it might be just noise) */
- else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) {
-
- /* if lazy mouse, interpolate the last and current mouse positions */
- if (GPENCIL_LAZY_MODE(p->brush, p->shift)) {
- float now_mouse[2];
- float last_mouse[2];
- copy_v2_v2(now_mouse, p->mval);
- copy_v2_v2(last_mouse, p->mvalo);
- interp_v2_v2v2(now_mouse, now_mouse, last_mouse, p->brush->smooth_stroke_factor);
- copy_v2_v2(p->mval, now_mouse);
- }
-
- /* try to add point */
- short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
-
- /* handle errors while adding point */
- if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
- /* finish off old stroke */
- gp_paint_strokeend(p);
- /* And start a new one!!! Else, projection errors! */
- gp_paint_initstroke(p, p->paintmode, depsgraph);
-
- /* start a new stroke, starting from previous point */
- /* XXX Must manually reset inittime... */
- /* XXX We only need to reuse previous point if overflow! */
- if (ok == GP_STROKEADD_OVERFLOW) {
- p->inittime = p->ocurtime;
- gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime);
- }
- else {
- p->inittime = p->curtime;
- }
- gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
- }
- else if (ok == GP_STROKEADD_INVALID) {
- /* the painting operation cannot continue... */
- BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke");
- p->status = GP_STATUS_ERROR;
-
- if (G.debug & G_DEBUG)
- printf("Error: Grease-Pencil Paint - Add Point Invalid\n");
- return;
- }
-
- /* store used values */
- copy_v2_v2(p->mvalo, p->mval);
- p->opressure = p->pressure;
- p->ocurtime = p->curtime;
-
- pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1;
- if (p->paintmode != GP_PAINTMODE_ERASER) {
- ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
- }
- }
- else if ((p->brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) &&
- (gpd->runtime.sbuffer_size > 0))
- {
- pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1;
- if (p->paintmode != GP_PAINTMODE_ERASER) {
- ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
- }
- }
+ bGPdata *gpd = p->gpd;
+ tGPspoint *pt = NULL;
+
+ /* handle drawing/erasing -> test for erasing first */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ /* do 'live' erasing now */
+ gp_stroke_doeraser(p);
+
+ /* store used values */
+ copy_v2_v2(p->mvalo, p->mval);
+ p->opressure = p->pressure;
+ }
+ /* only add current point to buffer if mouse moved (even though we got an event, it might be just noise) */
+ else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) {
+
+ /* if lazy mouse, interpolate the last and current mouse positions */
+ if (GPENCIL_LAZY_MODE(p->brush, p->shift)) {
+ float now_mouse[2];
+ float last_mouse[2];
+ copy_v2_v2(now_mouse, p->mval);
+ copy_v2_v2(last_mouse, p->mvalo);
+ interp_v2_v2v2(now_mouse, now_mouse, last_mouse, p->brush->smooth_stroke_factor);
+ copy_v2_v2(p->mval, now_mouse);
+ }
+
+ /* try to add point */
+ short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+
+ /* handle errors while adding point */
+ if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
+ /* finish off old stroke */
+ gp_paint_strokeend(p);
+ /* And start a new one!!! Else, projection errors! */
+ gp_paint_initstroke(p, p->paintmode, depsgraph);
+
+ /* start a new stroke, starting from previous point */
+ /* XXX Must manually reset inittime... */
+ /* XXX We only need to reuse previous point if overflow! */
+ if (ok == GP_STROKEADD_OVERFLOW) {
+ p->inittime = p->ocurtime;
+ gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime);
+ }
+ else {
+ p->inittime = p->curtime;
+ }
+ gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+ }
+ else if (ok == GP_STROKEADD_INVALID) {
+ /* the painting operation cannot continue... */
+ BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke");
+ p->status = GP_STATUS_ERROR;
+
+ if (G.debug & G_DEBUG)
+ printf("Error: Grease-Pencil Paint - Add Point Invalid\n");
+ return;
+ }
+
+ /* store used values */
+ copy_v2_v2(p->mvalo, p->mval);
+ p->opressure = p->pressure;
+ p->ocurtime = p->curtime;
+
+ pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1;
+ if (p->paintmode != GP_PAINTMODE_ERASER) {
+ ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ }
+ }
+ else if ((p->brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) &&
+ (gpd->runtime.sbuffer_size > 0)) {
+ pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1;
+ if (p->paintmode != GP_PAINTMODE_ERASER) {
+ ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ }
+ }
}
/* Helper to rotate point around origin */
-static void gp_rotate_v2_v2v2fl(float v[2], const float p[2], const float origin[2], const float angle)
+static void gp_rotate_v2_v2v2fl(float v[2],
+ const float p[2],
+ const float origin[2],
+ const float angle)
{
- float pt[2];
- float r[2];
- sub_v2_v2v2(pt, p, origin);
- rotate_v2_v2fl(r, pt, angle);
- add_v2_v2v2(v, r, origin);
+ float pt[2];
+ float r[2];
+ sub_v2_v2v2(pt, p, origin);
+ rotate_v2_v2fl(r, pt, angle);
+ add_v2_v2v2(v, r, origin);
}
/* Helper to snap value to grid */
static float gp_snap_to_grid_fl(float v, const float offset, const float spacing)
{
- if (spacing > 0.0f) {
- return roundf(v / spacing) * spacing + fmodf(offset, spacing);
- }
- else {
- return v;
- }
+ if (spacing > 0.0f) {
+ return roundf(v / spacing) * spacing + fmodf(offset, spacing);
+ }
+ else {
+ return v;
+ }
}
-static void UNUSED_FUNCTION(gp_snap_to_grid_v2)(float v[2], const float offset[2], const float spacing)
+static void UNUSED_FUNCTION(gp_snap_to_grid_v2)(float v[2],
+ const float offset[2],
+ const float spacing)
{
- v[0] = gp_snap_to_grid_fl(v[0], offset[0], spacing);
- v[1] = gp_snap_to_grid_fl(v[1], offset[1], spacing);
+ v[0] = gp_snap_to_grid_fl(v[0], offset[0], spacing);
+ v[1] = gp_snap_to_grid_fl(v[1], offset[1], spacing);
}
/* get reference point - screen coords to buffer coords */
static void gp_origin_set(wmOperator *op, const int mval[2])
{
- tGPsdata *p = op->customdata;
- GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
- float origin[2];
- float point[3];
- copy_v2fl_v2i(origin, mval);
- gp_stroke_convertcoords(p, origin, point, NULL);
- if (guide->reference_point == GP_GUIDE_REF_CUSTOM) {
- copy_v3_v3(guide->location, point);
- }
- else if (guide->reference_point == GP_GUIDE_REF_CURSOR) {
- copy_v3_v3(p->scene->cursor.location, point);
- }
+ tGPsdata *p = op->customdata;
+ GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
+ float origin[2];
+ float point[3];
+ copy_v2fl_v2i(origin, mval);
+ gp_stroke_convertcoords(p, origin, point, NULL);
+ if (guide->reference_point == GP_GUIDE_REF_CUSTOM) {
+ copy_v3_v3(guide->location, point);
+ }
+ else if (guide->reference_point == GP_GUIDE_REF_CURSOR) {
+ copy_v3_v3(p->scene->cursor.location, point);
+ }
}
/* get reference point - buffer coords to screen coords */
static void gp_origin_get(tGPsdata *p, float origin[2])
{
- GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
- float location[3];
- if (guide->reference_point == GP_GUIDE_REF_CUSTOM) {
- copy_v3_v3(location, guide->location);
- }
- else if (guide->reference_point == GP_GUIDE_REF_OBJECT &&
- guide->reference_object != NULL)
- {
- copy_v3_v3(location, guide->reference_object->loc);
- }
- else {
- copy_v3_v3(location, p->scene->cursor.location);
- }
- GP_SpaceConversion *gsc = &p->gsc;
- gp_point_3d_to_xy(gsc, p->gpd->runtime.sbuffer_sflag, location, origin);
+ GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
+ float location[3];
+ if (guide->reference_point == GP_GUIDE_REF_CUSTOM) {
+ copy_v3_v3(location, guide->location);
+ }
+ else if (guide->reference_point == GP_GUIDE_REF_OBJECT && guide->reference_object != NULL) {
+ copy_v3_v3(location, guide->reference_object->loc);
+ }
+ else {
+ copy_v3_v3(location, p->scene->cursor.location);
+ }
+ GP_SpaceConversion *gsc = &p->gsc;
+ gp_point_3d_to_xy(gsc, p->gpd->runtime.sbuffer_sflag, location, origin);
}
/* handle draw event */
-static void gpencil_draw_apply_event(bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y)
+static void gpencil_draw_apply_event(
+ bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y)
{
- tGPsdata *p = op->customdata;
- GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
- PointerRNA itemptr;
- float mousef[2];
- int tablet = 0;
-
- /* convert from window-space to area-space mouse coordinates
- * add any x,y override position for fake events
- */
- p->mval[0] = (float)event->mval[0] - x;
- p->mval[1] = (float)event->mval[1] - y;
- p->shift = event->shift;
-
- /* verify direction for straight lines */
- if ((guide->use_guide) || ((event->alt > 0) && (RNA_boolean_get(op->ptr, "disable_straight") == false))) {
- if (p->straight == 0) {
- int dx = (int)fabsf(p->mval[0] - p->mvali[0]);
- int dy = (int)fabsf(p->mval[1] - p->mvali[1]);
- if ((dx > 0) || (dy > 0)) {
- /* store mouse direction */
- if (dx > dy) {
- p->straight = STROKE_HORIZONTAL;
- }
- else if (dx < dy) {
- p->straight = STROKE_VERTICAL;
- }
- }
- }
- }
-
- p->curtime = PIL_check_seconds_timer();
-
- /* handle pressure sensitivity (which is supplied by tablets) */
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
-
- tablet = (wmtab->Active != EVT_TABLET_NONE);
- p->pressure = wmtab->Pressure;
-
- /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
- * The pen has to float over the tablet surface, resulting in
- * zero pressure (T47101). Ignore pressure values if floating
- * (i.e. "effectively zero" pressure), and only when the "active"
- * end is the stylus (i.e. the default when not eraser)
- */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
- p->pressure = 1.0f;
- }
- }
- }
- else {
- /* No tablet data -> No pressure info is available */
- p->pressure = 1.0f;
- }
-
- /* special eraser modes */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- if (event->shift > 0) {
- p->flags |= GP_PAINTFLAG_HARD_ERASER;
- }
- else {
- p->flags &= ~GP_PAINTFLAG_HARD_ERASER;
- }
- if (event->alt > 0) {
- p->flags |= GP_PAINTFLAG_STROKE_ERASER;
- }
- else {
- p->flags &= ~GP_PAINTFLAG_STROKE_ERASER;
- }
- }
-
- /* special exception for start of strokes (i.e. maybe for just a dot) */
- if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
- p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
-
- /* set values */
- copy_v2_v2(p->mvalo, p->mval);
- p->opressure = p->pressure;
- p->inittime = p->ocurtime = p->curtime;
- p->straight = 0;
-
- /* save initial mouse */
- copy_v2_v2(p->mvali, p->mval);
-
- /* calculate once and store snapping distance and origin */
- RegionView3D * rv3d = p->ar->regiondata;
- float scale = 1.0f;
- if (rv3d->is_persp) {
- float vec[3];
- gp_get_3d_reference(p, vec);
- mul_m4_v3(rv3d->persmat, vec);
- scale = vec[2] * rv3d->pixsize;
- }
- else {
- scale = rv3d->pixsize;
- }
- p->guide_spacing = guide->spacing / scale;
- p->half_spacing = p->guide_spacing * 0.5f;
- gp_origin_get(p, p->origin);
-
- /* special exception here for too high pressure values on first touch in
- * windows for some tablets, then we just skip first touch...
- */
- if (tablet && (p->pressure >= 0.99f)) {
- return;
- }
-
- /* special exception for grid snapping
- * it requires direction which needs at least two points
- */
- if (!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP) &&
- guide->use_guide &&
- guide->use_snapping &&
- (guide->type == GP_GUIDE_GRID))
- {
- p->flags |= GP_PAINTFLAG_REQ_VECTOR;
- }
- }
-
- /* wait for vector then add initial point */
- if (p->flags & GP_PAINTFLAG_REQ_VECTOR) {
- if (p->straight == 0) {
- return;
- }
-
- p->flags &= ~GP_PAINTFLAG_REQ_VECTOR;
-
- /* create fake events */
- float tmp[2];
- float pt[2];
- copy_v2_v2(tmp, p->mval);
- sub_v2_v2v2(pt, p->mval, p->mvali);
- gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), pt[0], pt[1]);
- if (len_v2v2(p->mval, p->mvalo)) {
- sub_v2_v2v2(pt, p->mval, p->mvalo);
- gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), pt[0], pt[1]);
- }
- copy_v2_v2(p->mval, tmp);
- }
-
- /* check if stroke is straight or guided */
- if ((p->paintmode != GP_PAINTMODE_ERASER) &&
- ((p->straight) || (guide->use_guide)))
- {
- /* guided stroke */
- if (guide->use_guide) {
- switch (guide->type) {
- default:
- case GP_GUIDE_CIRCULAR:
- {
- float distance;
- distance = len_v2v2(p->mvali, p->origin);
-
- if (guide->use_snapping && (guide->spacing > 0.0f)) {
- distance = gp_snap_to_grid_fl(distance, 0.0f, p->guide_spacing);
- }
-
- dist_ensure_v2_v2fl(p->mval, p->origin, distance);
- break;
- }
- case GP_GUIDE_RADIAL:
- {
- if (guide->use_snapping && (guide->angle_snap > 0.0f)) {
- float point[2];
- float xy[2];
- float angle;
- float half_angle = guide->angle_snap * 0.5f;
- sub_v2_v2v2(xy, p->mvali, p->origin);
- angle = atan2f(xy[1], xy[0]);
- angle += (M_PI * 2.0f);
- angle = fmodf(angle + half_angle, guide->angle_snap);
- angle -= half_angle;
- gp_rotate_v2_v2v2fl(point, p->mvali, p->origin, -angle);
- closest_to_line_v2(p->mval, p->mval, point, p->origin);
- }
- else {
- closest_to_line_v2(p->mval, p->mval, p->mvali, p->origin);
- }
- break;
- }
- case GP_GUIDE_PARALLEL:
- {
- float point[2];
- float unit[2];
- copy_v2_v2(unit, p->mvali);
- unit[0] += 1.0f; /* start from horizontal */
- gp_rotate_v2_v2v2fl(point, unit, p->mvali, guide->angle);
- closest_to_line_v2(p->mval, p->mval, p->mvali, point);
-
- if (guide->use_snapping && (guide->spacing > 0.0f)) {
- gp_rotate_v2_v2v2fl(p->mval, p->mval, p->origin, -guide->angle);
- p->mval[1] = gp_snap_to_grid_fl(p->mval[1] - p->half_spacing, p->origin[1], p->guide_spacing);
- gp_rotate_v2_v2v2fl(p->mval, p->mval, p->origin, guide->angle);
- }
- break;
- }
- case GP_GUIDE_GRID:
- {
- if (guide->use_snapping && (guide->spacing > 0.0f)) {
- float point[2];
- float unit[2];
- float angle;
- copy_v2_v2(unit, p->mvali);
- unit[0] += 1.0f; /* start from horizontal */
- angle = (p->straight == STROKE_VERTICAL) ? M_PI_2 : 0.0f;
- gp_rotate_v2_v2v2fl(point, unit, p->mvali, angle);
- closest_to_line_v2(p->mval, p->mval, p->mvali, point);
-
- if (p->straight == STROKE_HORIZONTAL) {
- p->mval[1] = gp_snap_to_grid_fl(p->mval[1] - p->half_spacing, p->origin[1], p->guide_spacing);
- }
- else {
- p->mval[0] = gp_snap_to_grid_fl(p->mval[0] - p->half_spacing, p->origin[0], p->guide_spacing);
- }
- }
- else if (p->straight == STROKE_HORIZONTAL) {
- p->mval[1] = p->mvali[1]; /* replace y */
- }
- else {
- p->mval[0] = p->mvali[0]; /* replace x */
- }
- break;
- }
- }
- }
- else if (p->straight == STROKE_HORIZONTAL) {
- p->mval[1] = p->mvali[1]; /* replace y */
- }
- else {
- p->mval[0] = p->mvali[0]; /* replace x */
- }
- }
-
- /* fill in stroke data (not actually used directly by gpencil_draw_apply) */
- RNA_collection_add(op->ptr, "stroke", &itemptr);
-
- mousef[0] = p->mval[0];
- mousef[1] = p->mval[1];
- RNA_float_set_array(&itemptr, "mouse", mousef);
- RNA_float_set(&itemptr, "pressure", p->pressure);
- RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN) != 0);
-
- RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
-
- /* apply the current latest drawing point */
- gpencil_draw_apply(C, op, p, depsgraph);
-
- /* force refresh */
- /* just active area for now, since doing whole screen is too slow */
- ED_region_tag_redraw(p->ar);
+ tGPsdata *p = op->customdata;
+ GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
+ PointerRNA itemptr;
+ float mousef[2];
+ int tablet = 0;
+
+ /* convert from window-space to area-space mouse coordinates
+ * add any x,y override position for fake events
+ */
+ p->mval[0] = (float)event->mval[0] - x;
+ p->mval[1] = (float)event->mval[1] - y;
+ p->shift = event->shift;
+
+ /* verify direction for straight lines */
+ if ((guide->use_guide) ||
+ ((event->alt > 0) && (RNA_boolean_get(op->ptr, "disable_straight") == false))) {
+ if (p->straight == 0) {
+ int dx = (int)fabsf(p->mval[0] - p->mvali[0]);
+ int dy = (int)fabsf(p->mval[1] - p->mvali[1]);
+ if ((dx > 0) || (dy > 0)) {
+ /* store mouse direction */
+ if (dx > dy) {
+ p->straight = STROKE_HORIZONTAL;
+ }
+ else if (dx < dy) {
+ p->straight = STROKE_VERTICAL;
+ }
+ }
+ }
+ }
+
+ p->curtime = PIL_check_seconds_timer();
+
+ /* handle pressure sensitivity (which is supplied by tablets) */
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+
+ tablet = (wmtab->Active != EVT_TABLET_NONE);
+ p->pressure = wmtab->Pressure;
+
+ /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
+ * The pen has to float over the tablet surface, resulting in
+ * zero pressure (T47101). Ignore pressure values if floating
+ * (i.e. "effectively zero" pressure), and only when the "active"
+ * end is the stylus (i.e. the default when not eraser)
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
+ p->pressure = 1.0f;
+ }
+ }
+ }
+ else {
+ /* No tablet data -> No pressure info is available */
+ p->pressure = 1.0f;
+ }
+
+ /* special eraser modes */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ if (event->shift > 0) {
+ p->flags |= GP_PAINTFLAG_HARD_ERASER;
+ }
+ else {
+ p->flags &= ~GP_PAINTFLAG_HARD_ERASER;
+ }
+ if (event->alt > 0) {
+ p->flags |= GP_PAINTFLAG_STROKE_ERASER;
+ }
+ else {
+ p->flags &= ~GP_PAINTFLAG_STROKE_ERASER;
+ }
+ }
+
+ /* special exception for start of strokes (i.e. maybe for just a dot) */
+ if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
+ p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
+
+ /* set values */
+ copy_v2_v2(p->mvalo, p->mval);
+ p->opressure = p->pressure;
+ p->inittime = p->ocurtime = p->curtime;
+ p->straight = 0;
+
+ /* save initial mouse */
+ copy_v2_v2(p->mvali, p->mval);
+
+ /* calculate once and store snapping distance and origin */
+ RegionView3D *rv3d = p->ar->regiondata;
+ float scale = 1.0f;
+ if (rv3d->is_persp) {
+ float vec[3];
+ gp_get_3d_reference(p, vec);
+ mul_m4_v3(rv3d->persmat, vec);
+ scale = vec[2] * rv3d->pixsize;
+ }
+ else {
+ scale = rv3d->pixsize;
+ }
+ p->guide_spacing = guide->spacing / scale;
+ p->half_spacing = p->guide_spacing * 0.5f;
+ gp_origin_get(p, p->origin);
+
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets, then we just skip first touch...
+ */
+ if (tablet && (p->pressure >= 0.99f)) {
+ return;
+ }
+
+ /* special exception for grid snapping
+ * it requires direction which needs at least two points
+ */
+ if (!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP) && guide->use_guide &&
+ guide->use_snapping && (guide->type == GP_GUIDE_GRID)) {
+ p->flags |= GP_PAINTFLAG_REQ_VECTOR;
+ }
+ }
+
+ /* wait for vector then add initial point */
+ if (p->flags & GP_PAINTFLAG_REQ_VECTOR) {
+ if (p->straight == 0) {
+ return;
+ }
+
+ p->flags &= ~GP_PAINTFLAG_REQ_VECTOR;
+
+ /* create fake events */
+ float tmp[2];
+ float pt[2];
+ copy_v2_v2(tmp, p->mval);
+ sub_v2_v2v2(pt, p->mval, p->mvali);
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), pt[0], pt[1]);
+ if (len_v2v2(p->mval, p->mvalo)) {
+ sub_v2_v2v2(pt, p->mval, p->mvalo);
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), pt[0], pt[1]);
+ }
+ copy_v2_v2(p->mval, tmp);
+ }
+
+ /* check if stroke is straight or guided */
+ if ((p->paintmode != GP_PAINTMODE_ERASER) && ((p->straight) || (guide->use_guide))) {
+ /* guided stroke */
+ if (guide->use_guide) {
+ switch (guide->type) {
+ default:
+ case GP_GUIDE_CIRCULAR: {
+ float distance;
+ distance = len_v2v2(p->mvali, p->origin);
+
+ if (guide->use_snapping && (guide->spacing > 0.0f)) {
+ distance = gp_snap_to_grid_fl(distance, 0.0f, p->guide_spacing);
+ }
+
+ dist_ensure_v2_v2fl(p->mval, p->origin, distance);
+ break;
+ }
+ case GP_GUIDE_RADIAL: {
+ if (guide->use_snapping && (guide->angle_snap > 0.0f)) {
+ float point[2];
+ float xy[2];
+ float angle;
+ float half_angle = guide->angle_snap * 0.5f;
+ sub_v2_v2v2(xy, p->mvali, p->origin);
+ angle = atan2f(xy[1], xy[0]);
+ angle += (M_PI * 2.0f);
+ angle = fmodf(angle + half_angle, guide->angle_snap);
+ angle -= half_angle;
+ gp_rotate_v2_v2v2fl(point, p->mvali, p->origin, -angle);
+ closest_to_line_v2(p->mval, p->mval, point, p->origin);
+ }
+ else {
+ closest_to_line_v2(p->mval, p->mval, p->mvali, p->origin);
+ }
+ break;
+ }
+ case GP_GUIDE_PARALLEL: {
+ float point[2];
+ float unit[2];
+ copy_v2_v2(unit, p->mvali);
+ unit[0] += 1.0f; /* start from horizontal */
+ gp_rotate_v2_v2v2fl(point, unit, p->mvali, guide->angle);
+ closest_to_line_v2(p->mval, p->mval, p->mvali, point);
+
+ if (guide->use_snapping && (guide->spacing > 0.0f)) {
+ gp_rotate_v2_v2v2fl(p->mval, p->mval, p->origin, -guide->angle);
+ p->mval[1] = gp_snap_to_grid_fl(
+ p->mval[1] - p->half_spacing, p->origin[1], p->guide_spacing);
+ gp_rotate_v2_v2v2fl(p->mval, p->mval, p->origin, guide->angle);
+ }
+ break;
+ }
+ case GP_GUIDE_GRID: {
+ if (guide->use_snapping && (guide->spacing > 0.0f)) {
+ float point[2];
+ float unit[2];
+ float angle;
+ copy_v2_v2(unit, p->mvali);
+ unit[0] += 1.0f; /* start from horizontal */
+ angle = (p->straight == STROKE_VERTICAL) ? M_PI_2 : 0.0f;
+ gp_rotate_v2_v2v2fl(point, unit, p->mvali, angle);
+ closest_to_line_v2(p->mval, p->mval, p->mvali, point);
+
+ if (p->straight == STROKE_HORIZONTAL) {
+ p->mval[1] = gp_snap_to_grid_fl(
+ p->mval[1] - p->half_spacing, p->origin[1], p->guide_spacing);
+ }
+ else {
+ p->mval[0] = gp_snap_to_grid_fl(
+ p->mval[0] - p->half_spacing, p->origin[0], p->guide_spacing);
+ }
+ }
+ else if (p->straight == STROKE_HORIZONTAL) {
+ p->mval[1] = p->mvali[1]; /* replace y */
+ }
+ else {
+ p->mval[0] = p->mvali[0]; /* replace x */
+ }
+ break;
+ }
+ }
+ }
+ else if (p->straight == STROKE_HORIZONTAL) {
+ p->mval[1] = p->mvali[1]; /* replace y */
+ }
+ else {
+ p->mval[0] = p->mvali[0]; /* replace x */
+ }
+ }
+
+ /* fill in stroke data (not actually used directly by gpencil_draw_apply) */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ mousef[0] = p->mval[0];
+ mousef[1] = p->mval[1];
+ RNA_float_set_array(&itemptr, "mouse", mousef);
+ RNA_float_set(&itemptr, "pressure", p->pressure);
+ RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN) != 0);
+
+ RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
+
+ /* apply the current latest drawing point */
+ gpencil_draw_apply(C, op, p, depsgraph);
+
+ /* force refresh */
+ /* just active area for now, since doing whole screen is too slow */
+ ED_region_tag_redraw(p->ar);
}
/* ------------------------------- */
@@ -2923,910 +2932,945 @@ static void gpencil_draw_apply_event(bContext *C, wmOperator *op, const wmEvent
/* operator 'redo' (i.e. after changing some properties, but also for repeat last) */
static int gpencil_draw_exec(bContext *C, wmOperator *op)
{
- tGPsdata *p = NULL;
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
-
- /* printf("GPencil - Starting Re-Drawing\n"); */
-
- /* try to initialize context data needed while drawing */
- if (!gpencil_draw_init(C, op, NULL)) {
- MEM_SAFE_FREE(op->customdata);
- /* printf("\tGP - no valid data\n"); */
- return OPERATOR_CANCELLED;
- }
- else
- p = op->customdata;
-
- /* printf("\tGP - Start redrawing stroke\n"); */
-
- /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement),
- * setting the relevant values in context at each step, then applying
- */
- RNA_BEGIN(op->ptr, itemptr, "stroke")
- {
- float mousef[2];
-
- /* printf("\t\tGP - stroke elem\n"); */
-
- /* get relevant data for this point from stroke */
- RNA_float_get_array(&itemptr, "mouse", mousef);
- p->mval[0] = mousef[0];
- p->mval[1] = mousef[1];
- p->pressure = RNA_float_get(&itemptr, "pressure");
- p->curtime = (double)RNA_float_get(&itemptr, "time") + p->inittime;
-
- if (RNA_boolean_get(&itemptr, "is_start")) {
- /* if first-run flag isn't set already (i.e. not true first stroke),
- * then we must terminate the previous one first before continuing
- */
- if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
- /* TODO: both of these ops can set error-status, but we probably don't need to worry */
- gp_paint_strokeend(p);
- gp_paint_initstroke(p, p->paintmode, depsgraph);
- }
- }
-
- /* if first run, set previous data too */
- if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
- p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
-
- p->mvalo[0] = p->mval[0];
- p->mvalo[1] = p->mval[1];
- p->opressure = p->pressure;
- p->ocurtime = p->curtime;
- }
-
- /* apply this data as necessary now (as per usual) */
- gpencil_draw_apply(C, op, p, depsgraph);
- }
- RNA_END;
-
- /* printf("\tGP - done\n"); */
-
- /* cleanup */
- gpencil_draw_exit(C, op);
-
- /* refreshes */
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
-
- /* done */
- return OPERATOR_FINISHED;
+ tGPsdata *p = NULL;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ /* printf("GPencil - Starting Re-Drawing\n"); */
+
+ /* try to initialize context data needed while drawing */
+ if (!gpencil_draw_init(C, op, NULL)) {
+ MEM_SAFE_FREE(op->customdata);
+ /* printf("\tGP - no valid data\n"); */
+ return OPERATOR_CANCELLED;
+ }
+ else
+ p = op->customdata;
+
+ /* printf("\tGP - Start redrawing stroke\n"); */
+
+ /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement),
+ * setting the relevant values in context at each step, then applying
+ */
+ RNA_BEGIN (op->ptr, itemptr, "stroke") {
+ float mousef[2];
+
+ /* printf("\t\tGP - stroke elem\n"); */
+
+ /* get relevant data for this point from stroke */
+ RNA_float_get_array(&itemptr, "mouse", mousef);
+ p->mval[0] = mousef[0];
+ p->mval[1] = mousef[1];
+ p->pressure = RNA_float_get(&itemptr, "pressure");
+ p->curtime = (double)RNA_float_get(&itemptr, "time") + p->inittime;
+
+ if (RNA_boolean_get(&itemptr, "is_start")) {
+ /* if first-run flag isn't set already (i.e. not true first stroke),
+ * then we must terminate the previous one first before continuing
+ */
+ if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
+ /* TODO: both of these ops can set error-status, but we probably don't need to worry */
+ gp_paint_strokeend(p);
+ gp_paint_initstroke(p, p->paintmode, depsgraph);
+ }
+ }
+
+ /* if first run, set previous data too */
+ if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
+ p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
+
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ p->opressure = p->pressure;
+ p->ocurtime = p->curtime;
+ }
+
+ /* apply this data as necessary now (as per usual) */
+ gpencil_draw_apply(C, op, p, depsgraph);
+ }
+ RNA_END;
+
+ /* printf("\tGP - done\n"); */
+
+ /* cleanup */
+ gpencil_draw_exit(C, op);
+
+ /* refreshes */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* done */
+ return OPERATOR_FINISHED;
}
/* ------------------------------- */
/* handle events for guides */
-static void gpencil_guide_event_handling(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p)
+static void gpencil_guide_event_handling(bContext *C,
+ wmOperator *op,
+ const wmEvent *event,
+ tGPsdata *p)
{
- bool add_notifier = false;
- GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
-
- /* Enter or exit set center point mode */
- if ((event->type == OKEY) && (event->val == KM_RELEASE)) {
- if (p->paintmode == GP_PAINTMODE_DRAW && guide->reference_point != GP_GUIDE_REF_OBJECT) {
- add_notifier = true;
- p->paintmode = GP_PAINTMODE_SET_CP;
- ED_gpencil_toggle_brush_cursor(C, false, NULL);
- }
- }
- /* Freehand mode, turn off speed guide */
- else if ((event->type == VKEY) && (event->val == KM_RELEASE)) {
- guide->use_guide = false;
- add_notifier = true;
- }
- /* Alternate or flip direction */
- else if ((event->type == MKEY) && (event->val == KM_RELEASE)) {
- if (guide->type == GP_GUIDE_CIRCULAR) {
- add_notifier = true;
- guide->type = GP_GUIDE_RADIAL;
- }
- else if (guide->type == GP_GUIDE_RADIAL) {
- add_notifier = true;
- guide->type = GP_GUIDE_CIRCULAR;
- }
- else if (guide->type == GP_GUIDE_PARALLEL) {
- add_notifier = true;
- guide->angle += M_PI_2;
- guide->angle = angle_compat_rad(guide->angle, M_PI);
- }
- else {
- add_notifier = false;
- }
- }
- /* Line guides */
- else if ((event->type == LKEY) && (event->val == KM_RELEASE)) {
- add_notifier = true;
- guide->use_guide = true;
- if (event->ctrl) {
- guide->angle = 0.0f;
- guide->type = GP_GUIDE_PARALLEL;
- }
- else if (event->alt) {
- guide->type = GP_GUIDE_PARALLEL;
- guide->angle = RNA_float_get(op->ptr, "guide_last_angle");
- }
- else {
- guide->type = GP_GUIDE_PARALLEL;
- }
- }
- /* Point guide */
- else if ((event->type == CKEY) && (event->val == KM_RELEASE)) {
- add_notifier = true;
- if (!guide->use_guide) {
- guide->use_guide = true;
- guide->type = GP_GUIDE_CIRCULAR;
- }
- else if (guide->type == GP_GUIDE_CIRCULAR) {
- guide->type = GP_GUIDE_RADIAL;
- }
- else if (guide->type == GP_GUIDE_RADIAL) {
- guide->type = GP_GUIDE_CIRCULAR;
- }
- else {
- guide->type = GP_GUIDE_CIRCULAR;
- }
- }
- /* Change line angle */
- else if (ELEM(event->type, JKEY, KKEY) && (event->val == KM_RELEASE)) {
- add_notifier = true;
- float angle = guide->angle;
- float adjust = (float)M_PI / 180.0f;
- if (event->alt)
- adjust *= 45.0f;
- else if (!event->shift)
- adjust *= 15.0f;
- angle += (event->type == JKEY) ? adjust : -adjust;
- angle = angle_compat_rad(angle, M_PI);
- guide->angle = angle;
- }
-
- if (add_notifier) {
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS | NC_GPENCIL | NA_EDITED, NULL);
- }
+ bool add_notifier = false;
+ GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
+
+ /* Enter or exit set center point mode */
+ if ((event->type == OKEY) && (event->val == KM_RELEASE)) {
+ if (p->paintmode == GP_PAINTMODE_DRAW && guide->reference_point != GP_GUIDE_REF_OBJECT) {
+ add_notifier = true;
+ p->paintmode = GP_PAINTMODE_SET_CP;
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ }
+ }
+ /* Freehand mode, turn off speed guide */
+ else if ((event->type == VKEY) && (event->val == KM_RELEASE)) {
+ guide->use_guide = false;
+ add_notifier = true;
+ }
+ /* Alternate or flip direction */
+ else if ((event->type == MKEY) && (event->val == KM_RELEASE)) {
+ if (guide->type == GP_GUIDE_CIRCULAR) {
+ add_notifier = true;
+ guide->type = GP_GUIDE_RADIAL;
+ }
+ else if (guide->type == GP_GUIDE_RADIAL) {
+ add_notifier = true;
+ guide->type = GP_GUIDE_CIRCULAR;
+ }
+ else if (guide->type == GP_GUIDE_PARALLEL) {
+ add_notifier = true;
+ guide->angle += M_PI_2;
+ guide->angle = angle_compat_rad(guide->angle, M_PI);
+ }
+ else {
+ add_notifier = false;
+ }
+ }
+ /* Line guides */
+ else if ((event->type == LKEY) && (event->val == KM_RELEASE)) {
+ add_notifier = true;
+ guide->use_guide = true;
+ if (event->ctrl) {
+ guide->angle = 0.0f;
+ guide->type = GP_GUIDE_PARALLEL;
+ }
+ else if (event->alt) {
+ guide->type = GP_GUIDE_PARALLEL;
+ guide->angle = RNA_float_get(op->ptr, "guide_last_angle");
+ }
+ else {
+ guide->type = GP_GUIDE_PARALLEL;
+ }
+ }
+ /* Point guide */
+ else if ((event->type == CKEY) && (event->val == KM_RELEASE)) {
+ add_notifier = true;
+ if (!guide->use_guide) {
+ guide->use_guide = true;
+ guide->type = GP_GUIDE_CIRCULAR;
+ }
+ else if (guide->type == GP_GUIDE_CIRCULAR) {
+ guide->type = GP_GUIDE_RADIAL;
+ }
+ else if (guide->type == GP_GUIDE_RADIAL) {
+ guide->type = GP_GUIDE_CIRCULAR;
+ }
+ else {
+ guide->type = GP_GUIDE_CIRCULAR;
+ }
+ }
+ /* Change line angle */
+ else if (ELEM(event->type, JKEY, KKEY) && (event->val == KM_RELEASE)) {
+ add_notifier = true;
+ float angle = guide->angle;
+ float adjust = (float)M_PI / 180.0f;
+ if (event->alt)
+ adjust *= 45.0f;
+ else if (!event->shift)
+ adjust *= 15.0f;
+ angle += (event->type == JKEY) ? adjust : -adjust;
+ angle = angle_compat_rad(angle, M_PI);
+ guide->angle = angle;
+ }
+
+ if (add_notifier) {
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS | NC_GPENCIL | NA_EDITED, NULL);
+ }
}
/* start of interactive drawing part of operator */
static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGPsdata *p = NULL;
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = (bGPdata *)ob->data;
-
- if (G.debug & G_DEBUG)
- printf("GPencil - Starting Drawing\n");
-
- /* support for tablets eraser pen */
- if (gpencil_is_tablet_eraser_active(event)) {
- RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER);
- }
-
- /* do not draw in locked or invisible layers */
- eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
- if (paintmode != GP_PAINTMODE_ERASER) {
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- if ((gpl) && ((gpl->flag & GP_LAYER_LOCKED) || (gpl->flag & GP_LAYER_HIDE))) {
- BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hide");
- return OPERATOR_CANCELLED;
- }
- }
- else {
- /* don't erase empty frames */
- bool has_layer_to_erase = false;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* Skip if layer not editable */
- if (gpencil_layer_is_editable(gpl)) {
- if (gpl->actframe && gpl->actframe->strokes.first) {
- has_layer_to_erase = true;
- break;
- }
- }
- }
- if (!has_layer_to_erase) {
- BKE_report(op->reports, RPT_ERROR, "Nothing to erase or all layers locked");
- return OPERATOR_FINISHED;
- }
- }
-
- /* try to initialize context data needed while drawing */
- if (!gpencil_draw_init(C, op, event)) {
- if (op->customdata)
- MEM_freeN(op->customdata);
- if (G.debug & G_DEBUG)
- printf("\tGP - no valid data\n");
- return OPERATOR_CANCELLED;
- }
- else
- p = op->customdata;
-
- /* TODO: set any additional settings that we can take from the events?
- * TODO? if tablet is erasing, force eraser to be on? */
-
- /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
-
- /* if eraser is on, draw radial aid */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- gpencil_draw_toggle_eraser_cursor(C, p, true);
- }
- else {
- ED_gpencil_toggle_brush_cursor(C, true, NULL);
- }
- /* set cursor
- * NOTE: This may change later (i.e. intentionally via brush toggle,
- * or unintentionally if the user scrolls outside the area)...
- */
- gpencil_draw_cursor_set(p);
-
- /* only start drawing immediately if we're allowed to do so... */
- if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
- /* hotkey invoked - start drawing */
- /* printf("\tGP - set first spot\n"); */
- p->status = GP_STATUS_PAINTING;
-
- /* handle the initial drawing - i.e. for just doing a simple dot */
- gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), 0.0f, 0.0f);
- op->flag |= OP_IS_MODAL_CURSOR_REGION;
- }
- else {
- /* toolbar invoked - don't start drawing yet... */
- /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */
- op->flag |= OP_IS_MODAL_CURSOR_REGION;
- }
-
- /* enable paint mode */
- /* handle speed guide events before drawing inside view3d */
- if (!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP)) {
- gpencil_guide_event_handling(C, op, event, p);
- }
-
- if (ob && (ob->type == OB_GPENCIL) && ((p->gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0)) {
- /* FIXME: use the mode switching operator, this misses notifiers, messages. */
- /* Just set paintmode flag... */
- p->gpd->flag |= GP_DATA_STROKE_PAINTMODE;
- /* disable other GP modes */
- p->gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
- p->gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
- p->gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
- /* set workspace mode */
- ob->restore_mode = ob->mode;
- ob->mode = OB_MODE_PAINT_GPENCIL;
- /* redraw mode on screen */
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
- }
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
-
- /* add a modal handler for this operator, so that we can then draw continuous strokes */
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
+ tGPsdata *p = NULL;
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ if (G.debug & G_DEBUG)
+ printf("GPencil - Starting Drawing\n");
+
+ /* support for tablets eraser pen */
+ if (gpencil_is_tablet_eraser_active(event)) {
+ RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER);
+ }
+
+ /* do not draw in locked or invisible layers */
+ eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
+ if (paintmode != GP_PAINTMODE_ERASER) {
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ if ((gpl) && ((gpl->flag & GP_LAYER_LOCKED) || (gpl->flag & GP_LAYER_HIDE))) {
+ BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hide");
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else {
+ /* don't erase empty frames */
+ bool has_layer_to_erase = false;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* Skip if layer not editable */
+ if (gpencil_layer_is_editable(gpl)) {
+ if (gpl->actframe && gpl->actframe->strokes.first) {
+ has_layer_to_erase = true;
+ break;
+ }
+ }
+ }
+ if (!has_layer_to_erase) {
+ BKE_report(op->reports, RPT_ERROR, "Nothing to erase or all layers locked");
+ return OPERATOR_FINISHED;
+ }
+ }
+
+ /* try to initialize context data needed while drawing */
+ if (!gpencil_draw_init(C, op, event)) {
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ if (G.debug & G_DEBUG)
+ printf("\tGP - no valid data\n");
+ return OPERATOR_CANCELLED;
+ }
+ else
+ p = op->customdata;
+
+ /* TODO: set any additional settings that we can take from the events?
+ * TODO? if tablet is erasing, force eraser to be on? */
+
+ /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
+
+ /* if eraser is on, draw radial aid */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ gpencil_draw_toggle_eraser_cursor(C, p, true);
+ }
+ else {
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ }
+ /* set cursor
+ * NOTE: This may change later (i.e. intentionally via brush toggle,
+ * or unintentionally if the user scrolls outside the area)...
+ */
+ gpencil_draw_cursor_set(p);
+
+ /* only start drawing immediately if we're allowed to do so... */
+ if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
+ /* hotkey invoked - start drawing */
+ /* printf("\tGP - set first spot\n"); */
+ p->status = GP_STATUS_PAINTING;
+
+ /* handle the initial drawing - i.e. for just doing a simple dot */
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), 0.0f, 0.0f);
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+ else {
+ /* toolbar invoked - don't start drawing yet... */
+ /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+
+ /* enable paint mode */
+ /* handle speed guide events before drawing inside view3d */
+ if (!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP)) {
+ gpencil_guide_event_handling(C, op, event, p);
+ }
+
+ if (ob && (ob->type == OB_GPENCIL) && ((p->gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0)) {
+ /* FIXME: use the mode switching operator, this misses notifiers, messages. */
+ /* Just set paintmode flag... */
+ p->gpd->flag |= GP_DATA_STROKE_PAINTMODE;
+ /* disable other GP modes */
+ p->gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ p->gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ p->gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ /* set workspace mode */
+ ob->restore_mode = ob->mode;
+ ob->mode = OB_MODE_PAINT_GPENCIL;
+ /* redraw mode on screen */
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* add a modal handler for this operator, so that we can then draw continuous strokes */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
static bool gpencil_area_exists(bContext *C, ScrArea *sa_test)
{
- bScreen *sc = CTX_wm_screen(C);
- return (BLI_findindex(&sc->areabase, sa_test) != -1);
+ bScreen *sc = CTX_wm_screen(C);
+ return (BLI_findindex(&sc->areabase, sa_test) != -1);
}
static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
{
- tGPsdata *p = op->customdata;
+ tGPsdata *p = op->customdata;
- /* we must check that we're still within the area that we're set up to work from
- * otherwise we could crash (see bug #20586)
- */
- if (CTX_wm_area(C) != p->sa) {
- printf("\t\t\tGP - wrong area execution abort!\n");
- p->status = GP_STATUS_ERROR;
- }
+ /* we must check that we're still within the area that we're set up to work from
+ * otherwise we could crash (see bug #20586)
+ */
+ if (CTX_wm_area(C) != p->sa) {
+ printf("\t\t\tGP - wrong area execution abort!\n");
+ p->status = GP_STATUS_ERROR;
+ }
- /* printf("\t\tGP - start stroke\n"); */
+ /* printf("\t\tGP - start stroke\n"); */
- /* we may need to set up paint env again if we're resuming */
- /* XXX: watch it with the paintmode! in future,
- * it'd be nice to allow changing paint-mode when in sketching-sessions */
+ /* we may need to set up paint env again if we're resuming */
+ /* XXX: watch it with the paintmode! in future,
+ * it'd be nice to allow changing paint-mode when in sketching-sessions */
- if (gp_session_initdata(C, op, p))
- gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C));
+ if (gp_session_initdata(C, op, p))
+ gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C));
- if (p->status != GP_STATUS_ERROR) {
- p->status = GP_STATUS_PAINTING;
- op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
- }
+ if (p->status != GP_STATUS_ERROR) {
+ p->status = GP_STATUS_PAINTING;
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
- return op->customdata;
+ return op->customdata;
}
static void gpencil_stroke_end(wmOperator *op)
{
- tGPsdata *p = op->customdata;
+ tGPsdata *p = op->customdata;
- gp_paint_cleanup(p);
+ gp_paint_cleanup(p);
- gpencil_undo_push(p->gpd);
+ gpencil_undo_push(p->gpd);
- gp_session_cleanup(p);
+ gp_session_cleanup(p);
- p->status = GP_STATUS_IDLING;
- op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
- p->gpd = NULL;
- p->gpl = NULL;
- p->gpf = NULL;
+ p->gpd = NULL;
+ p->gpl = NULL;
+ p->gpf = NULL;
}
/* Move last stroke in the listbase to the head to be drawn below all previous strokes in the layer */
static void gpencil_move_last_stroke_to_back(bContext *C)
{
- /* move last stroke (the polygon) to head of the listbase stroke to draw on back of all previous strokes */
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl, gpl->actframe)) {
- return;
- }
-
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps = gpf->strokes.last;
- if (ELEM(NULL, gps)) {
- return;
- }
-
- BLI_remlink(&gpf->strokes, gps);
- BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
+ /* move last stroke (the polygon) to head of the listbase stroke to draw on back of all previous strokes */
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl, gpl->actframe)) {
+ return;
+ }
+
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps = gpf->strokes.last;
+ if (ELEM(NULL, gps)) {
+ return;
+ }
+
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
}
/* add events for missing mouse movements when the artist draw very fast */
-static void gpencil_add_missing_events(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p)
+static void gpencil_add_missing_events(bContext *C,
+ wmOperator *op,
+ const wmEvent *event,
+ tGPsdata *p)
{
- Brush *brush = p->brush;
- GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
- int input_samples = brush->gpencil_settings->input_samples;
-
- /* ensure sampling when using circular guide */
- if (guide->use_guide && (guide->type == GP_GUIDE_CIRCULAR)) {
- input_samples = GP_MAX_INPUT_SAMPLES;
- }
-
- if (input_samples == 0) {
- return;
- }
-
- RegionView3D *rv3d = p->ar->regiondata;
- float defaultpixsize = rv3d->pixsize * 1000.0f;
- int samples = (GP_MAX_INPUT_SAMPLES - input_samples + 1);
- float thickness = (float)brush->size;
-
- float pt[2], a[2], b[2];
- float vec[3];
- float scale = 1.0f;
-
- /* get pixel scale */
- gp_get_3d_reference(p, vec);
- mul_m4_v3(rv3d->persmat, vec);
- if (rv3d->is_persp) {
- scale = vec[2] * defaultpixsize;
- }
- else {
- scale = defaultpixsize;
- }
-
- /* The thickness of the brush is reduced of thickness to get overlap dots */
- float dot_factor = 0.50f;
- if (samples < 2) {
- dot_factor = 0.05f;
- }
- else if (samples < 4) {
- dot_factor = 0.10f;
- }
- else if (samples < 7) {
- dot_factor = 0.3f;
- }
- else if (samples < 10) {
- dot_factor = 0.4f;
- }
- float factor = ((thickness * dot_factor) / scale) * samples;
-
- copy_v2_v2(a, p->mvalo);
- b[0] = (float)event->mval[0] + 1.0f;
- b[1] = (float)event->mval[1] + 1.0f;
-
- /* get distance in pixels */
- float dist = len_v2v2(a, b);
-
- /* for very small distances, add a half way point */
- if (dist <= 2.0f) {
- interp_v2_v2v2(pt, a, b, 0.5f);
- sub_v2_v2v2(pt, b, pt);
- /* create fake event */
- gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), pt[0], pt[1]);
- }
- else if (dist >= factor) {
- int slices = 2 + (int)((dist - 1.0) / factor);
- float n = 1.0f / slices;
- for (int i = 1; i < slices; i++) {
- interp_v2_v2v2(pt, a, b, n * i);
- sub_v2_v2v2(pt, b, pt);
- /* create fake event */
- gpencil_draw_apply_event(
- C, op, event, CTX_data_depsgraph(C),
- pt[0], pt[1]);
- }
- }
+ Brush *brush = p->brush;
+ GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
+ int input_samples = brush->gpencil_settings->input_samples;
+
+ /* ensure sampling when using circular guide */
+ if (guide->use_guide && (guide->type == GP_GUIDE_CIRCULAR)) {
+ input_samples = GP_MAX_INPUT_SAMPLES;
+ }
+
+ if (input_samples == 0) {
+ return;
+ }
+
+ RegionView3D *rv3d = p->ar->regiondata;
+ float defaultpixsize = rv3d->pixsize * 1000.0f;
+ int samples = (GP_MAX_INPUT_SAMPLES - input_samples + 1);
+ float thickness = (float)brush->size;
+
+ float pt[2], a[2], b[2];
+ float vec[3];
+ float scale = 1.0f;
+
+ /* get pixel scale */
+ gp_get_3d_reference(p, vec);
+ mul_m4_v3(rv3d->persmat, vec);
+ if (rv3d->is_persp) {
+ scale = vec[2] * defaultpixsize;
+ }
+ else {
+ scale = defaultpixsize;
+ }
+
+ /* The thickness of the brush is reduced of thickness to get overlap dots */
+ float dot_factor = 0.50f;
+ if (samples < 2) {
+ dot_factor = 0.05f;
+ }
+ else if (samples < 4) {
+ dot_factor = 0.10f;
+ }
+ else if (samples < 7) {
+ dot_factor = 0.3f;
+ }
+ else if (samples < 10) {
+ dot_factor = 0.4f;
+ }
+ float factor = ((thickness * dot_factor) / scale) * samples;
+
+ copy_v2_v2(a, p->mvalo);
+ b[0] = (float)event->mval[0] + 1.0f;
+ b[1] = (float)event->mval[1] + 1.0f;
+
+ /* get distance in pixels */
+ float dist = len_v2v2(a, b);
+
+ /* for very small distances, add a half way point */
+ if (dist <= 2.0f) {
+ interp_v2_v2v2(pt, a, b, 0.5f);
+ sub_v2_v2v2(pt, b, pt);
+ /* create fake event */
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), pt[0], pt[1]);
+ }
+ else if (dist >= factor) {
+ int slices = 2 + (int)((dist - 1.0) / factor);
+ float n = 1.0f / slices;
+ for (int i = 1; i < slices; i++) {
+ interp_v2_v2v2(pt, a, b, n * i);
+ sub_v2_v2v2(pt, b, pt);
+ /* create fake event */
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), pt[0], pt[1]);
+ }
+ }
}
/* events handling during interactive drawing part of operator */
static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGPsdata *p = op->customdata;
- ToolSettings *ts = CTX_data_tool_settings(C);
- GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
- /* default exit state - pass through to support MMB view nav, etc. */
- int estate = OPERATOR_PASS_THROUGH;
-
- /* if (event->type == NDOF_MOTION)
- * return OPERATOR_PASS_THROUGH;
- * -------------------------------
- * [mce] Not quite what I was looking
- * for, but a good start! GP continues to
- * draw on the screen while the 3D mouse
- * moves the viewpoint. Problem is that
- * the stroke is converted to 3D only after
- * it is finished. This approach should work
- * better in tools that immediately apply
- * in 3D space.
- */
-
- if (p->status == GP_STATUS_IDLING) {
- ARegion *ar = CTX_wm_region(C);
- p->ar = ar;
- }
-
- /* special mode for editing control points */
- if (p->paintmode == GP_PAINTMODE_SET_CP) {
- wmWindow *win = p->win;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
- bool drawmode = false;
-
- switch (event->type) {
- /* cancel */
- case ESCKEY:
- case RIGHTMOUSE:
- {
- if (ELEM(event->val, KM_RELEASE)) {
- drawmode = true;
- }
- break;
- }
- /* set */
- case LEFTMOUSE:
- {
- if (ELEM(event->val, KM_RELEASE)) {
- gp_origin_set(op, event->mval);
- drawmode = true;
- }
- break;
- }
- }
- if (drawmode) {
- p->status = GP_STATUS_IDLING;
- p->paintmode = GP_PAINTMODE_DRAW;
- ED_gpencil_toggle_brush_cursor(C, true, NULL);
- DEG_id_tag_update(&p->scene->id, ID_RECALC_COPY_ON_WRITE);
- }
- else {
- return OPERATOR_RUNNING_MODAL;
- }
- }
-
- /* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */
- if (ISKEYBOARD(event->type)) {
- if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) {
- /* allow some keys:
- * - for frame changing [#33412]
- * - for undo (during sketching sessions)
- */
- }
- else if (ELEM(event->type, PAD0, PAD1, PAD2, PAD3, PAD4, PAD5, PAD6, PAD7, PAD8, PAD9)) {
- /* allow numpad keys so that camera/view manipulations can still take place
- * - PAD0 in particular is really important for Grease Pencil drawing,
- * as animators may be working "to camera", so having this working
- * is essential for ensuring that they can quickly return to that view
- */
- }
- else if ((event->type == BKEY) && (event->val == KM_RELEASE)) {
- /* Add Blank Frame
- * - Since this operator is non-modal, we can just call it here, and keep going...
- * - This operator is especially useful when animating
- */
- WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL);
- estate = OPERATOR_RUNNING_MODAL;
- }
- else if ((!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP))) {
- gpencil_guide_event_handling(C, op, event, p);
- estate = OPERATOR_RUNNING_MODAL;
- }
- else {
- estate = OPERATOR_RUNNING_MODAL;
- }
- }
-
- //printf("\tGP - handle modal event...\n");
-
- /* exit painting mode (and/or end current stroke)
- * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647]
- */
- /* if polyline and release shift must cancel */
- if ((ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) ||
- ((p->paintmode == GP_PAINTMODE_DRAW_POLY) && (event->shift == 0)))
- {
- /* exit() ends the current stroke before cleaning up */
- /* printf("\t\tGP - end of paint op + end of stroke\n"); */
- /* if drawing polygon and enable on back, must move stroke */
- if (ts) {
- if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
- if (p->flags & GP_PAINTFLAG_STROKEADDED) {
- gpencil_move_last_stroke_to_back(C);
- }
- }
- }
-
- p->status = GP_STATUS_DONE;
- estate = OPERATOR_FINISHED;
- }
-
- /* toggle painting mode upon mouse-button movement
- * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
- * - RIGHTMOUSE = polyline (hotkey) / eraser (all)
- * (Disabling RIGHTMOUSE case here results in bugs like [#32647])
- * also making sure we have a valid event value, to not exit too early
- */
- if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) {
- /* if painting, end stroke */
- if (p->status == GP_STATUS_PAINTING) {
- int sketch = 0;
-
- /* basically, this should be mouse-button up = end stroke
- * BUT, polyline drawing is an exception -- all knots should be added during one session
- */
- sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY);
-
- if (sketch) {
- /* end stroke only, and then wait to resume painting soon */
- /* printf("\t\tGP - end stroke only\n"); */
- gpencil_stroke_end(op);
-
- /* If eraser mode is on, turn it off after the stroke finishes
- * NOTE: This just makes it nicer to work with drawing sessions
- */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- p->paintmode = RNA_enum_get(op->ptr, "mode");
-
- /* if the original mode was *still* eraser,
- * we'll let it say for now, since this gives
- * users an opportunity to have visual feedback
- * when adjusting eraser size
- */
- if (p->paintmode != GP_PAINTMODE_ERASER) {
- /* turn off cursor...
- * NOTE: this should be enough for now
- * Just hiding this makes it seem like
- * you can paint again...
- */
- gpencil_draw_toggle_eraser_cursor(C, p, false);
- }
- }
-
- /* we've just entered idling state, so this event was processed (but no others yet) */
- estate = OPERATOR_RUNNING_MODAL;
-
- /* stroke could be smoothed, send notifier to refresh screen */
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
- }
- else {
- /* printf("\t\tGP - end of stroke + op\n"); */
- /* if drawing polygon and enable on back, must move stroke */
- if (ts) {
- if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
- if (p->flags & GP_PAINTFLAG_STROKEADDED) {
- gpencil_move_last_stroke_to_back(C);
- }
- }
- }
- /* drawing batch cache is dirty now */
- gp_update_cache(p->gpd);
-
- p->status = GP_STATUS_DONE;
- estate = OPERATOR_FINISHED;
- }
- }
- else if (event->val == KM_PRESS) {
- bool in_bounds = false;
-
- /* Check if we're outside the bounds of the active region
- * NOTE: An exception here is that if launched from the toolbar,
- * whatever region we're now in should become the new region
- */
- if ((p->ar) && (p->ar->regiontype == RGN_TYPE_TOOLS)) {
- /* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
-
- if (G.debug & G_DEBUG) {
- printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
- current_region, p->ar, event->x, event->y,
- p->sa->totrct.xmin, p->sa->totrct.ymin, p->sa->totrct.xmax, p->sa->totrct.ymax);
- }
-
- if (current_region) {
- /* Assume that since we found the cursor in here, it is in bounds
- * and that this should be the region that we begin drawing in
- */
- p->ar = current_region;
- in_bounds = true;
- }
- else {
- /* Out of bounds, or invalid in some other way */
- p->status = GP_STATUS_ERROR;
- estate = OPERATOR_CANCELLED;
-
- if (G.debug & G_DEBUG)
- printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__);
- }
- }
- else if (p->ar) {
- rcti region_rect;
-
- /* Perform bounds check using */
- ED_region_visible_rect(p->ar, &region_rect);
- in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
- }
- else {
- /* No region */
- p->status = GP_STATUS_ERROR;
- estate = OPERATOR_CANCELLED;
-
- if (G.debug & G_DEBUG)
- printf("%s: No active region found in GP Paint session data\n", __func__);
- }
-
- if (in_bounds) {
- /* Switch paintmode (temporarily if need be) based on which button was used
- * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
- */
- if ((event->type == RIGHTMOUSE) || gpencil_is_tablet_eraser_active(event)) {
- /* turn on eraser */
- p->paintmode = GP_PAINTMODE_ERASER;
- }
- else if (event->type == LEFTMOUSE) {
- /* restore drawmode to default */
- p->paintmode = RNA_enum_get(op->ptr, "mode");
- }
-
- gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
-
- /* not painting, so start stroke (this should be mouse-button down) */
- p = gpencil_stroke_begin(C, op);
-
- if (p->status == GP_STATUS_ERROR) {
- estate = OPERATOR_CANCELLED;
- }
- }
- else if (p->status != GP_STATUS_ERROR) {
- /* User clicked outside bounds of window while idling, so exit paintmode
- * NOTE: Don't enter this case if an error occurred while finding the
- * region (as above)
- */
- /* if drawing polygon and enable on back, must move stroke */
- if (ts) {
- if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
- if (p->flags & GP_PAINTFLAG_STROKEADDED) {
- gpencil_move_last_stroke_to_back(C);
- }
- }
- }
- p->status = GP_STATUS_DONE;
- estate = OPERATOR_FINISHED;
- }
- }
- else if (event->val == KM_RELEASE) {
- p->status = GP_STATUS_IDLING;
- op->flag |= OP_IS_MODAL_CURSOR_REGION;
- ED_region_tag_redraw(p->ar);
- }
- }
-
- /* handle mode-specific events */
- if (p->status == GP_STATUS_PAINTING) {
- /* handle painting mouse-movements? */
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
- /* handle drawing event */
- /* printf("\t\tGP - add point\n"); */
-
- if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) || (guide->use_guide)) {
- gpencil_add_missing_events(C, op, event, p);
- }
-
- gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), 0.0f, 0.0f);
-
- /* finish painting operation if anything went wrong just now */
- if (p->status == GP_STATUS_ERROR) {
- printf("\t\t\t\tGP - add error done!\n");
- estate = OPERATOR_CANCELLED;
- }
- else {
- /* event handled, so just tag as running modal */
- /* printf("\t\t\t\tGP - add point handled!\n"); */
- estate = OPERATOR_RUNNING_MODAL;
- }
- }
- /* eraser size */
- else if ((p->paintmode == GP_PAINTMODE_ERASER) &&
- ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS))
- {
- /* just resize the brush (local version)
- * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys
- */
- /* printf("\t\tGP - resize eraser\n"); */
- switch (event->type) {
- case WHEELDOWNMOUSE: /* larger */
- case PADPLUSKEY:
- p->radius += 5;
- break;
-
- case WHEELUPMOUSE: /* smaller */
- case PADMINUS:
- p->radius -= 5;
-
- if (p->radius <= 0)
- p->radius = 1;
- break;
- }
-
- /* force refresh */
- /* just active area for now, since doing whole screen is too slow */
- ED_region_tag_redraw(p->ar);
-
- /* event handled, so just tag as running modal */
- estate = OPERATOR_RUNNING_MODAL;
- }
- /* there shouldn't be any other events, but just in case there are, let's swallow them
- * (i.e. to prevent problems with undo)
- */
- else {
- /* swallow event to save ourselves trouble */
- estate = OPERATOR_RUNNING_MODAL;
- }
- }
-
- /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
- if (0 == gpencil_area_exists(C, p->sa))
- estate = OPERATOR_CANCELLED;
- else {
- /* update status indicators - cursor, header, etc. */
- gpencil_draw_status_indicators(C, p);
- gpencil_draw_cursor_set(p); /* cursor may have changed outside our control - T44084 */
- }
-
- /* process last operations before exiting */
- switch (estate) {
- case OPERATOR_FINISHED:
- /* store stroke angle for parallel guide */
- if ((p->straight == 0) || (guide->use_guide && (guide->type == GP_GUIDE_CIRCULAR))) {
- float xy[2];
- sub_v2_v2v2(xy, p->mval, p->mvali);
- float angle = atan2f(xy[1], xy[0]);
- RNA_float_set(op->ptr, "guide_last_angle", angle);
- }
- /* one last flush before we're done */
- gpencil_draw_exit(C, op);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
- break;
-
- case OPERATOR_CANCELLED:
- gpencil_draw_exit(C, op);
- break;
-
- case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
- /* event doesn't need to be handled */
+ tGPsdata *p = op->customdata;
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
+ /* default exit state - pass through to support MMB view nav, etc. */
+ int estate = OPERATOR_PASS_THROUGH;
+
+ /* if (event->type == NDOF_MOTION)
+ * return OPERATOR_PASS_THROUGH;
+ * -------------------------------
+ * [mce] Not quite what I was looking
+ * for, but a good start! GP continues to
+ * draw on the screen while the 3D mouse
+ * moves the viewpoint. Problem is that
+ * the stroke is converted to 3D only after
+ * it is finished. This approach should work
+ * better in tools that immediately apply
+ * in 3D space.
+ */
+
+ if (p->status == GP_STATUS_IDLING) {
+ ARegion *ar = CTX_wm_region(C);
+ p->ar = ar;
+ }
+
+ /* special mode for editing control points */
+ if (p->paintmode == GP_PAINTMODE_SET_CP) {
+ wmWindow *win = p->win;
+ WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ bool drawmode = false;
+
+ switch (event->type) {
+ /* cancel */
+ case ESCKEY:
+ case RIGHTMOUSE: {
+ if (ELEM(event->val, KM_RELEASE)) {
+ drawmode = true;
+ }
+ break;
+ }
+ /* set */
+ case LEFTMOUSE: {
+ if (ELEM(event->val, KM_RELEASE)) {
+ gp_origin_set(op, event->mval);
+ drawmode = true;
+ }
+ break;
+ }
+ }
+ if (drawmode) {
+ p->status = GP_STATUS_IDLING;
+ p->paintmode = GP_PAINTMODE_DRAW;
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ DEG_id_tag_update(&p->scene->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ else {
+ return OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ /* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */
+ if (ISKEYBOARD(event->type)) {
+ if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) {
+ /* allow some keys:
+ * - for frame changing [#33412]
+ * - for undo (during sketching sessions)
+ */
+ }
+ else if (ELEM(event->type, PAD0, PAD1, PAD2, PAD3, PAD4, PAD5, PAD6, PAD7, PAD8, PAD9)) {
+ /* allow numpad keys so that camera/view manipulations can still take place
+ * - PAD0 in particular is really important for Grease Pencil drawing,
+ * as animators may be working "to camera", so having this working
+ * is essential for ensuring that they can quickly return to that view
+ */
+ }
+ else if ((event->type == BKEY) && (event->val == KM_RELEASE)) {
+ /* Add Blank Frame
+ * - Since this operator is non-modal, we can just call it here, and keep going...
+ * - This operator is especially useful when animating
+ */
+ WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL);
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ else if ((!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP))) {
+ gpencil_guide_event_handling(C, op, event, p);
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ //printf("\tGP - handle modal event...\n");
+
+ /* exit painting mode (and/or end current stroke)
+ * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647]
+ */
+ /* if polyline and release shift must cancel */
+ if ((ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) ||
+ ((p->paintmode == GP_PAINTMODE_DRAW_POLY) && (event->shift == 0))) {
+ /* exit() ends the current stroke before cleaning up */
+ /* printf("\t\tGP - end of paint op + end of stroke\n"); */
+ /* if drawing polygon and enable on back, must move stroke */
+ if (ts) {
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) &&
+ (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
+ }
+ }
+
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+
+ /* toggle painting mode upon mouse-button movement
+ * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
+ * - RIGHTMOUSE = polyline (hotkey) / eraser (all)
+ * (Disabling RIGHTMOUSE case here results in bugs like [#32647])
+ * also making sure we have a valid event value, to not exit too early
+ */
+ if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) {
+ /* if painting, end stroke */
+ if (p->status == GP_STATUS_PAINTING) {
+ int sketch = 0;
+
+ /* basically, this should be mouse-button up = end stroke
+ * BUT, polyline drawing is an exception -- all knots should be added during one session
+ */
+ sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY);
+
+ if (sketch) {
+ /* end stroke only, and then wait to resume painting soon */
+ /* printf("\t\tGP - end stroke only\n"); */
+ gpencil_stroke_end(op);
+
+ /* If eraser mode is on, turn it off after the stroke finishes
+ * NOTE: This just makes it nicer to work with drawing sessions
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ p->paintmode = RNA_enum_get(op->ptr, "mode");
+
+ /* if the original mode was *still* eraser,
+ * we'll let it say for now, since this gives
+ * users an opportunity to have visual feedback
+ * when adjusting eraser size
+ */
+ if (p->paintmode != GP_PAINTMODE_ERASER) {
+ /* turn off cursor...
+ * NOTE: this should be enough for now
+ * Just hiding this makes it seem like
+ * you can paint again...
+ */
+ gpencil_draw_toggle_eraser_cursor(C, p, false);
+ }
+ }
+
+ /* we've just entered idling state, so this event was processed (but no others yet) */
+ estate = OPERATOR_RUNNING_MODAL;
+
+ /* stroke could be smoothed, send notifier to refresh screen */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ }
+ else {
+ /* printf("\t\tGP - end of stroke + op\n"); */
+ /* if drawing polygon and enable on back, must move stroke */
+ if (ts) {
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) &&
+ (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
+ }
+ }
+ /* drawing batch cache is dirty now */
+ gp_update_cache(p->gpd);
+
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+ }
+ else if (event->val == KM_PRESS) {
+ bool in_bounds = false;
+
+ /* Check if we're outside the bounds of the active region
+ * NOTE: An exception here is that if launched from the toolbar,
+ * whatever region we're now in should become the new region
+ */
+ if ((p->ar) && (p->ar->regiontype == RGN_TYPE_TOOLS)) {
+ /* Change to whatever region is now under the mouse */
+ ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
+
+ if (G.debug & G_DEBUG) {
+ printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
+ current_region,
+ p->ar,
+ event->x,
+ event->y,
+ p->sa->totrct.xmin,
+ p->sa->totrct.ymin,
+ p->sa->totrct.xmax,
+ p->sa->totrct.ymax);
+ }
+
+ if (current_region) {
+ /* Assume that since we found the cursor in here, it is in bounds
+ * and that this should be the region that we begin drawing in
+ */
+ p->ar = current_region;
+ in_bounds = true;
+ }
+ else {
+ /* Out of bounds, or invalid in some other way */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__);
+ }
+ }
+ else if (p->ar) {
+ rcti region_rect;
+
+ /* Perform bounds check using */
+ ED_region_visible_rect(p->ar, &region_rect);
+ in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
+ }
+ else {
+ /* No region */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: No active region found in GP Paint session data\n", __func__);
+ }
+
+ if (in_bounds) {
+ /* Switch paintmode (temporarily if need be) based on which button was used
+ * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
+ */
+ if ((event->type == RIGHTMOUSE) || gpencil_is_tablet_eraser_active(event)) {
+ /* turn on eraser */
+ p->paintmode = GP_PAINTMODE_ERASER;
+ }
+ else if (event->type == LEFTMOUSE) {
+ /* restore drawmode to default */
+ p->paintmode = RNA_enum_get(op->ptr, "mode");
+ }
+
+ gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
+
+ /* not painting, so start stroke (this should be mouse-button down) */
+ p = gpencil_stroke_begin(C, op);
+
+ if (p->status == GP_STATUS_ERROR) {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ else if (p->status != GP_STATUS_ERROR) {
+ /* User clicked outside bounds of window while idling, so exit paintmode
+ * NOTE: Don't enter this case if an error occurred while finding the
+ * region (as above)
+ */
+ /* if drawing polygon and enable on back, must move stroke */
+ if (ts) {
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) &&
+ (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
+ }
+ }
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+ }
+ else if (event->val == KM_RELEASE) {
+ p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ ED_region_tag_redraw(p->ar);
+ }
+ }
+
+ /* handle mode-specific events */
+ if (p->status == GP_STATUS_PAINTING) {
+ /* handle painting mouse-movements? */
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
+ /* handle drawing event */
+ /* printf("\t\tGP - add point\n"); */
+
+ if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) || (guide->use_guide)) {
+ gpencil_add_missing_events(C, op, event, p);
+ }
+
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), 0.0f, 0.0f);
+
+ /* finish painting operation if anything went wrong just now */
+ if (p->status == GP_STATUS_ERROR) {
+ printf("\t\t\t\tGP - add error done!\n");
+ estate = OPERATOR_CANCELLED;
+ }
+ else {
+ /* event handled, so just tag as running modal */
+ /* printf("\t\t\t\tGP - add point handled!\n"); */
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ }
+ /* eraser size */
+ else if ((p->paintmode == GP_PAINTMODE_ERASER) &&
+ ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS)) {
+ /* just resize the brush (local version)
+ * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys
+ */
+ /* printf("\t\tGP - resize eraser\n"); */
+ switch (event->type) {
+ case WHEELDOWNMOUSE: /* larger */
+ case PADPLUSKEY:
+ p->radius += 5;
+ break;
+
+ case WHEELUPMOUSE: /* smaller */
+ case PADMINUS:
+ p->radius -= 5;
+
+ if (p->radius <= 0)
+ p->radius = 1;
+ break;
+ }
+
+ /* force refresh */
+ /* just active area for now, since doing whole screen is too slow */
+ ED_region_tag_redraw(p->ar);
+
+ /* event handled, so just tag as running modal */
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ /* there shouldn't be any other events, but just in case there are, let's swallow them
+ * (i.e. to prevent problems with undo)
+ */
+ else {
+ /* swallow event to save ourselves trouble */
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
+ if (0 == gpencil_area_exists(C, p->sa))
+ estate = OPERATOR_CANCELLED;
+ else {
+ /* update status indicators - cursor, header, etc. */
+ gpencil_draw_status_indicators(C, p);
+ gpencil_draw_cursor_set(p); /* cursor may have changed outside our control - T44084 */
+ }
+
+ /* process last operations before exiting */
+ switch (estate) {
+ case OPERATOR_FINISHED:
+ /* store stroke angle for parallel guide */
+ if ((p->straight == 0) || (guide->use_guide && (guide->type == GP_GUIDE_CIRCULAR))) {
+ float xy[2];
+ sub_v2_v2v2(xy, p->mval, p->mvali);
+ float angle = atan2f(xy[1], xy[0]);
+ RNA_float_set(op->ptr, "guide_last_angle", angle);
+ }
+ /* one last flush before we're done */
+ gpencil_draw_exit(C, op);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ break;
+
+ case OPERATOR_CANCELLED:
+ gpencil_draw_exit(C, op);
+ break;
+
+ case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
+ /* event doesn't need to be handled */
#if 0
- printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n",
- event->type, event->type == MIDDLEMOUSE, event->type == MOUSEMOVE);
+ printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n",
+ event->type, event->type == MIDDLEMOUSE, event->type == MOUSEMOVE);
#endif
- break;
- }
+ break;
+ }
- /* return status code */
- return estate;
+ /* return status code */
+ return estate;
}
/* ------------------------------- */
static const EnumPropertyItem prop_gpencil_drawmodes[] = {
- {GP_PAINTMODE_DRAW, "DRAW", 0, "Draw Freehand", "Draw freehand stroke(s)"},
- {GP_PAINTMODE_DRAW_STRAIGHT, "DRAW_STRAIGHT", 0, "Draw Straight Lines", "Draw straight line segment(s)"},
- {GP_PAINTMODE_DRAW_POLY, "DRAW_POLY", 0, "Draw Poly Line", "Click to place endpoints of straight line segments (connected)"},
- {GP_PAINTMODE_ERASER, "ERASER", 0, "Eraser", "Erase Grease Pencil strokes"},
- {0, NULL, 0, NULL, NULL},
+ {GP_PAINTMODE_DRAW, "DRAW", 0, "Draw Freehand", "Draw freehand stroke(s)"},
+ {GP_PAINTMODE_DRAW_STRAIGHT,
+ "DRAW_STRAIGHT",
+ 0,
+ "Draw Straight Lines",
+ "Draw straight line segment(s)"},
+ {GP_PAINTMODE_DRAW_POLY,
+ "DRAW_POLY",
+ 0,
+ "Draw Poly Line",
+ "Click to place endpoints of straight line segments (connected)"},
+ {GP_PAINTMODE_ERASER, "ERASER", 0, "Eraser", "Erase Grease Pencil strokes"},
+ {0, NULL, 0, NULL, NULL},
};
void GPENCIL_OT_draw(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Grease Pencil Draw";
- ot->idname = "GPENCIL_OT_draw";
- ot->description = "Draw a new stroke in the active Grease Pencil Object";
-
- /* api callbacks */
- ot->exec = gpencil_draw_exec;
- ot->invoke = gpencil_draw_invoke;
- ot->modal = gpencil_draw_modal;
- ot->cancel = gpencil_draw_cancel;
- ot->poll = gpencil_draw_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* settings for drawing */
- ot->prop = RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
-
- prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- /* NOTE: wait for input is enabled by default,
- * so that all UI code can work properly without needing users to know about this */
- prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Wait for first click instead of painting immediately");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- prop = RNA_def_boolean(ot->srna, "disable_straight", false, "No Straight lines", "Disable key for straight lines");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_boolean(ot->srna, "disable_fill", false, "No Fill Areas", "Disable fill to use stroke as fill boundary");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- /* guides */
- prop = RNA_def_float(ot->srna, "guide_last_angle", 0.0f, -10000.0f, 10000.0f, "Angle", "Speed guide angle", -10000.0f, 10000.0f);
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Grease Pencil Draw";
+ ot->idname = "GPENCIL_OT_draw";
+ ot->description = "Draw a new stroke in the active Grease Pencil Object";
+
+ /* api callbacks */
+ ot->exec = gpencil_draw_exec;
+ ot->invoke = gpencil_draw_invoke;
+ ot->modal = gpencil_draw_modal;
+ ot->cancel = gpencil_draw_cancel;
+ ot->poll = gpencil_draw_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* settings for drawing */
+ ot->prop = RNA_def_enum(
+ ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
+
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ /* NOTE: wait for input is enabled by default,
+ * so that all UI code can work properly without needing users to know about this */
+ prop = RNA_def_boolean(ot->srna,
+ "wait_for_input",
+ true,
+ "Wait for Input",
+ "Wait for first click instead of painting immediately");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(
+ ot->srna, "disable_straight", false, "No Straight lines", "Disable key for straight lines");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna,
+ "disable_fill",
+ false,
+ "No Fill Areas",
+ "Disable fill to use stroke as fill boundary");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ /* guides */
+ prop = RNA_def_float(ot->srna,
+ "guide_last_angle",
+ 0.0f,
+ -10000.0f,
+ 10000.0f,
+ "Angle",
+ "Speed guide angle",
+ -10000.0f,
+ 10000.0f);
}
/* additional OPs */
static int gpencil_guide_rotate(bContext *C, wmOperator *op)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- GP_Sculpt_Guide *guide = &ts->gp_sculpt.guide;
- float angle = RNA_float_get(op->ptr, "angle");
- bool increment = RNA_boolean_get(op->ptr, "increment");
- if (increment) {
- float oldangle = guide->angle;
- oldangle += angle;
- guide->angle = angle_compat_rad(oldangle, M_PI);
- }
- else {
- guide->angle = angle_compat_rad(angle, M_PI);
- }
-
- return OPERATOR_FINISHED;
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ GP_Sculpt_Guide *guide = &ts->gp_sculpt.guide;
+ float angle = RNA_float_get(op->ptr, "angle");
+ bool increment = RNA_boolean_get(op->ptr, "increment");
+ if (increment) {
+ float oldangle = guide->angle;
+ oldangle += angle;
+ guide->angle = angle_compat_rad(oldangle, M_PI);
+ }
+ else {
+ guide->angle = angle_compat_rad(angle, M_PI);
+ }
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_guide_rotate(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Rotate Guide Angle";
- ot->idname = "GPENCIL_OT_guide_rotate";
- ot->description = "Rotate guide angle";
+ /* identifiers */
+ ot->name = "Rotate Guide Angle";
+ ot->idname = "GPENCIL_OT_guide_rotate";
+ ot->description = "Rotate guide angle";
- /* api callbacks */
- ot->exec = gpencil_guide_rotate;
+ /* api callbacks */
+ ot->exec = gpencil_guide_rotate;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- PropertyRNA *prop;
+ PropertyRNA *prop;
- prop = RNA_def_boolean(ot->srna, "increment", true, "Increment", "Increment angle");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_float(ot->srna, "angle", 0.0f, -10000.0f, 10000.0f, "Angle", "Guide angle", -10000.0f, 10000.0f);
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "increment", true, "Increment", "Increment angle");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_float(
+ ot->srna, "angle", 0.0f, -10000.0f, 10000.0f, "Angle", "Guide angle", -10000.0f, 10000.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 374dbbf4d9c..f178d232376 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -97,193 +97,201 @@
#define SELECT_CP2 3
#define SELECT_END 4
-#define BIG_SIZE_CTL 15
-#define MID_SIZE_CTL 10
-#define SMALL_SIZE_CTL 8
+#define BIG_SIZE_CTL 15
+#define MID_SIZE_CTL 10
+#define SMALL_SIZE_CTL 8
#define MOVE_NONE 0
#define MOVE_ENDS 1
#define MOVE_CP 2
- /* ************************************************ */
- /* Core/Shared Utilities */
+/* ************************************************ */
+/* Core/Shared Utilities */
/* clear the session buffers (call this before AND after a paint operation) */
static void gp_session_validatebuffer(tGPDprimitive *p)
{
- bGPdata *gpd = p->gpd;
-
- /* clear memory of buffer (or allocate it if starting a new session) */
- if (gpd->runtime.sbuffer) {
- memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
- }
- else {
- gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
- }
-
- /* reset indices */
- gpd->runtime.sbuffer_size = 0;
-
- /* reset flags */
- gpd->runtime.sbuffer_sflag = 0;
- gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
-
- if (ELEM(p->type, GP_STROKE_BOX, GP_STROKE_CIRCLE))
- gpd->runtime.sbuffer_sflag |= GP_STROKE_CYCLIC;
+ bGPdata *gpd = p->gpd;
+
+ /* clear memory of buffer (or allocate it if starting a new session) */
+ if (gpd->runtime.sbuffer) {
+ memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
+ }
+ else {
+ gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX,
+ "gp_session_strokebuffer");
+ }
+
+ /* reset indices */
+ gpd->runtime.sbuffer_size = 0;
+
+ /* reset flags */
+ gpd->runtime.sbuffer_sflag = 0;
+ gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
+
+ if (ELEM(p->type, GP_STROKE_BOX, GP_STROKE_CIRCLE))
+ gpd->runtime.sbuffer_sflag |= GP_STROKE_CYCLIC;
}
static void gp_init_colors(tGPDprimitive *p)
{
- bGPdata *gpd = p->gpd;
- Brush *brush = p->brush;
-
- MaterialGPencilStyle *gp_style = NULL;
-
- /* use brush material */
- p->mat = BKE_gpencil_object_material_ensure_from_active_input_brush(p->bmain, p->ob, brush);
-
- /* assign color information to temp data */
- gp_style = p->mat->gp_style;
- if (gp_style) {
-
- /* set colors */
- if (gp_style->flag & GP_STYLE_STROKE_SHOW) {
- copy_v4_v4(gpd->runtime.scolor, gp_style->stroke_rgba);
- }
- else {
- /* if no stroke, use fill */
- copy_v4_v4(gpd->runtime.scolor, gp_style->fill_rgba);
- }
-
- copy_v4_v4(gpd->runtime.sfill, gp_style->fill_rgba);
- /* add some alpha to make easy the filling without hide strokes */
- if (gpd->runtime.sfill[3] > 0.8f) {
- gpd->runtime.sfill[3] = 0.8f;
- }
-
- gpd->runtime.mode = (short)gp_style->mode;
- gpd->runtime.bstroke_style = gp_style->stroke_style;
- gpd->runtime.bfill_style = gp_style->fill_style;
- }
+ bGPdata *gpd = p->gpd;
+ Brush *brush = p->brush;
+
+ MaterialGPencilStyle *gp_style = NULL;
+
+ /* use brush material */
+ p->mat = BKE_gpencil_object_material_ensure_from_active_input_brush(p->bmain, p->ob, brush);
+
+ /* assign color information to temp data */
+ gp_style = p->mat->gp_style;
+ if (gp_style) {
+
+ /* set colors */
+ if (gp_style->flag & GP_STYLE_STROKE_SHOW) {
+ copy_v4_v4(gpd->runtime.scolor, gp_style->stroke_rgba);
+ }
+ else {
+ /* if no stroke, use fill */
+ copy_v4_v4(gpd->runtime.scolor, gp_style->fill_rgba);
+ }
+
+ copy_v4_v4(gpd->runtime.sfill, gp_style->fill_rgba);
+ /* add some alpha to make easy the filling without hide strokes */
+ if (gpd->runtime.sfill[3] > 0.8f) {
+ gpd->runtime.sfill[3] = 0.8f;
+ }
+
+ gpd->runtime.mode = (short)gp_style->mode;
+ gpd->runtime.bstroke_style = gp_style->stroke_style;
+ gpd->runtime.bfill_style = gp_style->fill_style;
+ }
}
/* Helper to square a primitive */
static void gpencil_primitive_to_square(tGPDprimitive *tgpi, const float x, const float y)
{
- float w = fabsf(x);
- float h = fabsf(y);
- if ((x > 0 && y > 0) || (x < 0 && y < 0)) {
- if (w > h)
- tgpi->end[1] = tgpi->origin[1] + x;
- else
- tgpi->end[0] = tgpi->origin[0] + y;
- }
- else {
- if (w > h)
- tgpi->end[1] = tgpi->origin[1] - x;
- else
- tgpi->end[0] = tgpi->origin[0] - y;
- }
+ float w = fabsf(x);
+ float h = fabsf(y);
+ if ((x > 0 && y > 0) || (x < 0 && y < 0)) {
+ if (w > h)
+ tgpi->end[1] = tgpi->origin[1] + x;
+ else
+ tgpi->end[0] = tgpi->origin[0] + y;
+ }
+ else {
+ if (w > h)
+ tgpi->end[1] = tgpi->origin[1] - x;
+ else
+ tgpi->end[0] = tgpi->origin[0] - y;
+ }
}
/* Helper to rotate point around origin */
-static void gp_rotate_v2_v2v2fl(float v[2], const float p[2], const float origin[2], const float angle)
+static void gp_rotate_v2_v2v2fl(float v[2],
+ const float p[2],
+ const float origin[2],
+ const float angle)
{
- float pt[2];
- float r[2];
- sub_v2_v2v2(pt, p, origin);
- rotate_v2_v2fl(r, pt, angle);
- add_v2_v2v2(v, r, origin);
+ float pt[2];
+ float r[2];
+ sub_v2_v2v2(pt, p, origin);
+ rotate_v2_v2fl(r, pt, angle);
+ add_v2_v2v2(v, r, origin);
}
/* Helper to rotate line around line centre */
-static void gp_primitive_rotate_line(float va[2], float vb[2], const float a[2], const float b[2], const float angle)
+static void gp_primitive_rotate_line(
+ float va[2], float vb[2], const float a[2], const float b[2], const float angle)
{
- float midpoint[2];
- mid_v2_v2v2(midpoint, a, b);
- gp_rotate_v2_v2v2fl(va, a, midpoint, angle);
- gp_rotate_v2_v2v2fl(vb, b, midpoint, angle);
+ float midpoint[2];
+ mid_v2_v2v2(midpoint, a, b);
+ gp_rotate_v2_v2v2fl(va, a, midpoint, angle);
+ gp_rotate_v2_v2v2fl(vb, b, midpoint, angle);
}
/* Helper to update cps */
static void gp_primitive_update_cps(tGPDprimitive *tgpi)
{
- if (!tgpi->curve) {
- mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end);
- copy_v2_v2(tgpi->cp1, tgpi->midpoint);
- copy_v2_v2(tgpi->cp2, tgpi->cp1);
- }
- else if (tgpi->type == GP_STROKE_CURVE) {
- mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end);
- copy_v2_v2(tgpi->cp1, tgpi->midpoint);
- copy_v2_v2(tgpi->cp2, tgpi->cp1);
- }
- else if (tgpi->type == GP_STROKE_ARC) {
- if (tgpi->flip) {
- gp_primitive_rotate_line(tgpi->cp1, tgpi->cp2, tgpi->start, tgpi->end, M_PI_2);
- }
- else {
- gp_primitive_rotate_line(tgpi->cp1, tgpi->cp2, tgpi->end, tgpi->start, M_PI_2);
- }
- }
+ if (!tgpi->curve) {
+ mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end);
+ copy_v2_v2(tgpi->cp1, tgpi->midpoint);
+ copy_v2_v2(tgpi->cp2, tgpi->cp1);
+ }
+ else if (tgpi->type == GP_STROKE_CURVE) {
+ mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end);
+ copy_v2_v2(tgpi->cp1, tgpi->midpoint);
+ copy_v2_v2(tgpi->cp2, tgpi->cp1);
+ }
+ else if (tgpi->type == GP_STROKE_ARC) {
+ if (tgpi->flip) {
+ gp_primitive_rotate_line(tgpi->cp1, tgpi->cp2, tgpi->start, tgpi->end, M_PI_2);
+ }
+ else {
+ gp_primitive_rotate_line(tgpi->cp1, tgpi->cp2, tgpi->end, tgpi->start, M_PI_2);
+ }
+ }
}
/* Helper to reflect point */
-static void UNUSED_FUNCTION(gp_reflect_point_v2_v2v2v2)(
- float va[2], const float p[2], const float a[2], const float b[2])
+static void UNUSED_FUNCTION(gp_reflect_point_v2_v2v2v2)(float va[2],
+ const float p[2],
+ const float a[2],
+ const float b[2])
{
- float point[2];
- closest_to_line_v2(point, p, a, b);
- va[0] = point[0] - (p[0] - point[0]);
- va[1] = point[1] - (p[1] - point[1]);
+ float point[2];
+ closest_to_line_v2(point, p, a, b);
+ va[0] = point[0] - (p[0] - point[0]);
+ va[1] = point[1] - (p[1] - point[1]);
}
- /* Poll callback for primitive operators */
+/* Poll callback for primitive operators */
static bool gpencil_primitive_add_poll(bContext *C)
{
- /* only 3D view */
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype != SPACE_VIEW3D) {
- return 0;
- }
-
- /* need data to create primitive */
- bGPdata *gpd = CTX_data_gpencil_data(C);
- if (gpd == NULL) {
- return 0;
- }
-
- /* only in edit and paint modes
- * - paint as it's the "drawing/creation mode"
- * - edit as this is more of an atomic editing operation
- * (similar to copy/paste), and also for consistency
- */
- if ((gpd->flag & (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE)) == 0) {
- CTX_wm_operator_poll_msg_set(C, "Primitives can only be added in Draw or Edit modes");
- return 0;
- }
-
- /* don't allow operator to function if the active layer is locked/hidden
- * (BUT, if there isn't an active layer, we are free to add new layer when the time comes)
- */
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- if ((gpl) && (gpl->flag & (GP_LAYER_LOCKED | GP_LAYER_HIDE))) {
- CTX_wm_operator_poll_msg_set(C, "Primitives cannot be added as active layer is locked or hidden");
- return 0;
- }
-
- return 1;
+ /* only 3D view */
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype != SPACE_VIEW3D) {
+ return 0;
+ }
+
+ /* need data to create primitive */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ if (gpd == NULL) {
+ return 0;
+ }
+
+ /* only in edit and paint modes
+ * - paint as it's the "drawing/creation mode"
+ * - edit as this is more of an atomic editing operation
+ * (similar to copy/paste), and also for consistency
+ */
+ if ((gpd->flag & (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE)) == 0) {
+ CTX_wm_operator_poll_msg_set(C, "Primitives can only be added in Draw or Edit modes");
+ return 0;
+ }
+
+ /* don't allow operator to function if the active layer is locked/hidden
+ * (BUT, if there isn't an active layer, we are free to add new layer when the time comes)
+ */
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ if ((gpl) && (gpl->flag & (GP_LAYER_LOCKED | GP_LAYER_HIDE))) {
+ CTX_wm_operator_poll_msg_set(C,
+ "Primitives cannot be added as active layer is locked or hidden");
+ return 0;
+ }
+
+ return 1;
}
/* Allocate memory to stroke, adds MAX_EDGES on every call */
static void gpencil_primitive_allocate_memory(tGPDprimitive *tgpi)
{
- tgpi->point_count += (tgpi->type == GP_STROKE_BOX) ? (MAX_EDGES * 4 + 1) : (MAX_EDGES + 1);
- bGPDstroke *gpsf = tgpi->gpf->strokes.first;
- gpsf->points = MEM_reallocN(gpsf->points, sizeof(bGPDspoint) * tgpi->point_count);
- if (gpsf->dvert != NULL)
- gpsf->dvert = MEM_reallocN(gpsf->dvert, sizeof(MDeformVert) * tgpi->point_count);
- tgpi->points = MEM_reallocN(tgpi->points, sizeof(tGPspoint) * tgpi->point_count);
+ tgpi->point_count += (tgpi->type == GP_STROKE_BOX) ? (MAX_EDGES * 4 + 1) : (MAX_EDGES + 1);
+ bGPDstroke *gpsf = tgpi->gpf->strokes.first;
+ gpsf->points = MEM_reallocN(gpsf->points, sizeof(bGPDspoint) * tgpi->point_count);
+ if (gpsf->dvert != NULL)
+ gpsf->dvert = MEM_reallocN(gpsf->dvert, sizeof(MDeformVert) * tgpi->point_count);
+ tgpi->points = MEM_reallocN(tgpi->points, sizeof(tGPspoint) * tgpi->point_count);
}
/* ****************** Primitive Interactive *********************** */
@@ -291,1510 +299,1511 @@ static void gpencil_primitive_allocate_memory(tGPDprimitive *tgpi)
/* Helper: Create internal strokes primitives data */
static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
-
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
-
- /* if brush doesn't exist, create a new one */
- Paint *paint = &ts->gp_paint->paint;
- /* if not exist, create a new one */
- if (paint->brush == NULL) {
- /* create new brushes */
- BKE_brush_gpencil_presets(C);
- }
- tgpi->brush = paint->brush;
-
- /* if layer doesn't exist, create a new one */
- if (gpl == NULL) {
- gpl = BKE_gpencil_layer_addnew(tgpi->gpd, DATA_("Primitives"), true);
- }
- tgpi->gpl = gpl;
-
- /* create a new temporary frame */
- tgpi->gpf = MEM_callocN(sizeof(bGPDframe), "Temp bGPDframe");
- tgpi->gpf->framenum = tgpi->cframe = cfra_eval;
-
- /* create new temp stroke */
- bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "Temp bGPDstroke");
- gps->thickness = 2.0f;
- gps->gradient_f = 1.0f;
- gps->gradient_s[0] = 1.0f;
- gps->gradient_s[1] = 1.0f;
- gps->inittime = 0.0f;
-
- /* enable recalculation flag by default */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->flag &= ~GP_STROKE_SELECT;
- /* the polygon must be closed, so enabled cyclic */
- if (ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
- gps->flag |= GP_STROKE_CYCLIC;
- }
-
- gps->flag |= GP_STROKE_3DSPACE;
-
- gps->mat_nr = BKE_gpencil_object_material_get_index(tgpi->ob, tgpi->mat);
-
- /* allocate memory for storage points, but keep empty */
- gps->totpoints = 0;
- gps->points = MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
- /* initialize triangle memory to dummy data */
- gps->tot_triangles = 0;
- gps->triangles = NULL;
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* add to strokes */
- BLI_addtail(&tgpi->gpf->strokes, gps);
-
- /* allocate memory for storage points */
- gpencil_primitive_allocate_memory(tgpi);
-
- /* Random generator, only init once. */
- uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
- tgpi->rng = BLI_rng_new(rng_seed);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+
+ /* if brush doesn't exist, create a new one */
+ Paint *paint = &ts->gp_paint->paint;
+ /* if not exist, create a new one */
+ if (paint->brush == NULL) {
+ /* create new brushes */
+ BKE_brush_gpencil_presets(C);
+ }
+ tgpi->brush = paint->brush;
+
+ /* if layer doesn't exist, create a new one */
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_addnew(tgpi->gpd, DATA_("Primitives"), true);
+ }
+ tgpi->gpl = gpl;
+
+ /* create a new temporary frame */
+ tgpi->gpf = MEM_callocN(sizeof(bGPDframe), "Temp bGPDframe");
+ tgpi->gpf->framenum = tgpi->cframe = cfra_eval;
+
+ /* create new temp stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "Temp bGPDstroke");
+ gps->thickness = 2.0f;
+ gps->gradient_f = 1.0f;
+ gps->gradient_s[0] = 1.0f;
+ gps->gradient_s[1] = 1.0f;
+ gps->inittime = 0.0f;
+
+ /* enable recalculation flag by default */
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->flag &= ~GP_STROKE_SELECT;
+ /* the polygon must be closed, so enabled cyclic */
+ if (ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
+ gps->flag |= GP_STROKE_CYCLIC;
+ }
+
+ gps->flag |= GP_STROKE_3DSPACE;
+
+ gps->mat_nr = BKE_gpencil_object_material_get_index(tgpi->ob, tgpi->mat);
+
+ /* allocate memory for storage points, but keep empty */
+ gps->totpoints = 0;
+ gps->points = MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
+ /* initialize triangle memory to dummy data */
+ gps->tot_triangles = 0;
+ gps->triangles = NULL;
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* add to strokes */
+ BLI_addtail(&tgpi->gpf->strokes, gps);
+
+ /* allocate memory for storage points */
+ gpencil_primitive_allocate_memory(tgpi);
+
+ /* Random generator, only init once. */
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ tgpi->rng = BLI_rng_new(rng_seed);
}
/* add new segment to curve */
static void gpencil_primitive_add_segment(tGPDprimitive *tgpi)
{
- if (tgpi->tot_stored_edges > 0) {
- tgpi->tot_stored_edges += (tgpi->tot_edges - 1);
- }
- else {
- tgpi->tot_stored_edges += tgpi->tot_edges;
- }
- gpencil_primitive_allocate_memory(tgpi);
+ if (tgpi->tot_stored_edges > 0) {
+ tgpi->tot_stored_edges += (tgpi->tot_edges - 1);
+ }
+ else {
+ tgpi->tot_stored_edges += tgpi->tot_edges;
+ }
+ gpencil_primitive_allocate_memory(tgpi);
}
/* Helper: set control point */
static void gp_primitive_set_cp(tGPDprimitive *tgpi, float p[2], float color[4], int size)
{
- if (tgpi->flag == IN_PROGRESS) {
- return;
- }
-
- bGPDcontrolpoint *cp_points = tgpi->gpd->runtime.cp_points;
-
- if (tgpi->gpd->runtime.tot_cp_points < MAX_CP) {
- CLAMP(size, 5, 20);
- bGPDcontrolpoint *cp = &cp_points[tgpi->gpd->runtime.tot_cp_points];
- copy_v2_v2(&cp->x, p);
- copy_v4_v4(cp->color, color);
- color[3] = 0.8f;
- cp->size = size;
- tgpi->gpd->runtime.tot_cp_points += 1;
- }
+ if (tgpi->flag == IN_PROGRESS) {
+ return;
+ }
+
+ bGPDcontrolpoint *cp_points = tgpi->gpd->runtime.cp_points;
+
+ if (tgpi->gpd->runtime.tot_cp_points < MAX_CP) {
+ CLAMP(size, 5, 20);
+ bGPDcontrolpoint *cp = &cp_points[tgpi->gpd->runtime.tot_cp_points];
+ copy_v2_v2(&cp->x, p);
+ copy_v4_v4(cp->color, color);
+ color[3] = 0.8f;
+ cp->size = size;
+ tgpi->gpd->runtime.tot_cp_points += 1;
+ }
}
/* Helper: Draw status message while the user is running the operator */
static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi)
{
- Scene *scene = tgpi->scene;
- char status_str[UI_MAX_DRAW_STR];
- char msg_str[UI_MAX_DRAW_STR];
-
- if (tgpi->type == GP_STROKE_LINE) {
- BLI_strncpy(
- msg_str,
- IFACE_("Line: ESC to cancel, LMB set origin, Enter/MMB to confirm, WHEEL/+- to adjust subdivision number, Shift to align, Alt to center, E: extrude"),
- UI_MAX_DRAW_STR);
- }
- else if (tgpi->type == GP_STROKE_BOX) {
- BLI_strncpy(
- msg_str,
- IFACE_("Rectangle: ESC to cancel, LMB set origin, Enter/MMB to confirm, WHEEL/+- to adjust subdivision number, Shift to square, Alt to center"),
- UI_MAX_DRAW_STR);
- }
- else if (tgpi->type == GP_STROKE_CIRCLE) {
- BLI_strncpy(
- msg_str,
- IFACE_("Circle: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust edge number, Shift to square, Alt to center"),
- UI_MAX_DRAW_STR);
- }
- else if (tgpi->type == GP_STROKE_ARC) {
- BLI_strncpy(
- msg_str,
- IFACE_("Arc: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust edge number, Shift to square, Alt to center, M: Flip, E: extrude"),
- UI_MAX_DRAW_STR);
- }
- else if (tgpi->type == GP_STROKE_CURVE) {
- BLI_strncpy(
- msg_str,
- IFACE_("Curve: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust edge number, Shift to square, Alt to center, E: extrude"),
- UI_MAX_DRAW_STR);
- }
-
- if (ELEM(tgpi->type, GP_STROKE_CIRCLE, GP_STROKE_ARC, GP_STROKE_LINE, GP_STROKE_BOX)) {
- if (hasNumInput(&tgpi->num)) {
- char str_offs[NUM_STR_REP_LEN];
-
- outputNumInput(&tgpi->num, str_offs, &scene->unit);
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
- }
- else {
- if (tgpi->flag == IN_PROGRESS) {
- BLI_snprintf(
- status_str, sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, tgpi->tot_edges,
- (int)tgpi->start[0], (int)tgpi->start[1], (int)tgpi->end[0], (int)tgpi->end[1]);
- }
- else {
- BLI_snprintf(
- status_str, sizeof(status_str), "%s: %d (%d, %d)", msg_str, tgpi->tot_edges,
- (int)tgpi->end[0], (int)tgpi->end[1]);
- }
- }
- }
- else {
- if (tgpi->flag == IN_PROGRESS) {
- BLI_snprintf(
- status_str, sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, tgpi->tot_edges,
- (int)tgpi->start[0], (int)tgpi->start[1], (int)tgpi->end[0], (int)tgpi->end[1]);
- }
- else {
- BLI_snprintf(
- status_str, sizeof(status_str), "%s: (%d, %d)", msg_str,
- (int)tgpi->end[0], (int)tgpi->end[1]);
- }
- }
- ED_workspace_status_text(C, status_str);
+ Scene *scene = tgpi->scene;
+ char status_str[UI_MAX_DRAW_STR];
+ char msg_str[UI_MAX_DRAW_STR];
+
+ if (tgpi->type == GP_STROKE_LINE) {
+ BLI_strncpy(msg_str,
+ IFACE_("Line: ESC to cancel, LMB set origin, Enter/MMB to confirm, WHEEL/+- to "
+ "adjust subdivision number, Shift to align, Alt to center, E: extrude"),
+ UI_MAX_DRAW_STR);
+ }
+ else if (tgpi->type == GP_STROKE_BOX) {
+ BLI_strncpy(msg_str,
+ IFACE_("Rectangle: ESC to cancel, LMB set origin, Enter/MMB to confirm, WHEEL/+- "
+ "to adjust subdivision number, Shift to square, Alt to center"),
+ UI_MAX_DRAW_STR);
+ }
+ else if (tgpi->type == GP_STROKE_CIRCLE) {
+ BLI_strncpy(msg_str,
+ IFACE_("Circle: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust edge "
+ "number, Shift to square, Alt to center"),
+ UI_MAX_DRAW_STR);
+ }
+ else if (tgpi->type == GP_STROKE_ARC) {
+ BLI_strncpy(msg_str,
+ IFACE_("Arc: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust edge number, "
+ "Shift to square, Alt to center, M: Flip, E: extrude"),
+ UI_MAX_DRAW_STR);
+ }
+ else if (tgpi->type == GP_STROKE_CURVE) {
+ BLI_strncpy(msg_str,
+ IFACE_("Curve: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust edge "
+ "number, Shift to square, Alt to center, E: extrude"),
+ UI_MAX_DRAW_STR);
+ }
+
+ if (ELEM(tgpi->type, GP_STROKE_CIRCLE, GP_STROKE_ARC, GP_STROKE_LINE, GP_STROKE_BOX)) {
+ if (hasNumInput(&tgpi->num)) {
+ char str_offs[NUM_STR_REP_LEN];
+
+ outputNumInput(&tgpi->num, str_offs, &scene->unit);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
+ }
+ else {
+ if (tgpi->flag == IN_PROGRESS) {
+ BLI_snprintf(status_str,
+ sizeof(status_str),
+ "%s: %d (%d, %d) (%d, %d)",
+ msg_str,
+ tgpi->tot_edges,
+ (int)tgpi->start[0],
+ (int)tgpi->start[1],
+ (int)tgpi->end[0],
+ (int)tgpi->end[1]);
+ }
+ else {
+ BLI_snprintf(status_str,
+ sizeof(status_str),
+ "%s: %d (%d, %d)",
+ msg_str,
+ tgpi->tot_edges,
+ (int)tgpi->end[0],
+ (int)tgpi->end[1]);
+ }
+ }
+ }
+ else {
+ if (tgpi->flag == IN_PROGRESS) {
+ BLI_snprintf(status_str,
+ sizeof(status_str),
+ "%s: %d (%d, %d) (%d, %d)",
+ msg_str,
+ tgpi->tot_edges,
+ (int)tgpi->start[0],
+ (int)tgpi->start[1],
+ (int)tgpi->end[0],
+ (int)tgpi->end[1]);
+ }
+ else {
+ BLI_snprintf(status_str,
+ sizeof(status_str),
+ "%s: (%d, %d)",
+ msg_str,
+ (int)tgpi->end[0],
+ (int)tgpi->end[1]);
+ }
+ }
+ ED_workspace_status_text(C, status_str);
}
/* create a rectangle */
static void gp_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D)
{
- float coords[5][2];
-
- coords[0][0] = tgpi->start[0];
- coords[0][1] = tgpi->start[1];
- coords[1][0] = tgpi->end[0];
- coords[1][1] = tgpi->start[1];
- coords[2][0] = tgpi->end[0];
- coords[2][1] = tgpi->end[1];
- coords[3][0] = tgpi->start[0];
- coords[3][1] = tgpi->end[1];
- coords[4][0] = tgpi->start[0];
- coords[4][1] = tgpi->start[1];
-
- const float step = 1.0f / (float)(tgpi->tot_edges);
- int i = tgpi->tot_stored_edges;
-
- for (int j = 0; j < 4; j++) {
- float a = 0.0f;
- for (int k = 0; k < tgpi->tot_edges; k++) {
- tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2(&p2d->x, coords[j], coords[j + 1], a);
- a += step;
- i++;
- }
- }
-
- mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end);
- float color[4];
- UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
- gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
- if (tgpi->tot_stored_edges) {
- UI_GetThemeColor4fv(TH_REDALERT, color);
- gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
- }
- else {
- gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
- }
- UI_GetThemeColor4fv(TH_REDALERT, color);
- gp_primitive_set_cp(tgpi, tgpi->midpoint, color, SMALL_SIZE_CTL);
+ float coords[5][2];
+
+ coords[0][0] = tgpi->start[0];
+ coords[0][1] = tgpi->start[1];
+ coords[1][0] = tgpi->end[0];
+ coords[1][1] = tgpi->start[1];
+ coords[2][0] = tgpi->end[0];
+ coords[2][1] = tgpi->end[1];
+ coords[3][0] = tgpi->start[0];
+ coords[3][1] = tgpi->end[1];
+ coords[4][0] = tgpi->start[0];
+ coords[4][1] = tgpi->start[1];
+
+ const float step = 1.0f / (float)(tgpi->tot_edges);
+ int i = tgpi->tot_stored_edges;
+
+ for (int j = 0; j < 4; j++) {
+ float a = 0.0f;
+ for (int k = 0; k < tgpi->tot_edges; k++) {
+ tGPspoint *p2d = &points2D[i];
+ interp_v2_v2v2(&p2d->x, coords[j], coords[j + 1], a);
+ a += step;
+ i++;
+ }
+ }
+
+ mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end);
+ float color[4];
+ UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
+ gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
+ if (tgpi->tot_stored_edges) {
+ UI_GetThemeColor4fv(TH_REDALERT, color);
+ gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
+ }
+ else {
+ gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
+ }
+ UI_GetThemeColor4fv(TH_REDALERT, color);
+ gp_primitive_set_cp(tgpi, tgpi->midpoint, color, SMALL_SIZE_CTL);
}
/* create a line */
static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D)
{
- const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
- const float step = 1.0f / (float)(tgpi->tot_edges - 1);
- float a = tgpi->tot_stored_edges ? step : 0.0f;
-
- for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
- tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2(&p2d->x, tgpi->start, tgpi->end, a);
- a += step;
- }
-
- float color[4];
- UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
- gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
- if (tgpi->tot_stored_edges) {
- UI_GetThemeColor4fv(TH_REDALERT, color);
- gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
- }
- else {
- gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
- }
+ const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
+ const float step = 1.0f / (float)(tgpi->tot_edges - 1);
+ float a = tgpi->tot_stored_edges ? step : 0.0f;
+
+ for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
+ tGPspoint *p2d = &points2D[i];
+ interp_v2_v2v2(&p2d->x, tgpi->start, tgpi->end, a);
+ a += step;
+ }
+
+ float color[4];
+ UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
+ gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
+ if (tgpi->tot_stored_edges) {
+ UI_GetThemeColor4fv(TH_REDALERT, color);
+ gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
+ }
+ else {
+ gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
+ }
}
/* create an arc */
static void gp_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D)
{
- const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
- const float step = M_PI_2 / (float)(tgpi->tot_edges - 1);
- float start[2];
- float end[2];
- float cp1[2];
- float corner[2];
- float midpoint[2];
- float a = tgpi->tot_stored_edges ? step : 0.0f;
-
- mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end);
- copy_v2_v2(start, tgpi->start);
- copy_v2_v2(end, tgpi->end);
- copy_v2_v2(cp1, tgpi->cp1);
- copy_v2_v2(midpoint, tgpi->midpoint);
-
- corner[0] = midpoint[0] - (cp1[0] - midpoint[0]);
- corner[1] = midpoint[1] - (cp1[1] - midpoint[1]);
-
- for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
- tGPspoint *p2d = &points2D[i];
- p2d->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
- p2d->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
- a += step;
- }
- float color[4];
- UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
- gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
- if (tgpi->tot_stored_edges) {
- UI_GetThemeColor4fv(TH_REDALERT, color);
- gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
- }
- else {
- gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
- }
- UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
- gp_primitive_set_cp(tgpi, tgpi->cp1, color, BIG_SIZE_CTL * 0.9f);
+ const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
+ const float step = M_PI_2 / (float)(tgpi->tot_edges - 1);
+ float start[2];
+ float end[2];
+ float cp1[2];
+ float corner[2];
+ float midpoint[2];
+ float a = tgpi->tot_stored_edges ? step : 0.0f;
+
+ mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end);
+ copy_v2_v2(start, tgpi->start);
+ copy_v2_v2(end, tgpi->end);
+ copy_v2_v2(cp1, tgpi->cp1);
+ copy_v2_v2(midpoint, tgpi->midpoint);
+
+ corner[0] = midpoint[0] - (cp1[0] - midpoint[0]);
+ corner[1] = midpoint[1] - (cp1[1] - midpoint[1]);
+
+ for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
+ tGPspoint *p2d = &points2D[i];
+ p2d->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
+ p2d->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
+ a += step;
+ }
+ float color[4];
+ UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
+ gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
+ if (tgpi->tot_stored_edges) {
+ UI_GetThemeColor4fv(TH_REDALERT, color);
+ gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
+ }
+ else {
+ gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
+ }
+ UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
+ gp_primitive_set_cp(tgpi, tgpi->cp1, color, BIG_SIZE_CTL * 0.9f);
}
/* create a bezier */
static void gp_primitive_bezier(tGPDprimitive *tgpi, tGPspoint *points2D)
{
- const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
- const float step = 1.0f / (float)(tgpi->tot_edges - 1);
- float bcp1[2];
- float bcp2[2];
- float bcp3[2];
- float bcp4[2];
- float a = tgpi->tot_stored_edges ? step : 0.0f;
-
- copy_v2_v2(bcp1, tgpi->start);
- copy_v2_v2(bcp2, tgpi->cp1);
- copy_v2_v2(bcp3, tgpi->cp2);
- copy_v2_v2(bcp4, tgpi->end);
-
- for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
- tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2v2v2_cubic(&p2d->x, bcp1, bcp2, bcp3, bcp4, a);
- a += step;
- }
- float color[4];
- UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
- gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
- if (tgpi->tot_stored_edges) {
- UI_GetThemeColor4fv(TH_REDALERT, color);
- gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
- }
- else {
- gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
- }
- UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
- gp_primitive_set_cp(tgpi, tgpi->cp1, color, BIG_SIZE_CTL * 0.9f);
- gp_primitive_set_cp(tgpi, tgpi->cp2, color, BIG_SIZE_CTL * 0.9f);
+ const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
+ const float step = 1.0f / (float)(tgpi->tot_edges - 1);
+ float bcp1[2];
+ float bcp2[2];
+ float bcp3[2];
+ float bcp4[2];
+ float a = tgpi->tot_stored_edges ? step : 0.0f;
+
+ copy_v2_v2(bcp1, tgpi->start);
+ copy_v2_v2(bcp2, tgpi->cp1);
+ copy_v2_v2(bcp3, tgpi->cp2);
+ copy_v2_v2(bcp4, tgpi->end);
+
+ for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
+ tGPspoint *p2d = &points2D[i];
+ interp_v2_v2v2v2v2_cubic(&p2d->x, bcp1, bcp2, bcp3, bcp4, a);
+ a += step;
+ }
+ float color[4];
+ UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
+ gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
+ if (tgpi->tot_stored_edges) {
+ UI_GetThemeColor4fv(TH_REDALERT, color);
+ gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
+ }
+ else {
+ gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
+ }
+ UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
+ gp_primitive_set_cp(tgpi, tgpi->cp1, color, BIG_SIZE_CTL * 0.9f);
+ gp_primitive_set_cp(tgpi, tgpi->cp2, color, BIG_SIZE_CTL * 0.9f);
}
/* create a circle */
static void gp_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D)
{
- const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
- const float step = (2.0f * M_PI) / (float)(tgpi->tot_edges);
- float center[2];
- float radius[2];
- float a = 0.0f;
-
- center[0] = tgpi->start[0] + ((tgpi->end[0] - tgpi->start[0]) / 2.0f);
- center[1] = tgpi->start[1] + ((tgpi->end[1] - tgpi->start[1]) / 2.0f);
- radius[0] = fabsf(((tgpi->end[0] - tgpi->start[0]) / 2.0f));
- radius[1] = fabsf(((tgpi->end[1] - tgpi->start[1]) / 2.0f));
-
- for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
- tGPspoint *p2d = &points2D[i];
- p2d->x = (center[0] + cosf(a) * radius[0]);
- p2d->y = (center[1] + sinf(a) * radius[1]);
- a += step;
- }
- float color[4];
- UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
- gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
- gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
- UI_GetThemeColor4fv(TH_REDALERT, color);
- gp_primitive_set_cp(tgpi, center, color, SMALL_SIZE_CTL);
+ const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
+ const float step = (2.0f * M_PI) / (float)(tgpi->tot_edges);
+ float center[2];
+ float radius[2];
+ float a = 0.0f;
+
+ center[0] = tgpi->start[0] + ((tgpi->end[0] - tgpi->start[0]) / 2.0f);
+ center[1] = tgpi->start[1] + ((tgpi->end[1] - tgpi->start[1]) / 2.0f);
+ radius[0] = fabsf(((tgpi->end[0] - tgpi->start[0]) / 2.0f));
+ radius[1] = fabsf(((tgpi->end[1] - tgpi->start[1]) / 2.0f));
+
+ for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
+ tGPspoint *p2d = &points2D[i];
+ p2d->x = (center[0] + cosf(a) * radius[0]);
+ p2d->y = (center[1] + sinf(a) * radius[1]);
+ a += step;
+ }
+ float color[4];
+ UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
+ gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
+ gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
+ UI_GetThemeColor4fv(TH_REDALERT, color);
+ gp_primitive_set_cp(tgpi, center, color, SMALL_SIZE_CTL);
}
/* Helper: Update shape of the stroke */
static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
{
- ToolSettings *ts = tgpi->scene->toolsettings;
- bGPdata *gpd = tgpi->gpd;
- Brush *brush = tgpi->brush;
- bGPDstroke *gps = tgpi->gpf->strokes.first;
- GP_Sculpt_Settings *gset = &ts->gp_sculpt;
- int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
- const char *align_flag = &ts->gpencil_v3d_align;
- bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
- const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
- (tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth);
-
- if (tgpi->type == GP_STROKE_BOX)
- gps->totpoints = (tgpi->tot_edges * 4 + tgpi->tot_stored_edges);
- else
- gps->totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
-
- if (tgpi->tot_stored_edges)
- gps->totpoints--;
-
- tgpi->gpd->runtime.tot_cp_points = 0;
-
- /* compute screen-space coordinates for points */
- tGPspoint *points2D = tgpi->points;
-
- if (tgpi->tot_edges > 1) {
- switch (tgpi->type) {
- case GP_STROKE_BOX:
- gp_primitive_rectangle(tgpi, points2D);
- break;
- case GP_STROKE_LINE:
- gp_primitive_line(tgpi, points2D);
- break;
- case GP_STROKE_CIRCLE:
- gp_primitive_circle(tgpi, points2D);
- break;
- case GP_STROKE_ARC:
- gp_primitive_arc(tgpi, points2D);
- break;
- case GP_STROKE_CURVE:
- gp_primitive_bezier(tgpi, points2D);
- default:
- break;
- }
- }
-
- /* convert screen-coordinates to 3D coordinates */
- gp_session_validatebuffer(tgpi);
- gp_init_colors(tgpi);
- if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) {
- curvemapping_initialize(ts->gp_sculpt.cur_primitive);
- }
- if (tgpi->brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
- curvemapping_initialize(tgpi->brush->gpencil_settings->curve_jitter);
- }
- if (tgpi->brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
- curvemapping_initialize(tgpi->brush->gpencil_settings->curve_strength);
- }
-
- /* get an array of depths, far depths are blended */
- float *depth_arr = NULL;
- if (is_depth) {
- int i;
- int mval_i[2], mval_prev[2] = { 0 };
- bool interp_depth = false;
- bool found_depth = false;
-
- /* need to restore the original projection settings before packing up */
- view3d_region_operator_needs_opengl(tgpi->win, tgpi->ar);
- ED_view3d_autodist_init(
- tgpi->depsgraph, tgpi->ar, tgpi->v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
-
- depth_arr = MEM_mallocN(sizeof(float) * gps->totpoints, "depth_points");
- tGPspoint *ptc = &points2D[0];
- for (i = 0; i < gps->totpoints; i++, ptc++) {
- round_v2i_v2fl(mval_i, &ptc->x);
- if ((ED_view3d_autodist_depth(
- tgpi->ar, mval_i, depth_margin, depth_arr + i) == 0) &&
- (i && (ED_view3d_autodist_depth_seg(
- tgpi->ar, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
- {
- interp_depth = true;
- }
- else {
- found_depth = true;
- }
- copy_v2_v2_int(mval_prev, mval_i);
- }
-
- if (!found_depth) {
- for (i = 0; i < gps->totpoints; i++) {
- depth_arr[i] = 0.9999f;
- }
- }
- else {
- /* if all depth are too high disable */
- bool valid_depth = false;
- for (i = 0; i < gps->totpoints; i++) {
- if (depth_arr[i] < 0.9999f) {
- valid_depth = true;
- break;
- }
- }
- if (!valid_depth) {
- MEM_SAFE_FREE(depth_arr);
- is_depth = false;
- }
- else {
- if ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) ||
- (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_FIRST))
- {
- int first_valid = 0;
- int last_valid = 0;
-
- /* find first valid contact point */
- for (i = 0; i < gps->totpoints; i++) {
- if (depth_arr[i] != FLT_MAX)
- break;
- }
- first_valid = i;
-
- /* find last valid contact point */
- if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_FIRST) {
- last_valid = first_valid;
- }
- else {
- for (i = gps->totpoints - 1; i >= 0; i--) {
- if (depth_arr[i] != FLT_MAX)
- break;
- }
- last_valid = i;
- }
-
- /* invalidate any other point, to interpolate between
- * first and last contact in an imaginary line between them */
- for (i = 0; i < gps->totpoints; i++) {
- if ((i != first_valid) && (i != last_valid)) {
- depth_arr[i] = FLT_MAX;
- }
- }
- interp_depth = true;
- }
-
- if (interp_depth) {
- interp_sparse_array(depth_arr, gps->totpoints, FLT_MAX);
- }
- }
- }
- }
-
- /* load stroke points and sbuffer */
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- tGPspoint *p2d = &points2D[i];
-
- /* set rnd value for reuse */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && (p2d->rnd_dirty != true)) {
- p2d->rnd[0] = BLI_rng_get_float(tgpi->rng);
- p2d->rnd[1] = BLI_rng_get_float(tgpi->rng);
- p2d->rnd[2] = BLI_rng_get_float(tgpi->rng);
- p2d->rnd_dirty = true;
- }
-
- /* Copy points to buffer */
- tGPspoint *tpt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size);
-
- /* Store original points */
- float tmp_xyp[2];
- copy_v2_v2(tmp_xyp, &p2d->x);
-
- /* calc pressure */
- float curve_pressure = 1.0;
- float pressure = 1.0;
- float strength = brush->gpencil_settings->draw_strength;
-
- /* normalize value to evaluate curve */
- if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) {
- float value = (float)i / (gps->totpoints - 1);
- curve_pressure = curvemapping_evaluateF(gset->cur_primitive, 0, value);
- pressure = curve_pressure;
- }
-
- /* apply jitter to position */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_jitter > 0.0f))
- {
- float jitter;
-
- if (brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
- jitter = curvemapping_evaluateF(brush->gpencil_settings->curve_jitter, 0, curve_pressure);
- jitter *= brush->gpencil_settings->draw_sensitivity;
- }
- else {
- jitter = brush->gpencil_settings->draw_jitter;
- }
-
- /* exponential value */
- const float exfactor = SQUARE(brush->gpencil_settings->draw_jitter + 2.0f);
- const float fac = p2d->rnd[0] * exfactor * jitter;
-
- /* vector */
- float mvec[2], svec[2];
- if (i > 0) {
- mvec[0] = (p2d->x - (p2d - 1)->x);
- mvec[1] = (p2d->y - (p2d - 1)->y);
- normalize_v2(mvec);
- }
- else {
- zero_v2(mvec);
- }
- svec[0] = -mvec[1];
- svec[1] = mvec[0];
-
- if (p2d->rnd[1] > 0.5f) {
- mul_v2_fl(svec, -fac);
- }
- else {
- mul_v2_fl(svec, fac);
- }
- add_v2_v2(&p2d->x, svec);
- }
-
- /* apply randomness to pressure */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_random_press > 0.0f))
- {
- if (p2d->rnd[0] > 0.5f) {
- pressure -= brush->gpencil_settings->draw_random_press * p2d->rnd[1];
- }
- else {
- pressure += brush->gpencil_settings->draw_random_press * p2d->rnd[2];
- }
- }
-
- /* color strength */
- if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
- float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_strength, 0, curve_pressure);
- strength *= curvef * brush->gpencil_settings->draw_sensitivity;
- strength *= brush->gpencil_settings->draw_strength;
- }
-
- CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f);
-
- /* apply randomness to color strength */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_random_strength > 0.0f))
- {
- if (p2d->rnd[2] > 0.5f) {
- strength -= strength * brush->gpencil_settings->draw_random_strength * p2d->rnd[0];
- }
- else {
- strength += strength * brush->gpencil_settings->draw_random_strength * p2d->rnd[1];
- }
- CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f);
- }
-
- copy_v2_v2(&tpt->x, &p2d->x);
-
- CLAMP_MIN(pressure, 0.1f);
-
- tpt->pressure = pressure;
- tpt->strength = strength;
- tpt->time = p2d->time;
-
- /* point uv */
- if (gpd->runtime.sbuffer_size > 0) {
- MaterialGPencilStyle *gp_style = tgpi->mat->gp_style;
- const float pixsize = gp_style->texture_pixsize / 1000000.0f;
- tGPspoint *tptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1;
- bGPDspoint spt, spt2;
-
- /* get origin to reproject point */
- float origin[3];
- ED_gp_get_drawing_reference(
- tgpi->scene, tgpi->ob, tgpi->gpl,
- ts->gpencil_v3d_align, origin);
- /* reproject current */
- ED_gpencil_tpoint_to_point(tgpi->ar, origin, tpt, &spt);
- ED_gp_project_point_to_plane(
- tgpi->scene, tgpi->ob, tgpi->rv3d,
- origin, tgpi->lock_axis - 1, &spt);
-
- /* reproject previous */
- ED_gpencil_tpoint_to_point(tgpi->ar, origin, tptb, &spt2);
- ED_gp_project_point_to_plane(
- tgpi->scene, tgpi->ob, tgpi->rv3d,
- origin, tgpi->lock_axis - 1, &spt2);
- tgpi->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize;
- tpt->uv_fac = tgpi->totpixlen;
- if ((gp_style) && (gp_style->sima)) {
- tpt->uv_fac /= gp_style->sima->gen_x;
- }
- }
- else {
- tgpi->totpixlen = 0.0f;
- tpt->uv_fac = 0.0f;
- }
-
- tpt->uv_rot = p2d->uv_rot;
-
- gpd->runtime.sbuffer_size++;
-
- /* add small offset to keep stroke over the surface */
- if ((depth_arr) && (gpd->zdepth_offset > 0.0f)) {
- depth_arr[i] *= (1.0f - gpd->zdepth_offset);
- }
-
- /* convert screen-coordinates to 3D coordinates */
- gp_stroke_convertcoords_tpoint(
- tgpi->scene, tgpi->ar, tgpi->ob, tgpi->gpl,
- p2d, depth_arr ? depth_arr + i : NULL,
- &pt->x);
-
- pt->pressure = pressure;
- pt->strength = strength;
- pt->time = 0.0f;
- pt->flag = 0;
- pt->uv_fac = tpt->uv_fac;
-
- if (gps->dvert != NULL) {
- MDeformVert *dvert = &gps->dvert[i];
- dvert->totweight = 0;
- dvert->dw = NULL;
- }
-
- /* Restore original points */
- copy_v2_v2(&p2d->x, tmp_xyp);
- }
-
- /* store cps and convert coords */
- if (tgpi->gpd->runtime.tot_cp_points > 0) {
- bGPDcontrolpoint *cps = tgpi->gpd->runtime.cp_points;
- for (int i = 0; i < tgpi->gpd->runtime.tot_cp_points; i++) {
- bGPDcontrolpoint *cp = &cps[i];
- gp_stroke_convertcoords_tpoint(tgpi->scene, tgpi->ar, tgpi->ob, tgpi->gpl, (tGPspoint *)cp, NULL, &cp->x);
- }
- }
-
- /* reproject to plane */
- if (!is_depth) {
- float origin[3];
- ED_gp_get_drawing_reference(
- tgpi->scene, tgpi->ob, tgpi->gpl,
- ts->gpencil_v3d_align, origin);
- ED_gp_project_stroke_to_plane(
- tgpi->scene, tgpi->ob, tgpi->rv3d, gps,
- origin, ts->gp_sculpt.lock_axis - 1);
- }
-
- /* if parented change position relative to parent object */
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- gp_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpd, tgpi->gpl, pt);
- }
-
- /* if camera view, reproject flat to view to avoid perspective effect */
- if (is_camera) {
- ED_gpencil_project_stroke_to_view(C, tgpi->gpl, gps);
- }
-
- /* force fill recalc */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- MEM_SAFE_FREE(depth_arr);
-
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ ToolSettings *ts = tgpi->scene->toolsettings;
+ bGPdata *gpd = tgpi->gpd;
+ Brush *brush = tgpi->brush;
+ bGPDstroke *gps = tgpi->gpf->strokes.first;
+ GP_Sculpt_Settings *gset = &ts->gp_sculpt;
+ int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
+ const char *align_flag = &ts->gpencil_v3d_align;
+ bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
+ const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
+ (tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth);
+
+ if (tgpi->type == GP_STROKE_BOX)
+ gps->totpoints = (tgpi->tot_edges * 4 + tgpi->tot_stored_edges);
+ else
+ gps->totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
+
+ if (tgpi->tot_stored_edges)
+ gps->totpoints--;
+
+ tgpi->gpd->runtime.tot_cp_points = 0;
+
+ /* compute screen-space coordinates for points */
+ tGPspoint *points2D = tgpi->points;
+
+ if (tgpi->tot_edges > 1) {
+ switch (tgpi->type) {
+ case GP_STROKE_BOX:
+ gp_primitive_rectangle(tgpi, points2D);
+ break;
+ case GP_STROKE_LINE:
+ gp_primitive_line(tgpi, points2D);
+ break;
+ case GP_STROKE_CIRCLE:
+ gp_primitive_circle(tgpi, points2D);
+ break;
+ case GP_STROKE_ARC:
+ gp_primitive_arc(tgpi, points2D);
+ break;
+ case GP_STROKE_CURVE:
+ gp_primitive_bezier(tgpi, points2D);
+ default:
+ break;
+ }
+ }
+
+ /* convert screen-coordinates to 3D coordinates */
+ gp_session_validatebuffer(tgpi);
+ gp_init_colors(tgpi);
+ if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) {
+ curvemapping_initialize(ts->gp_sculpt.cur_primitive);
+ }
+ if (tgpi->brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
+ curvemapping_initialize(tgpi->brush->gpencil_settings->curve_jitter);
+ }
+ if (tgpi->brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
+ curvemapping_initialize(tgpi->brush->gpencil_settings->curve_strength);
+ }
+
+ /* get an array of depths, far depths are blended */
+ float *depth_arr = NULL;
+ if (is_depth) {
+ int i;
+ int mval_i[2], mval_prev[2] = {0};
+ bool interp_depth = false;
+ bool found_depth = false;
+
+ /* need to restore the original projection settings before packing up */
+ view3d_region_operator_needs_opengl(tgpi->win, tgpi->ar);
+ ED_view3d_autodist_init(tgpi->depsgraph,
+ tgpi->ar,
+ tgpi->v3d,
+ (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
+
+ depth_arr = MEM_mallocN(sizeof(float) * gps->totpoints, "depth_points");
+ tGPspoint *ptc = &points2D[0];
+ for (i = 0; i < gps->totpoints; i++, ptc++) {
+ round_v2i_v2fl(mval_i, &ptc->x);
+ if ((ED_view3d_autodist_depth(tgpi->ar, mval_i, depth_margin, depth_arr + i) == 0) &&
+ (i && (ED_view3d_autodist_depth_seg(
+ tgpi->ar, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
+ interp_depth = true;
+ }
+ else {
+ found_depth = true;
+ }
+ copy_v2_v2_int(mval_prev, mval_i);
+ }
+
+ if (!found_depth) {
+ for (i = 0; i < gps->totpoints; i++) {
+ depth_arr[i] = 0.9999f;
+ }
+ }
+ else {
+ /* if all depth are too high disable */
+ bool valid_depth = false;
+ for (i = 0; i < gps->totpoints; i++) {
+ if (depth_arr[i] < 0.9999f) {
+ valid_depth = true;
+ break;
+ }
+ }
+ if (!valid_depth) {
+ MEM_SAFE_FREE(depth_arr);
+ is_depth = false;
+ }
+ else {
+ if ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) ||
+ (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_FIRST)) {
+ int first_valid = 0;
+ int last_valid = 0;
+
+ /* find first valid contact point */
+ for (i = 0; i < gps->totpoints; i++) {
+ if (depth_arr[i] != FLT_MAX)
+ break;
+ }
+ first_valid = i;
+
+ /* find last valid contact point */
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_FIRST) {
+ last_valid = first_valid;
+ }
+ else {
+ for (i = gps->totpoints - 1; i >= 0; i--) {
+ if (depth_arr[i] != FLT_MAX)
+ break;
+ }
+ last_valid = i;
+ }
+
+ /* invalidate any other point, to interpolate between
+ * first and last contact in an imaginary line between them */
+ for (i = 0; i < gps->totpoints; i++) {
+ if ((i != first_valid) && (i != last_valid)) {
+ depth_arr[i] = FLT_MAX;
+ }
+ }
+ interp_depth = true;
+ }
+
+ if (interp_depth) {
+ interp_sparse_array(depth_arr, gps->totpoints, FLT_MAX);
+ }
+ }
+ }
+ }
+
+ /* load stroke points and sbuffer */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ tGPspoint *p2d = &points2D[i];
+
+ /* set rnd value for reuse */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && (p2d->rnd_dirty != true)) {
+ p2d->rnd[0] = BLI_rng_get_float(tgpi->rng);
+ p2d->rnd[1] = BLI_rng_get_float(tgpi->rng);
+ p2d->rnd[2] = BLI_rng_get_float(tgpi->rng);
+ p2d->rnd_dirty = true;
+ }
+
+ /* Copy points to buffer */
+ tGPspoint *tpt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size);
+
+ /* Store original points */
+ float tmp_xyp[2];
+ copy_v2_v2(tmp_xyp, &p2d->x);
+
+ /* calc pressure */
+ float curve_pressure = 1.0;
+ float pressure = 1.0;
+ float strength = brush->gpencil_settings->draw_strength;
+
+ /* normalize value to evaluate curve */
+ if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) {
+ float value = (float)i / (gps->totpoints - 1);
+ curve_pressure = curvemapping_evaluateF(gset->cur_primitive, 0, value);
+ pressure = curve_pressure;
+ }
+
+ /* apply jitter to position */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_jitter > 0.0f)) {
+ float jitter;
+
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
+ jitter = curvemapping_evaluateF(brush->gpencil_settings->curve_jitter, 0, curve_pressure);
+ jitter *= brush->gpencil_settings->draw_sensitivity;
+ }
+ else {
+ jitter = brush->gpencil_settings->draw_jitter;
+ }
+
+ /* exponential value */
+ const float exfactor = SQUARE(brush->gpencil_settings->draw_jitter + 2.0f);
+ const float fac = p2d->rnd[0] * exfactor * jitter;
+
+ /* vector */
+ float mvec[2], svec[2];
+ if (i > 0) {
+ mvec[0] = (p2d->x - (p2d - 1)->x);
+ mvec[1] = (p2d->y - (p2d - 1)->y);
+ normalize_v2(mvec);
+ }
+ else {
+ zero_v2(mvec);
+ }
+ svec[0] = -mvec[1];
+ svec[1] = mvec[0];
+
+ if (p2d->rnd[1] > 0.5f) {
+ mul_v2_fl(svec, -fac);
+ }
+ else {
+ mul_v2_fl(svec, fac);
+ }
+ add_v2_v2(&p2d->x, svec);
+ }
+
+ /* apply randomness to pressure */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_random_press > 0.0f)) {
+ if (p2d->rnd[0] > 0.5f) {
+ pressure -= brush->gpencil_settings->draw_random_press * p2d->rnd[1];
+ }
+ else {
+ pressure += brush->gpencil_settings->draw_random_press * p2d->rnd[2];
+ }
+ }
+
+ /* color strength */
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
+ float curvef = curvemapping_evaluateF(
+ brush->gpencil_settings->curve_strength, 0, curve_pressure);
+ strength *= curvef * brush->gpencil_settings->draw_sensitivity;
+ strength *= brush->gpencil_settings->draw_strength;
+ }
+
+ CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f);
+
+ /* apply randomness to color strength */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_random_strength > 0.0f)) {
+ if (p2d->rnd[2] > 0.5f) {
+ strength -= strength * brush->gpencil_settings->draw_random_strength * p2d->rnd[0];
+ }
+ else {
+ strength += strength * brush->gpencil_settings->draw_random_strength * p2d->rnd[1];
+ }
+ CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+
+ copy_v2_v2(&tpt->x, &p2d->x);
+
+ CLAMP_MIN(pressure, 0.1f);
+
+ tpt->pressure = pressure;
+ tpt->strength = strength;
+ tpt->time = p2d->time;
+
+ /* point uv */
+ if (gpd->runtime.sbuffer_size > 0) {
+ MaterialGPencilStyle *gp_style = tgpi->mat->gp_style;
+ const float pixsize = gp_style->texture_pixsize / 1000000.0f;
+ tGPspoint *tptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1;
+ bGPDspoint spt, spt2;
+
+ /* get origin to reproject point */
+ float origin[3];
+ ED_gp_get_drawing_reference(tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin);
+ /* reproject current */
+ ED_gpencil_tpoint_to_point(tgpi->ar, origin, tpt, &spt);
+ ED_gp_project_point_to_plane(
+ tgpi->scene, tgpi->ob, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt);
+
+ /* reproject previous */
+ ED_gpencil_tpoint_to_point(tgpi->ar, origin, tptb, &spt2);
+ ED_gp_project_point_to_plane(
+ tgpi->scene, tgpi->ob, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt2);
+ tgpi->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize;
+ tpt->uv_fac = tgpi->totpixlen;
+ if ((gp_style) && (gp_style->sima)) {
+ tpt->uv_fac /= gp_style->sima->gen_x;
+ }
+ }
+ else {
+ tgpi->totpixlen = 0.0f;
+ tpt->uv_fac = 0.0f;
+ }
+
+ tpt->uv_rot = p2d->uv_rot;
+
+ gpd->runtime.sbuffer_size++;
+
+ /* add small offset to keep stroke over the surface */
+ if ((depth_arr) && (gpd->zdepth_offset > 0.0f)) {
+ depth_arr[i] *= (1.0f - gpd->zdepth_offset);
+ }
+
+ /* convert screen-coordinates to 3D coordinates */
+ gp_stroke_convertcoords_tpoint(
+ tgpi->scene, tgpi->ar, tgpi->ob, tgpi->gpl, p2d, depth_arr ? depth_arr + i : NULL, &pt->x);
+
+ pt->pressure = pressure;
+ pt->strength = strength;
+ pt->time = 0.0f;
+ pt->flag = 0;
+ pt->uv_fac = tpt->uv_fac;
+
+ if (gps->dvert != NULL) {
+ MDeformVert *dvert = &gps->dvert[i];
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ }
+
+ /* Restore original points */
+ copy_v2_v2(&p2d->x, tmp_xyp);
+ }
+
+ /* store cps and convert coords */
+ if (tgpi->gpd->runtime.tot_cp_points > 0) {
+ bGPDcontrolpoint *cps = tgpi->gpd->runtime.cp_points;
+ for (int i = 0; i < tgpi->gpd->runtime.tot_cp_points; i++) {
+ bGPDcontrolpoint *cp = &cps[i];
+ gp_stroke_convertcoords_tpoint(
+ tgpi->scene, tgpi->ar, tgpi->ob, tgpi->gpl, (tGPspoint *)cp, NULL, &cp->x);
+ }
+ }
+
+ /* reproject to plane */
+ if (!is_depth) {
+ float origin[3];
+ ED_gp_get_drawing_reference(tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin);
+ ED_gp_project_stroke_to_plane(
+ tgpi->scene, tgpi->ob, tgpi->rv3d, gps, origin, ts->gp_sculpt.lock_axis - 1);
+ }
+
+ /* if parented change position relative to parent object */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ gp_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpd, tgpi->gpl, pt);
+ }
+
+ /* if camera view, reproject flat to view to avoid perspective effect */
+ if (is_camera) {
+ ED_gpencil_project_stroke_to_view(C, tgpi->gpl, gps);
+ }
+
+ /* force fill recalc */
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ MEM_SAFE_FREE(depth_arr);
+
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
}
/* Update screen and stroke */
static void gpencil_primitive_update(bContext *C, wmOperator *op, tGPDprimitive *tgpi)
{
- /* update indicator in header */
- gpencil_primitive_status_indicators(C, tgpi);
- /* apply... */
- tgpi->type = RNA_enum_get(op->ptr, "type");
- tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
- /* update points position */
- gp_primitive_update_strokes(C, tgpi);
+ /* update indicator in header */
+ gpencil_primitive_status_indicators(C, tgpi);
+ /* apply... */
+ tgpi->type = RNA_enum_get(op->ptr, "type");
+ tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
+ /* update points position */
+ gp_primitive_update_strokes(C, tgpi);
}
static void gpencil_primitive_interaction_begin(tGPDprimitive *tgpi, const wmEvent *event)
{
- copy_v2fl_v2i(tgpi->mval, event->mval);
- copy_v2_v2(tgpi->origin, tgpi->mval);
- copy_v2_v2(tgpi->start, tgpi->mval);
- copy_v2_v2(tgpi->end, tgpi->mval);
- copy_v2_v2(tgpi->cp1, tgpi->mval);
- copy_v2_v2(tgpi->cp2, tgpi->mval);
+ copy_v2fl_v2i(tgpi->mval, event->mval);
+ copy_v2_v2(tgpi->origin, tgpi->mval);
+ copy_v2_v2(tgpi->start, tgpi->mval);
+ copy_v2_v2(tgpi->end, tgpi->mval);
+ copy_v2_v2(tgpi->cp1, tgpi->mval);
+ copy_v2_v2(tgpi->cp2, tgpi->mval);
}
/* Exit and free memory */
static void gpencil_primitive_exit(bContext *C, wmOperator *op)
{
- tGPDprimitive *tgpi = op->customdata;
- bGPdata *gpd = tgpi->gpd;
-
- /* don't assume that operator data exists at all */
- if (tgpi) {
- /* clear status message area */
- ED_workspace_status_text(C, NULL);
-
- MEM_SAFE_FREE(tgpi->points);
- tgpi->gpd->runtime.tot_cp_points = 0;
- MEM_SAFE_FREE(tgpi->gpd->runtime.cp_points);
- /* finally, free memory used by temp data */
- BKE_gpencil_free_strokes(tgpi->gpf);
- MEM_SAFE_FREE(tgpi->gpf);
-
- /* free random seed */
- if (tgpi->rng != NULL) {
- BLI_rng_free(tgpi->rng);
- }
-
- MEM_freeN(tgpi);
- }
-
- /* free stroke buffer */
- if ((gpd != NULL) && (gpd->runtime.sbuffer)) {
- MEM_SAFE_FREE(gpd->runtime.sbuffer);
- gpd->runtime.sbuffer = NULL;
-
- /* clear flags */
- gpd->runtime.sbuffer_size = 0;
- gpd->runtime.sbuffer_sflag = 0;
- }
-
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
-
- /* clear pointer */
- op->customdata = NULL;
+ tGPDprimitive *tgpi = op->customdata;
+ bGPdata *gpd = tgpi->gpd;
+
+ /* don't assume that operator data exists at all */
+ if (tgpi) {
+ /* clear status message area */
+ ED_workspace_status_text(C, NULL);
+
+ MEM_SAFE_FREE(tgpi->points);
+ tgpi->gpd->runtime.tot_cp_points = 0;
+ MEM_SAFE_FREE(tgpi->gpd->runtime.cp_points);
+ /* finally, free memory used by temp data */
+ BKE_gpencil_free_strokes(tgpi->gpf);
+ MEM_SAFE_FREE(tgpi->gpf);
+
+ /* free random seed */
+ if (tgpi->rng != NULL) {
+ BLI_rng_free(tgpi->rng);
+ }
+
+ MEM_freeN(tgpi);
+ }
+
+ /* free stroke buffer */
+ if ((gpd != NULL) && (gpd->runtime.sbuffer)) {
+ MEM_SAFE_FREE(gpd->runtime.sbuffer);
+ gpd->runtime.sbuffer = NULL;
+
+ /* clear flags */
+ gpd->runtime.sbuffer_size = 0;
+ gpd->runtime.sbuffer_sflag = 0;
+ }
+
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* clear pointer */
+ op->customdata = NULL;
}
/* Init new temporary primitive data */
static void gpencil_primitive_init(bContext *C, wmOperator *op)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- bGPdata *gpd = CTX_data_gpencil_data(C);
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
-
- /* create temporary operator data */
- tGPDprimitive *tgpi = MEM_callocN(sizeof(tGPDprimitive), "GPencil Primitive Data");
- op->customdata = tgpi;
-
- tgpi->points = MEM_callocN(sizeof(tGPspoint), "gp primitive points2D");
-
- /* set current scene and window info */
- tgpi->bmain = CTX_data_main(C);
- tgpi->scene = scene;
- tgpi->ob = CTX_data_active_object(C);
- tgpi->sa = CTX_wm_area(C);
- tgpi->ar = CTX_wm_region(C);
- tgpi->rv3d = tgpi->ar->regiondata;
- tgpi->v3d = tgpi->sa->spacedata.first;
- tgpi->depsgraph = CTX_data_depsgraph(C);
- tgpi->win = CTX_wm_window(C);
-
- /* save original type */
- tgpi->orign_type = RNA_enum_get(op->ptr, "type");
-
- /* set current frame number */
- tgpi->cframe = cfra_eval;
-
- /* set GP datablock */
- tgpi->gpd = gpd;
- /* region where paint was originated */
- tgpi->gpd->runtime.ar = tgpi->ar;
-
- /* control points */
- tgpi->gpd->runtime.cp_points = MEM_callocN(sizeof(bGPDcontrolpoint) * MAX_CP, "gp primitive cpoint");
- tgpi->gpd->runtime.tot_cp_points = 0;
-
- /* getcolor info */
- tgpi->mat = BKE_gpencil_object_material_ensure_from_active_input_toolsettings(bmain, tgpi->ob, ts);
-
- /* set parameters */
- tgpi->type = RNA_enum_get(op->ptr, "type");
-
- if (ELEM(tgpi->type, GP_STROKE_ARC, GP_STROKE_CURVE)) {
- tgpi->curve = true;
- }
- else {
- tgpi->curve = false;
- }
-
- /* set default edge count */
- switch (tgpi->type) {
- case GP_STROKE_LINE:
- {
- RNA_int_set(op->ptr, "edges", 8);
- break;
- }
- case GP_STROKE_BOX:
- {
- RNA_int_set(op->ptr, "edges", 8);
- break;
- }
- case GP_STROKE_CIRCLE:
- {
- RNA_int_set(op->ptr, "edges", 96);
- break;
- }
- default:
- {
- RNA_int_set(op->ptr, "edges", 64);
- break;
- }
- }
-
- tgpi->tot_stored_edges = 0;
- tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
- tgpi->flag = IDLE;
- tgpi->lock_axis = ts->gp_sculpt.lock_axis;
-
- /* set temp layer, frame and stroke */
- gp_primitive_set_initdata(C, tgpi);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ /* create temporary operator data */
+ tGPDprimitive *tgpi = MEM_callocN(sizeof(tGPDprimitive), "GPencil Primitive Data");
+ op->customdata = tgpi;
+
+ tgpi->points = MEM_callocN(sizeof(tGPspoint), "gp primitive points2D");
+
+ /* set current scene and window info */
+ tgpi->bmain = CTX_data_main(C);
+ tgpi->scene = scene;
+ tgpi->ob = CTX_data_active_object(C);
+ tgpi->sa = CTX_wm_area(C);
+ tgpi->ar = CTX_wm_region(C);
+ tgpi->rv3d = tgpi->ar->regiondata;
+ tgpi->v3d = tgpi->sa->spacedata.first;
+ tgpi->depsgraph = CTX_data_depsgraph(C);
+ tgpi->win = CTX_wm_window(C);
+
+ /* save original type */
+ tgpi->orign_type = RNA_enum_get(op->ptr, "type");
+
+ /* set current frame number */
+ tgpi->cframe = cfra_eval;
+
+ /* set GP datablock */
+ tgpi->gpd = gpd;
+ /* region where paint was originated */
+ tgpi->gpd->runtime.ar = tgpi->ar;
+
+ /* control points */
+ tgpi->gpd->runtime.cp_points = MEM_callocN(sizeof(bGPDcontrolpoint) * MAX_CP,
+ "gp primitive cpoint");
+ tgpi->gpd->runtime.tot_cp_points = 0;
+
+ /* getcolor info */
+ tgpi->mat = BKE_gpencil_object_material_ensure_from_active_input_toolsettings(
+ bmain, tgpi->ob, ts);
+
+ /* set parameters */
+ tgpi->type = RNA_enum_get(op->ptr, "type");
+
+ if (ELEM(tgpi->type, GP_STROKE_ARC, GP_STROKE_CURVE)) {
+ tgpi->curve = true;
+ }
+ else {
+ tgpi->curve = false;
+ }
+
+ /* set default edge count */
+ switch (tgpi->type) {
+ case GP_STROKE_LINE: {
+ RNA_int_set(op->ptr, "edges", 8);
+ break;
+ }
+ case GP_STROKE_BOX: {
+ RNA_int_set(op->ptr, "edges", 8);
+ break;
+ }
+ case GP_STROKE_CIRCLE: {
+ RNA_int_set(op->ptr, "edges", 96);
+ break;
+ }
+ default: {
+ RNA_int_set(op->ptr, "edges", 64);
+ break;
+ }
+ }
+
+ tgpi->tot_stored_edges = 0;
+ tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
+ tgpi->flag = IDLE;
+ tgpi->lock_axis = ts->gp_sculpt.lock_axis;
+
+ /* set temp layer, frame and stroke */
+ gp_primitive_set_initdata(C, tgpi);
}
/* Invoke handler: Initialize the operator */
static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- wmWindow *win = CTX_wm_window(C);
- bGPdata *gpd = CTX_data_gpencil_data(C);
- tGPDprimitive *tgpi = NULL;
+ wmWindow *win = CTX_wm_window(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ tGPDprimitive *tgpi = NULL;
- /* initialize operator runtime data */
- gpencil_primitive_init(C, op);
- tgpi = op->customdata;
+ /* initialize operator runtime data */
+ gpencil_primitive_init(C, op);
+ tgpi = op->customdata;
- const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
- if (!is_modal) {
- tgpi->flag = IN_PROGRESS;
- gpencil_primitive_interaction_begin(tgpi, event);
- }
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ if (!is_modal) {
+ tgpi->flag = IN_PROGRESS;
+ gpencil_primitive_interaction_begin(tgpi, event);
+ }
- /* if in tools region, wait till we get to the main (3d-space)
- * region before allowing drawing to take place.
- */
- op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ /* if in tools region, wait till we get to the main (3d-space)
+ * region before allowing drawing to take place.
+ */
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
- /* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_CROSSCURSOR);
+ /* set cursor to indicate modal */
+ WM_cursor_modal_set(win, BC_CROSSCURSOR);
- /* update sindicator in header */
- gpencil_primitive_status_indicators(C, tgpi);
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ /* update sindicator in header */
+ gpencil_primitive_status_indicators(C, tgpi);
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
- /* add a modal handler for this operator */
- WM_event_add_modal_handler(C, op);
+ /* add a modal handler for this operator */
+ WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
/* Helper to complete a primitive */
-static void gpencil_primitive_interaction_end(bContext *C, wmOperator *op, wmWindow *win, tGPDprimitive *tgpi)
+static void gpencil_primitive_interaction_end(bContext *C,
+ wmOperator *op,
+ wmWindow *win,
+ tGPDprimitive *tgpi)
{
- bGPDframe *gpf;
- bGPDstroke *gps;
-
- ToolSettings *ts = tgpi->scene->toolsettings;
- Brush *brush = tgpi->brush;
-
- const int def_nr = tgpi->ob->actdef - 1;
- const bool have_weight = (bool)BLI_findlink(&tgpi->ob->defbase, def_nr);
-
- /* return to normal cursor and header status */
- ED_workspace_status_text(C, NULL);
- WM_cursor_modal_restore(win);
-
- /* insert keyframes as required... */
- short add_frame_mode;
- if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
- add_frame_mode = GP_GETFRAME_ADD_COPY;
- }
- else {
- add_frame_mode = GP_GETFRAME_ADD_NEW;
- }
-
- gpf = BKE_gpencil_layer_getframe(tgpi->gpl, tgpi->cframe, add_frame_mode);
-
- /* prepare stroke to get transferred */
- gps = tgpi->gpf->strokes.first;
- if (gps) {
- gps->thickness = brush->size;
- gps->gradient_f = brush->gpencil_settings->gradient_f;
- copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
-
- /* calculate UVs along the stroke */
- ED_gpencil_calc_stroke_uv(tgpi->ob, gps);
- }
-
- /* transfer stroke from temporary buffer to the actual frame */
- if (ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) {
- BLI_movelisttolist_reverse(&gpf->strokes, &tgpi->gpf->strokes);
- }
- else {
- BLI_movelisttolist(&gpf->strokes, &tgpi->gpf->strokes);
- }
- BLI_assert(BLI_listbase_is_empty(&tgpi->gpf->strokes));
-
- /* add weights if required */
- if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
- BKE_gpencil_dvert_ensure(gps);
- for (int i = 0; i < gps->totpoints; i++) {
- MDeformVert *ve = &gps->dvert[i];
- MDeformWeight *dw = defvert_verify_index(ve, def_nr);
- if (dw) {
- dw->weight = ts->vgroup_weight;
- }
- }
- }
-
- DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_COPY_ON_WRITE);
- DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-
- /* clean up temp data */
- gpencil_primitive_exit(C, op);
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+
+ ToolSettings *ts = tgpi->scene->toolsettings;
+ Brush *brush = tgpi->brush;
+
+ const int def_nr = tgpi->ob->actdef - 1;
+ const bool have_weight = (bool)BLI_findlink(&tgpi->ob->defbase, def_nr);
+
+ /* return to normal cursor and header status */
+ ED_workspace_status_text(C, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* insert keyframes as required... */
+ short add_frame_mode;
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
+ add_frame_mode = GP_GETFRAME_ADD_COPY;
+ }
+ else {
+ add_frame_mode = GP_GETFRAME_ADD_NEW;
+ }
+
+ gpf = BKE_gpencil_layer_getframe(tgpi->gpl, tgpi->cframe, add_frame_mode);
+
+ /* prepare stroke to get transferred */
+ gps = tgpi->gpf->strokes.first;
+ if (gps) {
+ gps->thickness = brush->size;
+ gps->gradient_f = brush->gpencil_settings->gradient_f;
+ copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
+
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
+
+ /* calculate UVs along the stroke */
+ ED_gpencil_calc_stroke_uv(tgpi->ob, gps);
+ }
+
+ /* transfer stroke from temporary buffer to the actual frame */
+ if (ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) {
+ BLI_movelisttolist_reverse(&gpf->strokes, &tgpi->gpf->strokes);
+ }
+ else {
+ BLI_movelisttolist(&gpf->strokes, &tgpi->gpf->strokes);
+ }
+ BLI_assert(BLI_listbase_is_empty(&tgpi->gpf->strokes));
+
+ /* add weights if required */
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ for (int i = 0; i < gps->totpoints; i++) {
+ MDeformVert *ve = &gps->dvert[i];
+ MDeformWeight *dw = defvert_verify_index(ve, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+ }
+ }
+
+ DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+
+ /* clean up temp data */
+ gpencil_primitive_exit(C, op);
}
/* edit event handling */
-static void gpencil_primitive_edit_event_handling(bContext *C, wmOperator *op, wmWindow *win, const wmEvent *event, tGPDprimitive *tgpi)
+static void gpencil_primitive_edit_event_handling(
+ bContext *C, wmOperator *op, wmWindow *win, const wmEvent *event, tGPDprimitive *tgpi)
{
- /* calculate nearest point then set cursor */
- int move = MOVE_NONE;
- float a = len_v2v2(tgpi->mval, tgpi->start);
- float b = len_v2v2(tgpi->mval, tgpi->end);
-
- float c = len_v2v2(tgpi->mval, tgpi->cp1);
- float d = len_v2v2(tgpi->mval, tgpi->cp2);
-
- if (tgpi->flag == IN_CURVE_EDIT) {
- if ((a < BIG_SIZE_CTL && tgpi->tot_stored_edges == 0) || b < BIG_SIZE_CTL) {
- move = MOVE_ENDS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
- }
- else if (tgpi->curve) {
- move = MOVE_CP;
- WM_cursor_modal_set(win, BC_HANDCURSOR);
- }
- else {
- WM_cursor_modal_set(win, BC_CROSSCURSOR);
- }
- }
- else if (tgpi->flag == IN_PROGRESS) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
- }
-
- switch (event->type) {
- case MOUSEMOVE:
- {
- if ((event->val == KM_PRESS) && tgpi->sel_cp != SELECT_NONE) {
- if (tgpi->sel_cp == SELECT_START && tgpi->tot_stored_edges == 0) {
- copy_v2_v2(tgpi->start, tgpi->mval);
- }
- else if (tgpi->sel_cp == SELECT_END) {
- copy_v2_v2(tgpi->end, tgpi->mval);
- }
- else if (tgpi->sel_cp == SELECT_CP1 || (tgpi->sel_cp == SELECT_CP2 && tgpi->type != GP_STROKE_CURVE)) {
- float dx = (tgpi->mval[0] - tgpi->mvalo[0]);
- float dy = (tgpi->mval[1] - tgpi->mvalo[1]);
- tgpi->cp1[0] += dx;
- tgpi->cp1[1] += dy;
- if (event->shift)
- copy_v2_v2(tgpi->cp2, tgpi->cp1);
- }
- else if (tgpi->sel_cp == SELECT_CP2) {
- float dx = (tgpi->mval[0] - tgpi->mvalo[0]);
- float dy = (tgpi->mval[1] - tgpi->mvalo[1]);
- tgpi->cp2[0] += dx;
- tgpi->cp2[1] += dy;
- if (event->shift)
- copy_v2_v2(tgpi->cp1, tgpi->cp2);
- }
- /* update screen */
- gpencil_primitive_update(C, op, tgpi);
- }
- break;
- }
- case LEFTMOUSE:
- {
- if ((event->val == KM_PRESS)) {
- /* find nearest cp based on stroke end points */
- if (move == MOVE_ENDS)
- tgpi->sel_cp = (a < b) ? SELECT_START : SELECT_END;
- else if (move == MOVE_CP)
- tgpi->sel_cp = (c < d) ? SELECT_CP1 : SELECT_CP2;
- else
- tgpi->sel_cp = SELECT_NONE;
- break;
- }
- else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
- /* set control points and enter edit mode */
- tgpi->flag = IN_CURVE_EDIT;
- gp_primitive_update_cps(tgpi);
- gpencil_primitive_update(C, op, tgpi);
- }
- else {
- tgpi->sel_cp = SELECT_NONE;
- }
- break;
- }
- case MKEY:
- {
- if ((event->val == KM_PRESS) &&
- (tgpi->curve) &&
- (ELEM(tgpi->orign_type, GP_STROKE_ARC) ))
- {
- tgpi->flip ^= 1;
- gp_primitive_update_cps(tgpi);
- gpencil_primitive_update(C, op, tgpi);
- }
- break;
- }
- case EKEY:
- {
- if (tgpi->flag == IN_CURVE_EDIT && !ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
- tgpi->flag = IN_PROGRESS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
- gpencil_primitive_add_segment(tgpi);
- copy_v2_v2(tgpi->start, tgpi->end);
- copy_v2_v2(tgpi->origin, tgpi->start);
- gp_primitive_update_cps(tgpi);
- }
- break;
- }
- }
+ /* calculate nearest point then set cursor */
+ int move = MOVE_NONE;
+ float a = len_v2v2(tgpi->mval, tgpi->start);
+ float b = len_v2v2(tgpi->mval, tgpi->end);
+
+ float c = len_v2v2(tgpi->mval, tgpi->cp1);
+ float d = len_v2v2(tgpi->mval, tgpi->cp2);
+
+ if (tgpi->flag == IN_CURVE_EDIT) {
+ if ((a < BIG_SIZE_CTL && tgpi->tot_stored_edges == 0) || b < BIG_SIZE_CTL) {
+ move = MOVE_ENDS;
+ WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ }
+ else if (tgpi->curve) {
+ move = MOVE_CP;
+ WM_cursor_modal_set(win, BC_HANDCURSOR);
+ }
+ else {
+ WM_cursor_modal_set(win, BC_CROSSCURSOR);
+ }
+ }
+ else if (tgpi->flag == IN_PROGRESS) {
+ WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ }
+
+ switch (event->type) {
+ case MOUSEMOVE: {
+ if ((event->val == KM_PRESS) && tgpi->sel_cp != SELECT_NONE) {
+ if (tgpi->sel_cp == SELECT_START && tgpi->tot_stored_edges == 0) {
+ copy_v2_v2(tgpi->start, tgpi->mval);
+ }
+ else if (tgpi->sel_cp == SELECT_END) {
+ copy_v2_v2(tgpi->end, tgpi->mval);
+ }
+ else if (tgpi->sel_cp == SELECT_CP1 ||
+ (tgpi->sel_cp == SELECT_CP2 && tgpi->type != GP_STROKE_CURVE)) {
+ float dx = (tgpi->mval[0] - tgpi->mvalo[0]);
+ float dy = (tgpi->mval[1] - tgpi->mvalo[1]);
+ tgpi->cp1[0] += dx;
+ tgpi->cp1[1] += dy;
+ if (event->shift)
+ copy_v2_v2(tgpi->cp2, tgpi->cp1);
+ }
+ else if (tgpi->sel_cp == SELECT_CP2) {
+ float dx = (tgpi->mval[0] - tgpi->mvalo[0]);
+ float dy = (tgpi->mval[1] - tgpi->mvalo[1]);
+ tgpi->cp2[0] += dx;
+ tgpi->cp2[1] += dy;
+ if (event->shift)
+ copy_v2_v2(tgpi->cp1, tgpi->cp2);
+ }
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case LEFTMOUSE: {
+ if ((event->val == KM_PRESS)) {
+ /* find nearest cp based on stroke end points */
+ if (move == MOVE_ENDS)
+ tgpi->sel_cp = (a < b) ? SELECT_START : SELECT_END;
+ else if (move == MOVE_CP)
+ tgpi->sel_cp = (c < d) ? SELECT_CP1 : SELECT_CP2;
+ else
+ tgpi->sel_cp = SELECT_NONE;
+ break;
+ }
+ else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
+ /* set control points and enter edit mode */
+ tgpi->flag = IN_CURVE_EDIT;
+ gp_primitive_update_cps(tgpi);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ else {
+ tgpi->sel_cp = SELECT_NONE;
+ }
+ break;
+ }
+ case MKEY: {
+ if ((event->val == KM_PRESS) && (tgpi->curve) && (ELEM(tgpi->orign_type, GP_STROKE_ARC))) {
+ tgpi->flip ^= 1;
+ gp_primitive_update_cps(tgpi);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case EKEY: {
+ if (tgpi->flag == IN_CURVE_EDIT && !ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
+ tgpi->flag = IN_PROGRESS;
+ WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ gpencil_primitive_add_segment(tgpi);
+ copy_v2_v2(tgpi->start, tgpi->end);
+ copy_v2_v2(tgpi->origin, tgpi->start);
+ gp_primitive_update_cps(tgpi);
+ }
+ break;
+ }
+ }
}
/* brush strength */
static void gpencil_primitive_strength(tGPDprimitive *tgpi, bool reset)
{
- Brush *brush = tgpi->brush;
- if (brush) {
- if (reset) {
- brush->gpencil_settings->draw_strength = tgpi->brush_strength;
- tgpi->brush_strength = 0.0f;
- }
- else {
- if (tgpi->brush_strength == 0.0f) {
- tgpi->brush_strength = brush->gpencil_settings->draw_strength;
- }
- float move[2];
- sub_v2_v2v2(move, tgpi->mval, tgpi->mvalo);
- float adjust = (move[1] > 0.0f) ? 0.01f : -0.01f;
- brush->gpencil_settings->draw_strength += adjust * fabsf(len_manhattan_v2(move));
- }
-
- /* limit low limit because below 0.2f the stroke is invisible */
- CLAMP(brush->gpencil_settings->draw_strength, 0.2f, 1.0f);
- }
+ Brush *brush = tgpi->brush;
+ if (brush) {
+ if (reset) {
+ brush->gpencil_settings->draw_strength = tgpi->brush_strength;
+ tgpi->brush_strength = 0.0f;
+ }
+ else {
+ if (tgpi->brush_strength == 0.0f) {
+ tgpi->brush_strength = brush->gpencil_settings->draw_strength;
+ }
+ float move[2];
+ sub_v2_v2v2(move, tgpi->mval, tgpi->mvalo);
+ float adjust = (move[1] > 0.0f) ? 0.01f : -0.01f;
+ brush->gpencil_settings->draw_strength += adjust * fabsf(len_manhattan_v2(move));
+ }
+
+ /* limit low limit because below 0.2f the stroke is invisible */
+ CLAMP(brush->gpencil_settings->draw_strength, 0.2f, 1.0f);
+ }
}
/* brush size */
static void gpencil_primitive_size(tGPDprimitive *tgpi, bool reset)
{
- Brush *brush = tgpi->brush;
- if (brush) {
- if (reset) {
- brush->size = tgpi->brush_size;
- tgpi->brush_size = 0;
- }
- else {
- if (tgpi->brush_size == 0) {
- tgpi->brush_size = brush->size;
- }
- float move[2];
- sub_v2_v2v2(move, tgpi->mval, tgpi->mvalo);
- int adjust = (move[1] > 0.0f) ? 1 : -1;
- brush->size += adjust * (int)fabsf(len_manhattan_v2(move));
- }
- CLAMP_MIN(brush->size, 1);
- }
+ Brush *brush = tgpi->brush;
+ if (brush) {
+ if (reset) {
+ brush->size = tgpi->brush_size;
+ tgpi->brush_size = 0;
+ }
+ else {
+ if (tgpi->brush_size == 0) {
+ tgpi->brush_size = brush->size;
+ }
+ float move[2];
+ sub_v2_v2v2(move, tgpi->mval, tgpi->mvalo);
+ int adjust = (move[1] > 0.0f) ? 1 : -1;
+ brush->size += adjust * (int)fabsf(len_manhattan_v2(move));
+ }
+ CLAMP_MIN(brush->size, 1);
+ }
}
/* move */
static void gpencil_primitive_move(tGPDprimitive *tgpi, bool reset)
{
- float move[2];
- zero_v2(move);
-
- if (reset) {
- sub_v2_v2(move, tgpi->move);
- zero_v2(tgpi->move);
- }
- else {
- sub_v2_v2v2(move, tgpi->mval, tgpi->mvalo);
- add_v2_v2(tgpi->move, move);
- }
-
- bGPDstroke *gps = tgpi->gpf->strokes.first;
- tGPspoint *points2D = tgpi->points;
-
- for (int i = 0; i < gps->totpoints; i++) {
- tGPspoint *p2d = &points2D[i];
- add_v2_v2(&p2d->x, move);
- }
-
- add_v2_v2(tgpi->start, move);
- add_v2_v2(tgpi->end, move);
- add_v2_v2(tgpi->cp1, move);
- add_v2_v2(tgpi->cp2, move);
- add_v2_v2(tgpi->origin, move);
+ float move[2];
+ zero_v2(move);
+
+ if (reset) {
+ sub_v2_v2(move, tgpi->move);
+ zero_v2(tgpi->move);
+ }
+ else {
+ sub_v2_v2v2(move, tgpi->mval, tgpi->mvalo);
+ add_v2_v2(tgpi->move, move);
+ }
+
+ bGPDstroke *gps = tgpi->gpf->strokes.first;
+ tGPspoint *points2D = tgpi->points;
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ tGPspoint *p2d = &points2D[i];
+ add_v2_v2(&p2d->x, move);
+ }
+
+ add_v2_v2(tgpi->start, move);
+ add_v2_v2(tgpi->end, move);
+ add_v2_v2(tgpi->cp1, move);
+ add_v2_v2(tgpi->cp2, move);
+ add_v2_v2(tgpi->origin, move);
}
/* Modal handler: Events handling during interactive part */
static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGPDprimitive *tgpi = op->customdata;
- wmWindow *win = CTX_wm_window(C);
- const bool has_numinput = hasNumInput(&tgpi->num);
-
- copy_v2fl_v2i(tgpi->mval, event->mval);
-
- if (tgpi->flag == IN_MOVE) {
-
- switch (event->type) {
- case MOUSEMOVE:
- {
- gpencil_primitive_move(tgpi, false);
- gpencil_primitive_update(C, op, tgpi);
- break;
- }
- case ESCKEY:
- case LEFTMOUSE:
- {
- zero_v2(tgpi->move);
- tgpi->flag = IN_CURVE_EDIT;
- break;
- }
- case RIGHTMOUSE:
- {
- if (event->val == KM_RELEASE) {
- tgpi->flag = IN_CURVE_EDIT;
- gpencil_primitive_move(tgpi, true);
- gpencil_primitive_update(C, op, tgpi);
- }
- break;
- }
- }
- copy_v2_v2(tgpi->mvalo, tgpi->mval);
- return OPERATOR_RUNNING_MODAL;
- }
- else if (tgpi->flag == IN_BRUSH_SIZE) {
- switch (event->type) {
- case MOUSEMOVE:
- gpencil_primitive_size(tgpi, false);
- gpencil_primitive_update(C, op, tgpi);
- break;
- case ESCKEY:
- case MIDDLEMOUSE:
- case LEFTMOUSE:
- tgpi->brush_size = 0;
- tgpi->flag = IN_CURVE_EDIT;
- break;
- case RIGHTMOUSE:
- if (event->val == KM_RELEASE) {
- tgpi->flag = IN_CURVE_EDIT;
- gpencil_primitive_size(tgpi, true);
- gpencil_primitive_update(C, op, tgpi);
- }
- break;
- }
- copy_v2_v2(tgpi->mvalo, tgpi->mval);
- return OPERATOR_RUNNING_MODAL;
- }
- else if (tgpi->flag == IN_BRUSH_STRENGTH) {
- switch (event->type) {
- case MOUSEMOVE:
- gpencil_primitive_strength(tgpi, false);
- gpencil_primitive_update(C, op, tgpi);
- break;
- case ESCKEY:
- case MIDDLEMOUSE:
- case LEFTMOUSE:
- tgpi->brush_strength = 0.0f;
- tgpi->flag = IN_CURVE_EDIT;
- break;
- case RIGHTMOUSE:
- if (event->val == KM_RELEASE) {
- tgpi->flag = IN_CURVE_EDIT;
- gpencil_primitive_strength(tgpi, true);
- gpencil_primitive_update(C, op, tgpi);
- }
- break;
- }
- copy_v2_v2(tgpi->mvalo, tgpi->mval);
- return OPERATOR_RUNNING_MODAL;
- }
- else if (tgpi->flag != IDLE) {
- gpencil_primitive_edit_event_handling(C, op, win, event, tgpi);
- }
-
- switch (event->type) {
- case LEFTMOUSE:
- {
- if ((event->val == KM_PRESS) && (tgpi->flag == IDLE)) {
- /* start drawing primitive */
- /* TODO: Ignore if not in main region yet */
- tgpi->flag = IN_PROGRESS;
- gpencil_primitive_interaction_begin(tgpi, event);
- }
- else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_MOVE)) {
- tgpi->flag = IN_CURVE_EDIT;
- }
- else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
- /* set control points and enter edit mode */
- tgpi->flag = IN_CURVE_EDIT;
- gp_primitive_update_cps(tgpi);
- gpencil_primitive_update(C, op, tgpi);
- }
- else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) && (tgpi->type != GP_STROKE_CURVE)) {
- /* stop drawing primitive */
- tgpi->flag = IDLE;
- gpencil_primitive_interaction_end(C, op, win, tgpi);
- /* done! */
- return OPERATOR_FINISHED;
- }
- else {
- if (G.debug & G_DEBUG) {
- printf("GP Add Primitive Modal: LEFTMOUSE %d, Status = %d\n", event->val, tgpi->flag);
- }
- }
- break;
- }
- case SPACEKEY: /* confirm */
- case MIDDLEMOUSE:
- case RETKEY:
- {
- tgpi->flag = IDLE;
- gpencil_primitive_interaction_end(C, op, win, tgpi);
- /* done! */
- return OPERATOR_FINISHED;
- }
- case RIGHTMOUSE:
- {
- /* exception to cancel current stroke when we have previous strokes in buffer */
- if (tgpi->tot_stored_edges > 0) {
- tgpi->flag = IDLE;
- tgpi->tot_edges = 0;
- gp_primitive_update_strokes(C, tgpi);
- gpencil_primitive_interaction_end(C, op, win, tgpi);
- /* done! */
- return OPERATOR_FINISHED;
- }
- ATTR_FALLTHROUGH;
- }
- case ESCKEY:
- {
- /* return to normal cursor and header status */
- ED_workspace_status_text(C, NULL);
- WM_cursor_modal_restore(win);
-
- /* clean up temp data */
- gpencil_primitive_exit(C, op);
-
- /* canceled! */
- return OPERATOR_CANCELLED;
- }
- case PADPLUSKEY:
- case WHEELUPMOUSE:
- {
- if ((event->val != KM_RELEASE)) {
- tgpi->tot_edges = tgpi->tot_edges + 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
- RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
-
- /* update screen */
- gpencil_primitive_update(C, op, tgpi);
- }
- break;
- }
- case PADMINUS:
- case WHEELDOWNMOUSE:
- {
- if ((event->val != KM_RELEASE)) {
- tgpi->tot_edges = tgpi->tot_edges - 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
- RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
-
- /* update screen */
- gpencil_primitive_update(C, op, tgpi);
- }
- break;
- }
- case GKEY: /* grab mode */
- {
- if ((event->val == KM_PRESS)) {
- tgpi->flag = IN_MOVE;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
- }
- break;
- }
- case FKEY: /* brush thickness/ brush strength */
- {
- if ((event->val == KM_PRESS)) {
- if (event->shift) {
- tgpi->flag = IN_BRUSH_STRENGTH;
- }
- else {
- tgpi->flag = IN_BRUSH_SIZE;
- }
- WM_cursor_modal_set(win, BC_NS_SCROLLCURSOR);
- }
- break;
- }
- case CKEY: /* curve mode */
- {
- if ((event->val == KM_PRESS) &&
- (tgpi->orign_type == GP_STROKE_CURVE))
- {
- switch (tgpi->type) {
- case GP_STROKE_CURVE:
- tgpi->type = GP_STROKE_ARC;
- break;
- default:
- case GP_STROKE_ARC:
- tgpi->type = GP_STROKE_CURVE;
- break;
- }
-
- RNA_enum_set(op->ptr, "type", tgpi->type);
- gp_primitive_update_cps(tgpi);
- gpencil_primitive_update(C, op, tgpi);
- }
- break;
- }
- case TABKEY:
- {
- if (tgpi->flag == IN_CURVE_EDIT) {
- tgpi->flag = IN_PROGRESS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
- gp_primitive_update_cps(tgpi);
- gpencil_primitive_update(C, op, tgpi);
- }
- break;
- }
- case MOUSEMOVE: /* calculate new position */
- {
- if (tgpi->flag == IN_CURVE_EDIT) {
- break;
- }
- /* only handle mousemove if not doing numinput */
- if (has_numinput == false) {
- /* update position of mouse */
- copy_v2_v2(tgpi->end, tgpi->mval);
- copy_v2_v2(tgpi->start, tgpi->origin);
- if (tgpi->flag == IDLE) {
- copy_v2_v2(tgpi->origin, tgpi->mval);
- }
- /* Keep square if shift key */
- if (event->shift) {
- float x = tgpi->end[0] - tgpi->origin[0];
- float y = tgpi->end[1] - tgpi->origin[1];
- if (tgpi->type == GP_STROKE_LINE || tgpi->curve) {
- float angle = fabsf(atan2f(y, x));
- if (angle < 0.4f || angle > (M_PI - 0.4f)) {
- tgpi->end[1] = tgpi->origin[1];
- }
- else if (angle > (M_PI_2 - 0.4f) && angle < (M_PI_2 + 0.4f)) {
- tgpi->end[0] = tgpi->origin[0];
- }
- else {
- gpencil_primitive_to_square(tgpi, x, y);
- }
- }
- else {
- gpencil_primitive_to_square(tgpi, x, y);
- }
- }
- /* Center primitive if alt key */
- if (event->alt) {
- tgpi->start[0] = tgpi->origin[0] - (tgpi->end[0] - tgpi->origin[0]);
- tgpi->start[1] = tgpi->origin[1] - (tgpi->end[1] - tgpi->origin[1]);
- }
- gp_primitive_update_cps(tgpi);
- /* update screen */
- gpencil_primitive_update(C, op, tgpi);
- }
- break;
- }
- default:
- {
- if (tgpi->flag != IN_CURVE_EDIT && (event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
- float value;
-
- /* Grab data from numeric input, and store this new value (the user see an int) */
- value = tgpi->tot_edges;
- applyNumInput(&tgpi->num, &value);
- tgpi->tot_edges = value;
-
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
- RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
-
- /* update screen */
- gpencil_primitive_update(C, op, tgpi);
-
- break;
- }
- else {
- /* unhandled event - allow to pass through */
- return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
- }
- }
- }
-
- copy_v2_v2(tgpi->mvalo, tgpi->mval);
- /* still running... */
- return OPERATOR_RUNNING_MODAL;
+ tGPDprimitive *tgpi = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+ const bool has_numinput = hasNumInput(&tgpi->num);
+
+ copy_v2fl_v2i(tgpi->mval, event->mval);
+
+ if (tgpi->flag == IN_MOVE) {
+
+ switch (event->type) {
+ case MOUSEMOVE: {
+ gpencil_primitive_move(tgpi, false);
+ gpencil_primitive_update(C, op, tgpi);
+ break;
+ }
+ case ESCKEY:
+ case LEFTMOUSE: {
+ zero_v2(tgpi->move);
+ tgpi->flag = IN_CURVE_EDIT;
+ break;
+ }
+ case RIGHTMOUSE: {
+ if (event->val == KM_RELEASE) {
+ tgpi->flag = IN_CURVE_EDIT;
+ gpencil_primitive_move(tgpi, true);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ }
+ copy_v2_v2(tgpi->mvalo, tgpi->mval);
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else if (tgpi->flag == IN_BRUSH_SIZE) {
+ switch (event->type) {
+ case MOUSEMOVE:
+ gpencil_primitive_size(tgpi, false);
+ gpencil_primitive_update(C, op, tgpi);
+ break;
+ case ESCKEY:
+ case MIDDLEMOUSE:
+ case LEFTMOUSE:
+ tgpi->brush_size = 0;
+ tgpi->flag = IN_CURVE_EDIT;
+ break;
+ case RIGHTMOUSE:
+ if (event->val == KM_RELEASE) {
+ tgpi->flag = IN_CURVE_EDIT;
+ gpencil_primitive_size(tgpi, true);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ copy_v2_v2(tgpi->mvalo, tgpi->mval);
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else if (tgpi->flag == IN_BRUSH_STRENGTH) {
+ switch (event->type) {
+ case MOUSEMOVE:
+ gpencil_primitive_strength(tgpi, false);
+ gpencil_primitive_update(C, op, tgpi);
+ break;
+ case ESCKEY:
+ case MIDDLEMOUSE:
+ case LEFTMOUSE:
+ tgpi->brush_strength = 0.0f;
+ tgpi->flag = IN_CURVE_EDIT;
+ break;
+ case RIGHTMOUSE:
+ if (event->val == KM_RELEASE) {
+ tgpi->flag = IN_CURVE_EDIT;
+ gpencil_primitive_strength(tgpi, true);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ copy_v2_v2(tgpi->mvalo, tgpi->mval);
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else if (tgpi->flag != IDLE) {
+ gpencil_primitive_edit_event_handling(C, op, win, event, tgpi);
+ }
+
+ switch (event->type) {
+ case LEFTMOUSE: {
+ if ((event->val == KM_PRESS) && (tgpi->flag == IDLE)) {
+ /* start drawing primitive */
+ /* TODO: Ignore if not in main region yet */
+ tgpi->flag = IN_PROGRESS;
+ gpencil_primitive_interaction_begin(tgpi, event);
+ }
+ else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_MOVE)) {
+ tgpi->flag = IN_CURVE_EDIT;
+ }
+ else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
+ /* set control points and enter edit mode */
+ tgpi->flag = IN_CURVE_EDIT;
+ gp_primitive_update_cps(tgpi);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) &&
+ (tgpi->type != GP_STROKE_CURVE)) {
+ /* stop drawing primitive */
+ tgpi->flag = IDLE;
+ gpencil_primitive_interaction_end(C, op, win, tgpi);
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+ else {
+ if (G.debug & G_DEBUG) {
+ printf("GP Add Primitive Modal: LEFTMOUSE %d, Status = %d\n", event->val, tgpi->flag);
+ }
+ }
+ break;
+ }
+ case SPACEKEY: /* confirm */
+ case MIDDLEMOUSE:
+ case RETKEY: {
+ tgpi->flag = IDLE;
+ gpencil_primitive_interaction_end(C, op, win, tgpi);
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+ case RIGHTMOUSE: {
+ /* exception to cancel current stroke when we have previous strokes in buffer */
+ if (tgpi->tot_stored_edges > 0) {
+ tgpi->flag = IDLE;
+ tgpi->tot_edges = 0;
+ gp_primitive_update_strokes(C, tgpi);
+ gpencil_primitive_interaction_end(C, op, win, tgpi);
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+ ATTR_FALLTHROUGH;
+ }
+ case ESCKEY: {
+ /* return to normal cursor and header status */
+ ED_workspace_status_text(C, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* clean up temp data */
+ gpencil_primitive_exit(C, op);
+
+ /* canceled! */
+ return OPERATOR_CANCELLED;
+ }
+ case PADPLUSKEY:
+ case WHEELUPMOUSE: {
+ if ((event->val != KM_RELEASE)) {
+ tgpi->tot_edges = tgpi->tot_edges + 1;
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case PADMINUS:
+ case WHEELDOWNMOUSE: {
+ if ((event->val != KM_RELEASE)) {
+ tgpi->tot_edges = tgpi->tot_edges - 1;
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case GKEY: /* grab mode */
+ {
+ if ((event->val == KM_PRESS)) {
+ tgpi->flag = IN_MOVE;
+ WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ }
+ break;
+ }
+ case FKEY: /* brush thickness/ brush strength */
+ {
+ if ((event->val == KM_PRESS)) {
+ if (event->shift) {
+ tgpi->flag = IN_BRUSH_STRENGTH;
+ }
+ else {
+ tgpi->flag = IN_BRUSH_SIZE;
+ }
+ WM_cursor_modal_set(win, BC_NS_SCROLLCURSOR);
+ }
+ break;
+ }
+ case CKEY: /* curve mode */
+ {
+ if ((event->val == KM_PRESS) && (tgpi->orign_type == GP_STROKE_CURVE)) {
+ switch (tgpi->type) {
+ case GP_STROKE_CURVE:
+ tgpi->type = GP_STROKE_ARC;
+ break;
+ default:
+ case GP_STROKE_ARC:
+ tgpi->type = GP_STROKE_CURVE;
+ break;
+ }
+
+ RNA_enum_set(op->ptr, "type", tgpi->type);
+ gp_primitive_update_cps(tgpi);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case TABKEY: {
+ if (tgpi->flag == IN_CURVE_EDIT) {
+ tgpi->flag = IN_PROGRESS;
+ WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ gp_primitive_update_cps(tgpi);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case MOUSEMOVE: /* calculate new position */
+ {
+ if (tgpi->flag == IN_CURVE_EDIT) {
+ break;
+ }
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* update position of mouse */
+ copy_v2_v2(tgpi->end, tgpi->mval);
+ copy_v2_v2(tgpi->start, tgpi->origin);
+ if (tgpi->flag == IDLE) {
+ copy_v2_v2(tgpi->origin, tgpi->mval);
+ }
+ /* Keep square if shift key */
+ if (event->shift) {
+ float x = tgpi->end[0] - tgpi->origin[0];
+ float y = tgpi->end[1] - tgpi->origin[1];
+ if (tgpi->type == GP_STROKE_LINE || tgpi->curve) {
+ float angle = fabsf(atan2f(y, x));
+ if (angle < 0.4f || angle > (M_PI - 0.4f)) {
+ tgpi->end[1] = tgpi->origin[1];
+ }
+ else if (angle > (M_PI_2 - 0.4f) && angle < (M_PI_2 + 0.4f)) {
+ tgpi->end[0] = tgpi->origin[0];
+ }
+ else {
+ gpencil_primitive_to_square(tgpi, x, y);
+ }
+ }
+ else {
+ gpencil_primitive_to_square(tgpi, x, y);
+ }
+ }
+ /* Center primitive if alt key */
+ if (event->alt) {
+ tgpi->start[0] = tgpi->origin[0] - (tgpi->end[0] - tgpi->origin[0]);
+ tgpi->start[1] = tgpi->origin[1] - (tgpi->end[1] - tgpi->origin[1]);
+ }
+ gp_primitive_update_cps(tgpi);
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ default: {
+ if (tgpi->flag != IN_CURVE_EDIT && (event->val == KM_PRESS) &&
+ handleNumInput(C, &tgpi->num, event)) {
+ float value;
+
+ /* Grab data from numeric input, and store this new value (the user see an int) */
+ value = tgpi->tot_edges;
+ applyNumInput(&tgpi->num, &value);
+ tgpi->tot_edges = value;
+
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+
+ break;
+ }
+ else {
+ /* unhandled event - allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
+ }
+ }
+
+ copy_v2_v2(tgpi->mvalo, tgpi->mval);
+ /* still running... */
+ return OPERATOR_RUNNING_MODAL;
}
/* Cancel handler */
static void gpencil_primitive_cancel(bContext *C, wmOperator *op)
{
- /* this is just a wrapper around exit() */
- gpencil_primitive_exit(C, op);
+ /* this is just a wrapper around exit() */
+ gpencil_primitive_exit(C, op);
}
void GPENCIL_OT_primitive(wmOperatorType *ot)
{
- static EnumPropertyItem primitive_type[] = {
- {GP_STROKE_BOX, "BOX", 0, "Box", ""},
- {GP_STROKE_LINE, "LINE", 0, "Line", ""},
- {GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", ""},
- {GP_STROKE_ARC, "ARC", 0, "Arc", ""},
- {GP_STROKE_CURVE, "CURVE", 0, "Curve", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Grease Pencil Shapes";
- ot->idname = "GPENCIL_OT_primitive";
- ot->description = "Create predefined grease pencil stroke shapes";
-
- /* callbacks */
- ot->invoke = gpencil_primitive_invoke;
- ot->modal = gpencil_primitive_modal;
- ot->cancel = gpencil_primitive_cancel;
- ot->poll = gpencil_primitive_add_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* properties */
- PropertyRNA *prop;
-
- prop = RNA_def_int(ot->srna, "edges", 4, MIN_EDGES, MAX_EDGES, "Edges", "Number of polygon edges", MIN_EDGES, MAX_EDGES);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- RNA_def_enum(ot->srna, "type", primitive_type, GP_STROKE_BOX, "Type", "Type of shape");
-
- prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ static EnumPropertyItem primitive_type[] = {
+ {GP_STROKE_BOX, "BOX", 0, "Box", ""},
+ {GP_STROKE_LINE, "LINE", 0, "Line", ""},
+ {GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", ""},
+ {GP_STROKE_ARC, "ARC", 0, "Arc", ""},
+ {GP_STROKE_CURVE, "CURVE", 0, "Curve", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Grease Pencil Shapes";
+ ot->idname = "GPENCIL_OT_primitive";
+ ot->description = "Create predefined grease pencil stroke shapes";
+
+ /* callbacks */
+ ot->invoke = gpencil_primitive_invoke;
+ ot->modal = gpencil_primitive_modal;
+ ot->cancel = gpencil_primitive_cancel;
+ ot->poll = gpencil_primitive_add_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ prop = RNA_def_int(ot->srna,
+ "edges",
+ 4,
+ MIN_EDGES,
+ MAX_EDGES,
+ "Edges",
+ "Number of polygon edges",
+ MIN_EDGES,
+ MAX_EDGES);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ RNA_def_enum(ot->srna, "type", primitive_type, GP_STROKE_BOX, "Type", "Type of shape");
+
+ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 99bbf10cdc1..ef7a198111b 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -69,16 +69,16 @@
static bool gpencil_select_poll(bContext *C)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
- /* we just need some visible strokes, and to be in editmode or other modes only to catch event */
- if (GPENCIL_ANY_MODE(gpd)) {
- /* TODO: include a check for visible strokes? */
- if (gpd->layers.first)
- return true;
- }
+ /* we just need some visible strokes, and to be in editmode or other modes only to catch event */
+ if (GPENCIL_ANY_MODE(gpd)) {
+ /* TODO: include a check for visible strokes? */
+ if (gpd->layers.first)
+ return true;
+ }
- return false;
+ return false;
}
/** \} */
@@ -89,47 +89,47 @@ static bool gpencil_select_poll(bContext *C)
static int gpencil_select_all_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- int action = RNA_enum_get(op->ptr, "action");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ int action = RNA_enum_get(op->ptr, "action");
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
- return OPERATOR_CANCELLED;
- }
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
- /* if not edit/sculpt mode, the event is catched but not processed */
- if (GPENCIL_NONE_EDIT_MODE(gpd)) {
- return OPERATOR_CANCELLED;
- }
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
- ED_gpencil_select_toggle_all(C, action);
+ ED_gpencil_select_toggle_all(C, action);
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- return OPERATOR_FINISHED;
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_select_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "(De)select All Strokes";
- ot->idname = "GPENCIL_OT_select_all";
- ot->description = "Change selection of all Grease Pencil strokes currently visible";
+ /* identifiers */
+ ot->name = "(De)select All Strokes";
+ ot->idname = "GPENCIL_OT_select_all";
+ ot->description = "Change selection of all Grease Pencil strokes currently visible";
- /* callbacks */
- ot->exec = gpencil_select_all_exec;
- ot->poll = gpencil_select_poll;
+ /* callbacks */
+ ot->exec = gpencil_select_all_exec;
+ ot->poll = gpencil_select_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_select_all(ot);
+ WM_operator_properties_select_all(ot);
}
/** \} */
@@ -140,56 +140,55 @@ void GPENCIL_OT_select_all(wmOperatorType *ot)
static int gpencil_select_linked_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
-
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
- return OPERATOR_CANCELLED;
- }
-
- /* if not edit/sculpt mode, the event is catched but not processed */
- if (GPENCIL_NONE_EDIT_MODE(gpd)) {
- return OPERATOR_CANCELLED;
- }
-
- /* select all points in selected strokes */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag |= GP_SPOINT_SELECT;
- }
- }
- }
- CTX_DATA_END;
-
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* select all points in selected strokes */
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_select_linked(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Linked";
- ot->idname = "GPENCIL_OT_select_linked";
- ot->description = "Select all points in same strokes as already selected points";
+ /* identifiers */
+ ot->name = "Select Linked";
+ ot->idname = "GPENCIL_OT_select_linked";
+ ot->description = "Select all points in same strokes as already selected points";
- /* callbacks */
- ot->exec = gpencil_select_linked_exec;
- ot->poll = gpencil_select_poll;
+ /* callbacks */
+ ot->exec = gpencil_select_linked_exec;
+ ot->poll = gpencil_select_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
@@ -200,80 +199,83 @@ void GPENCIL_OT_select_linked(wmOperatorType *ot)
static int gpencil_select_alternate_exec(bContext *C, wmOperator *op)
{
- const bool unselect_ends = RNA_boolean_get(op->ptr, "unselect_ends");
- bGPdata *gpd = ED_gpencil_data_get_active(C);
-
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
- return OPERATOR_CANCELLED;
- }
-
- /* if not edit/sculpt mode, the event is catched but not processed */
- if (GPENCIL_NONE_EDIT_MODE(gpd)) {
- return OPERATOR_CANCELLED;
- }
-
- /* select all points in selected strokes */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) {
- bGPDspoint *pt;
- int row = 0;
- int start = 0;
- if (unselect_ends) {
- start = 1;
- }
-
- for (int i = start; i < gps->totpoints; i++) {
- pt = &gps->points[i];
- if ((row % 2) == 0) {
- pt->flag |= GP_SPOINT_SELECT;
- }
- else {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
- row++;
- }
-
- /* unselect start and end points */
- if (unselect_ends) {
- pt = &gps->points[0];
- pt->flag &= ~GP_SPOINT_SELECT;
-
- pt = &gps->points[gps->totpoints - 1];
- pt->flag &= ~GP_SPOINT_SELECT;
- }
- }
- }
- CTX_DATA_END;
-
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- return OPERATOR_FINISHED;
+ const bool unselect_ends = RNA_boolean_get(op->ptr, "unselect_ends");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* select all points in selected strokes */
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) {
+ bGPDspoint *pt;
+ int row = 0;
+ int start = 0;
+ if (unselect_ends) {
+ start = 1;
+ }
+
+ for (int i = start; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ if ((row % 2) == 0) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ row++;
+ }
+
+ /* unselect start and end points */
+ if (unselect_ends) {
+ pt = &gps->points[0];
+ pt->flag &= ~GP_SPOINT_SELECT;
+
+ pt = &gps->points[gps->totpoints - 1];
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_select_alternate(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Alternated";
- ot->idname = "GPENCIL_OT_select_alternate";
- ot->description = "Select alternative points in same strokes as already selected points";
-
- /* callbacks */
- ot->exec = gpencil_select_alternate_exec;
- ot->poll = gpencil_select_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "unselect_ends", true, "Unselect Ends", "Do not select the first and last point of the stroke");
+ /* identifiers */
+ ot->name = "Alternated";
+ ot->idname = "GPENCIL_OT_select_alternate";
+ ot->description = "Select alternative points in same strokes as already selected points";
+
+ /* callbacks */
+ ot->exec = gpencil_select_alternate_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "unselect_ends",
+ true,
+ "Unselect Ends",
+ "Do not select the first and last point of the stroke");
}
/** \} */
@@ -283,14 +285,14 @@ void GPENCIL_OT_select_alternate(wmOperatorType *ot)
* \{ */
typedef enum eGP_SelectGrouped {
- /* Select strokes in the same layer */
- GP_SEL_SAME_LAYER = 0,
+ /* Select strokes in the same layer */
+ GP_SEL_SAME_LAYER = 0,
- /* Select strokes with the same color */
- GP_SEL_SAME_MATERIAL = 1,
+ /* Select strokes with the same color */
+ GP_SEL_SAME_MATERIAL = 1,
- /* TODO: All with same prefix - Useful for isolating all layers for a particular character for instance */
- /* TODO: All with same appearance - colour/opacity/volumetric/fills ? */
+ /* TODO: All with same prefix - Useful for isolating all layers for a particular character for instance */
+ /* TODO: All with same appearance - colour/opacity/volumetric/fills ? */
} eGP_SelectGrouped;
/* ----------------------------------- */
@@ -298,146 +300,143 @@ typedef enum eGP_SelectGrouped {
/* On each visible layer, check for selected strokes - if found, select all others */
static void gp_select_same_layer(bContext *C)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
- bGPDstroke *gps;
- bool found = false;
-
- if (gpf == NULL)
- continue;
-
- /* Search for a selected stroke */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- if (gps->flag & GP_STROKE_SELECT) {
- found = true;
- break;
- }
- }
- }
-
- /* Select all if found */
- if (found) {
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- bGPDspoint *pt;
- int i;
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag |= GP_SPOINT_SELECT;
- }
-
- gps->flag |= GP_STROKE_SELECT;
- }
- }
- }
- }
- CTX_DATA_END;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
+ bGPDstroke *gps;
+ bool found = false;
+
+ if (gpf == NULL)
+ continue;
+
+ /* Search for a selected stroke */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ /* Select all if found */
+ if (found) {
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
}
/* Select all strokes with same colors as selected ones */
static void gp_select_same_material(bContext *C)
{
- /* First, build set containing all the colors of selected strokes */
- GSet *selected_colors = BLI_gset_str_new("GP Selected Colors");
-
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- if (gps->flag & GP_STROKE_SELECT) {
- /* add instead of insert here, otherwise the uniqueness check gets skipped,
- * and we get many duplicate entries...
- */
- BLI_gset_add(selected_colors, &gps->mat_nr);
- }
- }
- CTX_DATA_END;
-
- /* Second, select any visible stroke that uses these colors */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- if (BLI_gset_haskey(selected_colors, &gps->mat_nr)) {
- /* select this stroke */
- bGPDspoint *pt;
- int i;
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag |= GP_SPOINT_SELECT;
- }
-
- gps->flag |= GP_STROKE_SELECT;
- }
- }
- CTX_DATA_END;
-
- /* free memomy */
- if (selected_colors != NULL) {
- BLI_gset_free(selected_colors, NULL);
- }
+ /* First, build set containing all the colors of selected strokes */
+ GSet *selected_colors = BLI_gset_str_new("GP Selected Colors");
+
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* add instead of insert here, otherwise the uniqueness check gets skipped,
+ * and we get many duplicate entries...
+ */
+ BLI_gset_add(selected_colors, &gps->mat_nr);
+ }
+ }
+ CTX_DATA_END;
+
+ /* Second, select any visible stroke that uses these colors */
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if (BLI_gset_haskey(selected_colors, &gps->mat_nr)) {
+ /* select this stroke */
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ }
+ CTX_DATA_END;
+
+ /* free memomy */
+ if (selected_colors != NULL) {
+ BLI_gset_free(selected_colors, NULL);
+ }
}
-
/* ----------------------------------- */
static int gpencil_select_grouped_exec(bContext *C, wmOperator *op)
{
- eGP_SelectGrouped mode = RNA_enum_get(op->ptr, "type");
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- /* if not edit/sculpt mode, the event is catched but not processed */
- if (GPENCIL_NONE_EDIT_MODE(gpd)) {
- return OPERATOR_CANCELLED;
- }
-
- switch (mode) {
- case GP_SEL_SAME_LAYER:
- gp_select_same_layer(C);
- break;
- case GP_SEL_SAME_MATERIAL:
- gp_select_same_material(C);
- break;
-
- default:
- BLI_assert(!"unhandled select grouped gpencil mode");
- break;
- }
-
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- return OPERATOR_FINISHED;
+ eGP_SelectGrouped mode = RNA_enum_get(op->ptr, "type");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (mode) {
+ case GP_SEL_SAME_LAYER:
+ gp_select_same_layer(C);
+ break;
+ case GP_SEL_SAME_MATERIAL:
+ gp_select_same_material(C);
+ break;
+
+ default:
+ BLI_assert(!"unhandled select grouped gpencil mode");
+ break;
+ }
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_select_grouped(wmOperatorType *ot)
{
- static const EnumPropertyItem prop_select_grouped_types[] = {
- {GP_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"},
- {GP_SEL_SAME_MATERIAL, "MATERIAL", 0, "Material", "Shared materials"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Select Grouped";
- ot->idname = "GPENCIL_OT_select_grouped";
- ot->description = "Select all strokes with similar characteristics";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = gpencil_select_grouped_exec;
- ot->poll = gpencil_select_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, GP_SEL_SAME_LAYER, "Type", "");
+ static const EnumPropertyItem prop_select_grouped_types[] = {
+ {GP_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"},
+ {GP_SEL_SAME_MATERIAL, "MATERIAL", 0, "Material", "Shared materials"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Select Grouped";
+ ot->idname = "GPENCIL_OT_select_grouped";
+ ot->description = "Select all strokes with similar characteristics";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gpencil_select_grouped_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ ot->prop = RNA_def_enum(
+ ot->srna, "type", prop_select_grouped_types, GP_SEL_SAME_LAYER, "Type", "");
}
/** \} */
@@ -448,71 +447,77 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot)
static int gpencil_select_first_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- /* if not edit/sculpt mode, the event is catched but not processed */
- if (GPENCIL_NONE_EDIT_MODE(gpd)) {
- return OPERATOR_CANCELLED;
- }
-
- const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
-
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- /* skip stroke if we're only manipulating selected strokes */
- if (only_selected && !(gps->flag & GP_STROKE_SELECT)) {
- continue;
- }
-
- /* select first point */
- BLI_assert(gps->totpoints >= 1);
-
- gps->points->flag |= GP_SPOINT_SELECT;
- gps->flag |= GP_STROKE_SELECT;
-
- /* deselect rest? */
- if ((extend == false) && (gps->totpoints > 1)) {
- /* start from index 1, to skip the first point that we'd just selected... */
- bGPDspoint *pt = &gps->points[1];
- int i = 1;
-
- for (; i < gps->totpoints; i++, pt++) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
- }
- }
- CTX_DATA_END;
-
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ /* skip stroke if we're only manipulating selected strokes */
+ if (only_selected && !(gps->flag & GP_STROKE_SELECT)) {
+ continue;
+ }
+
+ /* select first point */
+ BLI_assert(gps->totpoints >= 1);
+
+ gps->points->flag |= GP_SPOINT_SELECT;
+ gps->flag |= GP_STROKE_SELECT;
+
+ /* deselect rest? */
+ if ((extend == false) && (gps->totpoints > 1)) {
+ /* start from index 1, to skip the first point that we'd just selected... */
+ bGPDspoint *pt = &gps->points[1];
+ int i = 1;
+
+ for (; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_select_first(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select First";
- ot->idname = "GPENCIL_OT_select_first";
- ot->description = "Select first point in Grease Pencil strokes";
-
- /* callbacks */
- ot->exec = gpencil_select_first_exec;
- ot->poll = gpencil_select_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "only_selected_strokes", false, "Selected Strokes Only",
- "Only select the first point of strokes that already have points selected");
-
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points");
+ /* identifiers */
+ ot->name = "Select First";
+ ot->idname = "GPENCIL_OT_select_first";
+ ot->description = "Select first point in Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_select_first_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "only_selected_strokes",
+ false,
+ "Selected Strokes Only",
+ "Only select the first point of strokes that already have points selected");
+
+ RNA_def_boolean(ot->srna,
+ "extend",
+ false,
+ "Extend",
+ "Extend selection instead of deselecting all other selected points");
}
/** \} */
@@ -523,71 +528,77 @@ void GPENCIL_OT_select_first(wmOperatorType *ot)
static int gpencil_select_last_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- /* if not edit/sculpt mode, the event is catched but not processed */
- if (GPENCIL_NONE_EDIT_MODE(gpd)) {
- return OPERATOR_CANCELLED;
- }
-
- const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
-
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- /* skip stroke if we're only manipulating selected strokes */
- if (only_selected && !(gps->flag & GP_STROKE_SELECT)) {
- continue;
- }
-
- /* select last point */
- BLI_assert(gps->totpoints >= 1);
-
- gps->points[gps->totpoints - 1].flag |= GP_SPOINT_SELECT;
- gps->flag |= GP_STROKE_SELECT;
-
- /* deselect rest? */
- if ((extend == false) && (gps->totpoints > 1)) {
- /* don't include the last point... */
- bGPDspoint *pt = gps->points;
- int i = 1;
-
- for (; i < gps->totpoints - 1; i++, pt++) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
- }
- }
- CTX_DATA_END;
-
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ /* skip stroke if we're only manipulating selected strokes */
+ if (only_selected && !(gps->flag & GP_STROKE_SELECT)) {
+ continue;
+ }
+
+ /* select last point */
+ BLI_assert(gps->totpoints >= 1);
+
+ gps->points[gps->totpoints - 1].flag |= GP_SPOINT_SELECT;
+ gps->flag |= GP_STROKE_SELECT;
+
+ /* deselect rest? */
+ if ((extend == false) && (gps->totpoints > 1)) {
+ /* don't include the last point... */
+ bGPDspoint *pt = gps->points;
+ int i = 1;
+
+ for (; i < gps->totpoints - 1; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_select_last(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Last";
- ot->idname = "GPENCIL_OT_select_last";
- ot->description = "Select last point in Grease Pencil strokes";
-
- /* callbacks */
- ot->exec = gpencil_select_last_exec;
- ot->poll = gpencil_select_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "only_selected_strokes", false, "Selected Strokes Only",
- "Only select the last point of strokes that already have points selected");
-
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points");
+ /* identifiers */
+ ot->name = "Select Last";
+ ot->idname = "GPENCIL_OT_select_last";
+ ot->description = "Select last point in Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_select_last_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "only_selected_strokes",
+ false,
+ "Selected Strokes Only",
+ "Only select the last point of strokes that already have points selected");
+
+ RNA_def_boolean(ot->srna,
+ "extend",
+ false,
+ "Extend",
+ "Extend selection instead of deselecting all other selected points");
}
/** \} */
@@ -598,81 +609,80 @@ void GPENCIL_OT_select_last(wmOperatorType *ot)
static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- /* if not edit/sculpt mode, the event is catched but not processed */
- if (GPENCIL_NONE_EDIT_MODE(gpd)) {
- return OPERATOR_CANCELLED;
- }
-
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
- bool prev_sel;
-
- /* First Pass: Go in forward order, expanding selection if previous was selected (pre changes)...
- * - This pass covers the "after" edges of selection islands
- */
- prev_sel = false;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- /* selected point - just set flag for next point */
- prev_sel = true;
- }
- else {
- /* unselected point - expand selection if previous was selected... */
- if (prev_sel) {
- pt->flag |= GP_SPOINT_SELECT;
- }
- prev_sel = false;
- }
- }
-
- /* Second Pass: Go in reverse order, doing the same as before (except in opposite order)
- * - This pass covers the "before" edges of selection islands
- */
- prev_sel = false;
- for (pt -= 1; i > 0; i--, pt--) {
- if (pt->flag & GP_SPOINT_SELECT) {
- prev_sel = true;
- }
- else {
- /* unselected point - expand selection if previous was selected... */
- if (prev_sel) {
- pt->flag |= GP_SPOINT_SELECT;
- }
- prev_sel = false;
- }
- }
- }
- }
- CTX_DATA_END;
-
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+ bool prev_sel;
+
+ /* First Pass: Go in forward order, expanding selection if previous was selected (pre changes)...
+ * - This pass covers the "after" edges of selection islands
+ */
+ prev_sel = false;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* selected point - just set flag for next point */
+ prev_sel = true;
+ }
+ else {
+ /* unselected point - expand selection if previous was selected... */
+ if (prev_sel) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ prev_sel = false;
+ }
+ }
+
+ /* Second Pass: Go in reverse order, doing the same as before (except in opposite order)
+ * - This pass covers the "before" edges of selection islands
+ */
+ prev_sel = false;
+ for (pt -= 1; i > 0; i--, pt--) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ prev_sel = true;
+ }
+ else {
+ /* unselected point - expand selection if previous was selected... */
+ if (prev_sel) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ prev_sel = false;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_select_more(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select More";
- ot->idname = "GPENCIL_OT_select_more";
- ot->description = "Grow sets of selected Grease Pencil points";
+ /* identifiers */
+ ot->name = "Select More";
+ ot->idname = "GPENCIL_OT_select_more";
+ ot->description = "Grow sets of selected Grease Pencil points";
- /* callbacks */
- ot->exec = gpencil_select_more_exec;
- ot->poll = gpencil_select_poll;
+ /* callbacks */
+ ot->exec = gpencil_select_more_exec;
+ ot->poll = gpencil_select_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
@@ -683,82 +693,81 @@ void GPENCIL_OT_select_more(wmOperatorType *ot)
static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- /* if not edit/sculpt mode, the event is catched but not processed */
- if (GPENCIL_NONE_EDIT_MODE(gpd)) {
- return OPERATOR_CANCELLED;
- }
-
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
- bool prev_sel;
-
- /* First Pass: Go in forward order, shrinking selection if previous was not selected (pre changes)...
- * - This pass covers the "after" edges of selection islands
- */
- prev_sel = false;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- /* shrink if previous wasn't selected */
- if (prev_sel == false) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
- prev_sel = true;
- }
- else {
- /* mark previous as being unselected - and hence, is trigger for shrinking */
- prev_sel = false;
- }
- }
-
- /* Second Pass: Go in reverse order, doing the same as before (except in opposite order)
- * - This pass covers the "before" edges of selection islands
- */
- prev_sel = false;
- for (pt -= 1; i > 0; i--, pt--) {
- if (pt->flag & GP_SPOINT_SELECT) {
- /* shrink if previous wasn't selected */
- if (prev_sel == false) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
- prev_sel = true;
- }
- else {
- /* mark previous as being unselected - and hence, is trigger for shrinking */
- prev_sel = false;
- }
- }
- }
- }
- CTX_DATA_END;
-
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+ bool prev_sel;
+
+ /* First Pass: Go in forward order, shrinking selection if previous was not selected (pre changes)...
+ * - This pass covers the "after" edges of selection islands
+ */
+ prev_sel = false;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* shrink if previous wasn't selected */
+ if (prev_sel == false) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ prev_sel = true;
+ }
+ else {
+ /* mark previous as being unselected - and hence, is trigger for shrinking */
+ prev_sel = false;
+ }
+ }
+
+ /* Second Pass: Go in reverse order, doing the same as before (except in opposite order)
+ * - This pass covers the "before" edges of selection islands
+ */
+ prev_sel = false;
+ for (pt -= 1; i > 0; i--, pt--) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* shrink if previous wasn't selected */
+ if (prev_sel == false) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ prev_sel = true;
+ }
+ else {
+ /* mark previous as being unselected - and hence, is trigger for shrinking */
+ prev_sel = false;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_select_less(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Less";
- ot->idname = "GPENCIL_OT_select_less";
- ot->description = "Shrink sets of selected Grease Pencil points";
+ /* identifiers */
+ ot->name = "Select Less";
+ ot->idname = "GPENCIL_OT_select_less";
+ ot->description = "Shrink sets of selected Grease Pencil points";
- /* callbacks */
- ot->exec = gpencil_select_less_exec;
- ot->poll = gpencil_select_poll;
+ /* callbacks */
+ ot->exec = gpencil_select_less_exec;
+ ot->poll = gpencil_select_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
@@ -771,216 +780,213 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
/* NOTE: Code here is adapted (i.e. copied directly) from gpencil_paint.c::gp_stroke_eraser_dostroke()
* It would be great to de-duplicate the logic here sometime, but that can wait...
*/
-static bool gp_stroke_do_circle_sel(
- bGPDlayer *gpl,
- bGPDstroke *gps, GP_SpaceConversion *gsc,
- const int mx, const int my, const int radius,
- const bool select, rcti *rect, float diff_mat[4][4], const int selectmode,
- const float scale)
+static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
+ bGPDstroke *gps,
+ GP_SpaceConversion *gsc,
+ const int mx,
+ const int my,
+ const int radius,
+ const bool select,
+ rcti *rect,
+ float diff_mat[4][4],
+ const int selectmode,
+ const float scale)
{
- bGPDspoint *pt1 = NULL;
- bGPDspoint *pt2 = NULL;
- int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
- int i;
- bool changed = false;
-
- if (gps->totpoints == 1) {
- bGPDspoint pt_temp;
- gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
- gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0);
-
- /* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
- /* only check if point is inside */
- if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) {
- /* change selection */
- if (select) {
- gps->points->flag |= GP_SPOINT_SELECT;
- gps->flag |= GP_STROKE_SELECT;
- }
- else {
- gps->points->flag &= ~GP_SPOINT_SELECT;
- gps->flag &= ~GP_STROKE_SELECT;
- }
-
- return true;
- }
- }
- }
- else {
- /* Loop over the points in the stroke, checking for intersections
- * - an intersection means that we touched the stroke
- */
- bool hit = false;
- for (i = 0; (i + 1) < gps->totpoints; i++) {
- /* get points to work with */
- pt1 = gps->points + i;
- pt2 = gps->points + i + 1;
- bGPDspoint npt;
- gp_point_to_parent_space(pt1, diff_mat, &npt);
- gp_point_to_xy(gsc, gps, &npt, &x0, &y0);
-
- gp_point_to_parent_space(pt2, diff_mat, &npt);
- gp_point_to_xy(gsc, gps, &npt, &x1, &y1);
-
- /* check that point segment of the boundbox of the selection stroke */
- if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
- ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1)))
- {
- float mval[2] = {(float)mx, (float)my};
- float mvalo[2] = {(float)mx, (float)my}; /* dummy - this isn't used... */
-
- /* check if point segment of stroke had anything to do with
- * eraser region (either within stroke painted, or on its lines)
- * - this assumes that linewidth is irrelevant
- */
- if (gp_stroke_inside_circle(mval, mvalo, radius, x0, y0, x1, y1)) {
- /* change selection of stroke, and then of both points
- * (as the last point otherwise wouldn't get selected
- * as we only do n-1 loops through).
- */
- hit = true;
- if (select) {
- pt1->flag |= GP_SPOINT_SELECT;
- pt2->flag |= GP_SPOINT_SELECT;
-
- changed = true;
- }
- else {
- pt1->flag &= ~GP_SPOINT_SELECT;
- pt2->flag &= ~GP_SPOINT_SELECT;
-
- changed = true;
- }
- }
- }
- /* if stroke mode, don't check more points */
- if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
- break;
- }
- }
-
- /* if stroke mode expand selection */
- if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
- for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) {
- if (select) {
- pt1->flag |= GP_SPOINT_SELECT;
- }
- else {
- pt1->flag &= ~GP_SPOINT_SELECT;
- }
- }
- }
-
- /* expand selection to segment */
- if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select)) {
- float r_hita[3], r_hitb[3];
- bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT);
- ED_gpencil_select_stroke_segment(
- gpl, gps, pt1, hit_select, false, scale, r_hita, r_hitb);
- }
-
- /* Ensure that stroke selection is in sync with its points */
- BKE_gpencil_stroke_sync_selection(gps);
- }
-
- return changed;
+ bGPDspoint *pt1 = NULL;
+ bGPDspoint *pt2 = NULL;
+ int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
+ int i;
+ bool changed = false;
+
+ if (gps->totpoints == 1) {
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0);
+
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
+ /* only check if point is inside */
+ if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) {
+ /* change selection */
+ if (select) {
+ gps->points->flag |= GP_SPOINT_SELECT;
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ else {
+ gps->points->flag &= ~GP_SPOINT_SELECT;
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+
+ return true;
+ }
+ }
+ }
+ else {
+ /* Loop over the points in the stroke, checking for intersections
+ * - an intersection means that we touched the stroke
+ */
+ bool hit = false;
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+ /* get points to work with */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &x0, &y0);
+
+ gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &x1, &y1);
+
+ /* check that point segment of the boundbox of the selection stroke */
+ if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
+ ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1))) {
+ float mval[2] = {(float)mx, (float)my};
+ float mvalo[2] = {(float)mx, (float)my}; /* dummy - this isn't used... */
+
+ /* check if point segment of stroke had anything to do with
+ * eraser region (either within stroke painted, or on its lines)
+ * - this assumes that linewidth is irrelevant
+ */
+ if (gp_stroke_inside_circle(mval, mvalo, radius, x0, y0, x1, y1)) {
+ /* change selection of stroke, and then of both points
+ * (as the last point otherwise wouldn't get selected
+ * as we only do n-1 loops through).
+ */
+ hit = true;
+ if (select) {
+ pt1->flag |= GP_SPOINT_SELECT;
+ pt2->flag |= GP_SPOINT_SELECT;
+
+ changed = true;
+ }
+ else {
+ pt1->flag &= ~GP_SPOINT_SELECT;
+ pt2->flag &= ~GP_SPOINT_SELECT;
+
+ changed = true;
+ }
+ }
+ }
+ /* if stroke mode, don't check more points */
+ if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
+ break;
+ }
+ }
+
+ /* if stroke mode expand selection */
+ if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
+ for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) {
+ if (select) {
+ pt1->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pt1->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+ }
+
+ /* expand selection to segment */
+ if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select)) {
+ float r_hita[3], r_hitb[3];
+ bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT);
+ ED_gpencil_select_stroke_segment(gpl, gps, pt1, hit_select, false, scale, r_hita, r_hitb);
+ }
+
+ /* Ensure that stroke selection is in sync with its points */
+ BKE_gpencil_stroke_sync_selection(gps);
+ }
+
+ return changed;
}
-
static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- const int selectmode = ts->gpencil_selectmode;
- const float scale = ts->gp_sculpt.isect_threshold;
-
- /* if not edit/sculpt mode, the event is catched but not processed */
- if (GPENCIL_NONE_EDIT_MODE(gpd)) {
- return OPERATOR_CANCELLED;
- }
-
- ScrArea *sa = CTX_wm_area(C);
-
- const int mx = RNA_int_get(op->ptr, "x");
- const int my = RNA_int_get(op->ptr, "y");
- const int radius = RNA_int_get(op->ptr, "radius");
-
- GP_SpaceConversion gsc = {NULL};
- /* for bounding rect around circle (for quicky intersection testing) */
- rcti rect = {0};
-
- bool changed = false;
-
-
- /* sanity checks */
- if (sa == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active area");
- return OPERATOR_CANCELLED;
- }
-
- const eSelectOp sel_op = ED_select_op_modal(
- RNA_enum_get(op->ptr, "mode"), WM_gesture_is_modal_first(op->customdata));
- const bool select = (sel_op != SEL_OP_SUB);
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- ED_gpencil_select_toggle_all(C, SEL_DESELECT);
- changed = true;
- }
-
- /* init space conversion stuff */
- gp_point_conversion_init(C, &gsc);
-
-
- /* rect is rectangle of selection circle */
- rect.xmin = mx - radius;
- rect.ymin = my - radius;
- rect.xmax = mx + radius;
- rect.ymax = my + radius;
-
-
- /* find visible strokes, and select if hit */
- GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
- changed |= gp_stroke_do_circle_sel(
- gpl, gps, &gsc, mx, my, radius, select, &rect,
- gpstroke_iter.diff_mat, selectmode, scale);
- }
- GP_EDITABLE_STROKES_END(gpstroke_iter);
-
- /* updates */
- if (changed) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- }
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ const int selectmode = ts->gpencil_selectmode;
+ const float scale = ts->gp_sculpt.isect_threshold;
+
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ScrArea *sa = CTX_wm_area(C);
+
+ const int mx = RNA_int_get(op->ptr, "x");
+ const int my = RNA_int_get(op->ptr, "y");
+ const int radius = RNA_int_get(op->ptr, "radius");
+
+ GP_SpaceConversion gsc = {NULL};
+ /* for bounding rect around circle (for quicky intersection testing) */
+ rcti rect = {0};
+
+ bool changed = false;
+
+ /* sanity checks */
+ if (sa == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active area");
+ return OPERATOR_CANCELLED;
+ }
+
+ const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
+ WM_gesture_is_modal_first(op->customdata));
+ const bool select = (sel_op != SEL_OP_SUB);
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ ED_gpencil_select_toggle_all(C, SEL_DESELECT);
+ changed = true;
+ }
+
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
+
+ /* rect is rectangle of selection circle */
+ rect.xmin = mx - radius;
+ rect.ymin = my - radius;
+ rect.xmax = mx + radius;
+ rect.ymax = my + radius;
+
+ /* find visible strokes, and select if hit */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ changed |= gp_stroke_do_circle_sel(
+ gpl, gps, &gsc, mx, my, radius, select, &rect, gpstroke_iter.diff_mat, selectmode, scale);
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* updates */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ }
+
+ return OPERATOR_FINISHED;
}
void GPENCIL_OT_select_circle(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Circle Select";
- ot->description = "Select Grease Pencil strokes using brush selection";
- ot->idname = "GPENCIL_OT_select_circle";
-
- /* callbacks */
- ot->invoke = WM_gesture_circle_invoke;
- ot->modal = WM_gesture_circle_modal;
- ot->exec = gpencil_circle_select_exec;
- ot->poll = gpencil_select_poll;
- ot->cancel = WM_gesture_circle_cancel;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
-
- /* properties */
- WM_operator_properties_gesture_circle(ot);
- WM_operator_properties_select_operation_simple(ot);
+ /* identifiers */
+ ot->name = "Circle Select";
+ ot->description = "Select Grease Pencil strokes using brush selection";
+ ot->idname = "GPENCIL_OT_select_circle";
+
+ /* callbacks */
+ ot->invoke = WM_gesture_circle_invoke;
+ ot->modal = WM_gesture_circle_modal;
+ ot->exec = gpencil_circle_select_exec;
+ ot->poll = gpencil_select_poll;
+ ot->cancel = WM_gesture_circle_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
+
+ /* properties */
+ WM_operator_properties_gesture_circle(ot);
+ WM_operator_properties_select_operation_simple(ot);
}
/** \} */
@@ -992,135 +998,132 @@ void GPENCIL_OT_select_circle(wmOperatorType *ot)
*
* \{ */
-typedef bool (*GPencilTestFn)(
- bGPDstroke *gps, bGPDspoint *pt,
- const GP_SpaceConversion *gsc, const float diff_mat[4][4], void *user_data);
+typedef bool (*GPencilTestFn)(bGPDstroke *gps,
+ bGPDspoint *pt,
+ const GP_SpaceConversion *gsc,
+ const float diff_mat[4][4],
+ void *user_data);
-static int gpencil_generic_select_exec(
- bContext *C, wmOperator *op,
- GPencilTestFn is_inside_fn, void *user_data)
+static int gpencil_generic_select_exec(bContext *C,
+ wmOperator *op,
+ GPencilTestFn is_inside_fn,
+ void *user_data)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- ScrArea *sa = CTX_wm_area(C);
- const bool strokemode = (
- (ts->gpencil_selectmode == GP_SELECTMODE_STROKE) &&
- ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
- const bool segmentmode = (
- (ts->gpencil_selectmode == GP_SELECTMODE_SEGMENT) &&
- ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
- const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- const float scale = ts->gp_sculpt.isect_threshold;
-
-
- GP_SpaceConversion gsc = {NULL};
-
- bool changed = false;
-
- /* sanity checks */
- if (sa == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active area");
- return OPERATOR_CANCELLED;
- }
-
- /* init space conversion stuff */
- gp_point_conversion_init(C, &gsc);
-
- /* deselect all strokes first? */
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
-
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- bGPDspoint *pt;
- int i;
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
-
- gps->flag &= ~GP_STROKE_SELECT;
- }
- CTX_DATA_END;
- }
-
- /* select/deselect points */
- GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
-
- bGPDspoint *pt;
- int i;
- bool hit = false;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- /* convert point coords to screenspace */
- const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
-
- if (strokemode == false) {
- const bool is_select = (pt->flag & GP_SPOINT_SELECT) != 0;
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
- if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(pt->flag, sel_op_result, GP_SPOINT_SELECT);
- changed = true;
-
- /* expand selection to segment */
- if ((sel_op_result != -1) && (segmentmode)) {
- bool hit_select = (bool)(pt->flag & GP_SPOINT_SELECT);
- float r_hita[3], r_hitb[3];
- ED_gpencil_select_stroke_segment(
- gpl, gps, pt, hit_select, false, scale, r_hita, r_hitb);
- }
-
- }
- }
- else {
- if (is_inside) {
- hit = true;
- break;
- }
- }
- }
-
- /* if stroke mode expand selection */
- if (strokemode) {
- const bool is_select = BKE_gpencil_stroke_select_check(gps);
- const bool is_inside = hit;
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
- if (sel_op_result != -1) {
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (sel_op_result) {
- pt->flag |= GP_SPOINT_SELECT;
- }
- else {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
- }
- changed = true;
- }
- }
-
- /* Ensure that stroke selection is in sync with its points */
- BKE_gpencil_stroke_sync_selection(gps);
- }
- GP_EDITABLE_STROKES_END(gpstroke_iter);
-
- /* if paint mode,delete selected points */
- if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
- gp_delete_selected_point_wrap(C);
- changed = true;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- }
-
- /* updates */
- if (changed) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- }
-
- return OPERATOR_FINISHED;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ ScrArea *sa = CTX_wm_area(C);
+ const bool strokemode = ((ts->gpencil_selectmode == GP_SELECTMODE_STROKE) &&
+ ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
+ const bool segmentmode = ((ts->gpencil_selectmode == GP_SELECTMODE_SEGMENT) &&
+ ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
+ const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ const float scale = ts->gp_sculpt.isect_threshold;
+
+ GP_SpaceConversion gsc = {NULL};
+
+ bool changed = false;
+
+ /* sanity checks */
+ if (sa == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active area");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
+
+ /* deselect all strokes first? */
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ CTX_DATA_END;
+ }
+
+ /* select/deselect points */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+
+ bGPDspoint *pt;
+ int i;
+ bool hit = false;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ /* convert point coords to screenspace */
+ const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
+
+ if (strokemode == false) {
+ const bool is_select = (pt->flag & GP_SPOINT_SELECT) != 0;
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(pt->flag, sel_op_result, GP_SPOINT_SELECT);
+ changed = true;
+
+ /* expand selection to segment */
+ if ((sel_op_result != -1) && (segmentmode)) {
+ bool hit_select = (bool)(pt->flag & GP_SPOINT_SELECT);
+ float r_hita[3], r_hitb[3];
+ ED_gpencil_select_stroke_segment(
+ gpl, gps, pt, hit_select, false, scale, r_hita, r_hitb);
+ }
+ }
+ }
+ else {
+ if (is_inside) {
+ hit = true;
+ break;
+ }
+ }
+ }
+
+ /* if stroke mode expand selection */
+ if (strokemode) {
+ const bool is_select = BKE_gpencil_stroke_select_check(gps);
+ const bool is_inside = hit;
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (sel_op_result) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+ changed = true;
+ }
+ }
+
+ /* Ensure that stroke selection is in sync with its points */
+ BKE_gpencil_stroke_sync_selection(gps);
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* if paint mode,delete selected points */
+ if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
+ gp_delete_selected_point_wrap(C);
+ changed = true;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+
+ /* updates */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ }
+
+ return OPERATOR_FINISHED;
}
/** \} */
@@ -1130,52 +1133,51 @@ static int gpencil_generic_select_exec(
* \{ */
struct GP_SelectBoxUserData {
- rcti rect;
+ rcti rect;
};
-static bool gpencil_test_box(
- bGPDstroke *gps, bGPDspoint *pt,
- const GP_SpaceConversion *gsc, const float diff_mat[4][4], void *user_data)
+static bool gpencil_test_box(bGPDstroke *gps,
+ bGPDspoint *pt,
+ const GP_SpaceConversion *gsc,
+ const float diff_mat[4][4],
+ void *user_data)
{
- const struct GP_SelectBoxUserData *data = user_data;
- bGPDspoint pt2;
- int x0, y0;
- gp_point_to_parent_space(pt, diff_mat, &pt2);
- gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
- return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) &&
- BLI_rcti_isect_pt(&data->rect, x0, y0));
+ const struct GP_SelectBoxUserData *data = user_data;
+ bGPDspoint pt2;
+ int x0, y0;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
+ return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0));
}
static int gpencil_box_select_exec(bContext *C, wmOperator *op)
{
- struct GP_SelectBoxUserData data = {0};
- WM_operator_properties_border_to_rcti(op, &data.rect);
- return gpencil_generic_select_exec(
- C, op,
- gpencil_test_box, &data);
+ struct GP_SelectBoxUserData data = {0};
+ WM_operator_properties_border_to_rcti(op, &data.rect);
+ return gpencil_generic_select_exec(C, op, gpencil_test_box, &data);
}
void GPENCIL_OT_select_box(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Box Select";
- ot->description = "Select Grease Pencil strokes within a rectangular region";
- ot->idname = "GPENCIL_OT_select_box";
+ /* identifiers */
+ ot->name = "Box Select";
+ ot->description = "Select Grease Pencil strokes within a rectangular region";
+ ot->idname = "GPENCIL_OT_select_box";
- /* callbacks */
- ot->invoke = WM_gesture_box_invoke;
- ot->exec = gpencil_box_select_exec;
- ot->modal = WM_gesture_box_modal;
- ot->cancel = WM_gesture_box_cancel;
+ /* callbacks */
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = gpencil_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
- ot->poll = gpencil_select_poll;
+ ot->poll = gpencil_select_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
- /* properties */
- WM_operator_properties_gesture_box(ot);
- WM_operator_properties_select_operation(ot);
+ /* properties */
+ WM_operator_properties_gesture_box(ot);
+ WM_operator_properties_select_operation(ot);
}
/** \} */
@@ -1185,67 +1187,65 @@ void GPENCIL_OT_select_box(wmOperatorType *ot)
* \{ */
struct GP_SelectLassoUserData {
- rcti rect;
- const int (*mcords)[2];
- int mcords_len;
+ rcti rect;
+ const int (*mcords)[2];
+ int mcords_len;
};
-static bool gpencil_test_lasso(
- bGPDstroke *gps, bGPDspoint *pt,
- const GP_SpaceConversion *gsc, const float diff_mat[4][4],
- void *user_data)
+static bool gpencil_test_lasso(bGPDstroke *gps,
+ bGPDspoint *pt,
+ const GP_SpaceConversion *gsc,
+ const float diff_mat[4][4],
+ void *user_data)
{
- const struct GP_SelectLassoUserData *data = user_data;
- bGPDspoint pt2;
- int x0, y0;
- gp_point_to_parent_space(pt, diff_mat, &pt2);
- gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
- /* test if in lasso boundbox + within the lasso noose */
- return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) &&
- BLI_rcti_isect_pt(&data->rect, x0, y0) &&
- BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX));
+ const struct GP_SelectLassoUserData *data = user_data;
+ bGPDspoint pt2;
+ int x0, y0;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
+ /* test if in lasso boundbox + within the lasso noose */
+ return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) &&
+ BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX));
}
static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
{
- struct GP_SelectLassoUserData data = {0};
- data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len);
+ struct GP_SelectLassoUserData data = {0};
+ data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len);
- /* Sanity check. */
- if (data.mcords == NULL) {
- return OPERATOR_PASS_THROUGH;
- }
+ /* Sanity check. */
+ if (data.mcords == NULL) {
+ return OPERATOR_PASS_THROUGH;
+ }
- /* Compute boundbox of lasso (for faster testing later). */
- BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
+ /* Compute boundbox of lasso (for faster testing later). */
+ BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
- int ret = gpencil_generic_select_exec(
- C, op,
- gpencil_test_lasso, &data);
+ int ret = gpencil_generic_select_exec(C, op, gpencil_test_lasso, &data);
- MEM_freeN((void *)data.mcords);
+ MEM_freeN((void *)data.mcords);
- return ret;
+ return ret;
}
void GPENCIL_OT_select_lasso(wmOperatorType *ot)
{
- ot->name = "Lasso Select Strokes";
- ot->description = "Select Grease Pencil strokes using lasso selection";
- ot->idname = "GPENCIL_OT_select_lasso";
-
- ot->invoke = WM_gesture_lasso_invoke;
- ot->modal = WM_gesture_lasso_modal;
- ot->exec = gpencil_lasso_select_exec;
- ot->poll = gpencil_select_poll;
- ot->cancel = WM_gesture_lasso_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
-
- /* properties */
- WM_operator_properties_select_operation(ot);
- WM_operator_properties_gesture_lasso(ot);
+ ot->name = "Lasso Select Strokes";
+ ot->description = "Select Grease Pencil strokes using lasso selection";
+ ot->idname = "GPENCIL_OT_select_lasso";
+
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = gpencil_lasso_select_exec;
+ ot->poll = gpencil_select_poll;
+ ot->cancel = WM_gesture_lasso_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
+
+ /* properties */
+ WM_operator_properties_select_operation(ot);
+ WM_operator_properties_gesture_lasso(ot);
}
/** \} */
@@ -1257,215 +1257,225 @@ void GPENCIL_OT_select_lasso(wmOperatorType *ot)
/* helper to deselect all selected strokes/points */
static void deselect_all_selected(bContext *C)
{
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- /* deselect stroke and its points if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
-
- /* deselect points */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
-
- /* deselect stroke itself too */
- gps->flag &= ~GP_STROKE_SELECT;
- }
- }
- CTX_DATA_END;
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ /* deselect stroke and its points if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ /* deselect points */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ /* deselect stroke itself too */
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ }
+ CTX_DATA_END;
}
static int gpencil_select_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- const float scale = ts->gp_sculpt.isect_threshold;
-
- /* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */
- const float radius = 0.50f * U.widget_unit;
- const int radius_squared = (int)(radius * radius);
-
- bool extend = RNA_boolean_get(op->ptr, "extend");
- bool deselect = RNA_boolean_get(op->ptr, "deselect");
- bool toggle = RNA_boolean_get(op->ptr, "toggle");
- bool whole = RNA_boolean_get(op->ptr, "entire_strokes");
-
- int mval[2] = {0};
-
- GP_SpaceConversion gsc = {NULL};
-
- bGPDlayer *hit_layer = NULL;
- bGPDstroke *hit_stroke = NULL;
- bGPDspoint *hit_point = NULL;
- int hit_distance = radius_squared;
-
- /* sanity checks */
- if (sa == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active area");
- return OPERATOR_CANCELLED;
- }
-
- /* if select mode is stroke, use whole stroke */
- if (ts->gpencil_selectmode == GP_SELECTMODE_STROKE) {
- whole = true;
- }
-
- /* init space conversion stuff */
- gp_point_conversion_init(C, &gsc);
-
- /* get mouse location */
- RNA_int_get_array(op->ptr, "location", mval);
-
- /* First Pass: Find stroke point which gets hit */
- /* XXX: maybe we should go from the top of the stack down instead... */
- GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
- bGPDspoint *pt;
- int i;
-
- /* firstly, check for hit-point */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- int xy[2];
-
- bGPDspoint pt2;
- gp_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2);
- gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]);
-
- /* do boundbox check first */
- if (!ELEM(V2D_IS_CLIPPED, xy[0], xy[1])) {
- const int pt_distance = len_manhattan_v2v2_int(mval, xy);
-
- /* check if point is inside */
- if (pt_distance <= radius_squared) {
- /* only use this point if it is a better match than the current hit - T44685 */
- if (pt_distance < hit_distance) {
- hit_layer = gpl;
- hit_stroke = gps;
- hit_point = pt;
- hit_distance = pt_distance;
- }
- }
- }
- }
- }
- GP_EDITABLE_STROKES_END(gpstroke_iter);
-
- /* Abort if nothing hit... */
- if (ELEM(NULL, hit_stroke, hit_point)) {
-
- /* since left mouse select change, deselect all if click outside any hit */
- deselect_all_selected(C);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
-
- return OPERATOR_CANCELLED;
- }
-
- /* adjust selection behavior - for toggle option */
- if (toggle) {
- deselect = (hit_point->flag & GP_SPOINT_SELECT) != 0;
- }
-
- /* If not extending selection, deselect everything else */
- if (extend == false) {
- deselect_all_selected(C);
- }
-
- /* Perform selection operations... */
- if (whole) {
- bGPDspoint *pt;
- int i;
-
- /* entire stroke's points */
- for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; i++, pt++) {
- if (deselect == false)
- pt->flag |= GP_SPOINT_SELECT;
- else
- pt->flag &= ~GP_SPOINT_SELECT;
- }
-
- /* stroke too... */
- if (deselect == false)
- hit_stroke->flag |= GP_STROKE_SELECT;
- else
- hit_stroke->flag &= ~GP_STROKE_SELECT;
- }
- else {
- /* just the point (and the stroke) */
- if (deselect == false) {
- /* we're adding selection, so selection must be true */
- hit_point->flag |= GP_SPOINT_SELECT;
- hit_stroke->flag |= GP_STROKE_SELECT;
-
- /* expand selection to segment */
- if (ts->gpencil_selectmode == GP_SELECTMODE_SEGMENT) {
- float r_hita[3], r_hitb[3];
- bool hit_select = (bool)(hit_point->flag & GP_SPOINT_SELECT);
- ED_gpencil_select_stroke_segment(
- hit_layer, hit_stroke, hit_point, hit_select,
- false, scale, r_hita, r_hitb);
- }
- }
- else {
- /* deselect point */
- hit_point->flag &= ~GP_SPOINT_SELECT;
-
- /* ensure that stroke is selected correctly */
- BKE_gpencil_stroke_sync_selection(hit_stroke);
- }
- }
-
- /* updates */
- if (hit_point != NULL) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
- /* copy on write tag is needed, or else no refresh happens */
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
- }
-
- return OPERATOR_FINISHED;
+ ScrArea *sa = CTX_wm_area(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ const float scale = ts->gp_sculpt.isect_threshold;
+
+ /* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */
+ const float radius = 0.50f * U.widget_unit;
+ const int radius_squared = (int)(radius * radius);
+
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ bool deselect = RNA_boolean_get(op->ptr, "deselect");
+ bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ bool whole = RNA_boolean_get(op->ptr, "entire_strokes");
+
+ int mval[2] = {0};
+
+ GP_SpaceConversion gsc = {NULL};
+
+ bGPDlayer *hit_layer = NULL;
+ bGPDstroke *hit_stroke = NULL;
+ bGPDspoint *hit_point = NULL;
+ int hit_distance = radius_squared;
+
+ /* sanity checks */
+ if (sa == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active area");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* if select mode is stroke, use whole stroke */
+ if (ts->gpencil_selectmode == GP_SELECTMODE_STROKE) {
+ whole = true;
+ }
+
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
+
+ /* get mouse location */
+ RNA_int_get_array(op->ptr, "location", mval);
+
+ /* First Pass: Find stroke point which gets hit */
+ /* XXX: maybe we should go from the top of the stack down instead... */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ bGPDspoint *pt;
+ int i;
+
+ /* firstly, check for hit-point */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ int xy[2];
+
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2);
+ gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]);
+
+ /* do boundbox check first */
+ if (!ELEM(V2D_IS_CLIPPED, xy[0], xy[1])) {
+ const int pt_distance = len_manhattan_v2v2_int(mval, xy);
+
+ /* check if point is inside */
+ if (pt_distance <= radius_squared) {
+ /* only use this point if it is a better match than the current hit - T44685 */
+ if (pt_distance < hit_distance) {
+ hit_layer = gpl;
+ hit_stroke = gps;
+ hit_point = pt;
+ hit_distance = pt_distance;
+ }
+ }
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* Abort if nothing hit... */
+ if (ELEM(NULL, hit_stroke, hit_point)) {
+
+ /* since left mouse select change, deselect all if click outside any hit */
+ deselect_all_selected(C);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+
+ return OPERATOR_CANCELLED;
+ }
+
+ /* adjust selection behavior - for toggle option */
+ if (toggle) {
+ deselect = (hit_point->flag & GP_SPOINT_SELECT) != 0;
+ }
+
+ /* If not extending selection, deselect everything else */
+ if (extend == false) {
+ deselect_all_selected(C);
+ }
+
+ /* Perform selection operations... */
+ if (whole) {
+ bGPDspoint *pt;
+ int i;
+
+ /* entire stroke's points */
+ for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; i++, pt++) {
+ if (deselect == false)
+ pt->flag |= GP_SPOINT_SELECT;
+ else
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ /* stroke too... */
+ if (deselect == false)
+ hit_stroke->flag |= GP_STROKE_SELECT;
+ else
+ hit_stroke->flag &= ~GP_STROKE_SELECT;
+ }
+ else {
+ /* just the point (and the stroke) */
+ if (deselect == false) {
+ /* we're adding selection, so selection must be true */
+ hit_point->flag |= GP_SPOINT_SELECT;
+ hit_stroke->flag |= GP_STROKE_SELECT;
+
+ /* expand selection to segment */
+ if (ts->gpencil_selectmode == GP_SELECTMODE_SEGMENT) {
+ float r_hita[3], r_hitb[3];
+ bool hit_select = (bool)(hit_point->flag & GP_SPOINT_SELECT);
+ ED_gpencil_select_stroke_segment(
+ hit_layer, hit_stroke, hit_point, hit_select, false, scale, r_hita, r_hitb);
+ }
+ }
+ else {
+ /* deselect point */
+ hit_point->flag &= ~GP_SPOINT_SELECT;
+
+ /* ensure that stroke is selected correctly */
+ BKE_gpencil_stroke_sync_selection(hit_stroke);
+ }
+ }
+
+ /* updates */
+ if (hit_point != NULL) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ }
+
+ return OPERATOR_FINISHED;
}
static int gpencil_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- RNA_int_set_array(op->ptr, "location", event->mval);
- return gpencil_select_exec(C, op);
+ RNA_int_set_array(op->ptr, "location", event->mval);
+ return gpencil_select_exec(C, op);
}
void GPENCIL_OT_select(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Select";
- ot->description = "Select Grease Pencil strokes and/or stroke points";
- ot->idname = "GPENCIL_OT_select";
-
- /* callbacks */
- ot->invoke = gpencil_select_invoke;
- ot->exec = gpencil_select_exec;
- ot->poll = gpencil_select_poll;
-
- /* flag */
- ot->flag = OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
-
- /* properties */
- WM_operator_properties_mouse_select(ot);
-
- prop = RNA_def_boolean(ot->srna, "entire_strokes", false, "Entire Strokes", "Select entire strokes instead of just the nearest stroke vertex");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, INT_MIN, INT_MAX, "Location", "Mouse location", INT_MIN, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select";
+ ot->description = "Select Grease Pencil strokes and/or stroke points";
+ ot->idname = "GPENCIL_OT_select";
+
+ /* callbacks */
+ ot->invoke = gpencil_select_invoke;
+ ot->exec = gpencil_select_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flag */
+ ot->flag = OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
+
+ /* properties */
+ WM_operator_properties_mouse_select(ot);
+
+ prop = RNA_def_boolean(ot->srna,
+ "entire_strokes",
+ false,
+ "Entire Strokes",
+ "Select entire strokes instead of just the nearest stroke vertex");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_int_vector(ot->srna,
+ "location",
+ 2,
+ NULL,
+ INT_MIN,
+ INT_MAX,
+ "Location",
+ "Mouse location",
+ INT_MIN,
+ INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/** \} */
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index 7ed794a0a32..d91977bc0da 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -21,7 +21,6 @@
* \ingroup edgpencil
*/
-
#include <stdlib.h>
#include <string.h>
@@ -48,10 +47,10 @@
#include "gpencil_intern.h"
typedef struct bGPundonode {
- struct bGPundonode *next, *prev;
+ struct bGPundonode *next, *prev;
- char name[BKE_UNDO_STR_MAX];
- struct bGPdata *gpd;
+ char name[BKE_UNDO_STR_MAX];
+ struct bGPdata *gpd;
} bGPundonode;
static ListBase undo_nodes = {NULL, NULL};
@@ -59,140 +58,140 @@ static bGPundonode *cur_node = NULL;
int ED_gpencil_session_active(void)
{
- return (BLI_listbase_is_empty(&undo_nodes) == false);
+ return (BLI_listbase_is_empty(&undo_nodes) == false);
}
int ED_undo_gpencil_step(bContext *C, int step, const char *name)
{
- bGPdata **gpd_ptr = NULL, *new_gpd = NULL;
-
- gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- if (step == 1) { /* undo */
- //printf("\t\tGP - undo step\n");
- if (cur_node->prev) {
- if (!name || STREQ(cur_node->name, name)) {
- cur_node = cur_node->prev;
- new_gpd = cur_node->gpd;
- }
- }
- }
- else if (step == -1) {
- //printf("\t\tGP - redo step\n");
- if (cur_node->next) {
- if (!name || STREQ(cur_node->name, name)) {
- cur_node = cur_node->next;
- new_gpd = cur_node->gpd;
- }
- }
- }
-
- if (new_gpd) {
- if (gpd_ptr) {
- if (*gpd_ptr) {
- bGPdata *gpd = *gpd_ptr;
- bGPDlayer *gpl, *gpld;
-
- BKE_gpencil_free_layers(&gpd->layers);
-
- /* copy layers */
- BLI_listbase_clear(&gpd->layers);
-
- for (gpl = new_gpd->layers.first; gpl; gpl = gpl->next) {
- /* make a copy of source layer and its data */
- gpld = BKE_gpencil_layer_duplicate(gpl);
- BLI_addtail(&gpd->layers, gpld);
- }
- }
- }
- /* drawing batch cache is dirty now */
- DEG_id_tag_update(&new_gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- new_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- }
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ bGPdata **gpd_ptr = NULL, *new_gpd = NULL;
+
+ gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ if (step == 1) { /* undo */
+ //printf("\t\tGP - undo step\n");
+ if (cur_node->prev) {
+ if (!name || STREQ(cur_node->name, name)) {
+ cur_node = cur_node->prev;
+ new_gpd = cur_node->gpd;
+ }
+ }
+ }
+ else if (step == -1) {
+ //printf("\t\tGP - redo step\n");
+ if (cur_node->next) {
+ if (!name || STREQ(cur_node->name, name)) {
+ cur_node = cur_node->next;
+ new_gpd = cur_node->gpd;
+ }
+ }
+ }
+
+ if (new_gpd) {
+ if (gpd_ptr) {
+ if (*gpd_ptr) {
+ bGPdata *gpd = *gpd_ptr;
+ bGPDlayer *gpl, *gpld;
+
+ BKE_gpencil_free_layers(&gpd->layers);
+
+ /* copy layers */
+ BLI_listbase_clear(&gpd->layers);
+
+ for (gpl = new_gpd->layers.first; gpl; gpl = gpl->next) {
+ /* make a copy of source layer and its data */
+ gpld = BKE_gpencil_layer_duplicate(gpl);
+ BLI_addtail(&gpd->layers, gpld);
+ }
+ }
+ }
+ /* drawing batch cache is dirty now */
+ DEG_id_tag_update(&new_gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ new_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void gpencil_undo_init(bGPdata *gpd)
{
- gpencil_undo_push(gpd);
+ gpencil_undo_push(gpd);
}
static void gpencil_undo_free_node(bGPundonode *undo_node)
{
- /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
- * or else the real copy will segfault when accessed
- */
- undo_node->gpd->adt = NULL;
+ /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
+ * or else the real copy will segfault when accessed
+ */
+ undo_node->gpd->adt = NULL;
- BKE_gpencil_free(undo_node->gpd, false);
- MEM_freeN(undo_node->gpd);
+ BKE_gpencil_free(undo_node->gpd, false);
+ MEM_freeN(undo_node->gpd);
}
void gpencil_undo_push(bGPdata *gpd)
{
- bGPundonode *undo_node;
+ bGPundonode *undo_node;
- //printf("\t\tGP - undo push\n");
+ //printf("\t\tGP - undo push\n");
- if (cur_node) {
- /* remove all un-done nodes from stack */
- undo_node = cur_node->next;
+ if (cur_node) {
+ /* remove all un-done nodes from stack */
+ undo_node = cur_node->next;
- while (undo_node) {
- bGPundonode *next_node = undo_node->next;
+ while (undo_node) {
+ bGPundonode *next_node = undo_node->next;
- gpencil_undo_free_node(undo_node);
- BLI_freelinkN(&undo_nodes, undo_node);
+ gpencil_undo_free_node(undo_node);
+ BLI_freelinkN(&undo_nodes, undo_node);
- undo_node = next_node;
- }
- }
+ undo_node = next_node;
+ }
+ }
- /* limit number of undo steps to the maximum undo steps
- * - to prevent running out of memory during **really**
- * long drawing sessions (triggering swapping)
- */
- /* TODO: Undo-memory constraint is not respected yet, but can be added if we have any need for it */
- if (U.undosteps && !BLI_listbase_is_empty(&undo_nodes)) {
- /* remove anything older than n-steps before cur_node */
- int steps = 0;
+ /* limit number of undo steps to the maximum undo steps
+ * - to prevent running out of memory during **really**
+ * long drawing sessions (triggering swapping)
+ */
+ /* TODO: Undo-memory constraint is not respected yet, but can be added if we have any need for it */
+ if (U.undosteps && !BLI_listbase_is_empty(&undo_nodes)) {
+ /* remove anything older than n-steps before cur_node */
+ int steps = 0;
- undo_node = (cur_node) ? cur_node : undo_nodes.last;
- while (undo_node) {
- bGPundonode *prev_node = undo_node->prev;
+ undo_node = (cur_node) ? cur_node : undo_nodes.last;
+ while (undo_node) {
+ bGPundonode *prev_node = undo_node->prev;
- if (steps >= U.undosteps) {
- gpencil_undo_free_node(undo_node);
- BLI_freelinkN(&undo_nodes, undo_node);
- }
+ if (steps >= U.undosteps) {
+ gpencil_undo_free_node(undo_node);
+ BLI_freelinkN(&undo_nodes, undo_node);
+ }
- steps++;
- undo_node = prev_node;
- }
- }
+ steps++;
+ undo_node = prev_node;
+ }
+ }
- /* create new undo node */
- undo_node = MEM_callocN(sizeof(bGPundonode), "gpencil undo node");
- undo_node->gpd = BKE_gpencil_data_duplicate(NULL, gpd, true);
+ /* create new undo node */
+ undo_node = MEM_callocN(sizeof(bGPundonode), "gpencil undo node");
+ undo_node->gpd = BKE_gpencil_data_duplicate(NULL, gpd, true);
- cur_node = undo_node;
+ cur_node = undo_node;
- BLI_addtail(&undo_nodes, undo_node);
+ BLI_addtail(&undo_nodes, undo_node);
}
void gpencil_undo_finish(void)
{
- bGPundonode *undo_node = undo_nodes.first;
+ bGPundonode *undo_node = undo_nodes.first;
- while (undo_node) {
- gpencil_undo_free_node(undo_node);
- undo_node = undo_node->next;
- }
+ while (undo_node) {
+ gpencil_undo_free_node(undo_node);
+ undo_node = undo_node->next;
+ }
- BLI_freelistN(&undo_nodes);
+ BLI_freelistN(&undo_nodes);
- cur_node = NULL;
+ cur_node = NULL;
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index f582b52713d..858415061b1 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -88,120 +88,129 @@
/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it,
* when context info is not available.
*/
-bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, ScrArea *sa, Scene *scene, Object *ob, PointerRNA *r_ptr)
+bGPdata **ED_gpencil_data_get_pointers_direct(
+ ID *screen_id, ScrArea *sa, Scene *scene, Object *ob, PointerRNA *r_ptr)
{
- /* if there's an active area, check if the particular editor may
- * have defined any special Grease Pencil context for editing...
- */
- if (sa) {
- SpaceLink *sl = sa->spacedata.first;
-
- switch (sa->spacetype) {
- /* XXX: Should we reduce reliance on context.gpencil_data for these cases? */
- case SPACE_PROPERTIES: /* properties */
- case SPACE_INFO: /* header info (needed after workspaces merge) */
- {
- if (ob && (ob->type == OB_GPENCIL)) {
- /* GP Object */
- if (r_ptr) RNA_id_pointer_create(&ob->id, r_ptr);
- return (bGPdata **)&ob->data;
- }
- else {
- return NULL;
- }
-
- break;
- }
-
- case SPACE_TOPBAR: /* Topbar (needed after topbar merge) */
- case SPACE_VIEW3D: /* 3D-View */
- {
- if (ob && (ob->type == OB_GPENCIL)) {
- /* GP Object */
- if (r_ptr) RNA_id_pointer_create(&ob->id, r_ptr);
- return (bGPdata **)&ob->data;
- }
- else {
- /* Annotations */
- /* XXX: */
- if (r_ptr) RNA_id_pointer_create(&scene->id, r_ptr);
- return &scene->gpd;
- }
-
- break;
- }
- case SPACE_NODE: /* Nodes Editor */
- {
- SpaceNode *snode = (SpaceNode *)sl;
-
- /* return the GP data for the active node block/node */
- if (snode && snode->nodetree) {
- /* for now, as long as there's an active node tree,
- * default to using that in the Nodes Editor */
- if (r_ptr) RNA_id_pointer_create(&snode->nodetree->id, r_ptr);
- return &snode->nodetree->gpd;
- }
-
- /* even when there is no node-tree, don't allow this to flow to scene */
- return NULL;
- }
- case SPACE_SEQ: /* Sequencer */
- {
- SpaceSeq *sseq = (SpaceSeq *)sl;
-
- /* for now, Grease Pencil data is associated with the space (actually preview region only) */
- /* XXX our convention for everything else is to link to data though... */
- if (r_ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, r_ptr);
- return &sseq->gpd;
- }
- case SPACE_IMAGE: /* Image/UV Editor */
- {
- SpaceImage *sima = (SpaceImage *)sl;
-
- /* for now, Grease Pencil data is associated with the space... */
- /* XXX our convention for everything else is to link to data though... */
- if (r_ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, r_ptr);
- return &sima->gpd;
- }
- case SPACE_CLIP: /* Nodes Editor */
- {
- SpaceClip *sc = (SpaceClip *)sl;
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (clip) {
- if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
- MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
-
- if (!track)
- return NULL;
-
- if (r_ptr) RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, r_ptr);
- return &track->gpd;
- }
- else {
- if (r_ptr) RNA_id_pointer_create(&clip->id, r_ptr);
- return &clip->gpd;
- }
- }
- break;
- }
- default: /* unsupported space */
- return NULL;
- }
- }
-
- return NULL;
+ /* if there's an active area, check if the particular editor may
+ * have defined any special Grease Pencil context for editing...
+ */
+ if (sa) {
+ SpaceLink *sl = sa->spacedata.first;
+
+ switch (sa->spacetype) {
+ /* XXX: Should we reduce reliance on context.gpencil_data for these cases? */
+ case SPACE_PROPERTIES: /* properties */
+ case SPACE_INFO: /* header info (needed after workspaces merge) */
+ {
+ if (ob && (ob->type == OB_GPENCIL)) {
+ /* GP Object */
+ if (r_ptr)
+ RNA_id_pointer_create(&ob->id, r_ptr);
+ return (bGPdata **)&ob->data;
+ }
+ else {
+ return NULL;
+ }
+
+ break;
+ }
+
+ case SPACE_TOPBAR: /* Topbar (needed after topbar merge) */
+ case SPACE_VIEW3D: /* 3D-View */
+ {
+ if (ob && (ob->type == OB_GPENCIL)) {
+ /* GP Object */
+ if (r_ptr)
+ RNA_id_pointer_create(&ob->id, r_ptr);
+ return (bGPdata **)&ob->data;
+ }
+ else {
+ /* Annotations */
+ /* XXX: */
+ if (r_ptr)
+ RNA_id_pointer_create(&scene->id, r_ptr);
+ return &scene->gpd;
+ }
+
+ break;
+ }
+ case SPACE_NODE: /* Nodes Editor */
+ {
+ SpaceNode *snode = (SpaceNode *)sl;
+
+ /* return the GP data for the active node block/node */
+ if (snode && snode->nodetree) {
+ /* for now, as long as there's an active node tree,
+ * default to using that in the Nodes Editor */
+ if (r_ptr)
+ RNA_id_pointer_create(&snode->nodetree->id, r_ptr);
+ return &snode->nodetree->gpd;
+ }
+
+ /* even when there is no node-tree, don't allow this to flow to scene */
+ return NULL;
+ }
+ case SPACE_SEQ: /* Sequencer */
+ {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+
+ /* for now, Grease Pencil data is associated with the space (actually preview region only) */
+ /* XXX our convention for everything else is to link to data though... */
+ if (r_ptr)
+ RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, r_ptr);
+ return &sseq->gpd;
+ }
+ case SPACE_IMAGE: /* Image/UV Editor */
+ {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ /* for now, Grease Pencil data is associated with the space... */
+ /* XXX our convention for everything else is to link to data though... */
+ if (r_ptr)
+ RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, r_ptr);
+ return &sima->gpd;
+ }
+ case SPACE_CLIP: /* Nodes Editor */
+ {
+ SpaceClip *sc = (SpaceClip *)sl;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+
+ if (clip) {
+ if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
+ MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
+
+ if (!track)
+ return NULL;
+
+ if (r_ptr)
+ RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, r_ptr);
+ return &track->gpd;
+ }
+ else {
+ if (r_ptr)
+ RNA_id_pointer_create(&clip->id, r_ptr);
+ return &clip->gpd;
+ }
+ }
+ break;
+ }
+ default: /* unsupported space */
+ return NULL;
+ }
+ }
+
+ return NULL;
}
/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
- ID *screen_id = (ID *)CTX_wm_screen(C);
- Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
- Object *ob = CTX_data_active_object(C);
+ ID *screen_id = (ID *)CTX_wm_screen(C);
+ Scene *scene = CTX_data_scene(C);
+ ScrArea *sa = CTX_wm_area(C);
+ Object *ob = CTX_data_active_object(C);
- return ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, r_ptr);
+ return ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, r_ptr);
}
/* -------------------------------------------------------- */
@@ -209,8 +218,8 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
/* Get the active Grease Pencil datablock, when context is not available */
bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, ScrArea *sa, Scene *scene, Object *ob)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, NULL);
- return (gpd_ptr) ? *(gpd_ptr) : NULL;
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, NULL);
+ return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
/**
@@ -220,8 +229,8 @@ bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, ScrArea *sa, Scene *sc
*/
bGPdata *ED_gpencil_data_get_active(const bContext *C)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
- return (gpd_ptr) ? *(gpd_ptr) : NULL;
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+ return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
/**
@@ -234,16 +243,16 @@ bGPdata *ED_gpencil_data_get_active(const bContext *C)
*/
bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
{
- ID *screen_id = (ID *)CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ID *screen_id = (ID *)CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
- const Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *ob = CTX_data_active_object(C);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob = CTX_data_active_object(C);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- /* if (ob && ob->type == OB_GPENCIL) BLI_assert(ob_eval->data == DEG_get_evaluated_id(ob->data)); */
- return ED_gpencil_data_get_active_direct(screen_id, sa, scene_eval, ob_eval);
+ /* if (ob && ob->type == OB_GPENCIL) BLI_assert(ob_eval->data == DEG_get_evaluated_id(ob->data)); */
+ return ED_gpencil_data_get_active_direct(screen_id, sa, scene_eval, ob_eval);
}
/* -------------------------------------------------------- */
@@ -254,10 +263,10 @@ bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
*/
bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
{
- /* Key Assumption: If the pointer is an object, we're dealing with a GP Object's data.
- * Otherwise, the GP datablock is being used for annotations (i.e. everywhere else)
- */
- return ((owner_ptr) && (owner_ptr->type != &RNA_Object));
+ /* Key Assumption: If the pointer is an object, we're dealing with a GP Object's data.
+ * Otherwise, the GP datablock is being used for annotations (i.e. everywhere else)
+ */
+ return ((owner_ptr) && (owner_ptr->type != &RNA_Object));
}
/* ******************************************************** */
@@ -266,21 +275,21 @@ bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
/* Check whether there's an active GP keyframe on the current frame */
bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
{
- if (ob && ob->data && (ob->type == OB_GPENCIL)) {
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->data);
- if (gpl) {
- if (gpl->actframe) {
- // XXX: assumes that frame has been fetched already
- return (gpl->actframe->framenum == cfra);
- }
- else {
- /* XXX: disabled as could be too much of a penalty */
- /* return BKE_gpencil_layer_find_frame(gpl, cfra); */
- }
- }
- }
-
- return false;
+ if (ob && ob->data && (ob->type == OB_GPENCIL)) {
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->data);
+ if (gpl) {
+ if (gpl->actframe) {
+ // XXX: assumes that frame has been fetched already
+ return (gpl->actframe->framenum == cfra);
+ }
+ else {
+ /* XXX: disabled as could be too much of a penalty */
+ /* return BKE_gpencil_layer_find_frame(gpl, cfra); */
+ }
+ }
+ }
+
+ return false;
}
/* ******************************************************** */
@@ -289,30 +298,30 @@ bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
/* poll callback for adding data/layers - special */
bool gp_add_poll(bContext *C)
{
- /* the base line we have is that we have somewhere to add Grease Pencil data */
- return ED_gpencil_data_get_pointers(C, NULL) != NULL;
+ /* the base line we have is that we have somewhere to add Grease Pencil data */
+ return ED_gpencil_data_get_pointers(C, NULL) != NULL;
}
/* poll callback for checking if there is an active layer */
bool gp_active_layer_poll(bContext *C)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- return (gpl != NULL);
+ return (gpl != NULL);
}
/* poll callback for checking if there is an active brush */
bool gp_active_brush_poll(bContext *C)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- Paint *paint = &ts->gp_paint->paint;
- if (paint) {
- return (paint->brush != NULL);
- }
- else {
- return false;
- }
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Paint *paint = &ts->gp_paint->paint;
+ if (paint) {
+ return (paint->brush != NULL);
+ }
+ else {
+ return false;
+ }
}
/* ******************************************************** */
@@ -320,88 +329,91 @@ bool gp_active_brush_poll(bContext *C)
/* NOTE: These include an option to create a new layer and use that... */
/* Just existing layers */
-const EnumPropertyItem *ED_gpencil_layers_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+const EnumPropertyItem *ED_gpencil_layers_enum_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDlayer *gpl;
- EnumPropertyItem *item = NULL, item_tmp = {0};
- int totitem = 0;
- int i = 0;
-
- if (ELEM(NULL, C, gpd)) {
- return DummyRNA_DEFAULT_items;
- }
-
- /* Existing layers */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next, i++) {
- item_tmp.identifier = gpl->info;
- item_tmp.name = gpl->info;
- item_tmp.value = i;
-
- if (gpl->flag & GP_LAYER_ACTIVE)
- item_tmp.icon = ICON_GREASEPENCIL;
- else
- item_tmp.icon = ICON_NONE;
-
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl;
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, gpd)) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* Existing layers */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next, i++) {
+ item_tmp.identifier = gpl->info;
+ item_tmp.name = gpl->info;
+ item_tmp.value = i;
+
+ if (gpl->flag & GP_LAYER_ACTIVE)
+ item_tmp.icon = ICON_GREASEPENCIL;
+ else
+ item_tmp.icon = ICON_NONE;
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
}
/* Existing + Option to add/use new layer */
-const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDlayer *gpl;
- EnumPropertyItem *item = NULL, item_tmp = {0};
- int totitem = 0;
- int i = 0;
-
- if (ELEM(NULL, C, gpd)) {
- return DummyRNA_DEFAULT_items;
- }
-
- /* Create new layer */
- /* TODO: have some way of specifying that we don't want this? */
- {
- /* "New Layer" entry */
- item_tmp.identifier = "__CREATE__";
- item_tmp.name = "New Layer";
- item_tmp.value = -1;
- item_tmp.icon = ICON_ADD;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
-
- /* separator */
- RNA_enum_item_add_separator(&item, &totitem);
- }
- const int tot = BLI_listbase_count(&gpd->layers);
- /* Existing layers */
- for (gpl = gpd->layers.last, i = 0; gpl; gpl = gpl->prev, i++) {
- item_tmp.identifier = gpl->info;
- item_tmp.name = gpl->info;
- item_tmp.value = tot - i - 1;
-
- if (gpl->flag & GP_LAYER_ACTIVE)
- item_tmp.icon = ICON_GREASEPENCIL;
- else
- item_tmp.icon = ICON_NONE;
-
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl;
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, gpd)) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* Create new layer */
+ /* TODO: have some way of specifying that we don't want this? */
+ {
+ /* "New Layer" entry */
+ item_tmp.identifier = "__CREATE__";
+ item_tmp.name = "New Layer";
+ item_tmp.value = -1;
+ item_tmp.icon = ICON_ADD;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+
+ /* separator */
+ RNA_enum_item_add_separator(&item, &totitem);
+ }
+ const int tot = BLI_listbase_count(&gpd->layers);
+ /* Existing layers */
+ for (gpl = gpd->layers.last, i = 0; gpl; gpl = gpl->prev, i++) {
+ item_tmp.identifier = gpl->info;
+ item_tmp.name = gpl->info;
+ item_tmp.value = tot - i - 1;
+
+ if (gpl->flag & GP_LAYER_ACTIVE)
+ item_tmp.icon = ICON_GREASEPENCIL;
+ else
+ item_tmp.icon = ICON_NONE;
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
}
-
/* ******************************************************** */
/* Brush Tool Core */
@@ -416,19 +428,18 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(
* \param x1, y1: The screen-space x and y coordinates of the end of the stroke segment
*/
bool gp_stroke_inside_circle(
- const float mval[2], const float UNUSED(mvalo[2]),
- int rad, int x0, int y0, int x1, int y1)
+ const float mval[2], const float UNUSED(mvalo[2]), int rad, int x0, int y0, int x1, int y1)
{
- /* simple within-radius check for now */
- const float screen_co_a[2] = {x0, y0};
- const float screen_co_b[2] = {x1, y1};
+ /* simple within-radius check for now */
+ const float screen_co_a[2] = {x0, y0};
+ const float screen_co_b[2] = {x1, y1};
- if (edge_inside_circle(mval, rad, screen_co_a, screen_co_b)) {
- return true;
- }
+ if (edge_inside_circle(mval, rad, screen_co_a, screen_co_b)) {
+ return true;
+ }
- /* not inside */
- return false;
+ /* not inside */
+ return false;
}
/* ******************************************************** */
@@ -438,50 +449,50 @@ bool gp_stroke_inside_circle(
/* TODO: do we need additional flags for screenspace vs dataspace? */
bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps)
{
- /* sanity check */
- if (ELEM(NULL, sa, gps))
- return false;
-
- /* filter stroke types by flags + spacetype */
- if (gps->flag & GP_STROKE_3DSPACE) {
- /* 3D strokes - only in 3D view */
- return ((sa->spacetype == SPACE_VIEW3D) || (sa->spacetype == SPACE_PROPERTIES));
- }
- else if (gps->flag & GP_STROKE_2DIMAGE) {
- /* Special "image" strokes - only in Image Editor */
- return (sa->spacetype == SPACE_IMAGE);
- }
- else if (gps->flag & GP_STROKE_2DSPACE) {
- /* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */
- return (sa->spacetype != SPACE_VIEW3D);
- }
- else {
- /* view aligned - anything goes */
- return true;
- }
+ /* sanity check */
+ if (ELEM(NULL, sa, gps))
+ return false;
+
+ /* filter stroke types by flags + spacetype */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* 3D strokes - only in 3D view */
+ return ((sa->spacetype == SPACE_VIEW3D) || (sa->spacetype == SPACE_PROPERTIES));
+ }
+ else if (gps->flag & GP_STROKE_2DIMAGE) {
+ /* Special "image" strokes - only in Image Editor */
+ return (sa->spacetype == SPACE_IMAGE);
+ }
+ else if (gps->flag & GP_STROKE_2DSPACE) {
+ /* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */
+ return (sa->spacetype != SPACE_VIEW3D);
+ }
+ else {
+ /* view aligned - anything goes */
+ return true;
+ }
}
/* Check whether given stroke can be edited in the current context */
bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
{
- ScrArea *sa = CTX_wm_area(C);
- return ED_gpencil_stroke_can_use_direct(sa, gps);
+ ScrArea *sa = CTX_wm_area(C);
+ return ED_gpencil_stroke_can_use_direct(sa, gps);
}
/* Check whether given stroke can be edited for the current color */
bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
{
- /* check if the color is editable */
- MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ /* check if the color is editable */
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
- if (gp_style != NULL) {
- if (gp_style->flag & GP_STYLE_COLOR_HIDE)
- return false;
- if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_STYLE_COLOR_LOCKED))
- return false;
- }
+ if (gp_style != NULL) {
+ if (gp_style->flag & GP_STYLE_COLOR_HIDE)
+ return false;
+ if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_STYLE_COLOR_LOCKED))
+ return false;
+ }
- return true;
+ return true;
}
/* ******************************************************** */
@@ -494,41 +505,42 @@ bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstr
*/
void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
-
- /* zero out the storage (just in case) */
- memset(r_gsc, 0, sizeof(GP_SpaceConversion));
- unit_m4(r_gsc->mat);
-
- /* store settings */
- r_gsc->scene = CTX_data_scene(C);
- r_gsc->ob = CTX_data_active_object(C);
-
- r_gsc->sa = sa;
- r_gsc->ar = ar;
- r_gsc->v2d = &ar->v2d;
-
- /* init region-specific stuff */
- if (sa->spacetype == SPACE_VIEW3D) {
- wmWindow *win = CTX_wm_window(C);
- Scene *scene = CTX_data_scene(C);
- struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
- View3D *v3d = (View3D *)CTX_wm_space_data(C);
- RegionView3D *rv3d = ar->regiondata;
-
- /* init 3d depth buffers */
- view3d_operator_needs_opengl(C);
-
- view3d_region_operator_needs_opengl(win, ar);
- ED_view3d_autodist_init(depsgraph, ar, v3d, 0);
-
- /* for camera view set the subrect */
- if (rv3d->persp == RV3D_CAMOB) {
- ED_view3d_calc_camera_border(scene, CTX_data_depsgraph(C), ar, v3d, rv3d, &r_gsc->subrect_data, true);
- r_gsc->subrect = &r_gsc->subrect_data;
- }
- }
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ /* zero out the storage (just in case) */
+ memset(r_gsc, 0, sizeof(GP_SpaceConversion));
+ unit_m4(r_gsc->mat);
+
+ /* store settings */
+ r_gsc->scene = CTX_data_scene(C);
+ r_gsc->ob = CTX_data_active_object(C);
+
+ r_gsc->sa = sa;
+ r_gsc->ar = ar;
+ r_gsc->v2d = &ar->v2d;
+
+ /* init region-specific stuff */
+ if (sa->spacetype == SPACE_VIEW3D) {
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = CTX_data_scene(C);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ View3D *v3d = (View3D *)CTX_wm_space_data(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* init 3d depth buffers */
+ view3d_operator_needs_opengl(C);
+
+ view3d_region_operator_needs_opengl(win, ar);
+ ED_view3d_autodist_init(depsgraph, ar, v3d, 0);
+
+ /* for camera view set the subrect */
+ if (rv3d->persp == RV3D_CAMOB) {
+ ED_view3d_calc_camera_border(
+ scene, CTX_data_depsgraph(C), ar, v3d, rv3d, &r_gsc->subrect_data, true);
+ r_gsc->subrect = &r_gsc->subrect_data;
+ }
+ }
}
/**
@@ -540,50 +552,52 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
*/
void gp_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4], bGPDspoint *r_pt)
{
- float fpt[3];
+ float fpt[3];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- copy_v3_v3(&r_pt->x, fpt);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ copy_v3_v3(&r_pt->x, fpt);
}
/**
* Change position relative to parent object
*/
-void gp_apply_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
+void gp_apply_parent(
+ Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
{
- bGPDspoint *pt;
- int i;
-
- /* undo matrix */
- float diff_mat[4][4];
- float inverse_diff_mat[4][4];
- float fpt[3];
-
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
- invert_m4_m4(inverse_diff_mat, diff_mat);
-
- for (i = 0; i < gps->totpoints; i++) {
- pt = &gps->points[i];
- mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
- copy_v3_v3(&pt->x, fpt);
- }
+ bGPDspoint *pt;
+ int i;
+
+ /* undo matrix */
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+ float fpt[3];
+
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+
+ for (i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
+ copy_v3_v3(&pt->x, fpt);
+ }
}
/**
* Change point position relative to parent object
*/
-void gp_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDspoint *pt)
+void gp_apply_parent_point(
+ Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDspoint *pt)
{
- /* undo matrix */
- float diff_mat[4][4];
- float inverse_diff_mat[4][4];
- float fpt[3];
+ /* undo matrix */
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+ float fpt[3];
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
- invert_m4_m4(inverse_diff_mat, diff_mat);
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ invert_m4_m4(inverse_diff_mat, diff_mat);
- mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
- copy_v3_v3(&pt->x, fpt);
+ mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
+ copy_v3_v3(&pt->x, fpt);
}
/**
@@ -595,46 +609,44 @@ void gp_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bG
* \warning This assumes that the caller has already checked whether the stroke in question can be drawn.
*/
void gp_point_to_xy(
- const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt,
- int *r_x, int *r_y)
+ const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt, int *r_x, int *r_y)
{
- const ARegion *ar = gsc->ar;
- const View2D *v2d = gsc->v2d;
- const rctf *subrect = gsc->subrect;
- int xyval[2];
-
- /* sanity checks */
- BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
- BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
-
-
- if (gps->flag & GP_STROKE_3DSPACE) {
- if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- *r_x = xyval[0];
- *r_y = xyval[1];
- }
- else {
- *r_x = V2D_IS_CLIPPED;
- *r_y = V2D_IS_CLIPPED;
- }
- }
- else if (gps->flag & GP_STROKE_2DSPACE) {
- float vec[3] = {pt->x, pt->y, 0.0f};
- mul_m4_v3(gsc->mat, vec);
- UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y);
- }
- else {
- if (subrect == NULL) {
- /* normal 3D view (or view space) */
- *r_x = (int)(pt->x / 100 * ar->winx);
- *r_y = (int)(pt->y / 100 * ar->winy);
- }
- else {
- /* camera view, use subrect */
- *r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin;
- *r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin;
- }
- }
+ const ARegion *ar = gsc->ar;
+ const View2D *v2d = gsc->v2d;
+ const rctf *subrect = gsc->subrect;
+ int xyval[2];
+
+ /* sanity checks */
+ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ *r_x = xyval[0];
+ *r_y = xyval[1];
+ }
+ else {
+ *r_x = V2D_IS_CLIPPED;
+ *r_y = V2D_IS_CLIPPED;
+ }
+ }
+ else if (gps->flag & GP_STROKE_2DSPACE) {
+ float vec[3] = {pt->x, pt->y, 0.0f};
+ mul_m4_v3(gsc->mat, vec);
+ UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y);
+ }
+ else {
+ if (subrect == NULL) {
+ /* normal 3D view (or view space) */
+ *r_x = (int)(pt->x / 100 * ar->winx);
+ *r_y = (int)(pt->y / 100 * ar->winy);
+ }
+ else {
+ /* camera view, use subrect */
+ *r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin;
+ *r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin;
+ }
+ }
}
/**
@@ -648,117 +660,119 @@ void gp_point_to_xy(
*
* \warning This assumes that the caller has already checked whether the stroke in question can be drawn.
*/
-void gp_point_to_xy_fl(
- const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt,
- float *r_x, float *r_y)
+void gp_point_to_xy_fl(const GP_SpaceConversion *gsc,
+ const bGPDstroke *gps,
+ const bGPDspoint *pt,
+ float *r_x,
+ float *r_y)
{
- const ARegion *ar = gsc->ar;
- const View2D *v2d = gsc->v2d;
- const rctf *subrect = gsc->subrect;
- float xyval[2];
-
- /* sanity checks */
- BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
- BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
-
-
- if (gps->flag & GP_STROKE_3DSPACE) {
- if (ED_view3d_project_float_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- *r_x = xyval[0];
- *r_y = xyval[1];
- }
- else {
- *r_x = 0.0f;
- *r_y = 0.0f;
- }
- }
- else if (gps->flag & GP_STROKE_2DSPACE) {
- float vec[3] = {pt->x, pt->y, 0.0f};
- int t_x, t_y;
-
- mul_m4_v3(gsc->mat, vec);
- UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
-
- if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
- /* XXX: Or should we just always use the values as-is? */
- *r_x = 0.0f;
- *r_y = 0.0f;
- }
- else {
- *r_x = (float)t_x;
- *r_y = (float)t_y;
- }
- }
- else {
- if (subrect == NULL) {
- /* normal 3D view (or view space) */
- *r_x = (pt->x / 100.0f * ar->winx);
- *r_y = (pt->y / 100.0f * ar->winy);
- }
- else {
- /* camera view, use subrect */
- *r_x = ((pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
- *r_y = ((pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
- }
- }
+ const ARegion *ar = gsc->ar;
+ const View2D *v2d = gsc->v2d;
+ const rctf *subrect = gsc->subrect;
+ float xyval[2];
+
+ /* sanity checks */
+ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ if (ED_view3d_project_float_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ *r_x = xyval[0];
+ *r_y = xyval[1];
+ }
+ else {
+ *r_x = 0.0f;
+ *r_y = 0.0f;
+ }
+ }
+ else if (gps->flag & GP_STROKE_2DSPACE) {
+ float vec[3] = {pt->x, pt->y, 0.0f};
+ int t_x, t_y;
+
+ mul_m4_v3(gsc->mat, vec);
+ UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
+
+ if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
+ /* XXX: Or should we just always use the values as-is? */
+ *r_x = 0.0f;
+ *r_y = 0.0f;
+ }
+ else {
+ *r_x = (float)t_x;
+ *r_y = (float)t_y;
+ }
+ }
+ else {
+ if (subrect == NULL) {
+ /* normal 3D view (or view space) */
+ *r_x = (pt->x / 100.0f * ar->winx);
+ *r_y = (pt->y / 100.0f * ar->winy);
+ }
+ else {
+ /* camera view, use subrect */
+ *r_x = ((pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
+ *r_y = ((pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
+ }
+ }
}
-
/**
* generic based on gp_point_to_xy_fl
*/
-void gp_point_3d_to_xy(const GP_SpaceConversion *gsc, const short flag, const float pt[3], float xy[2])
+void gp_point_3d_to_xy(const GP_SpaceConversion *gsc,
+ const short flag,
+ const float pt[3],
+ float xy[2])
{
- const ARegion *ar = gsc->ar;
- const View2D *v2d = gsc->v2d;
- const rctf *subrect = gsc->subrect;
- float xyval[2];
-
- /* sanity checks */
- BLI_assert((gsc->sa->spacetype == SPACE_VIEW3D));
-
- if (flag & GP_STROKE_3DSPACE) {
- if (ED_view3d_project_float_global(ar, pt, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- xy[0] = xyval[0];
- xy[1] = xyval[1];
- }
- else {
- xy[0] = 0.0f;
- xy[1] = 0.0f;
- }
- }
- else if (flag & GP_STROKE_2DSPACE) {
- float vec[3] = { pt[0], pt[1], 0.0f };
- int t_x, t_y;
-
- mul_m4_v3(gsc->mat, vec);
- UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
-
- if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
- /* XXX: Or should we just always use the values as-is? */
- xy[0] = 0.0f;
- xy[1] = 0.0f;
- }
- else {
- xy[0] = (float)t_x;
- xy[1] = (float)t_y;
- }
- }
- else {
- if (subrect == NULL) {
- /* normal 3D view (or view space) */
- xy[0] = (pt[0] / 100.0f * ar->winx);
- xy[1] = (pt[1] / 100.0f * ar->winy);
- }
- else {
- /* camera view, use subrect */
- xy[0] = ((pt[0] / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
- xy[1] = ((pt[1] / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
- }
- }
+ const ARegion *ar = gsc->ar;
+ const View2D *v2d = gsc->v2d;
+ const rctf *subrect = gsc->subrect;
+ float xyval[2];
+
+ /* sanity checks */
+ BLI_assert((gsc->sa->spacetype == SPACE_VIEW3D));
+
+ if (flag & GP_STROKE_3DSPACE) {
+ if (ED_view3d_project_float_global(ar, pt, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ xy[0] = xyval[0];
+ xy[1] = xyval[1];
+ }
+ else {
+ xy[0] = 0.0f;
+ xy[1] = 0.0f;
+ }
+ }
+ else if (flag & GP_STROKE_2DSPACE) {
+ float vec[3] = {pt[0], pt[1], 0.0f};
+ int t_x, t_y;
+
+ mul_m4_v3(gsc->mat, vec);
+ UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
+
+ if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
+ /* XXX: Or should we just always use the values as-is? */
+ xy[0] = 0.0f;
+ xy[1] = 0.0f;
+ }
+ else {
+ xy[0] = (float)t_x;
+ xy[1] = (float)t_y;
+ }
+ }
+ else {
+ if (subrect == NULL) {
+ /* normal 3D view (or view space) */
+ xy[0] = (pt[0] / 100.0f * ar->winx);
+ xy[1] = (pt[1] / 100.0f * ar->winy);
+ }
+ else {
+ /* camera view, use subrect */
+ xy[0] = ((pt[0] / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
+ xy[1] = ((pt[1] / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
+ }
+ }
}
-
/**
* Project screenspace coordinates to 3D-space
*
@@ -774,34 +788,37 @@ void gp_point_3d_to_xy(const GP_SpaceConversion *gsc, const short flag, const fl
*
* \warning Assumes that it is getting called in a 3D view only.
*/
-bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc, Scene *scene, const float screen_co[2], float r_out[3])
+bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc,
+ Scene *scene,
+ const float screen_co[2],
+ float r_out[3])
{
- const RegionView3D *rv3d = gsc->ar->regiondata;
- float rvec[3];
+ const RegionView3D *rv3d = gsc->ar->regiondata;
+ float rvec[3];
- ED_gp_get_drawing_reference(
- scene, gsc->ob, gsc->gpl,
- scene->toolsettings->gpencil_v3d_align, rvec);
+ ED_gp_get_drawing_reference(
+ scene, gsc->ob, gsc->gpl, scene->toolsettings->gpencil_v3d_align, rvec);
- float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
+ float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
- float mval_f[2], mval_prj[2];
- float dvec[3];
+ float mval_f[2], mval_prj[2];
+ float dvec[3];
- copy_v2_v2(mval_f, screen_co);
+ copy_v2_v2(mval_f, screen_co);
- if (ED_view3d_project_float_global(gsc->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- sub_v2_v2v2(mval_f, mval_prj, mval_f);
- ED_view3d_win_to_delta(gsc->ar, mval_f, dvec, zfac);
- sub_v3_v3v3(r_out, rvec, dvec);
+ if (ED_view3d_project_float_global(gsc->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
+ V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval_f);
+ ED_view3d_win_to_delta(gsc->ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(r_out, rvec, dvec);
- return true;
- }
- else {
- zero_v3(r_out);
+ return true;
+ }
+ else {
+ zero_v3(r_out);
- return false;
- }
+ return false;
+ }
}
/**
@@ -812,43 +829,45 @@ bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc, Scene *scene, const float
* \param depth: Depth array (via #ED_view3d_autodist_depth()).
* \param[out] r_out: The resulting 2D point data.
*/
-void gp_stroke_convertcoords_tpoint(
- Scene *scene, ARegion *ar,
- Object *ob, bGPDlayer *gpl,
- const tGPspoint *point2D, float *depth,
- float r_out[3])
+void gp_stroke_convertcoords_tpoint(Scene *scene,
+ ARegion *ar,
+ Object *ob,
+ bGPDlayer *gpl,
+ const tGPspoint *point2D,
+ float *depth,
+ float r_out[3])
{
- ToolSettings *ts = scene->toolsettings;
-
- int mval_i[2];
- round_v2i_v2fl(mval_i, &point2D->x);
-
- if ((depth != NULL) && (ED_view3d_autodist_simple(ar, mval_i, r_out, 0, depth))) {
- /* projecting onto 3D-Geometry
- * - nothing more needs to be done here, since view_autodist_simple() has already done it
- */
- }
- else {
- float mval_f[2] = {point2D->x, point2D->y};
- float mval_prj[2];
- float rvec[3], dvec[3];
- float zfac;
-
- /* Current method just converts each point in screen-coordinates to
- * 3D-coordinates using the 3D-cursor as reference.
- */
- ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, rvec);
- zfac = ED_view3d_calc_zfac(ar->regiondata, rvec, NULL);
-
- if (ED_view3d_project_float_global(ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- sub_v2_v2v2(mval_f, mval_prj, mval_f);
- ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
- sub_v3_v3v3(r_out, rvec, dvec);
- }
- else {
- zero_v3(r_out);
- }
- }
+ ToolSettings *ts = scene->toolsettings;
+
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, &point2D->x);
+
+ if ((depth != NULL) && (ED_view3d_autodist_simple(ar, mval_i, r_out, 0, depth))) {
+ /* projecting onto 3D-Geometry
+ * - nothing more needs to be done here, since view_autodist_simple() has already done it
+ */
+ }
+ else {
+ float mval_f[2] = {point2D->x, point2D->y};
+ float mval_prj[2];
+ float rvec[3], dvec[3];
+ float zfac;
+
+ /* Current method just converts each point in screen-coordinates to
+ * 3D-coordinates using the 3D-cursor as reference.
+ */
+ ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, rvec);
+ zfac = ED_view3d_calc_zfac(ar->regiondata, rvec, NULL);
+
+ if (ED_view3d_project_float_global(ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval_f);
+ ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(r_out, rvec, dvec);
+ }
+ else {
+ zero_v3(r_out);
+ }
+ }
}
/**
@@ -856,209 +875,206 @@ void gp_stroke_convertcoords_tpoint(
* \param[out] r_vec : Reference point found
*/
void ED_gp_get_drawing_reference(
- const Scene *scene, const Object *ob, bGPDlayer *UNUSED(gpl),
- char align_flag, float r_vec[3])
+ const Scene *scene, const Object *ob, bGPDlayer *UNUSED(gpl), char align_flag, float r_vec[3])
{
- const float *fp = scene->cursor.location;
-
- /* if using a gpencil object at cursor mode, can use the location of the object */
- if (align_flag & GP_PROJECT_VIEWSPACE) {
- if (ob && (ob->type == OB_GPENCIL)) {
- /* fallback (no strokes) - use cursor or object location */
- if (align_flag & GP_PROJECT_CURSOR) {
- /* use 3D-cursor */
- copy_v3_v3(r_vec, fp);
- }
- else {
- /* use object location */
- copy_v3_v3(r_vec, ob->obmat[3]);
- }
- }
- }
- else {
- /* use 3D-cursor */
- copy_v3_v3(r_vec, fp);
- }
+ const float *fp = scene->cursor.location;
+
+ /* if using a gpencil object at cursor mode, can use the location of the object */
+ if (align_flag & GP_PROJECT_VIEWSPACE) {
+ if (ob && (ob->type == OB_GPENCIL)) {
+ /* fallback (no strokes) - use cursor or object location */
+ if (align_flag & GP_PROJECT_CURSOR) {
+ /* use 3D-cursor */
+ copy_v3_v3(r_vec, fp);
+ }
+ else {
+ /* use object location */
+ copy_v3_v3(r_vec, ob->obmat[3]);
+ }
+ }
+ }
+ else {
+ /* use 3D-cursor */
+ copy_v3_v3(r_vec, fp);
+ }
}
void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke *gps)
{
- Scene *scene = CTX_data_scene(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = (bGPdata *)ob->data;
- GP_SpaceConversion gsc = { NULL };
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ GP_SpaceConversion gsc = {NULL};
- bGPDspoint *pt;
- int i;
- float diff_mat[4][4];
- float inverse_diff_mat[4][4];
+ bGPDspoint *pt;
+ int i;
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
- /* init space conversion stuff */
- gp_point_conversion_init(C, &gsc);
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
- ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, diff_mat);
- invert_m4_m4(inverse_diff_mat, diff_mat);
+ ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, diff_mat);
+ invert_m4_m4(inverse_diff_mat, diff_mat);
- /* Adjust each point */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- float xy[2];
+ /* Adjust each point */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float xy[2];
- bGPDspoint pt2;
- gp_point_to_parent_space(pt, diff_mat, &pt2);
- gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
- /* Planar - All on same plane parallel to the viewplane */
- gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
+ /* Planar - All on same plane parallel to the viewplane */
+ gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
- /* Unapply parent corrections */
- mul_m4_v3(inverse_diff_mat, &pt->x);
- }
+ /* Unapply parent corrections */
+ mul_m4_v3(inverse_diff_mat, &pt->x);
+ }
}
/**
* Reproject all points of the stroke to a plane locked to axis to avoid stroke offset
*/
-void ED_gp_project_stroke_to_plane(
- const Scene *scene, const Object *ob,
- const RegionView3D *rv3d, bGPDstroke *gps,
- const float origin[3], const int axis)
+void ED_gp_project_stroke_to_plane(const Scene *scene,
+ const Object *ob,
+ const RegionView3D *rv3d,
+ bGPDstroke *gps,
+ const float origin[3],
+ const int axis)
{
- const ToolSettings *ts = scene->toolsettings;
- const View3DCursor *cursor = &scene->cursor;
- 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);
- if (axis < 0) {
- /* if the axis is not locked, need a vector to the view direction
- * in order to get the right size of the stroke.
- */
- ED_view3d_global_to_vector(rv3d, origin, plane_normal);
- }
- else if (axis < 3) {
- plane_normal[axis] = 1.0f;
- /* if object, apply object rotation */
- if (ob && (ob->type == OB_GPENCIL)) {
- float mat[4][4];
- copy_m4_m4(mat, ob->obmat);
-
- /* move origin to cursor */
- if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
- copy_v3_v3(mat[3], cursor->location);
- }
-
- mul_mat3_m4_v3(mat, plane_normal);
- }
- }
- else {
- float scale[3] = { 1.0f, 1.0f, 1.0f };
- plane_normal[2] = 1.0f;
- float mat[4][4];
- loc_eul_size_to_mat4(mat,
- cursor->location,
- cursor->rotation_euler,
- scale);
-
- /* move origin to object */
- if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
- copy_v3_v3(mat[3], ob->obmat[3]);
- }
-
- mul_mat3_m4_v3(mat, plane_normal);
- }
-
- /* 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 extreme 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);
- }
- }
+ const ToolSettings *ts = scene->toolsettings;
+ const View3DCursor *cursor = &scene->cursor;
+ 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);
+ if (axis < 0) {
+ /* if the axis is not locked, need a vector to the view direction
+ * in order to get the right size of the stroke.
+ */
+ ED_view3d_global_to_vector(rv3d, origin, plane_normal);
+ }
+ else if (axis < 3) {
+ plane_normal[axis] = 1.0f;
+ /* if object, apply object rotation */
+ if (ob && (ob->type == OB_GPENCIL)) {
+ float mat[4][4];
+ copy_m4_m4(mat, ob->obmat);
+
+ /* move origin to cursor */
+ if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
+ copy_v3_v3(mat[3], cursor->location);
+ }
+
+ mul_mat3_m4_v3(mat, plane_normal);
+ }
+ }
+ else {
+ float scale[3] = {1.0f, 1.0f, 1.0f};
+ plane_normal[2] = 1.0f;
+ float mat[4][4];
+ loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, scale);
+
+ /* move origin to object */
+ if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
+ copy_v3_v3(mat[3], ob->obmat[3]);
+ }
+
+ mul_mat3_m4_v3(mat, plane_normal);
+ }
+
+ /* 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 extreme 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 given point to a plane locked to axis to avoid stroke offset
* \param[in,out] pt: Point to affect
*/
-void ED_gp_project_point_to_plane(
- const Scene *scene, const Object *ob,
- const RegionView3D *rv3d, const float origin[3],
- const int axis, bGPDspoint *pt)
+void ED_gp_project_point_to_plane(const Scene *scene,
+ const Object *ob,
+ const RegionView3D *rv3d,
+ const float origin[3],
+ const int axis,
+ bGPDspoint *pt)
{
- const ToolSettings *ts = scene->toolsettings;
- const View3DCursor *cursor = &scene->cursor;
- 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);
- if (axis < 0) {
- /* if the axis is not locked, need a vector to the view direction
- * in order to get the right size of the stroke.
- */
- ED_view3d_global_to_vector(rv3d, origin, plane_normal);
- }
- else if (axis < 3) {
- plane_normal[axis] = 1.0f;
- /* if object, apply object rotation */
- if (ob && (ob->type == OB_GPENCIL)) {
- float mat[4][4];
- copy_m4_m4(mat, ob->obmat);
-
- /* move origin to cursor */
- if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
- copy_v3_v3(mat[3], cursor->location);
- }
-
- mul_mat3_m4_v3(mat, plane_normal);
- }
- }
- else {
- float scale[3] = { 1.0f, 1.0f, 1.0f };
- plane_normal[2] = 1.0f;
- float mat[4][4];
- loc_eul_size_to_mat4(mat,
- cursor->location,
- cursor->rotation_euler,
- scale);
-
- /* move origin to object */
- if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
- copy_v3_v3(mat[3], ob->obmat[3]);
- }
-
- mul_mat3_m4_v3(mat, plane_normal);
- }
-
- /* Reproject the points in the plane */
- /* 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);
- }
+ const ToolSettings *ts = scene->toolsettings;
+ const View3DCursor *cursor = &scene->cursor;
+ 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);
+ if (axis < 0) {
+ /* if the axis is not locked, need a vector to the view direction
+ * in order to get the right size of the stroke.
+ */
+ ED_view3d_global_to_vector(rv3d, origin, plane_normal);
+ }
+ else if (axis < 3) {
+ plane_normal[axis] = 1.0f;
+ /* if object, apply object rotation */
+ if (ob && (ob->type == OB_GPENCIL)) {
+ float mat[4][4];
+ copy_m4_m4(mat, ob->obmat);
+
+ /* move origin to cursor */
+ if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
+ copy_v3_v3(mat[3], cursor->location);
+ }
+
+ mul_mat3_m4_v3(mat, plane_normal);
+ }
+ }
+ else {
+ float scale[3] = {1.0f, 1.0f, 1.0f};
+ plane_normal[2] = 1.0f;
+ float mat[4][4];
+ loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, scale);
+
+ /* move origin to object */
+ if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
+ copy_v3_v3(mat[3], ob->obmat[3]);
+ }
+
+ mul_mat3_m4_v3(mat, plane_normal);
+ }
+
+ /* Reproject the points in the plane */
+ /* 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);
+ }
}
/* ******************************************************** */
@@ -1072,92 +1088,92 @@ void ED_gp_project_point_to_plane(
*/
void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide)
{
- bGPDspoint *temp_points;
- int totnewpoints, oldtotpoints;
- int i2;
-
- /* loop as many times as levels */
- for (int s = 0; s < subdivide; s++) {
- totnewpoints = gps->totpoints - 1;
- /* duplicate points in a temp area */
- temp_points = MEM_dupallocN(gps->points);
- oldtotpoints = gps->totpoints;
-
- /* resize the points arrays */
- gps->totpoints += totnewpoints;
- gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
- if (gps->dvert != NULL) {
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
- }
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* move points from last to first to new place */
- i2 = gps->totpoints - 1;
- for (int i = oldtotpoints - 1; i > 0; i--) {
- bGPDspoint *pt = &temp_points[i];
- bGPDspoint *pt_final = &gps->points[i2];
-
- copy_v3_v3(&pt_final->x, &pt->x);
- pt_final->pressure = pt->pressure;
- pt_final->strength = pt->strength;
- pt_final->time = pt->time;
- pt_final->flag = pt->flag;
- pt_final->uv_fac = pt->uv_fac;
- pt_final->uv_rot = pt->uv_rot;
-
- if (gps->dvert != NULL) {
- MDeformVert *dvert = &gps->dvert[i];
- MDeformVert *dvert_final = &gps->dvert[i2];
-
- dvert_final->totweight = dvert->totweight;
- dvert_final->dw = dvert->dw;
- }
-
- i2 -= 2;
- }
- /* interpolate mid points */
- i2 = 1;
- for (int i = 0; i < oldtotpoints - 1; i++) {
- bGPDspoint *pt = &temp_points[i];
- bGPDspoint *next = &temp_points[i + 1];
- bGPDspoint *pt_final = &gps->points[i2];
-
- /* add a half way point */
- interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
- pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
- pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
- CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- pt_final->time = interpf(pt->time, next->time, 0.5f);
- pt_final->uv_fac = interpf(pt->uv_fac, next->uv_fac, 0.5f);
- pt_final->uv_rot = interpf(pt->uv_rot, next->uv_rot, 0.5f);
-
- if (gps->dvert != NULL) {
- MDeformVert *dvert_final = &gps->dvert[i2];
- dvert_final->totweight = 0;
- dvert_final->dw = NULL;
- }
-
- i2 += 2;
- }
-
- MEM_SAFE_FREE(temp_points);
-
- /* move points to smooth stroke */
- /* duplicate points in a temp area with the new subdivide data */
- temp_points = MEM_dupallocN(gps->points);
-
- /* extreme points are not changed */
- for (int i = 0; i < gps->totpoints - 2; i++) {
- bGPDspoint *pt = &temp_points[i];
- bGPDspoint *next = &temp_points[i + 1];
- bGPDspoint *pt_final = &gps->points[i + 1];
-
- /* move point */
- interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
- }
- /* free temp memory */
- MEM_SAFE_FREE(temp_points);
- }
+ bGPDspoint *temp_points;
+ int totnewpoints, oldtotpoints;
+ int i2;
+
+ /* loop as many times as levels */
+ for (int s = 0; s < subdivide; s++) {
+ totnewpoints = gps->totpoints - 1;
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+
+ /* resize the points arrays */
+ gps->totpoints += totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ }
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* move points from last to first to new place */
+ i2 = gps->totpoints - 1;
+ for (int i = oldtotpoints - 1; i > 0; i--) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+ pt_final->uv_fac = pt->uv_fac;
+ pt_final->uv_rot = pt->uv_rot;
+
+ if (gps->dvert != NULL) {
+ MDeformVert *dvert = &gps->dvert[i];
+ MDeformVert *dvert_final = &gps->dvert[i2];
+
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = dvert->dw;
+ }
+
+ i2 -= 2;
+ }
+ /* interpolate mid points */
+ i2 = 1;
+ for (int i = 0; i < oldtotpoints - 1; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ /* add a half way point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
+ pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
+ CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt_final->time = interpf(pt->time, next->time, 0.5f);
+ pt_final->uv_fac = interpf(pt->uv_fac, next->uv_fac, 0.5f);
+ pt_final->uv_rot = interpf(pt->uv_rot, next->uv_rot, 0.5f);
+
+ if (gps->dvert != NULL) {
+ MDeformVert *dvert_final = &gps->dvert[i2];
+ dvert_final->totweight = 0;
+ dvert_final->dw = NULL;
+ }
+
+ i2 += 2;
+ }
+
+ MEM_SAFE_FREE(temp_points);
+
+ /* move points to smooth stroke */
+ /* duplicate points in a temp area with the new subdivide data */
+ temp_points = MEM_dupallocN(gps->points);
+
+ /* extreme points are not changed */
+ for (int i = 0; i < gps->totpoints - 2; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i + 1];
+
+ /* move point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ }
+ /* free temp memory */
+ MEM_SAFE_FREE(temp_points);
+ }
}
/**
@@ -1167,184 +1183,189 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide)
*/
void gp_randomize_stroke(bGPDstroke *gps, Brush *brush, RNG *rng)
{
- bGPDspoint *pt1, *pt2, *pt3;
- float v1[3];
- float v2[3];
- if (gps->totpoints < 3) {
- return;
- }
-
- /* get two vectors using 3 points */
- pt1 = &gps->points[0];
- pt2 = &gps->points[1];
- pt3 = &gps->points[(int)(gps->totpoints * 0.75)];
-
- sub_v3_v3v3(v1, &pt2->x, &pt1->x);
- sub_v3_v3v3(v2, &pt3->x, &pt2->x);
- normalize_v3(v1);
- normalize_v3(v2);
-
- /* get normal vector to plane created by two vectors */
- float normal[3];
- cross_v3_v3v3(normal, v1, v2);
- normalize_v3(normal);
-
- /* get orthogonal vector to plane to rotate random effect */
- float ortho[3];
- cross_v3_v3v3(ortho, v1, normal);
- normalize_v3(ortho);
-
- /* Read all points and apply shift vector (first and last point not modified) */
- for (int i = 1; i < gps->totpoints - 1; i++) {
- bGPDspoint *pt = &gps->points[i];
- /* get vector with shift (apply a division because random is too sensitive */
- const float fac = BLI_rng_get_float(rng) * (brush->gpencil_settings->draw_random_sub / 10.0f);
- float svec[3];
- copy_v3_v3(svec, ortho);
- if (BLI_rng_get_float(rng) > 0.5f) {
- mul_v3_fl(svec, -fac);
- }
- else {
- mul_v3_fl(svec, fac);
- }
-
- /* apply shift */
- add_v3_v3(&pt->x, svec);
- }
+ bGPDspoint *pt1, *pt2, *pt3;
+ float v1[3];
+ float v2[3];
+ if (gps->totpoints < 3) {
+ return;
+ }
+
+ /* get two vectors using 3 points */
+ pt1 = &gps->points[0];
+ pt2 = &gps->points[1];
+ pt3 = &gps->points[(int)(gps->totpoints * 0.75)];
+
+ sub_v3_v3v3(v1, &pt2->x, &pt1->x);
+ sub_v3_v3v3(v2, &pt3->x, &pt2->x);
+ normalize_v3(v1);
+ normalize_v3(v2);
+
+ /* get normal vector to plane created by two vectors */
+ float normal[3];
+ cross_v3_v3v3(normal, v1, v2);
+ normalize_v3(normal);
+
+ /* get orthogonal vector to plane to rotate random effect */
+ float ortho[3];
+ cross_v3_v3v3(ortho, v1, normal);
+ normalize_v3(ortho);
+
+ /* Read all points and apply shift vector (first and last point not modified) */
+ for (int i = 1; i < gps->totpoints - 1; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ /* get vector with shift (apply a division because random is too sensitive */
+ const float fac = BLI_rng_get_float(rng) * (brush->gpencil_settings->draw_random_sub / 10.0f);
+ float svec[3];
+ copy_v3_v3(svec, ortho);
+ if (BLI_rng_get_float(rng) > 0.5f) {
+ mul_v3_fl(svec, -fac);
+ }
+ else {
+ mul_v3_fl(svec, fac);
+ }
+
+ /* apply shift */
+ add_v3_v3(&pt->x, svec);
+ }
}
/* ******************************************************** */
/* Layer Parenting - Compute Parent Transforms */
/* calculate difference matrix */
-void ED_gpencil_parent_location(
- const Depsgraph *depsgraph, Object *obact, bGPdata *UNUSED(gpd),
- bGPDlayer *gpl, float diff_mat[4][4])
+void ED_gpencil_parent_location(const Depsgraph *depsgraph,
+ Object *obact,
+ bGPdata *UNUSED(gpd),
+ bGPDlayer *gpl,
+ float diff_mat[4][4])
{
- Object *ob_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obact) : obact;
- Object *obparent = gpl->parent;
- Object *obparent_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obparent) : obparent;
-
- /* if not layer parented, try with object parented */
- if (obparent_eval == NULL) {
- if (ob_eval != NULL) {
- if (ob_eval->type == OB_GPENCIL) {
- copy_m4_m4(diff_mat, ob_eval->obmat);
- return;
- }
- }
- /* not gpencil object */
- unit_m4(diff_mat);
- return;
- }
- else {
- if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
- mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse);
- return;
- }
- else if (gpl->partype == PARBONE) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(obparent_eval->pose, gpl->parsubstr);
- if (pchan) {
- float tmp_mat[4][4];
- mul_m4_m4m4(tmp_mat, obparent_eval->obmat, pchan->pose_mat);
- mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse);
- }
- else {
- /* if bone not found use object (armature) */
- mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse);
- }
- return;
- }
- else {
- unit_m4(diff_mat); /* not defined type */
- }
- }
+ Object *ob_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obact) : obact;
+ Object *obparent = gpl->parent;
+ Object *obparent_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obparent) :
+ obparent;
+
+ /* if not layer parented, try with object parented */
+ if (obparent_eval == NULL) {
+ if (ob_eval != NULL) {
+ if (ob_eval->type == OB_GPENCIL) {
+ copy_m4_m4(diff_mat, ob_eval->obmat);
+ return;
+ }
+ }
+ /* not gpencil object */
+ unit_m4(diff_mat);
+ return;
+ }
+ else {
+ if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
+ mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse);
+ return;
+ }
+ else if (gpl->partype == PARBONE) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(obparent_eval->pose, gpl->parsubstr);
+ if (pchan) {
+ float tmp_mat[4][4];
+ mul_m4_m4m4(tmp_mat, obparent_eval->obmat, pchan->pose_mat);
+ mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse);
+ }
+ else {
+ /* if bone not found use object (armature) */
+ mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse);
+ }
+ return;
+ }
+ else {
+ unit_m4(diff_mat); /* not defined type */
+ }
+ }
}
/* reset parent matrix for all layers */
void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd)
{
- bGPDspoint *pt;
- int i;
- float diff_mat[4][4];
- float cur_mat[4][4];
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->parent != NULL) {
- /* calculate new matrix */
- if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
- invert_m4_m4(cur_mat, gpl->parent->obmat);
- }
- else if (gpl->partype == PARBONE) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr);
- if (pchan) {
- float tmp_mat[4][4];
- mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat);
- invert_m4_m4(cur_mat, tmp_mat);
- }
- }
-
- /* only redo if any change */
- if (!equals_m4m4(gpl->inverse, cur_mat)) {
- /* first apply current transformation to all strokes */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- mul_m4_v3(diff_mat, &pt->x);
- }
- }
- }
- /* set new parent matrix */
- copy_m4_m4(gpl->inverse, cur_mat);
- }
- }
- }
+ bGPDspoint *pt;
+ int i;
+ float diff_mat[4][4];
+ float cur_mat[4][4];
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->parent != NULL) {
+ /* calculate new matrix */
+ if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
+ invert_m4_m4(cur_mat, gpl->parent->obmat);
+ }
+ else if (gpl->partype == PARBONE) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr);
+ if (pchan) {
+ float tmp_mat[4][4];
+ mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat);
+ invert_m4_m4(cur_mat, tmp_mat);
+ }
+ }
+
+ /* only redo if any change */
+ if (!equals_m4m4(gpl->inverse, cur_mat)) {
+ /* first apply current transformation to all strokes */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ mul_m4_v3(diff_mat, &pt->x);
+ }
+ }
+ }
+ /* set new parent matrix */
+ copy_m4_m4(gpl->inverse, cur_mat);
+ }
+ }
+ }
}
/* ******************************************************** */
/* GP Object Stuff */
/* Helper function to create new OB_GPENCIL Object */
-Object *ED_gpencil_add_object(bContext *C, Scene *UNUSED(scene), const float loc[3], ushort local_view_bits)
+Object *ED_gpencil_add_object(bContext *C,
+ Scene *UNUSED(scene),
+ const float loc[3],
+ ushort local_view_bits)
{
- float rot[3] = {0.0f};
+ float rot[3] = {0.0f};
- Object *ob = ED_object_add_type(C, OB_GPENCIL, NULL, loc, rot, false, local_view_bits);
+ Object *ob = ED_object_add_type(C, OB_GPENCIL, NULL, loc, rot, false, local_view_bits);
- /* create default brushes and colors */
- ED_gpencil_add_defaults(C, ob);
+ /* create default brushes and colors */
+ ED_gpencil_add_defaults(C, ob);
- return ob;
+ return ob;
}
/* Helper function to create default colors and drawing brushes */
void ED_gpencil_add_defaults(bContext *C, Object *ob)
{
- Main *bmain = CTX_data_main(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- BKE_paint_ensure(ts, (Paint **)&ts->gp_paint);
- Paint *paint = &ts->gp_paint->paint;
- /* if not exist, create a new one */
- if (paint->brush == NULL) {
- /* create new brushes */
- BKE_brush_gpencil_presets(C);
- }
-
- /* ensure a color exists and is assigned to object */
- BKE_gpencil_object_material_ensure_from_active_input_toolsettings(bmain, ob, ts);
-
- /* ensure multiframe falloff curve */
- if (ts->gp_sculpt.cur_falloff == NULL) {
- ts->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- CurveMapping *gp_falloff_curve = ts->gp_sculpt.cur_falloff;
- curvemapping_initialize(gp_falloff_curve);
- curvemap_reset(
- gp_falloff_curve->cm,
- &gp_falloff_curve->clipr,
- CURVE_PRESET_GAUSS,
- CURVEMAP_SLOPE_POSITIVE);
- }
+ Main *bmain = CTX_data_main(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ BKE_paint_ensure(ts, (Paint **)&ts->gp_paint);
+ Paint *paint = &ts->gp_paint->paint;
+ /* if not exist, create a new one */
+ if (paint->brush == NULL) {
+ /* create new brushes */
+ BKE_brush_gpencil_presets(C);
+ }
+
+ /* ensure a color exists and is assigned to object */
+ BKE_gpencil_object_material_ensure_from_active_input_toolsettings(bmain, ob, ts);
+
+ /* ensure multiframe falloff curve */
+ if (ts->gp_sculpt.cur_falloff == NULL) {
+ ts->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ CurveMapping *gp_falloff_curve = ts->gp_sculpt.cur_falloff;
+ curvemapping_initialize(gp_falloff_curve);
+ curvemap_reset(gp_falloff_curve->cm,
+ &gp_falloff_curve->clipr,
+ CURVE_PRESET_GAUSS,
+ CURVEMAP_SLOPE_POSITIVE);
+ }
}
/* ******************************************************** */
@@ -1353,213 +1374,209 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob)
/* assign points to vertex group */
void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
{
- bGPdata *gpd = (bGPdata *)ob->data;
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const int def_nr = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, def_nr))
- return;
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- bGPDstroke *gps = NULL;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- if (gpf == NULL)
- continue;
-
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- if (gps->flag & GP_STROKE_SELECT) {
- /* verify the weight array is created */
- BKE_gpencil_dvert_ensure(gps);
-
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- MDeformVert *dvert = &gps->dvert[i];
- if (pt->flag & GP_SPOINT_SELECT) {
- MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
- if (dw) {
- dw->weight = weight;
- }
- }
- }
- }
- }
- }
-
- /* if not multiedit, exit loop*/
- if (!is_multiedit) {
- break;
- }
- }
- }
- CTX_DATA_END;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return;
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ bGPDstroke *gps = NULL;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* verify the weight array is created */
+ BKE_gpencil_dvert_ensure(gps);
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+ if (pt->flag & GP_SPOINT_SELECT) {
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = weight;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
}
/* remove points from vertex group */
void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
{
- bGPdata *gpd = (bGPdata *)ob->data;
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const int def_nr = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, def_nr))
- return;
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- bGPDstroke *gps = NULL;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- if (gpf == NULL)
- continue;
-
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- if (gps->dvert == NULL) {
- continue;
- }
- MDeformVert *dvert = &gps->dvert[i];
-
- if ((pt->flag & GP_SPOINT_SELECT) && (dvert->totweight > 0)) {
- MDeformWeight *dw = defvert_find_index(dvert, def_nr);
- if (dw != NULL) {
- defvert_remove_group(dvert, dw);
- }
- }
- }
- }
- }
-
- /* if not multiedit, exit loop*/
- if (!is_multiedit) {
- break;
- }
- }
- }
- CTX_DATA_END;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return;
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ bGPDstroke *gps = NULL;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ if (gps->dvert == NULL) {
+ continue;
+ }
+ MDeformVert *dvert = &gps->dvert[i];
+
+ if ((pt->flag & GP_SPOINT_SELECT) && (dvert->totweight > 0)) {
+ MDeformWeight *dw = defvert_find_index(dvert, def_nr);
+ if (dw != NULL) {
+ defvert_remove_group(dvert, dw);
+ }
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
}
/* select points of vertex group */
void ED_gpencil_vgroup_select(bContext *C, Object *ob)
{
- bGPdata *gpd = (bGPdata *)ob->data;
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const int def_nr = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, def_nr))
- return;
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- bGPDstroke *gps = NULL;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- if (gpf == NULL)
- continue;
-
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- if (gps->dvert == NULL) {
- continue;
- }
- MDeformVert *dvert = &gps->dvert[i];
-
- if (defvert_find_index(dvert, def_nr) != NULL) {
- pt->flag |= GP_SPOINT_SELECT;
- gps->flag |= GP_STROKE_SELECT;
- }
- }
- }
- }
-
- /* if not multiedit, exit loop*/
- if (!is_multiedit) {
- break;
- }
- }
- }
- CTX_DATA_END;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return;
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ bGPDstroke *gps = NULL;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ if (gps->dvert == NULL) {
+ continue;
+ }
+ MDeformVert *dvert = &gps->dvert[i];
+
+ if (defvert_find_index(dvert, def_nr) != NULL) {
+ pt->flag |= GP_SPOINT_SELECT;
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
}
/* unselect points of vertex group */
void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
{
- bGPdata *gpd = (bGPdata *)ob->data;
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const int def_nr = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, def_nr))
- return;
-
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *init_gpf = gpl->actframe;
- bGPDstroke *gps = NULL;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- if (gpf == NULL)
- continue;
-
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
-
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- if (gps->dvert == NULL) {
- continue;
- }
- MDeformVert *dvert = &gps->dvert[i];
-
- if (defvert_find_index(dvert, def_nr) != NULL) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
- }
- }
- }
-
- /* if not multiedit, exit loop*/
- if (!is_multiedit) {
- break;
- }
- }
- }
- CTX_DATA_END;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return;
+
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = gpl->actframe;
+ bGPDstroke *gps = NULL;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ if (gps->dvert == NULL) {
+ continue;
+ }
+ MDeformVert *dvert = &gps->dvert[i];
+
+ if (defvert_find_index(dvert, def_nr) != NULL) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
}
/* ******************************************************** */
@@ -1568,903 +1585,902 @@ void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
/* check if cursor is in drawing region */
static bool gp_check_cursor_region(bContext *C, int mval_i[2])
{
- ARegion *ar = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
- Object *ob = CTX_data_active_object(C);
-
- if ((ob == NULL) ||
- (!ELEM(ob->mode, OB_MODE_PAINT_GPENCIL, OB_MODE_SCULPT_GPENCIL, OB_MODE_WEIGHT_GPENCIL)))
- {
- return false;
- }
-
- /* TODO: add more spacetypes */
- if (!ELEM(sa->spacetype, SPACE_VIEW3D)) {
- return false;
- }
- if ((ar) && (ar->regiontype != RGN_TYPE_WINDOW)) {
- return false;
- }
- else if (ar) {
- return BLI_rcti_isect_pt_v(&ar->winrct, mval_i);
- }
- else {
- return false;
- }
+ ARegion *ar = CTX_wm_region(C);
+ ScrArea *sa = CTX_wm_area(C);
+ Object *ob = CTX_data_active_object(C);
+
+ if ((ob == NULL) ||
+ (!ELEM(ob->mode, OB_MODE_PAINT_GPENCIL, OB_MODE_SCULPT_GPENCIL, OB_MODE_WEIGHT_GPENCIL))) {
+ return false;
+ }
+
+ /* TODO: add more spacetypes */
+ if (!ELEM(sa->spacetype, SPACE_VIEW3D)) {
+ return false;
+ }
+ if ((ar) && (ar->regiontype != RGN_TYPE_WINDOW)) {
+ return false;
+ }
+ else if (ar) {
+ return BLI_rcti_isect_pt_v(&ar->winrct, mval_i);
+ }
+ else {
+ return false;
+ }
}
/* draw eraser cursor */
void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y)
{
- short radius = (short)brush->size;
+ short radius = (short)brush->size;
- GPUVertFormat *format = immVertexFormat();
- const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ GPUVertFormat *format = immVertexFormat();
+ const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- GPU_line_smooth(true);
- GPU_blend(true);
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- immUniformColor4ub(255, 100, 100, 20);
- imm_draw_circle_fill_2d(shdr_pos, x, y, radius, 40);
+ immUniformColor4ub(255, 100, 100, 20);
+ imm_draw_circle_fill_2d(shdr_pos, x, y, radius, 40);
- immUnbindProgram();
+ immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- float viewport_size[4];
- glGetFloatv(GL_VIEWPORT, viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
- immUniform1i("colors_len", 0); /* "simple" mode */
- immUniform1f("dash_width", 12.0f);
- immUniform1f("dash_factor", 0.5f);
+ immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniform1f("dash_width", 12.0f);
+ immUniform1f("dash_factor", 0.5f);
- imm_draw_circle_wire_2d(
- shdr_pos, x, y, radius,
- /* XXX Dashed shader gives bad results with sets of small segments currently,
- * temp hack around the issue. :( */
- max_ii(8, radius / 2)); /* was fixed 40 */
+ imm_draw_circle_wire_2d(
+ shdr_pos,
+ x,
+ y,
+ radius,
+ /* XXX Dashed shader gives bad results with sets of small segments currently,
+ * temp hack around the issue. :( */
+ max_ii(8, radius / 2)); /* was fixed 40 */
- immUnbindProgram();
+ immUnbindProgram();
- GPU_blend(false);
- GPU_line_smooth(false);
+ GPU_blend(false);
+ GPU_line_smooth(false);
}
static bool gp_brush_cursor_poll(bContext *C)
{
- if (WM_toolsystem_active_tool_is_brush(C)) {
- return true;
- }
- return false;
+ if (WM_toolsystem_active_tool_is_brush(C)) {
+ return true;
+ }
+ return false;
}
/* Helper callback for drawing the cursor itself */
static void gp_brush_cursor_draw(bContext *C, int x, int y, void *customdata)
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- ARegion *ar = CTX_wm_region(C);
-
- GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- GP_Sculpt_Data *gp_brush = NULL;
- Brush *brush = NULL;
- Material *ma = NULL;
- MaterialGPencilStyle *gp_style = NULL;
- float *last_mouse_position = customdata;
-
- if ((gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE)) {
- gp_brush = &gset->brush[gset->weighttype];
- }
- else {
- gp_brush = &gset->brush[gset->brushtype];
- }
-
- /* default radius and color */
- float color[3] = {1.0f, 1.0f, 1.0f};
- float darkcolor[3];
- float radius = 3.0f;
-
- int mval_i[2] = {x, y};
- /* check if cursor is in drawing region and has valid datablock */
- if ((!gp_check_cursor_region(C, mval_i)) || (gpd == NULL)) {
- return;
- }
-
- /* for paint use paint brush size and color */
- if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
- brush = scene->toolsettings->gp_paint->paint.brush;
- if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
- return;
- }
-
- /* while drawing hide */
- if ((gpd->runtime.sbuffer_size > 0) &&
- ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
- ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0))
- {
- return;
- }
-
- if ((brush->gpencil_settings->flag & GP_BRUSH_ENABLE_CURSOR) == 0) {
- return;
- }
-
- /* eraser has special shape and use a different shader program */
- if (brush->gpencil_tool == GPAINT_TOOL_ERASE) {
- ED_gpencil_brush_draw_eraser(brush, x, y);
- return;
- }
-
- /* get current drawing color */
- ma = BKE_gpencil_object_material_get_from_brush(ob, brush);
-
- if (ma) {
- gp_style = ma->gp_style;
-
- /* after some testing, display the size of the brush is not practical because
- * is too disruptive and the size of cursor does not change with zoom factor.
- * The decision was to use a fix size, instead of brush->thickness value.
- */
- if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
- ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
- ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
- (brush->gpencil_tool == GPAINT_TOOL_DRAW))
- {
- radius = 2.0f;
- copy_v3_v3(color, gp_style->stroke_rgba);
- }
- else {
- radius = 5.0f;
- copy_v3_v3(color, brush->add_col);
- }
- }
- }
-
- /* for sculpt use sculpt brush size */
- if (GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd)) {
- if (gp_brush) {
- if ((gp_brush->flag & GP_SCULPT_FLAG_ENABLE_CURSOR) == 0) {
- return;
- }
-
- radius = gp_brush->size;
- if (gp_brush->flag & (GP_SCULPT_FLAG_INVERT | GP_SCULPT_FLAG_TMP_INVERT)) {
- copy_v3_v3(color, gp_brush->curcolor_sub);
- }
- else {
- copy_v3_v3(color, gp_brush->curcolor_add);
- }
- }
- }
-
- /* draw icon */
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- GPU_line_smooth(true);
- GPU_blend(true);
-
- /* Inner Ring: Color from UI panel */
- immUniformColor4f(color[0], color[1], color[2], 0.8f);
- if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
- ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
- ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
- (brush->gpencil_tool == GPAINT_TOOL_DRAW))
- {
- imm_draw_circle_fill_2d(pos, x, y, radius, 40);
- }
- else {
- imm_draw_circle_wire_2d(pos, x, y, radius, 40);
- }
-
- /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
- mul_v3_v3fl(darkcolor, color, 0.40f);
- immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
- imm_draw_circle_wire_2d(pos, x, y, radius + 1, 40);
-
- GPU_blend(false);
- GPU_line_smooth(false);
-
- /* Draw line for lazy mouse */
- if ((last_mouse_position) &&
- (brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP))
- {
- GPU_line_smooth(true);
- GPU_blend(true);
-
- copy_v3_v3(color, brush->add_col);
- immUniformColor4f(color[0], color[1], color[2], 0.8f);
-
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, x, y);
- immVertex2f(
- pos,
- last_mouse_position[0] + ar->winrct.xmin,
- last_mouse_position[1] + ar->winrct.ymin);
- immEnd();
-
- GPU_blend(false);
- GPU_line_smooth(false);
- }
-
- immUnbindProgram();
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ GP_Sculpt_Data *gp_brush = NULL;
+ Brush *brush = NULL;
+ Material *ma = NULL;
+ MaterialGPencilStyle *gp_style = NULL;
+ float *last_mouse_position = customdata;
+
+ if ((gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE)) {
+ gp_brush = &gset->brush[gset->weighttype];
+ }
+ else {
+ gp_brush = &gset->brush[gset->brushtype];
+ }
+
+ /* default radius and color */
+ float color[3] = {1.0f, 1.0f, 1.0f};
+ float darkcolor[3];
+ float radius = 3.0f;
+
+ int mval_i[2] = {x, y};
+ /* check if cursor is in drawing region and has valid datablock */
+ if ((!gp_check_cursor_region(C, mval_i)) || (gpd == NULL)) {
+ return;
+ }
+
+ /* for paint use paint brush size and color */
+ if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
+ brush = scene->toolsettings->gp_paint->paint.brush;
+ if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
+ return;
+ }
+
+ /* while drawing hide */
+ if ((gpd->runtime.sbuffer_size > 0) &&
+ ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
+ ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0)) {
+ return;
+ }
+
+ if ((brush->gpencil_settings->flag & GP_BRUSH_ENABLE_CURSOR) == 0) {
+ return;
+ }
+
+ /* eraser has special shape and use a different shader program */
+ if (brush->gpencil_tool == GPAINT_TOOL_ERASE) {
+ ED_gpencil_brush_draw_eraser(brush, x, y);
+ return;
+ }
+
+ /* get current drawing color */
+ ma = BKE_gpencil_object_material_get_from_brush(ob, brush);
+
+ if (ma) {
+ gp_style = ma->gp_style;
+
+ /* after some testing, display the size of the brush is not practical because
+ * is too disruptive and the size of cursor does not change with zoom factor.
+ * The decision was to use a fix size, instead of brush->thickness value.
+ */
+ if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
+ ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
+ ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
+ (brush->gpencil_tool == GPAINT_TOOL_DRAW)) {
+ radius = 2.0f;
+ copy_v3_v3(color, gp_style->stroke_rgba);
+ }
+ else {
+ radius = 5.0f;
+ copy_v3_v3(color, brush->add_col);
+ }
+ }
+ }
+
+ /* for sculpt use sculpt brush size */
+ if (GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd)) {
+ if (gp_brush) {
+ if ((gp_brush->flag & GP_SCULPT_FLAG_ENABLE_CURSOR) == 0) {
+ return;
+ }
+
+ radius = gp_brush->size;
+ if (gp_brush->flag & (GP_SCULPT_FLAG_INVERT | GP_SCULPT_FLAG_TMP_INVERT)) {
+ copy_v3_v3(color, gp_brush->curcolor_sub);
+ }
+ else {
+ copy_v3_v3(color, gp_brush->curcolor_add);
+ }
+ }
+ }
+
+ /* draw icon */
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ GPU_line_smooth(true);
+ GPU_blend(true);
+
+ /* Inner Ring: Color from UI panel */
+ immUniformColor4f(color[0], color[1], color[2], 0.8f);
+ if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
+ ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
+ ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
+ (brush->gpencil_tool == GPAINT_TOOL_DRAW)) {
+ imm_draw_circle_fill_2d(pos, x, y, radius, 40);
+ }
+ else {
+ imm_draw_circle_wire_2d(pos, x, y, radius, 40);
+ }
+
+ /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
+ mul_v3_v3fl(darkcolor, color, 0.40f);
+ immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
+ imm_draw_circle_wire_2d(pos, x, y, radius + 1, 40);
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
+
+ /* Draw line for lazy mouse */
+ if ((last_mouse_position) && (brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP)) {
+ GPU_line_smooth(true);
+ GPU_blend(true);
+
+ copy_v3_v3(color, brush->add_col);
+ immUniformColor4f(color[0], color[1], color[2], 0.8f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, x, y);
+ immVertex2f(
+ pos, last_mouse_position[0] + ar->winrct.xmin, last_mouse_position[1] + ar->winrct.ymin);
+ immEnd();
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
+ }
+
+ immUnbindProgram();
}
/* Turn brush cursor in on/off */
void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
{
- Scene *scene = CTX_data_scene(C);
- GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
- float *lastpost = customdata;
-
- if (gset->paintcursor && !enable) {
- /* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
- gset->paintcursor = NULL;
- }
- else if (enable) {
- /* in some situations cursor could be duplicated, so it is better disable first if exist */
- if (gset->paintcursor) {
- /* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
- gset->paintcursor = NULL;
- }
- /* enable cursor */
- gset->paintcursor = WM_paint_cursor_activate(
- CTX_wm_manager(C),
- SPACE_TYPE_ANY, RGN_TYPE_ANY,
- gp_brush_cursor_poll,
- gp_brush_cursor_draw,
- (lastpost) ? customdata : NULL);
- }
+ Scene *scene = CTX_data_scene(C);
+ GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
+ float *lastpost = customdata;
+
+ if (gset->paintcursor && !enable) {
+ /* clear cursor */
+ WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
+ gset->paintcursor = NULL;
+ }
+ else if (enable) {
+ /* in some situations cursor could be duplicated, so it is better disable first if exist */
+ if (gset->paintcursor) {
+ /* clear cursor */
+ WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
+ gset->paintcursor = NULL;
+ }
+ /* enable cursor */
+ gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ gp_brush_cursor_poll,
+ gp_brush_cursor_draw,
+ (lastpost) ? customdata : NULL);
+ }
}
/* verify if is using the right brush */
static void gpencil_verify_brush_type(bContext *C, int newmode)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- GP_Sculpt_Settings *gset = &ts->gp_sculpt;
-
- switch (newmode) {
- case OB_MODE_SCULPT_GPENCIL:
- gset->flag &= ~GP_SCULPT_SETT_FLAG_WEIGHT_MODE;
- if ((gset->brushtype < 0) || (gset->brushtype >= GP_SCULPT_TYPE_WEIGHT)) {
- gset->brushtype = GP_SCULPT_TYPE_PUSH;
- }
- break;
- case OB_MODE_WEIGHT_GPENCIL:
- gset->flag |= GP_SCULPT_SETT_FLAG_WEIGHT_MODE;
- if ((gset->weighttype < GP_SCULPT_TYPE_WEIGHT) || (gset->weighttype >= GP_SCULPT_TYPE_MAX)) {
- gset->weighttype = GP_SCULPT_TYPE_WEIGHT;
- }
- break;
- default:
- break;
- }
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ GP_Sculpt_Settings *gset = &ts->gp_sculpt;
+
+ switch (newmode) {
+ case OB_MODE_SCULPT_GPENCIL:
+ gset->flag &= ~GP_SCULPT_SETT_FLAG_WEIGHT_MODE;
+ if ((gset->brushtype < 0) || (gset->brushtype >= GP_SCULPT_TYPE_WEIGHT)) {
+ gset->brushtype = GP_SCULPT_TYPE_PUSH;
+ }
+ break;
+ case OB_MODE_WEIGHT_GPENCIL:
+ gset->flag |= GP_SCULPT_SETT_FLAG_WEIGHT_MODE;
+ if ((gset->weighttype < GP_SCULPT_TYPE_WEIGHT) || (gset->weighttype >= GP_SCULPT_TYPE_MAX)) {
+ gset->weighttype = GP_SCULPT_TYPE_WEIGHT;
+ }
+ break;
+ default:
+ break;
+ }
}
/* set object modes */
void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
{
- if (!gpd) {
- return;
- }
-
- switch (newmode) {
- case OB_MODE_EDIT_GPENCIL:
- gpd->flag |= GP_DATA_STROKE_EDITMODE;
- gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
- gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
- gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
- ED_gpencil_toggle_brush_cursor(C, false, NULL);
- break;
- case OB_MODE_PAINT_GPENCIL:
- gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
- gpd->flag |= GP_DATA_STROKE_PAINTMODE;
- gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
- gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
- ED_gpencil_toggle_brush_cursor(C, true, NULL);
- break;
- case OB_MODE_SCULPT_GPENCIL:
- gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
- gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
- gpd->flag |= GP_DATA_STROKE_SCULPTMODE;
- gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
- gpencil_verify_brush_type(C, OB_MODE_SCULPT_GPENCIL);
- ED_gpencil_toggle_brush_cursor(C, true, NULL);
- break;
- case OB_MODE_WEIGHT_GPENCIL:
- gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
- gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
- gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
- gpd->flag |= GP_DATA_STROKE_WEIGHTMODE;
- gpencil_verify_brush_type(C, OB_MODE_WEIGHT_GPENCIL);
- ED_gpencil_toggle_brush_cursor(C, true, NULL);
- break;
- default:
- gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
- gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
- gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
- gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
- ED_gpencil_toggle_brush_cursor(C, false, NULL);
- break;
- }
+ if (!gpd) {
+ return;
+ }
+
+ switch (newmode) {
+ case OB_MODE_EDIT_GPENCIL:
+ gpd->flag |= GP_DATA_STROKE_EDITMODE;
+ gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ break;
+ case OB_MODE_PAINT_GPENCIL:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ gpd->flag |= GP_DATA_STROKE_PAINTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ break;
+ case OB_MODE_SCULPT_GPENCIL:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
+ gpd->flag |= GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ gpencil_verify_brush_type(C, OB_MODE_SCULPT_GPENCIL);
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ break;
+ case OB_MODE_WEIGHT_GPENCIL:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag |= GP_DATA_STROKE_WEIGHTMODE;
+ gpencil_verify_brush_type(C, OB_MODE_WEIGHT_GPENCIL);
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ break;
+ default:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ break;
+ }
}
/* helper to convert 2d to 3d for simple drawing buffer */
-static void gpencil_stroke_convertcoords(ARegion *ar, const tGPspoint *point2D, float origin[3], float out[3])
+static void gpencil_stroke_convertcoords(ARegion *ar,
+ const tGPspoint *point2D,
+ float origin[3],
+ float out[3])
{
- float mval_f[2] = { (float)point2D->x, (float)point2D->y };
- float mval_prj[2];
- float rvec[3], dvec[3];
- float zfac;
-
- copy_v3_v3(rvec, origin);
-
- zfac = ED_view3d_calc_zfac(ar->regiondata, rvec, NULL);
-
- if (ED_view3d_project_float_global(ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- sub_v2_v2v2(mval_f, mval_prj, mval_f);
- ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
- sub_v3_v3v3(out, rvec, dvec);
- }
- else {
- zero_v3(out);
- }
+ float mval_f[2] = {(float)point2D->x, (float)point2D->y};
+ float mval_prj[2];
+ float rvec[3], dvec[3];
+ float zfac;
+
+ copy_v3_v3(rvec, origin);
+
+ zfac = ED_view3d_calc_zfac(ar->regiondata, rvec, NULL);
+
+ if (ED_view3d_project_float_global(ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval_f);
+ ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(out, rvec, dvec);
+ }
+ else {
+ zero_v3(out);
+ }
}
/* convert 2d tGPspoint to 3d bGPDspoint */
void ED_gpencil_tpoint_to_point(ARegion *ar, float origin[3], const tGPspoint *tpt, bGPDspoint *pt)
{
- float p3d[3];
- /* conversion to 3d format */
- gpencil_stroke_convertcoords(ar, tpt, origin, p3d);
- copy_v3_v3(&pt->x, p3d);
-
- pt->pressure = tpt->pressure;
- pt->strength = tpt->strength;
- pt->uv_fac = tpt->uv_fac;
- pt->uv_rot = tpt->uv_rot;
+ float p3d[3];
+ /* conversion to 3d format */
+ gpencil_stroke_convertcoords(ar, tpt, origin, p3d);
+ copy_v3_v3(&pt->x, p3d);
+
+ pt->pressure = tpt->pressure;
+ pt->strength = tpt->strength;
+ pt->uv_fac = tpt->uv_fac;
+ pt->uv_rot = tpt->uv_rot;
}
/* texture coordinate utilities */
void ED_gpencil_calc_stroke_uv(Object *ob, bGPDstroke *gps)
{
- if (gps == NULL) {
- return;
- }
- MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
- float pixsize;
- if (gp_style) {
- pixsize = gp_style->texture_pixsize / 1000000.0f;
- }
- else {
- /* use this value by default */
- pixsize = 0.0001f;
- }
- pixsize = MAX2(pixsize, 0.0000001f);
-
- bGPDspoint *pt = NULL;
- bGPDspoint *ptb = NULL;
- int i;
- float totlen = 0.0f;
-
- /* first read all points and calc distance */
- for (i = 0; i < gps->totpoints; i++) {
- pt = &gps->points[i];
- /* first point */
- if (i == 0) {
- pt->uv_fac = 0.0f;
- continue;
- }
-
- ptb = &gps->points[i - 1];
- totlen += len_v3v3(&pt->x, &ptb->x) / pixsize;
- pt->uv_fac = totlen;
- }
-
- /* normalize the distance using a factor */
- float factor;
-
- /* if image, use texture width */
- if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) &&
- (gp_style->sima))
- {
- factor = gp_style->sima->gen_x;
- }
- else if (totlen == 0) {
- return;
- }
- else {
- factor = totlen;
- }
-
- for (i = 0; i < gps->totpoints; i++) {
- pt = &gps->points[i];
- pt->uv_fac /= factor;
- }
+ if (gps == NULL) {
+ return;
+ }
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ float pixsize;
+ if (gp_style) {
+ pixsize = gp_style->texture_pixsize / 1000000.0f;
+ }
+ else {
+ /* use this value by default */
+ pixsize = 0.0001f;
+ }
+ pixsize = MAX2(pixsize, 0.0000001f);
+
+ bGPDspoint *pt = NULL;
+ bGPDspoint *ptb = NULL;
+ int i;
+ float totlen = 0.0f;
+
+ /* first read all points and calc distance */
+ for (i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ /* first point */
+ if (i == 0) {
+ pt->uv_fac = 0.0f;
+ continue;
+ }
+
+ ptb = &gps->points[i - 1];
+ totlen += len_v3v3(&pt->x, &ptb->x) / pixsize;
+ pt->uv_fac = totlen;
+ }
+
+ /* normalize the distance using a factor */
+ float factor;
+
+ /* if image, use texture width */
+ if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) &&
+ (gp_style->sima)) {
+ factor = gp_style->sima->gen_x;
+ }
+ else if (totlen == 0) {
+ return;
+ }
+ else {
+ factor = totlen;
+ }
+
+ for (i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ pt->uv_fac /= factor;
+ }
}
/* recalc uv for any stroke using the material */
void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
{
- Material *gps_ma = NULL;
- /* read all strokes */
- for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- if (ob->type == OB_GPENCIL) {
- bGPdata *gpd = ob->data;
- if (gpd == NULL) {
- continue;
- }
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl)) {
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* check if it is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
- continue;
- }
- gps_ma = give_current_material(ob, gps->mat_nr + 1);
- /* update */
- if ((gps_ma) && (gps_ma == mat)) {
- ED_gpencil_calc_stroke_uv(ob, gps);
- }
- }
- }
- }
- }
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- }
- }
+ Material *gps_ma = NULL;
+ /* read all strokes */
+ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
+ if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = ob->data;
+ if (gpd == NULL) {
+ continue;
+ }
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl)) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* check if it is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ gps_ma = give_current_material(ob, gps->mat_nr + 1);
+ /* update */
+ if ((gps_ma) && (gps_ma == mat)) {
+ ED_gpencil_calc_stroke_uv(ob, gps);
+ }
+ }
+ }
+ }
+ }
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+ }
}
-static bool gpencil_check_collision(
- bGPDstroke *gps, bGPDstroke **gps_array, GHash *all_2d,
- int totstrokes, float p2d_a1[2], float p2d_a2[2], float r_hit[2])
+static bool gpencil_check_collision(bGPDstroke *gps,
+ bGPDstroke **gps_array,
+ GHash *all_2d,
+ int totstrokes,
+ float p2d_a1[2],
+ float p2d_a2[2],
+ float r_hit[2])
{
- bool hit = false;
- /* check segment with all segments of all strokes */
- for (int s = 0; s < totstrokes; s++) {
- bGPDstroke *gps_iter = gps_array[s];
- if (gps_iter->totpoints < 2) {
- continue;
- }
- /* get stroke 2d version */
- float(*points2d)[2] = BLI_ghash_lookup(all_2d, gps_iter);
-
- for (int i2 = 0; i2 < gps_iter->totpoints - 1; i2++) {
- float p2d_b1[2], p2d_b2[2];
- copy_v2_v2(p2d_b1, points2d[i2]);
- copy_v2_v2(p2d_b2, points2d[i2 + 1]);
-
- /* don't self check */
- if (gps == gps_iter) {
- if (equals_v2v2(p2d_a1, p2d_b1) || equals_v2v2(p2d_a1, p2d_b2)) {
- continue;
- }
- if (equals_v2v2(p2d_a2, p2d_b1) || equals_v2v2(p2d_a2, p2d_b2)) {
- continue;
- }
- }
- /* check collision */
- int check = isect_seg_seg_v2_point(p2d_a1, p2d_a2, p2d_b1, p2d_b2, r_hit);
- if (check > 0) {
- hit = true;
- break;
- }
- }
-
- if (hit) {
- break;
- }
- }
-
- if (!hit) {
- zero_v2(r_hit);
- }
-
- return hit;
+ bool hit = false;
+ /* check segment with all segments of all strokes */
+ for (int s = 0; s < totstrokes; s++) {
+ bGPDstroke *gps_iter = gps_array[s];
+ if (gps_iter->totpoints < 2) {
+ continue;
+ }
+ /* get stroke 2d version */
+ float(*points2d)[2] = BLI_ghash_lookup(all_2d, gps_iter);
+
+ for (int i2 = 0; i2 < gps_iter->totpoints - 1; i2++) {
+ float p2d_b1[2], p2d_b2[2];
+ copy_v2_v2(p2d_b1, points2d[i2]);
+ copy_v2_v2(p2d_b2, points2d[i2 + 1]);
+
+ /* don't self check */
+ if (gps == gps_iter) {
+ if (equals_v2v2(p2d_a1, p2d_b1) || equals_v2v2(p2d_a1, p2d_b2)) {
+ continue;
+ }
+ if (equals_v2v2(p2d_a2, p2d_b1) || equals_v2v2(p2d_a2, p2d_b2)) {
+ continue;
+ }
+ }
+ /* check collision */
+ int check = isect_seg_seg_v2_point(p2d_a1, p2d_a2, p2d_b1, p2d_b2, r_hit);
+ if (check > 0) {
+ hit = true;
+ break;
+ }
+ }
+
+ if (hit) {
+ break;
+ }
+ }
+
+ if (!hit) {
+ zero_v2(r_hit);
+ }
+
+ return hit;
}
-static void gp_copy_points(
- bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final, int i, int i2)
+static void gp_copy_points(bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final, int i, int i2)
{
- /* don't copy same point */
- if (i == i2) {
- return;
- }
-
- copy_v3_v3(&pt_final->x, &pt->x);
- pt_final->pressure = pt->pressure;
- pt_final->strength = pt->strength;
- pt_final->time = pt->time;
- pt_final->flag = pt->flag;
- pt_final->uv_fac = pt->uv_fac;
- pt_final->uv_rot = pt->uv_rot;
-
- if (gps->dvert != NULL) {
- MDeformVert *dvert = &gps->dvert[i];
- MDeformVert *dvert_final = &gps->dvert[i2];
- MEM_SAFE_FREE(dvert_final->dw);
-
- dvert_final->totweight = dvert->totweight;
- if (dvert->dw == NULL) {
- dvert_final->dw = NULL;
- dvert_final->totweight = 0;
- }
- else {
- dvert_final->dw = MEM_dupallocN(dvert->dw);
- }
- }
-
+ /* don't copy same point */
+ if (i == i2) {
+ return;
+ }
+
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+ pt_final->uv_fac = pt->uv_fac;
+ pt_final->uv_rot = pt->uv_rot;
+
+ if (gps->dvert != NULL) {
+ MDeformVert *dvert = &gps->dvert[i];
+ MDeformVert *dvert_final = &gps->dvert[i2];
+ MEM_SAFE_FREE(dvert_final->dw);
+
+ dvert_final->totweight = dvert->totweight;
+ if (dvert->dw == NULL) {
+ dvert_final->dw = NULL;
+ dvert_final->totweight = 0;
+ }
+ else {
+ dvert_final->dw = MEM_dupallocN(dvert->dw);
+ }
+ }
}
static void gp_insert_point(
- bGPDstroke *gps,
- bGPDspoint *a_pt, bGPDspoint *b_pt,
- float co_a[3], float co_b[3])
+ bGPDstroke *gps, bGPDspoint *a_pt, bGPDspoint *b_pt, float co_a[3], float co_b[3])
{
- bGPDspoint *temp_points;
- int totnewpoints, oldtotpoints;
-
- totnewpoints = gps->totpoints;
- if (a_pt) {
- totnewpoints++;
- }
- if (b_pt) {
- totnewpoints++;
- }
-
- /* duplicate points in a temp area */
- temp_points = MEM_dupallocN(gps->points);
- oldtotpoints = gps->totpoints;
-
- /* look index of base points because memory is changed when resize points array */
- int a_idx = -1;
- int b_idx = -1;
- for (int i = 0; i < oldtotpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- if (pt == a_pt) {
- a_idx = i;
- }
- if (pt == b_pt) {
- b_idx = i;
- }
- }
-
- /* resize the points arrays */
- gps->totpoints = totnewpoints;
- gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
- if (gps->dvert != NULL) {
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
- }
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* copy all points */
- int i2 = 0;
- for (int i = 0; i < oldtotpoints; i++) {
- bGPDspoint *pt = &temp_points[i];
- bGPDspoint *pt_final = &gps->points[i2];
- gp_copy_points(gps, pt, pt_final, i, i2);
-
- /* create new point duplicating point and copy location */
- if ((i == a_idx) || (i == b_idx)) {
- i2++;
- pt_final = &gps->points[i2];
- gp_copy_points(gps, pt, pt_final, i, i2);
- copy_v3_v3(&pt_final->x, (i == a_idx) ? co_a : co_b);
-
- /* unselect */
- pt_final->flag &= ~GP_SPOINT_SELECT;
- /* tag to avoid more checking with this point */
- pt_final->flag |= GP_SPOINT_TAG;
- }
-
- i2++;
- }
-
- MEM_SAFE_FREE(temp_points);
+ bGPDspoint *temp_points;
+ int totnewpoints, oldtotpoints;
+
+ totnewpoints = gps->totpoints;
+ if (a_pt) {
+ totnewpoints++;
+ }
+ if (b_pt) {
+ totnewpoints++;
+ }
+
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+
+ /* look index of base points because memory is changed when resize points array */
+ int a_idx = -1;
+ int b_idx = -1;
+ for (int i = 0; i < oldtotpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ if (pt == a_pt) {
+ a_idx = i;
+ }
+ if (pt == b_pt) {
+ b_idx = i;
+ }
+ }
+
+ /* resize the points arrays */
+ gps->totpoints = totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ }
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* copy all points */
+ int i2 = 0;
+ for (int i = 0; i < oldtotpoints; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
+ gp_copy_points(gps, pt, pt_final, i, i2);
+
+ /* create new point duplicating point and copy location */
+ if ((i == a_idx) || (i == b_idx)) {
+ i2++;
+ pt_final = &gps->points[i2];
+ gp_copy_points(gps, pt, pt_final, i, i2);
+ copy_v3_v3(&pt_final->x, (i == a_idx) ? co_a : co_b);
+
+ /* unselect */
+ pt_final->flag &= ~GP_SPOINT_SELECT;
+ /* tag to avoid more checking with this point */
+ pt_final->flag |= GP_SPOINT_TAG;
+ }
+
+ i2++;
+ }
+
+ MEM_SAFE_FREE(temp_points);
}
static float gp_calc_factor(float p2d_a1[2], float p2d_a2[2], float r_hit2d[2])
{
- float dist1 = len_squared_v2v2(p2d_a1, p2d_a2);
- float dist2 = len_squared_v2v2(p2d_a1, r_hit2d);
- float f = dist1 > 0.0f ? dist2 / dist1 : 0.0f;
-
- /* apply a correction factor */
- float v1[2];
- interp_v2_v2v2(v1, p2d_a1, p2d_a2, f);
- float dist3 = len_squared_v2v2(p2d_a1, v1);
- float f1 = dist1 > 0.0f ? dist3 / dist1 : 0.0f;
- f = f + (f - f1);
-
- return f;
+ float dist1 = len_squared_v2v2(p2d_a1, p2d_a2);
+ float dist2 = len_squared_v2v2(p2d_a1, r_hit2d);
+ float f = dist1 > 0.0f ? dist2 / dist1 : 0.0f;
+
+ /* apply a correction factor */
+ float v1[2];
+ interp_v2_v2v2(v1, p2d_a1, p2d_a2, f);
+ float dist3 = len_squared_v2v2(p2d_a1, v1);
+ float f1 = dist1 > 0.0f ? dist3 / dist1 : 0.0f;
+ f = f + (f - f1);
+
+ return f;
}
/* extend selection to stroke intersections */
-int ED_gpencil_select_stroke_segment(
- bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *pt,
- bool select, bool insert, const float scale,
- float r_hita[3], float r_hitb[3])
+int ED_gpencil_select_stroke_segment(bGPDlayer *gpl,
+ bGPDstroke *gps,
+ bGPDspoint *pt,
+ bool select,
+ bool insert,
+ const float scale,
+ float r_hita[3],
+ float r_hitb[3])
{
- const float min_factor = 0.0015f;
- bGPDspoint *pta1 = NULL;
- bGPDspoint *pta2 = NULL;
- float f = 0.0f;
- int i2 = 0;
-
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL) {
- return 0;
- }
-
- int memsize = BLI_listbase_count(&gpf->strokes);
- bGPDstroke **gps_array = MEM_callocN(sizeof(bGPDstroke *) * memsize, __func__);
-
- /* save points */
- bGPDspoint *oldpoints = MEM_dupallocN(gps->points);
-
- /* Save list of strokes to check */
- int totstrokes = 0;
- for (bGPDstroke *gps_iter = gpf->strokes.first; gps_iter; gps_iter = gps_iter->next) {
- if (gps_iter->totpoints < 2) {
- continue;
- }
- gps_array[totstrokes] = gps_iter;
- totstrokes++;
- }
-
- if (totstrokes == 0) {
- return 0;
- }
-
- /* look for index of the current point */
- int cur_idx = -1;
- for (int i = 0; i < gps->totpoints; i++) {
- pta1 = &gps->points[i];
- if (pta1 == pt) {
- cur_idx = i;
- break;
- }
- }
- if (cur_idx < 0) {
- return 0;
- }
-
- /* convert all gps points to 2d and save in a hash to avoid recalculation */
- int direction = 0;
- float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
- BKE_gpencil_stroke_2d_flat_ref(
- gps->points, gps->totpoints,
- gps->points, gps->totpoints, points2d, scale, &direction);
-
- GHash *all_2d = BLI_ghash_ptr_new(__func__);
-
- for (int s = 0; s < totstrokes; s++) {
- bGPDstroke *gps_iter = gps_array[s];
- float(*points2d_iter)[2] = MEM_mallocN(sizeof(*points2d_iter) * gps_iter->totpoints, __func__);
-
- /* the extremes of the stroke are scaled to improve collision detection
- * for near lines */
- BKE_gpencil_stroke_2d_flat_ref(
- gps->points, gps->totpoints,
- gps_iter->points, gps_iter->totpoints, points2d_iter,
- scale, &direction);
- BLI_ghash_insert(all_2d, gps_iter, points2d_iter);
- }
-
- bool hit_a = false;
- bool hit_b = false;
- float p2d_a1[2] = {0.0f, 0.0f};
- float p2d_a2[2] = {0.0f, 0.0f};
- float r_hit2d[2];
- bGPDspoint *hit_pointa = NULL;
- bGPDspoint *hit_pointb = NULL;
-
- /* analyze points before current */
- if (cur_idx > 0) {
- for (int i = cur_idx; i >= 0; i--) {
- pta1 = &gps->points[i];
- copy_v2_v2(p2d_a1, points2d[i]);
-
- i2 = i - 1;
- CLAMP_MIN(i2, 0);
- pta2 = &gps->points[i2];
- copy_v2_v2(p2d_a2, points2d[i2]);
-
- hit_a = gpencil_check_collision(
- gps, gps_array, all_2d, totstrokes, p2d_a1, p2d_a2, r_hit2d);
-
- if (select) {
- pta1->flag |= GP_SPOINT_SELECT;
- }
- else {
- pta1->flag &= ~GP_SPOINT_SELECT;
- }
-
- if (hit_a) {
- f = gp_calc_factor(p2d_a1, p2d_a2, r_hit2d);
- interp_v3_v3v3(r_hita, &pta1->x, &pta2->x, f);
- if (f > min_factor) {
- hit_pointa = pta2; /* first point is second (inverted loop) */
- }
- else {
- pta1->flag &= ~GP_SPOINT_SELECT;
- }
- break;
- }
- }
- }
-
- /* analyze points after current */
- for (int i = cur_idx; i < gps->totpoints; i++) {
- pta1 = &gps->points[i];
- copy_v2_v2(p2d_a1, points2d[i]);
-
- i2 = i + 1;
- CLAMP_MAX(i2, gps->totpoints - 1);
- pta2 = &gps->points[i2];
- copy_v2_v2(p2d_a2, points2d[i2]);
-
- hit_b = gpencil_check_collision(
- gps, gps_array, all_2d, totstrokes, p2d_a1, p2d_a2, r_hit2d);
-
- if (select) {
- pta1->flag |= GP_SPOINT_SELECT;
- }
- else {
- pta1->flag &= ~GP_SPOINT_SELECT;
- }
-
- if (hit_b) {
- f = gp_calc_factor(p2d_a1, p2d_a2, r_hit2d);
- interp_v3_v3v3(r_hitb, &pta1->x, &pta2->x, f);
- if (f > min_factor) {
- hit_pointb = pta1;
- }
- else {
- pta1->flag &= ~GP_SPOINT_SELECT;
- }
- break;
- }
- }
-
- /* insert new point in the collision points */
- if (insert) {
- gp_insert_point(gps, hit_pointa, hit_pointb, r_hita, r_hitb);
- }
-
- /* free memory */
- if (all_2d) {
- GHashIterator gh_iter;
- GHASH_ITER(gh_iter, all_2d) {
- float(*p2d)[2] = BLI_ghashIterator_getValue(&gh_iter);
- MEM_SAFE_FREE(p2d);
- }
- BLI_ghash_free(all_2d, NULL, NULL);
- }
-
- /* if no hit, reset selection flag */
- if ((!hit_a) && (!hit_b)) {
- for (int i = 0; i < gps->totpoints; i++) {
- pta1 = &gps->points[i];
- pta2 = &oldpoints[i];
- pta1->flag = pta2->flag;
- }
- }
-
- MEM_SAFE_FREE(points2d);
- MEM_SAFE_FREE(gps_array);
- MEM_SAFE_FREE(oldpoints);
-
- /* return type of hit */
- if ((hit_a) && (hit_b)) {
- return 3;
- }
- else if (hit_a) {
- return 1;
- }
- else if (hit_b) {
- return 2;
- }
- else {
- return 0;
- }
+ const float min_factor = 0.0015f;
+ bGPDspoint *pta1 = NULL;
+ bGPDspoint *pta2 = NULL;
+ float f = 0.0f;
+ int i2 = 0;
+
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL) {
+ return 0;
+ }
+
+ int memsize = BLI_listbase_count(&gpf->strokes);
+ bGPDstroke **gps_array = MEM_callocN(sizeof(bGPDstroke *) * memsize, __func__);
+
+ /* save points */
+ bGPDspoint *oldpoints = MEM_dupallocN(gps->points);
+
+ /* Save list of strokes to check */
+ int totstrokes = 0;
+ for (bGPDstroke *gps_iter = gpf->strokes.first; gps_iter; gps_iter = gps_iter->next) {
+ if (gps_iter->totpoints < 2) {
+ continue;
+ }
+ gps_array[totstrokes] = gps_iter;
+ totstrokes++;
+ }
+
+ if (totstrokes == 0) {
+ return 0;
+ }
+
+ /* look for index of the current point */
+ int cur_idx = -1;
+ for (int i = 0; i < gps->totpoints; i++) {
+ pta1 = &gps->points[i];
+ if (pta1 == pt) {
+ cur_idx = i;
+ break;
+ }
+ }
+ if (cur_idx < 0) {
+ return 0;
+ }
+
+ /* convert all gps points to 2d and save in a hash to avoid recalculation */
+ int direction = 0;
+ float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints,
+ "GP Stroke temp 2d points");
+ BKE_gpencil_stroke_2d_flat_ref(
+ gps->points, gps->totpoints, gps->points, gps->totpoints, points2d, scale, &direction);
+
+ GHash *all_2d = BLI_ghash_ptr_new(__func__);
+
+ for (int s = 0; s < totstrokes; s++) {
+ bGPDstroke *gps_iter = gps_array[s];
+ float(*points2d_iter)[2] = MEM_mallocN(sizeof(*points2d_iter) * gps_iter->totpoints, __func__);
+
+ /* the extremes of the stroke are scaled to improve collision detection
+ * for near lines */
+ BKE_gpencil_stroke_2d_flat_ref(gps->points,
+ gps->totpoints,
+ gps_iter->points,
+ gps_iter->totpoints,
+ points2d_iter,
+ scale,
+ &direction);
+ BLI_ghash_insert(all_2d, gps_iter, points2d_iter);
+ }
+
+ bool hit_a = false;
+ bool hit_b = false;
+ float p2d_a1[2] = {0.0f, 0.0f};
+ float p2d_a2[2] = {0.0f, 0.0f};
+ float r_hit2d[2];
+ bGPDspoint *hit_pointa = NULL;
+ bGPDspoint *hit_pointb = NULL;
+
+ /* analyze points before current */
+ if (cur_idx > 0) {
+ for (int i = cur_idx; i >= 0; i--) {
+ pta1 = &gps->points[i];
+ copy_v2_v2(p2d_a1, points2d[i]);
+
+ i2 = i - 1;
+ CLAMP_MIN(i2, 0);
+ pta2 = &gps->points[i2];
+ copy_v2_v2(p2d_a2, points2d[i2]);
+
+ hit_a = gpencil_check_collision(gps, gps_array, all_2d, totstrokes, p2d_a1, p2d_a2, r_hit2d);
+
+ if (select) {
+ pta1->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pta1->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ if (hit_a) {
+ f = gp_calc_factor(p2d_a1, p2d_a2, r_hit2d);
+ interp_v3_v3v3(r_hita, &pta1->x, &pta2->x, f);
+ if (f > min_factor) {
+ hit_pointa = pta2; /* first point is second (inverted loop) */
+ }
+ else {
+ pta1->flag &= ~GP_SPOINT_SELECT;
+ }
+ break;
+ }
+ }
+ }
+
+ /* analyze points after current */
+ for (int i = cur_idx; i < gps->totpoints; i++) {
+ pta1 = &gps->points[i];
+ copy_v2_v2(p2d_a1, points2d[i]);
+
+ i2 = i + 1;
+ CLAMP_MAX(i2, gps->totpoints - 1);
+ pta2 = &gps->points[i2];
+ copy_v2_v2(p2d_a2, points2d[i2]);
+
+ hit_b = gpencil_check_collision(gps, gps_array, all_2d, totstrokes, p2d_a1, p2d_a2, r_hit2d);
+
+ if (select) {
+ pta1->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pta1->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ if (hit_b) {
+ f = gp_calc_factor(p2d_a1, p2d_a2, r_hit2d);
+ interp_v3_v3v3(r_hitb, &pta1->x, &pta2->x, f);
+ if (f > min_factor) {
+ hit_pointb = pta1;
+ }
+ else {
+ pta1->flag &= ~GP_SPOINT_SELECT;
+ }
+ break;
+ }
+ }
+
+ /* insert new point in the collision points */
+ if (insert) {
+ gp_insert_point(gps, hit_pointa, hit_pointb, r_hita, r_hitb);
+ }
+
+ /* free memory */
+ if (all_2d) {
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, all_2d) {
+ float(*p2d)[2] = BLI_ghashIterator_getValue(&gh_iter);
+ MEM_SAFE_FREE(p2d);
+ }
+ BLI_ghash_free(all_2d, NULL, NULL);
+ }
+
+ /* if no hit, reset selection flag */
+ if ((!hit_a) && (!hit_b)) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ pta1 = &gps->points[i];
+ pta2 = &oldpoints[i];
+ pta1->flag = pta2->flag;
+ }
+ }
+
+ MEM_SAFE_FREE(points2d);
+ MEM_SAFE_FREE(gps_array);
+ MEM_SAFE_FREE(oldpoints);
+
+ /* return type of hit */
+ if ((hit_a) && (hit_b)) {
+ return 3;
+ }
+ else if (hit_a) {
+ return 1;
+ }
+ else if (hit_b) {
+ return 2;
+ }
+ else {
+ return 0;
+ }
}
void ED_gpencil_select_toggle_all(bContext *C, int action)
{
- /* for "toggle", test for existing selected strokes */
- if (action == SEL_TOGGLE) {
- action = SEL_SELECT;
-
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- if (gps->flag & GP_STROKE_SELECT) {
- action = SEL_DESELECT;
- break; // XXX: this only gets out of the inner loop...
- }
- }
- CTX_DATA_END;
- }
-
- /* if deselecting, we need to deselect strokes across all frames
- * - Currently, an exception is only given for deselection
- * Selecting and toggling should only affect what's visible,
- * while deselecting helps clean up unintended/forgotten
- * stuff on other frames
- */
- if (action == SEL_DESELECT) {
- /* deselect strokes across editable layers
- * NOTE: we limit ourselves to editable layers, since once a layer is "locked/hidden
- * nothing should be able to touch it
- */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *gpf;
-
- /* deselect all strokes on all frames */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- bGPDstroke *gps;
-
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- bGPDspoint *pt;
- int i;
-
- /* only edit strokes that are valid in this view... */
- if (ED_gpencil_stroke_can_use(C, gps)) {
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
-
- gps->flag &= ~GP_STROKE_SELECT;
- }
- }
- }
- }
- CTX_DATA_END;
- }
- else {
- /* select or deselect all strokes */
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- bGPDspoint *pt;
- int i;
- bool selected = false;
-
- /* Change selection status of all points, then make the stroke match */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- switch (action) {
- case SEL_SELECT:
- pt->flag |= GP_SPOINT_SELECT;
- break;
- //case SEL_DESELECT:
- // pt->flag &= ~GP_SPOINT_SELECT;
- // break;
- case SEL_INVERT:
- pt->flag ^= GP_SPOINT_SELECT;
- break;
- }
-
- if (pt->flag & GP_SPOINT_SELECT)
- selected = true;
- }
-
- /* Change status of stroke */
- if (selected)
- gps->flag |= GP_STROKE_SELECT;
- else
- gps->flag &= ~GP_STROKE_SELECT;
- }
- CTX_DATA_END;
- }
+ /* for "toggle", test for existing selected strokes */
+ if (action == SEL_TOGGLE) {
+ action = SEL_SELECT;
+
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ action = SEL_DESELECT;
+ break; // XXX: this only gets out of the inner loop...
+ }
+ }
+ CTX_DATA_END;
+ }
+
+ /* if deselecting, we need to deselect strokes across all frames
+ * - Currently, an exception is only given for deselection
+ * Selecting and toggling should only affect what's visible,
+ * while deselecting helps clean up unintended/forgotten
+ * stuff on other frames
+ */
+ if (action == SEL_DESELECT) {
+ /* deselect strokes across editable layers
+ * NOTE: we limit ourselves to editable layers, since once a layer is "locked/hidden
+ * nothing should be able to touch it
+ */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *gpf;
+
+ /* deselect all strokes on all frames */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ bGPDstroke *gps;
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
+ /* only edit strokes that are valid in this view... */
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+ }
+ else {
+ /* select or deselect all strokes */
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ bGPDspoint *pt;
+ int i;
+ bool selected = false;
+
+ /* Change selection status of all points, then make the stroke match */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ switch (action) {
+ case SEL_SELECT:
+ pt->flag |= GP_SPOINT_SELECT;
+ break;
+ //case SEL_DESELECT:
+ // pt->flag &= ~GP_SPOINT_SELECT;
+ // break;
+ case SEL_INVERT:
+ pt->flag ^= GP_SPOINT_SELECT;
+ break;
+ }
+
+ if (pt->flag & GP_SPOINT_SELECT)
+ selected = true;
+ }
+
+ /* Change status of stroke */
+ if (selected)
+ gps->flag |= GP_STROKE_SELECT;
+ else
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ CTX_DATA_END;
+ }
}