GPencil: New Dots gradient
authorAntonioya <blendergit@gmail.com>
Mon, 15 Apr 2019 08:32:06 +0000 (10:32 +0200)
committerAntonioya <blendergit@gmail.com>
Mon, 15 Apr 2019 08:32:25 +0000 (10:32 +0200)
This commit adds support for drawing Dots strokes with a gradient factor to get artistic effects like watercolor.

Currently, the option is only supported by Dots materials, and in the future will be added to line strokes, but now there is a limitation on drawing engine and we will keep disabled on Line materials.

Also, added the option to align Dots and Boxes strokes textures aligned with the drawing path to get more fluid strokes.

24 files changed:
release/scripts/startup/bl_ui/properties_material_gpencil.py
release/scripts/startup/bl_ui/space_view3d_toolbar.py
source/blender/blenkernel/intern/brush.c
source/blender/blenkernel/intern/gpencil.c
source/blender/blenloader/intern/versioning_280.c
source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
source/blender/draw/engines/gpencil/gpencil_draw_utils.c
source/blender/draw/engines/gpencil/gpencil_engine.h
source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl
source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
source/blender/editors/gpencil/annotate_paint.c
source/blender/editors/gpencil/gpencil_fill.c
source/blender/editors/gpencil/gpencil_merge.c
source/blender/editors/gpencil/gpencil_paint.c
source/blender/editors/gpencil/gpencil_primitive.c
source/blender/editors/space_view3d/view3d_gizmo_ruler.c
source/blender/makesdna/DNA_brush_types.h
source/blender/makesdna/DNA_gpencil_types.h
source/blender/makesdna/DNA_material_types.h
source/blender/makesrna/intern/rna_brush.c
source/blender/makesrna/intern/rna_gpencil.c
source/blender/makesrna/intern/rna_material.c

index 24ba786f7af436a7ded9fe8558f5686cafde5361..8cb59ceee5cd4c4982c40a3f86c08a64d9c353bd 100644 (file)
@@ -148,6 +148,9 @@ class MATERIAL_PT_gpencil_strokecolor(GPMaterialButtonsPanel, Panel):
             if gpcolor.stroke_style == 'SOLID' or gpcolor.use_stroke_pattern is True:
                 col.prop(gpcolor, "color", text="Color")
 
+            if gpcolor.mode in {'DOTS', 'BOX'}:
+                col.prop(gpcolor, "use_follow_path", text="Follow Drawing Path")
+
 
 class MATERIAL_PT_gpencil_fillcolor(GPMaterialButtonsPanel, Panel):
     bl_label = "Fill"
index 17dd35d9fc443a9ad3e3cb1b932b0c0b7a1a412b..7c1fa0f9663421efc4a69749d2ca29868915d3d3 100644 (file)
@@ -1716,9 +1716,9 @@ class VIEW3D_PT_tools_grease_pencil_brush_option(View3DPanel, Panel):
         layout.use_property_decorate = False
 
         brush = context.tool_settings.gpencil_paint.brush
-        gp_settings = brush.gpencil_settings
 
         if brush is not None:
+            gp_settings = brush.gpencil_settings
             col = layout.column(align=True)
             col.prop(gp_settings, "input_samples")
             col.separator()
@@ -1728,7 +1728,20 @@ class VIEW3D_PT_tools_grease_pencil_brush_option(View3DPanel, Panel):
 
             col.prop(gp_settings, "angle", slider=True)
             col.prop(gp_settings, "angle_factor", text="Factor", slider=True)
+
+            ob = context.object
+            if ob:
+                ma = ob.active_material
+                    
+            if brush.gpencil_settings.material:
+                ma = brush.gpencil_settings.material
+
             col.separator()
+            subcol = col.column(align=True)
+            if ma and ma.grease_pencil.mode != 'DOTS':
+                subcol.enabled = False
+            subcol.prop(gp_settings, "gradient_factor", slider=True)
+            subcol.prop(gp_settings, "gradient_shape")
 
 
 class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(View3DPanel, Panel):
index ea5605d8ed102727f133ef7cb76f1ad89ef1d7b9..e0bc914dd78b64a0a50dfeaccbac7484b3375fc5 100644 (file)
@@ -304,6 +304,10 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
        brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
 
+       brush->gpencil_settings->gradient_f = 1.0f;
+       brush->gpencil_settings->gradient_s[0] = 1.0f;
+       brush->gpencil_settings->gradient_s[1] = 1.0f;
+
        /* Pen brush */
        brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen");
        deft = brush; /* save default brush */
@@ -336,6 +340,10 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
        brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
 
+       brush->gpencil_settings->gradient_f = 1.0f;
+       brush->gpencil_settings->gradient_s[0] = 1.0f;
+       brush->gpencil_settings->gradient_s[1] = 1.0f;
+
        /* Ink brush */
        brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink");
        brush->size = 60.0f;
@@ -365,6 +373,10 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
        brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
 
+       brush->gpencil_settings->gradient_f = 1.0f;
+       brush->gpencil_settings->gradient_s[0] = 1.0f;
+       brush->gpencil_settings->gradient_s[1] = 1.0f;
+
        /* Curve */
        custom_curve = brush->gpencil_settings->curve_sensitivity;
        curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
@@ -408,6 +420,10 @@ void BKE_brush_gpencil_presets(bContext *C)
        curvemapping_initialize(custom_curve);
        brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INKNOISE);
 
+       brush->gpencil_settings->gradient_f = 1.0f;
+       brush->gpencil_settings->gradient_s[0] = 1.0f;
+       brush->gpencil_settings->gradient_s[1] = 1.0f;
+
        /* Block Basic brush */
        brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block");
        brush->size = 150.0f;
@@ -436,6 +452,10 @@ void BKE_brush_gpencil_presets(bContext *C)
        brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
        brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
 
+       brush->gpencil_settings->gradient_f = 1.0f;
+       brush->gpencil_settings->gradient_s[0] = 1.0f;
+       brush->gpencil_settings->gradient_s[1] = 1.0f;
+
        /* Marker brush */
        brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker");
        brush->size = 80.0f;
@@ -472,6 +492,10 @@ void BKE_brush_gpencil_presets(bContext *C)
        curvemapping_initialize(custom_curve);
        brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER);
 
+       brush->gpencil_settings->gradient_f = 1.0f;
+       brush->gpencil_settings->gradient_s[0] = 1.0f;
+       brush->gpencil_settings->gradient_s[1] = 1.0f;
+
        /* Fill brush */
        brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area");
        brush->size = 1.0f;
@@ -495,6 +519,10 @@ void BKE_brush_gpencil_presets(bContext *C)
 
        brush->gpencil_settings->draw_strength = 1.0f;
 
+       brush->gpencil_settings->gradient_f = 1.0f;
+       brush->gpencil_settings->gradient_s[0] = 1.0f;
+       brush->gpencil_settings->gradient_s[1] = 1.0f;
+
        /* Soft Eraser brush */
        brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft");
        brush->size = 30.0f;
index c204a8128c166e46acb142a44461a0b736e87449..d47b3f20a28091cb10e82a660d55036b3974962a 100644 (file)
@@ -467,6 +467,10 @@ bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, s
        bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
 
        gps->thickness = thickness;
+       gps->gradient_f = 1.0f;
+       gps->gradient_s[0] = 1.0f;
+       gps->gradient_s[1] = 1.0f;
+
        gps->inittime = 0;
 
        /* enable recalculation flag by default */
index ce2345b44db8bef874f136456d33214fe7a1aa4b..41b1627e873b5094fbe3dfc71fc745359539ece8 100644 (file)
@@ -3110,6 +3110,33 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
                                }
                        }
                }
+
+               /* init grease pencil brush gradients */
+               if (!DNA_struct_elem_find(fd->filesdna, "BrushGpencilSettings", "float", "gradient_f")) {
+                       for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
+                               if (brush->gpencil_settings != NULL) {
+                                       BrushGpencilSettings *gp = brush->gpencil_settings;
+                                       gp->gradient_f = 1.0f;
+                                       gp->gradient_s[0] = 1.0f;
+                                       gp->gradient_s[1] = 1.0f;
+                               }
+                       }
+               }
+
+               /* init grease pencil stroke gradients */
+               if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "float", "gradient_f")) {
+                       for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) {
+                               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) {
+                                                       gps->gradient_f = 1.0f;
+                                                       gps->gradient_s[0] = 1.0f;
+                                                       gps->gradient_s[1] = 1.0f;
+                                               }
+                                       }
+                               }
+                       }
+               }
        }
 
        {
index b72a6ebebbde95bb16a3149decdc5876de2d7a56..3bcc963c96690046f18099150ebab297e4299e3e 100644 (file)
@@ -95,6 +95,7 @@ void DRW_gpencil_get_point_geom(GpencilBatchCacheElem *be, bGPDstroke *gps, shor
                be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
                be->thickness_id = GPU_vertformat_attr_add(&be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
                be->uvdata_id = GPU_vertformat_attr_add(&be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+               be->prev_pos_id = GPU_vertformat_attr_add(&be->format, "prev_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
 
                be->vbo = GPU_vertbuf_create_with_format(&be->format);
                GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
@@ -123,6 +124,26 @@ void DRW_gpencil_get_point_geom(GpencilBatchCacheElem *be, bGPDstroke *gps, shor
                GPU_vertbuf_attr_set(be->vbo, be->uvdata_id, be->vbo_len, uvdata);
 
                GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
+
+               /* use previous point to determine stroke direction */
+               bGPDspoint *pt2 = NULL;
+               if (i == 0) {
+                       if (gps->totpoints > 1) {
+                               /* extrapolate a point before first point */
+                               float fpt[3];
+                               pt2 = &gps->points[1];
+                               interp_v3_v3v3(fpt, &pt2->x, &pt->x, 1.5f);
+                               GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt);
+                       }
+                       else {
+                               GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, &pt->x);
+                       }
+               }
+               else {
+                       pt2 = &gps->points[i - 1];
+                       GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, &pt2->x);
+               }
+
                be->vbo_len++;
        }
 }
index 6aefd2a69c56cdcd4c5faa7f14c1ffd9ad70e7c0..8ecee86d92b75efc5071024d582e4e6309a6088c 100644 (file)
@@ -532,6 +532,10 @@ DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(
                stl->shgroups[id].caps_mode[1] = gps->caps[1];
                DRW_shgroup_uniform_int(grp, "caps_mode", &stl->shgroups[id].caps_mode[0], 2);
 
+               stl->shgroups[id].gradient_f = gps->gradient_f;
+               copy_v2_v2(stl->shgroups[id].gradient_s, gps->gradient_s);
+               DRW_shgroup_uniform_float(grp, "gradient_f", &stl->shgroups[id].gradient_f, 1);
+
                /* viewport x-ray */
                stl->shgroups[id].is_xray = (ob->dt == OB_WIRE) ? 1 : stl->storage->is_xray;
                DRW_shgroup_uniform_int(grp, "viewport_xray", (const int *)&stl->shgroups[id].is_xray, 1);
@@ -565,6 +569,8 @@ DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(
                const int zero[2] = { 0, 0 };
                DRW_shgroup_uniform_int(grp, "caps_mode", &zero[0], 2);
 
+               DRW_shgroup_uniform_float(grp, "gradient_f", &stl->storage->gradient_f, 1);
+
                /* viewport x-ray */
                DRW_shgroup_uniform_int(grp, "viewport_xray", &stl->storage->is_xray, 1);
                DRW_shgroup_uniform_int(grp, "shading_type", (const int *)&stl->storage->shade_render, 2);
@@ -611,7 +617,7 @@ DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(
 /* create shading group for points */
 static DRWShadingGroup *DRW_gpencil_shgroup_point_create(
         GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob,
-        bGPdata *gpd, bGPDlayer *gpl,
+        bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps,
         MaterialGPencilStyle *gp_style, int id, bool onion,
         const float scale, const int shading_type[2])
 {
@@ -651,6 +657,11 @@ static DRWShadingGroup *DRW_gpencil_shgroup_point_create(
                DRW_shgroup_uniform_int(grp, "mode", &stl->shgroups[id].mode, 1);
                DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
 
+               stl->shgroups[id].gradient_f = gps->gradient_f;
+               copy_v2_v2(stl->shgroups[id].gradient_s, gps->gradient_s);
+               DRW_shgroup_uniform_float(grp, "gradient_f", &stl->shgroups[id].gradient_f, 1);
+               DRW_shgroup_uniform_vec2(grp, "gradient_s", stl->shgroups[id].gradient_s, 1);
+
                /* viewport x-ray */
                stl->shgroups[id].is_xray = (ob->dt == OB_WIRE) ? 1 : stl->storage->is_xray;
                DRW_shgroup_uniform_int(grp, "viewport_xray", (const int *)&stl->shgroups[id].is_xray, 1);
@@ -684,6 +695,10 @@ static DRWShadingGroup *DRW_gpencil_shgroup_point_create(
                else {
                        DRW_shgroup_uniform_float(grp, "pixfactor", &stl->storage->pixfactor, 1);
                }
+
+               DRW_shgroup_uniform_float(grp, "gradient_f", &stl->storage->gradient_f, 1);
+               DRW_shgroup_uniform_vec2(grp, "gradient_s", stl->storage->gradient_s, 1);
+
                /* viewport x-ray */
                stl->shgroups[id].is_xray = ((ob) && (ob->dt == OB_WIRE)) ? 1 : stl->storage->is_xray;
                DRW_shgroup_uniform_int(grp, "viewport_xray", (const int *)&stl->shgroups[id].is_xray, 1);
@@ -693,12 +708,21 @@ static DRWShadingGroup *DRW_gpencil_shgroup_point_create(
        if ((gpd) && (id > -1)) {
                stl->shgroups[id].xray_mode = (ob->dtx & OB_DRAWXRAY) ? GP_XRAY_FRONT : GP_XRAY_3DSPACE;
                DRW_shgroup_uniform_int(grp, "xraymode", (const int *)&stl->shgroups[id].xray_mode, 1);
+
+               /* lock rotation of dots and boxes */
+               stl->shgroups[id].use_follow_path = (gp_style->flag & GP_STYLE_COLOR_LOCK_DOTS) ? 0 : 1;
+               DRW_shgroup_uniform_int(grp, "use_follow_path", &stl->shgroups[id].use_follow_path, 1);
        }
        else {
                /* for drawing always on predefined z-depth */
                DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
+
+               /* lock rotation of dots and boxes */
+               DRW_shgroup_uniform_int(grp, "use_follow_path", &stl->storage->use_follow_path, 1);
        }
 
+
+
        /* image texture */
        if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
                ImBuf *ibuf;
@@ -1374,6 +1398,12 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, T
                         * i.e. tGPspoints NOT bGPDspoints
                         */
                        short lthick = brush->size * obscale;
+
+                       /* save gradient info */
+                       stl->storage->gradient_f = brush->gpencil_settings->gradient_f;
+                       copy_v2_v2(stl->storage->gradient_s, brush->gpencil_settings->gradient_s);
+                       stl->storage->use_follow_path = (gp_style->flag & GP_STYLE_COLOR_LOCK_DOTS) ? 0 : 1;
+
                        /* if only one point, don't need to draw buffer because the user has no time to see it */
                        if (gpd->runtime.sbuffer_size > 1) {
                                if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
@@ -1385,7 +1415,7 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, T
                                else {
                                        stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_point_create(
                                                e_data, vedata, psl->drawing_pass, e_data->gpencil_point_sh, NULL,
-                                               gpd, NULL, gp_style, -1,
+                                               gpd, NULL, NULL, gp_style, -1,
                                                false, 1.0f, (const int *)stl->storage->shade_render);
                                }
 
@@ -1582,7 +1612,7 @@ static void DRW_gpencil_shgroups_create(
 
                                shgrp = DRW_gpencil_shgroup_point_create(
                                        e_data, vedata, stroke_pass, e_data->gpencil_point_sh,
-                                       ob, gpd, gpl, gp_style, stl->storage->shgroup_id, elm->onion,
+                                       ob, gpd, gpl, gps, gp_style, stl->storage->shgroup_id, elm->onion,
                                        scale, cache_ob->shading_type);
 
                                DRW_shgroup_call_range_add(
index 8af74ec745142291ab8bb30019d7d46e67368736..5d0d2397f8dd09e7af18567f0cdaabaa412f9a8c 100644 (file)
@@ -119,6 +119,10 @@ typedef struct GPENCIL_shgroup {
        int caps_mode[2];
        float obj_scale;
        int xray_mode;
+       int use_follow_path;
+
+       float gradient_f;
+       float gradient_s[2];
 
        /* color of the wireframe */
        float wire_color[4];
@@ -164,6 +168,10 @@ typedef struct GPENCIL_Storage {
        bool simplify_fx;
        bool simplify_blend;
 
+       float gradient_f;
+       float gradient_s[2];
+       int use_follow_path;
+
        /* Render Matrices and data */
        float persmat[4][4], persinv[4][4];
        float viewmat[4][4], viewinv[4][4];
@@ -334,6 +342,7 @@ typedef struct GpencilBatchCacheElem {
        uint color_id;
        uint thickness_id;
        uint uvdata_id;
+       uint prev_pos_id;
 
        /* size for VBO alloc */
        int tot_vertex;
index a1285029e4c4bbda2c16a2ae0ea94ee0f7fd286c..ca8c888fe213f579262f271610e14445bed687dc 100644 (file)
@@ -2,6 +2,9 @@ uniform int color_type;
 uniform int mode;
 uniform sampler2D myTexture;
 
+uniform float gradient_f;
+uniform vec2 gradient_s;
+
 in vec4 mColor;
 in vec2 mTexCoord;
 out vec4 fragColor;
@@ -17,15 +20,23 @@ out vec4 fragColor;
 #define GPENCIL_COLOR_TEXTURE 1
 #define GPENCIL_COLOR_PATTERN 2
 
+/* Function to check the point inside ellipse */
+float checkpoint(vec2 pt, vec2 radius) 
+{ 
+    float p = (pow(pt.x, 2) / pow(radius.x, 2)) + (pow(pt.y, 2) / pow(radius.y, 2)); 
+  
+    return p; 
+} 
+
 void main()
 {
        vec2 centered = mTexCoord - vec2(0.5);
-       float dist_squared = dot(centered, centered);
-       const float rad_squared = 0.25;
+       float ellip = checkpoint(centered, vec2(gradient_s / 2.0));
 
-        /* Round point with jaggy edges. */
-       if ((mode != GPENCIL_MODE_BOX) && (dist_squared > rad_squared)) {
-               discard;
+       if (mode != GPENCIL_MODE_BOX) {
+               if (ellip > 1.0) {
+                       discard;
+               }
        }
 
        vec4 tmp_color = texture2D(myTexture, mTexCoord);
@@ -47,6 +58,15 @@ void main()
                /* mult both alpha factor to use strength factor with color alpha limit */
                fragColor.a = min(text_color.a * mColor.a, mColor.a);
        }
-       if(fragColor.a < 0.0035)
+       
+       if ((mode == GPENCIL_MODE_DOTS) && (gradient_f < 1.0)) {
+               float dist = length(centered) * 2;
+               float decay = dist * (1.0 - gradient_f) * fragColor.a;
+               fragColor.a = clamp(fragColor.a - decay, 0.0, 1.0);
+               fragColor.a = fragColor.a * (1.0 - ellip);
+       }
+       
+       if(fragColor.a < 0.0035) {
                discard;
+       }
 }
index 6c22633c521c02ec4a6bc510d95d6ad3492ec565..32aaa057298f10b67633b8be924479949c6f1dc3 100644 (file)
@@ -1,6 +1,7 @@
 uniform mat4 ModelViewProjectionMatrix;
 uniform vec2 Viewport;
 uniform int xraymode;
+uniform int use_follow_path;
 
 layout(points) in;
 layout(triangle_strip, max_vertices = 4) out;
@@ -8,6 +9,7 @@ layout(triangle_strip, max_vertices = 4) out;
 in vec4 finalColor[1];
 in float finalThickness[1];
 in vec2 finaluvdata[1];
+in vec4 finalprev_pos[1];
 
 out vec4 mColor;
 out vec2 mTexCoord;
@@ -15,6 +17,10 @@ out vec2 mTexCoord;
 #define GP_XRAY_FRONT 0
 #define GP_XRAY_3DSPACE 1
 
+#define M_PI        3.14159265358979323846  /* pi */
+#define M_2PI       6.28318530717958647692  /* 2*pi */
+#define FALSE       0
+
 /* project 3d point to 2d on screen space */
 vec2 toScreenSpace(vec4 vertex)
 {
@@ -45,33 +51,89 @@ vec2 rotateUV(vec2 uv, float angle)
        return rot_uv + vec2(0.5f, 0.5f);
 }
 
+vec2 rotatePoint(vec2 center, vec2 point, float angle)
+{
+       /* translate center of rotation to the center */
+       vec2 new_point = point - center;
+       vec2 rot_point;
+       rot_point.x = new_point.x * cos(angle) - new_point.y * sin(angle);
+       rot_point.y = new_point.y * cos(angle) + new_point.x * sin(angle);
+       return rot_point + center;
+}
+
+/* Calculate angle of the stroke using previous point as reference.
+ * The angle is calculated using the x axis (1, 0) as 0 degrees */
+float getAngle(vec2 pt0, vec2 pt1)
+{
+       /* do not rotate one point only (no reference to rotate) */
+       if (pt0 == pt1) {
+               return 0.0;
+       }       
+
+       if (use_follow_path == FALSE) {
+               return 0.0;
+       }
+
+       /* default horizontal line (x-axis) in screen space */
+       vec2 v0 = vec2(1.0, 0.0);
+       
+       /* vector of direction */
+       vec2 vn = vec2(normalize(pt1 - pt0));
+       
+       /* angle signed (function ported from angle_signed_v2v2) */
+       float perp_dot = (v0[1] * vn[0]) - (v0[0] * vn[1]);
+       float angle = atan(perp_dot, dot(v0, vn));
+       
+       /* get full circle rotation */
+       if (angle > 0.0) {
+               angle = M_PI + (M_PI - angle);
+       }
+       else {
+               angle *= -1.0;
+       }
+
+       return angle;
+}
+
 void main(void)
 {
-       /* receive points */
+       /* receive points */
        vec4 P0 = gl_in[0].gl_Position;
        vec2 sp0 = toScreenSpace(P0);
 
+       vec4 P1 = finalprev_pos[0];
+       vec2 sp1 = toScreenSpace(P1);
+    vec2 point;
+
        float size = finalThickness[0];
-       float aspect = 1.0;
+       vec2 center = vec2(sp0.x, sp0.y);
+       
+       /* get angle of stroke to rotate texture */
+       float angle = getAngle(sp0, sp1);
+
        /* generate the triangle strip */
        mTexCoord = rotateUV(vec2(0, 1), finaluvdata[0].y);
        mColor = finalColor[0];
-       gl_Position = vec4(vec2(sp0.x - size, sp0.y + size * aspect) / Viewport, getZdepth(P0), 1.0);
+       point = rotatePoint(center, vec2(sp0.x - size, sp0.y + size), angle);
+       gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0);
        EmitVertex();
 
        mTexCoord = rotateUV(vec2(0, 0), finaluvdata[0].y);
        mColor = finalColor[0];
-       gl_Position = vec4(vec2(sp0.x - size, sp0.y - size * aspect) / Viewport, getZdepth(P0), 1.0);
+       point = rotatePoint(center, vec2(sp0.x - size, sp0.y - size), angle);
+       gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0);
        EmitVertex();
 
        mTexCoord = rotateUV(vec2(1, 1), finaluvdata[0].y);
        mColor = finalColor[0];
-       gl_Position = vec4(vec2(sp0.x + size, sp0.y + size * aspect) / Viewport, getZdepth(P0), 1.0);
+       point = rotatePoint(center, vec2(sp0.x + size, sp0.y + size), angle);
+       gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0);
        EmitVertex();
 
        mTexCoord = rotateUV(vec2(1, 0), finaluvdata[0].y);
        mColor = finalColor[0];
-       gl_Position = vec4(vec2(sp0.x + size, sp0.y - size * aspect) / Viewport, getZdepth(P0), 1.0);
+       point = rotatePoint(center, vec2(sp0.x + size, sp0.y - size), angle);
+       gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0);
        EmitVertex();
 
        EndPrimitive();
index 2606bbf878eed1571849e6a215be9c15f6970cd4..7deca5441761ece952e51790604c675956694452 100644 (file)
@@ -13,10 +13,12 @@ in vec3 pos;
 in vec4 color;
 in float thickness;
 in vec2 uvdata;
+in vec3 prev_pos;
 
 out vec4 finalColor;
 out float finalThickness;
 out vec2 finaluvdata;
+out vec4 finalprev_pos;
 
 #define TRUE 1
 
@@ -30,7 +32,8 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor);
 
 void main()
 {
-       gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+       gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+       finalprev_pos = ModelViewProjectionMatrix * vec4(prev_pos, 1.0);
        finalColor = color;
 
        if (keep_size == TRUE) {
index 80fa899b13ae29e9e287b3ec5b08e36b560717b2..a49a6e84f1712d8ce40bd70f8d634afdd2b513ed 100644 (file)
@@ -1,6 +1,8 @@
 uniform int color_type;
 uniform sampler2D myTexture;
 
+uniform float gradient_f;
+
 in vec4 mColor;
 in vec2 mTexCoord;
 in vec2 uvfac;
@@ -18,6 +20,7 @@ out vec4 fragColor;
 
 void main()
 {
+       
        vec4 tColor = vec4(mColor);
        /* if uvfac[1]  == 1, then encap */
        if (uvfac[1] == ENDCAP) {
@@ -54,6 +57,16 @@ void main()
                fragColor.a = min(text_color.a * tColor.a, tColor.a);
        }
 
+       /* gradient */
+       /* keep this disabled while the line glitch bug exists
+       if (gradient_f < 1.0) {
+               float d = abs(mTexCoord.y - 0.5)  * (1.1 - gradient_f);
+               float alpha = 1.0 - clamp((fragColor.a - (d * 2.0)), 0.03, 1.0);
+               fragColor.a = smoothstep(fragColor.a, 0.0, alpha);
+               
+       }
+       */
+
        if(fragColor.a < 0.0035)
                discard;
 }
index 5152bcb0a90c0ffa67070e166f394082b701f6e7..dcecd87a86262a52ddc7a17f5ebcf633eddee34c 100644 (file)
@@ -681,6 +681,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
        /* 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;
 
index e13dfb38c7ddc81ea2e415db2ce213801a6f0a32..76d15557055af5350a4e022d95dc7cf2a9a9c630 100644 (file)
@@ -1011,6 +1011,8 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
        /* 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 */
index 80b26a366fea892878e43ebfb7b31ee7c585ffbb..10bf45a9e2fa29656c87fda89b3ebe1b39d0a7c6 100644 (file)
@@ -127,6 +127,8 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo
        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;
index daea24ecaa3253d1cdd0b68c73b50fa7db7e377f..aadaff5b7cc80cc9bd18134c3a53c1bd05d4c2da 100644 (file)
@@ -944,6 +944,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
        /* 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;
 
index f92398520fa4a6891472f8e163f118261d4f6519..374dbbf4d9c336aa62b44a8dc3df5840a8981ae7 100644 (file)
@@ -319,6 +319,9 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
        /* 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 */
@@ -1199,6 +1202,7 @@ static void gpencil_primitive_interaction_end(bContext *C, wmOperator *op, wmWin
        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);
@@ -1221,7 +1225,10 @@ static void gpencil_primitive_interaction_end(bContext *C, wmOperator *op, wmWin
        /* prepare stroke to get transferred */
        gps = tgpi->gpf->strokes.first;
        if (gps) {
-               gps->thickness = tgpi->brush->size;
+               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;
 
index f8f92d8bef85d8e342cb9b078b1be77ee94ae7a6..253e02ca63913a90d2b3d74ad1ae465966f4cba9 100644 (file)
@@ -437,6 +437,9 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
                }
                gps->flag = GP_STROKE_3DSPACE;
                gps->thickness = 3;
+               gps->gradient_f = 1.0f;
+               gps->gradient_s[0] = 1.0f;
+               gps->gradient_s[1] = 1.0f;
 
                BLI_addtail(&gpf->strokes, gps);
                changed = true;
index 4bfbb3655af1677b33cc660c2942188d3e7c6a0a..9aa6ff8c1c8cfc523be0c03cfac5887eda81f35d 100644 (file)
@@ -111,6 +111,12 @@ typedef struct BrushGpencilSettings {
        /** Internal grease pencil drawing flags. */
        int flag;
 
+       /** gradient control along y for color */
+       float gradient_f;
+       /** factor xy of shape for dots gradients */
+       float gradient_s[2];
+       char _pad_2[4];
+
        struct CurveMapping *curve_sensitivity;
        struct CurveMapping *curve_strength;
        struct CurveMapping *curve_jitter;
index 56e17fe91497a4d482ad567df8a5a80d8d68b676..dc752cc0bc90a69e3da0a381abc11533d3fc657f 100644 (file)
@@ -199,6 +199,12 @@ typedef struct bGPDstroke {
        /** Caps mode for each stroke extreme */
        short caps[2];
 
+       /** gradient control along y for color */
+       float gradient_f;
+       /** factor xy of shape for dots gradients */
+       float gradient_s[2];
+       char _pad_3[4];
+
        /** Vertex weight data. */
        struct MDeformVert *dvert;
        void *_pad3;
index 3db8bf92f5664aa3437426bffc49fcc7ffdf7bae..a8f3384ea853679f91dd0d8948a91eb68ada071c 100644 (file)
@@ -121,6 +121,8 @@ typedef enum eMaterialGPencilStyle_Flag {
        GP_STYLE_STROKE_SHOW = (1 << 8),
        /* Fill  show main switch */
        GP_STYLE_FILL_SHOW = (1 << 9),
+       /* Don't rotate dots/boxes */
+       GP_STYLE_COLOR_LOCK_DOTS = (1 << 10)
 } eMaterialGPencilStyle_Flag;
 
 typedef enum eMaterialGPencilStyle_Mode {
index ce5b18331c69a4f3a68bab77c695d186c14a6574..23ae314f885f8ba1538167f1f668585ae37462cc 100644 (file)
@@ -1197,6 +1197,25 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
        RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
        RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 
+       /* gradient control */
+       prop = RNA_def_property(srna, "gradient_factor", PROP_FLOAT, PROP_FACTOR);
+       RNA_def_property_float_sdna(prop, NULL, "gradient_f");
+       RNA_def_property_range(prop, 0.001f, 1.0f);
+       RNA_def_property_float_default(prop, 1.0f);
+       RNA_def_property_ui_text(
+               prop, "Border Opacity Factor",
+               "Amount of gradient for Dot strokes (set to 1 for full solid)");
+       RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+       /* gradient shape ratio */
+       prop = RNA_def_property(srna, "gradient_shape", PROP_FLOAT, PROP_XYZ);
+       RNA_def_property_float_sdna(prop, NULL, "gradient_s");
+       RNA_def_property_array(prop, 2);
+       RNA_def_property_range(prop, 0.01f, 1.0f);
+       RNA_def_property_float_default(prop, 1.0f);
+       RNA_def_property_ui_text(prop, "Aspect Ratio", "");
+       RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
        prop = RNA_def_property(srna, "input_samples", PROP_INT, PROP_NONE);
        RNA_def_property_int_sdna(prop, NULL, "input_samples");
        RNA_def_property_range(prop, 0, GP_MAX_INPUT_SAMPLES);
index 73203beb3e2fd9790dc61fbb116c3dd118bc3a68..d154f8de4ad8e9a8b57436dafd3749347c67d4eb 100644 (file)
@@ -998,6 +998,24 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Thickness", "Thickness of stroke (in pixels)");
        RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
 
+       /* gradient control along y */
+       prop = RNA_def_property(srna, "gradient_factor", PROP_FLOAT, PROP_FACTOR);
+       RNA_def_property_float_sdna(prop, NULL, "gradient_f");
+       RNA_def_property_range(prop, 0.001f, 1.0f);
+       RNA_def_property_float_default(prop, 1.0f);
+       RNA_def_property_ui_text(prop, "Border Opacity Factor",
+               "Amount of gradient along section of stroke");
+       RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+       RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+       /* gradient shape ratio */
+       prop = RNA_def_property(srna, "gradient_shape", PROP_FLOAT, PROP_XYZ);
+       RNA_def_property_float_sdna(prop, NULL, "gradient_s");
+       RNA_def_property_array(prop, 2);
+       RNA_def_property_range(prop, 0.01f, 1.0f);
+       RNA_def_property_float_default(prop, 1.0f);
+       RNA_def_property_ui_text(prop, "Aspect Ratio", "");
+       RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
 }
 
 static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop)
index 8e5f486fea13b6d89310f30fb09446b2a0257933..a57f47a8090dacc11d258dcd2974442e8e1bd2d5 100644 (file)
@@ -585,6 +585,13 @@ static void rna_def_material_greasepencil(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Show Fill", "Show stroke fills of this material");
        RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
 
+       /* keep Dots and Boxes aligned to screen and not to drawing path */
+       prop = RNA_def_property(srna, "use_follow_path", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_STYLE_COLOR_LOCK_DOTS);
+       RNA_def_property_ui_text(prop, "Follow Path",
+               "Keep Dots and Boxes aligned to drawing path");
+       RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update");
+
        /* pass index for future compositing and editing tools */
        prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
        RNA_def_property_int_sdna(prop, NULL, "index");