Grease Pencil v2 Branch
authorAntonio Vazquez <blendergit@gmail.com>
Wed, 3 Aug 2016 21:31:48 +0000 (23:31 +0200)
committerJulian Eisel <eiseljulian@gmail.com>
Wed, 3 Aug 2016 21:39:36 +0000 (23:39 +0200)
Improve current Grease Pencil in order to get a better 2D animation tool.

More info in WIKI pages: https://wiki.blender.org/index.php/User:Antoniov

Reviewed By: Severin, aligorith, campbellbarton

Patch by @antoniov, with edits by @Severin.

Differential Revision: https://developer.blender.org/D2115

58 files changed:
release/datafiles/blender_icons.svg
release/datafiles/blender_icons16/icon16_restrict_color_off.dat [new file with mode: 0644]
release/datafiles/blender_icons16/icon16_restrict_color_on.dat [new file with mode: 0644]
release/datafiles/blender_icons32/icon32_restrict_color_off.dat [new file with mode: 0644]
release/datafiles/blender_icons32/icon32_restrict_color_on.dat [new file with mode: 0644]
release/scripts/startup/bl_ui/properties_grease_pencil_common.py
release/scripts/startup/bl_ui/space_clip.py
release/scripts/startup/bl_ui/space_image.py
release/scripts/startup/bl_ui/space_node.py
release/scripts/startup/bl_ui/space_sequencer.py
release/scripts/startup/bl_ui/space_view3d.py
release/scripts/startup/bl_ui/space_view3d_toolbar.py
source/blender/blenkernel/BKE_blender_version.h
source/blender/blenkernel/BKE_context.h
source/blender/blenkernel/BKE_gpencil.h
source/blender/blenkernel/intern/context.c
source/blender/blenkernel/intern/gpencil.c
source/blender/blenkernel/intern/library_remap.c
source/blender/blenkernel/intern/scene.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/versioning_270.c
source/blender/blenloader/intern/versioning_defaults.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/animation/anim_channels_defines.c
source/blender/editors/gpencil/drawgpencil.c
source/blender/editors/gpencil/gpencil_brush.c
source/blender/editors/gpencil/gpencil_convert.c
source/blender/editors/gpencil/gpencil_data.c
source/blender/editors/gpencil/gpencil_edit.c
source/blender/editors/gpencil/gpencil_intern.h
source/blender/editors/gpencil/gpencil_ops.c
source/blender/editors/gpencil/gpencil_paint.c
source/blender/editors/gpencil/gpencil_select.c
source/blender/editors/gpencil/gpencil_undo.c
source/blender/editors/gpencil/gpencil_utils.c
source/blender/editors/include/ED_gpencil.h
source/blender/editors/include/UI_icons.h
source/blender/editors/object/object_add.c
source/blender/editors/object/object_relations.c
source/blender/editors/render/render_opengl.c
source/blender/editors/screen/screen_context.c
source/blender/editors/space_node/drawnode.c
source/blender/editors/space_outliner/outliner_draw.c
source/blender/editors/space_view3d/view3d_ruler.c
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_manipulator.c
source/blender/makesdna/DNA_gpencil_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_gpencil.c
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_sculpt_paint.c
source/blender/render/extern/include/RE_pipeline.h
source/blender/render/intern/include/render_result.h
source/blender/render/intern/source/pipeline.c
source/blender/render/intern/source/render_result.c
source/blenderplayer/bad_level_call_stubs/stubs.c

index 40b974661fac4ec3d9f4c1b22ea75a7ee79ada47..030953cf6145fa9c75528c1cd7500bb7b0300112 100644 (file)
        y1="-16"
        x2="-93.75"
        y2="-16.264704" />
+    <filter
+       inkscape:label="Opacity"
+       style="color-interpolation-filters:sRGB"
+       id="filter17385">
+      <feColorMatrix
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 5 -1 "
+         result="colormatrix"
+         id="feColorMatrix17387" />
+      <feComposite
+         k4="0"
+         k3="0"
+         k1="0"
+         in2="colormatrix"
+         operator="arithmetic"
+         k2="0.24"
+         result="composite"
+         id="feComposite17389" />
+    </filter>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient18134"
+       id="radialGradient37501-3-6-2"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.08933014,-0.7764284,0.7350832,-0.08334857,57.410559,233.30156)"
+       cx="135.83771"
+       cy="117.97826"
+       fx="135.83771"
+       fy="117.97826"
+       r="8" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient18134"
+       id="radialGradient37501-3-6"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.08933014,-0.7764284,0.7350832,-0.08334857,57.410559,233.30156)"
+       cx="135.83771"
+       cy="117.97826"
+       fx="135.83771"
+       fy="117.97826"
+       r="8" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient18134"
+       id="linearGradient17463"
+       gradientUnits="userSpaceOnUse"
+       x1="121.19734"
+       y1="105.94044"
+       x2="148.06364"
+       y2="137.6748" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient16595"
+       id="linearGradient17281"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(144,188)"
+       x1="209"
+       y1="238"
+       x2="226.625"
+       y2="251.71078" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient18134"
+       id="linearGradient31399"
+       gradientUnits="userSpaceOnUse"
+       x1="62.793919"
+       y1="133.73566"
+       x2="64.109718"
+       y2="135.18265" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient319"
+       id="linearGradient31452"
+       gradientUnits="userSpaceOnUse"
+       x1="121.19734"
+       y1="105.94044"
+       x2="148.06364"
+       y2="137.6748" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient1610-36-6-5"
+       id="linearGradient31454"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(144,188)"
+       x1="209"
+       y1="238"
+       x2="226.625"
+       y2="251.71078" />
   </defs>
   <sodipodi:namedview
      id="base"
      objecttolerance="10000"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="40.768576"
-     inkscape:cx="236.56738"
-     inkscape:cy="163.14077"
+     inkscape:zoom="10.192144"
+     inkscape:cx="406.73801"
+     inkscape:cy="204.25086"
      inkscape:document-units="px"
      inkscape:current-layer="g24024-1"
      showgrid="true"
-     inkscape:window-width="1920"
-     inkscape:window-height="982"
-     inkscape:window-x="0"
-     inkscape:window-y="28"
+     inkscape:window-width="1680"
+     inkscape:window-height="987"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
      inkscape:snap-nodes="false"
      inkscape:snap-bbox="true"
      showguides="true"
              cx="304.0946"
              cy="242.89087"
              rx="0.59120387"
-             ry="0.61330098"
-             d="m 304.68581,242.89087 c 0,0.33872 -0.26469,0.6133 -0.59121,0.6133 -0.32651,0 -0.5912,-0.27458 -0.5912,-0.6133 0,-0.33872 0.26469,-0.6133 0.5912,-0.6133 0.32652,0 0.59121,0.27458 0.59121,0.6133 z" />
+             ry="0.61330098" />
           <ellipse
              sodipodi:ry="0.61330098"
              sodipodi:rx="0.59120387"
              cx="315.98523"
              cy="242.95337"
              rx="0.59120387"
-             ry="0.61330098"
-             d="m 316.57643,242.95337 c 0,0.33872 -0.26469,0.6133 -0.5912,0.6133 -0.32651,0 -0.5912,-0.27458 -0.5912,-0.6133 0,-0.33872 0.26469,-0.6133 0.5912,-0.6133 0.32651,0 0.5912,0.27458 0.5912,0.6133 z" />
+             ry="0.61330098" />
         </g>
         <g
            clip-path="url(#clipPath15455-9)"
              cy="242.89087"
              cx="304.0946"
              id="ellipse15366"
-             style="opacity:0.51799999;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
-             d="m 304.68581,242.89087 c 0,0.33872 -0.26469,0.6133 -0.59121,0.6133 -0.32651,0 -0.5912,-0.27458 -0.5912,-0.6133 0,-0.33872 0.26469,-0.6133 0.5912,-0.6133 0.32652,0 0.59121,0.27458 0.59121,0.6133 z" />
+             style="opacity:0.51799999;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
           <ellipse
              sodipodi:ry="0.61330098"
              sodipodi:rx="0.59120387"
              cy="242.95337"
              cx="315.98523"
              id="ellipse15368"
-             style="opacity:0.51799999;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
-             d="m 316.57643,242.95337 c 0,0.33872 -0.26469,0.6133 -0.5912,0.6133 -0.32651,0 -0.5912,-0.27458 -0.5912,-0.6133 0,-0.33872 0.26469,-0.6133 0.5912,-0.6133 0.32651,0 0.5912,0.27458 0.5912,0.6133 z" />
+             style="opacity:0.51799999;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
         </g>
         <g
            transform="translate(189.00803,-79.37555)"
                style="color:#000000;fill:url(#radialGradient14216);fill-opacity:1;stroke:none;stroke-width:1.20000005;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
           </g>
         </g>
+        <g
+           style="display:inline;enable-background:new"
+           id="g17465"
+           transform="translate(62.844714,-106.93345)">
+          <g
+             transform="matrix(0.7,0,0,0.7,146.7,264.8)"
+             id="ICON_COLOR-1-9"
+             style="display:inline;enable-background:new">
+            <rect
+               y="238"
+               x="341"
+               height="16"
+               width="16"
+               id="rect36341-2-0"
+               style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" />
+            <g
+               id="g36343-7-5"
+               transform="translate(0,-12)">
+              <g
+                 transform="matrix(1.1658027,0,0,1.1657997,198.71028,-2.0560643)"
+                 id="g36345-0-4">
+                <path
+                   transform="matrix(0.6969448,0,0,0.6969467,36.918512,140.83126)"
+                   sodipodi:type="arc"
+                   style="fill:#ff6600;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                   id="path36349-4-2"
+                   sodipodi:cx="132"
+                   sodipodi:cy="118"
+                   sodipodi:rx="8"
+                   sodipodi:ry="8"
+                   d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+                   inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                   inkscape:export-xdpi="90"
+                   inkscape:export-ydpi="90"
+                   sodipodi:start="4.712389"
+                   sodipodi:end="5.7595865"
+                   inkscape:transform-center-x="-2.8145849"
+                   inkscape:transform-center-y="-3.2499984" />
+                <path
+                   inkscape:transform-center-y="1.6729808e-005"
+                   inkscape:transform-center-x="-3.2630798"
+                   sodipodi:end="5.7595865"
+                   sodipodi:start="4.712389"
+                   inkscape:export-ydpi="90"
+                   inkscape:export-xdpi="90"
+                   inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                   d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+                   sodipodi:ry="8"
+                   sodipodi:rx="8"
+                   sodipodi:cy="118"
+                   sodipodi:cx="132"
+                   id="path36351-3-6"
+                   style="fill:#ad2f94;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                   sodipodi:type="arc"
+                   transform="matrix(0.3484724,0.6035735,-0.603572,0.3484734,154.13836,102.27942)" />
+                <path
+                   transform="matrix(-0.3484724,0.6035735,-0.603572,-0.3484733,246.13507,184.51913)"
+                   sodipodi:type="arc"
+                   style="fill:#0060f0;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                   id="path36353-9-8"
+                   sodipodi:cx="132"
+                   sodipodi:cy="118"
+                   sodipodi:rx="8"
+                   sodipodi:ry="8"
+                   d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+                   inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                   inkscape:export-xdpi="90"
+                   inkscape:export-ydpi="90"
+                   sodipodi:start="4.712389"
+                   sodipodi:end="5.7595865"
+                   inkscape:transform-center-x="-2.8145756"
+                   inkscape:transform-center-y="3.2500173" />
+                <path
+                   inkscape:transform-center-y="3.249994"
+                   inkscape:transform-center-x="2.8145978"
+                   sodipodi:end="5.7595865"
+                   sodipodi:start="4.712389"
+                   inkscape:export-ydpi="90"
+                   inkscape:export-xdpi="90"
+                   inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                   d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+                   sodipodi:ry="8"
+                   sodipodi:rx="8"
+                   sodipodi:cy="118"
+                   sodipodi:cx="132"
+                   id="path36355-6-4"
+                   style="fill:#00d4aa;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                   sodipodi:type="arc"
+                   transform="matrix(-0.6969448,2.2484149e-8,-4.6257528e-8,-0.6969467,220.91956,305.31067)" />
+                <path
+                   transform="matrix(-0.3484724,-0.6035734,0.603572,-0.3484734,103.69972,343.86251)"
+                   sodipodi:type="arc"
+                   style="fill:#ccff00;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                   id="path36357-5-2"
+                   sodipodi:cx="132"
+                   sodipodi:cy="118"
+                   sodipodi:rx="8"
+                   sodipodi:ry="8"
+                   d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+                   inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                   inkscape:export-xdpi="90"
+                   inkscape:export-ydpi="90"
+                   sodipodi:start="4.712389"
+                   sodipodi:end="5.7595865"
+                   inkscape:transform-center-x="3.2630773" />
+                <path
+                   inkscape:transform-center-x="2.8145777"
+                   sodipodi:end="5.7595865"
+                   sodipodi:start="4.712389"
+                   inkscape:export-ydpi="90"
+                   inkscape:export-xdpi="90"
+                   inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                   d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+                   sodipodi:ry="8"
+                   sodipodi:rx="8"
+                   sodipodi:cy="118"
+                   sodipodi:cx="132"
+                   id="path36359-0-5"
+                   style="fill:#ffbf0e;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                   sodipodi:type="arc"
+                   transform="matrix(0.3484724,-0.6035734,0.603572,0.3484733,11.703006,261.6228)"
+                   inkscape:transform-center-y="-3.2500006" />
+              </g>
+              <circle
+                 inkscape:export-ydpi="90"
+                 inkscape:export-xdpi="90"
+                 inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                 id="path36361-8-8"
+                 style="fill:none;stroke:#000000;stroke-width:0.98948926;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+                 transform="matrix(0.8124999,0,0,0.8045157,241.75,163.13011)"
+                 cx="132"
+                 cy="118"
+                 r="8" />
+              <circle
+                 style="display:inline;opacity:0.3;fill:url(#radialGradient37501-3-6);fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 id="path36363-2-9"
+                 inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                 inkscape:export-xdpi="90"
+                 inkscape:export-ydpi="90"
+                 transform="matrix(-0.7451143,-0.08386971,0.08492794,-0.7396793,437.33358,356.39712)"
+                 cx="132"
+                 cy="118"
+                 r="8" />
+              <circle
+                 transform="matrix(0.6860851,0,0,0.6874876,258.44808,176.87656)"
+                 style="fill:none;stroke:url(#linearGradient17463);stroke-width:1.45605874;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+                 id="path36365-2-9"
+                 inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                 inkscape:export-xdpi="90"
+                 inkscape:export-ydpi="90"
+                 cx="132"
+                 cy="118"
+                 r="8" />
+            </g>
+          </g>
+          <g
+             inkscape:transform-center-y="0.19622957"
+             inkscape:transform-center-x="-1.373607"
+             id="ICON_RESTRICT_SELECT_OFF-9"
+             style="display:inline;enable-background:new"
+             transform="matrix(0.45975513,-0.19653299,0.19653299,0.45975513,138.04837,311.70175)">
+            <path
+               style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient17281);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+               d="m 367.75,440.75 1.75,-1.5 2.5,5.25 1.75,-1 -2.25,-5 2.5,0 -6.25,-6.25 z"
+               id="path45378-1-5-6-6"
+               sodipodi:nodetypes="cccccccc"
+               inkscape:connector-curvature="0" />
+            <rect
+               style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+               id="rect45374-0-5-6-1"
+               width="16"
+               height="16"
+               x="362"
+               y="430" />
+            <path
+               style="fill:none;stroke:#000000;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+               d="m 367.5,431.5 7,7.25 -3,0 2.5,4.75 -1.75,1 -2.5,-5 -2.25,2.25 z"
+               id="path17835-7-5"
+               inkscape:connector-curvature="0"
+               sodipodi:nodetypes="cccccccc" />
+            <path
+               style="fill:none;stroke:#ffffff;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+               d="m 368.34375,433.75 0,5.75"
+               id="path17845-9-6"
+               inkscape:connector-curvature="0"
+               sodipodi:nodetypes="cc" />
+          </g>
+        </g>
+        <g
+           style="display:inline;filter:url(#filter17385);enable-background:new"
+           id="g17465-0"
+           transform="translate(41.727744,-106.93345)">
+          <g
+             transform="matrix(0.7,0,0,0.7,146.7,264.8)"
+             id="ICON_COLOR-1-9-4"
+             style="display:inline;enable-background:new">
+            <rect
+               y="238"
+               x="341"
+               height="16"
+               width="16"
+               id="rect36341-2-0-1"
+               style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" />
+            <g
+               id="g36343-7-5-5"
+               transform="translate(0,-12)">
+              <g
+                 transform="matrix(1.1658027,0,0,1.1657997,198.71028,-2.0560643)"
+                 id="g36345-0-4-4">
+                <path
+                   transform="matrix(0.6969448,0,0,0.6969467,36.918512,140.83126)"
+                   sodipodi:type="arc"
+                   style="fill:#ff6600;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                   id="path36349-4-2-6"
+                   sodipodi:cx="132"
+                   sodipodi:cy="118"
+                   sodipodi:rx="8"
+                   sodipodi:ry="8"
+                   d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+                   inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                   inkscape:export-xdpi="90"
+                   inkscape:export-ydpi="90"
+                   sodipodi:start="4.712389"
+                   sodipodi:end="5.7595865"
+                   inkscape:transform-center-x="-2.8145849"
+                   inkscape:transform-center-y="-3.2499984" />
+                <path
+                   inkscape:transform-center-y="1.6729808e-005"
+                   inkscape:transform-center-x="-3.2630798"
+                   sodipodi:end="5.7595865"
+                   sodipodi:start="4.712389"
+                   inkscape:export-ydpi="90"
+                   inkscape:export-xdpi="90"
+                   inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                   d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+                   sodipodi:ry="8"
+                   sodipodi:rx="8"
+                   sodipodi:cy="118"
+                   sodipodi:cx="132"
+                   id="path36351-3-6-5"
+                   style="fill:#ad2f94;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                   sodipodi:type="arc"
+                   transform="matrix(0.3484724,0.6035735,-0.603572,0.3484734,154.13836,102.27942)" />
+                <path
+                   transform="matrix(-0.3484724,0.6035735,-0.603572,-0.3484733,246.13507,184.51913)"
+                   sodipodi:type="arc"
+                   style="fill:#0060f0;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                   id="path36353-9-8-2"
+                   sodipodi:cx="132"
+                   sodipodi:cy="118"
+                   sodipodi:rx="8"
+                   sodipodi:ry="8"
+                   d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+                   inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                   inkscape:export-xdpi="90"
+                   inkscape:export-ydpi="90"
+                   sodipodi:start="4.712389"
+                   sodipodi:end="5.7595865"
+                   inkscape:transform-center-x="-2.8145756"
+                   inkscape:transform-center-y="3.2500173" />
+                <path
+                   inkscape:transform-center-y="3.249994"
+                   inkscape:transform-center-x="2.8145978"
+                   sodipodi:end="5.7595865"
+                   sodipodi:start="4.712389"
+                   inkscape:export-ydpi="90"
+                   inkscape:export-xdpi="90"
+                   inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                   d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+                   sodipodi:ry="8"
+                   sodipodi:rx="8"
+                   sodipodi:cy="118"
+                   sodipodi:cx="132"
+                   id="path36355-6-4-4"
+                   style="fill:#00d4aa;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                   sodipodi:type="arc"
+                   transform="matrix(-0.6969448,2.2484149e-8,-4.6257528e-8,-0.6969467,220.91956,305.31067)" />
+                <path
+                   transform="matrix(-0.3484724,-0.6035734,0.603572,-0.3484734,103.69972,343.86251)"
+                   sodipodi:type="arc"
+                   style="fill:#ccff00;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                   id="path36357-5-2-5"
+                   sodipodi:cx="132"
+                   sodipodi:cy="118"
+                   sodipodi:rx="8"
+                   sodipodi:ry="8"
+                   d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+                   inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                   inkscape:export-xdpi="90"
+                   inkscape:export-ydpi="90"
+                   sodipodi:start="4.712389"
+                   sodipodi:end="5.7595865"
+                   inkscape:transform-center-x="3.2630773" />
+                <path
+                   inkscape:transform-center-x="2.8145777"
+                   sodipodi:end="5.7595865"
+                   sodipodi:start="4.712389"
+                   inkscape:export-ydpi="90"
+                   inkscape:export-xdpi="90"
+                   inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                   d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 Z"
+                   sodipodi:ry="8"
+                   sodipodi:rx="8"
+                   sodipodi:cy="118"
+                   sodipodi:cx="132"
+                   id="path36359-0-5-9"
+                   style="fill:#ffbf0e;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                   sodipodi:type="arc"
+                   transform="matrix(0.3484724,-0.6035734,0.603572,0.3484733,11.703006,261.6228)"
+                   inkscape:transform-center-y="-3.2500006" />
+              </g>
+              <circle
+                 inkscape:export-ydpi="90"
+                 inkscape:export-xdpi="90"
+                 inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                 id="path36361-8-8-0"
+                 style="fill:none;stroke:#000000;stroke-width:0.98948926;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+                 transform="matrix(0.8124999,0,0,0.8045157,241.75,163.13011)"
+                 cx="132"
+                 cy="118"
+                 r="8" />
+              <circle
+                 style="display:inline;opacity:0.3;fill:url(#radialGradient37501-3-6-2);fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 id="path36363-2-9-7"
+                 inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                 inkscape:export-xdpi="90"
+                 inkscape:export-ydpi="90"
+                 transform="matrix(-0.7451143,-0.08386971,0.08492794,-0.7396793,437.33358,356.39712)"
+                 cx="132"
+                 cy="118"
+                 r="8" />
+              <circle
+                 transform="matrix(0.6860851,0,0,0.6874876,258.44808,176.87656)"
+                 style="fill:none;stroke:url(#linearGradient31452);stroke-width:1.45605874;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+                 id="path36365-2-9-7"
+                 inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png"
+                 inkscape:export-xdpi="90"
+                 inkscape:export-ydpi="90"
+                 cx="132"
+                 cy="118"
+                 r="8" />
+            </g>
+          </g>
+          <g
+             inkscape:transform-center-y="0.19622957"
+             inkscape:transform-center-x="-1.373607"
+             id="ICON_RESTRICT_SELECT_OFF-9-8"
+             style="display:inline;enable-background:new"
+             transform="matrix(0.45975513,-0.19653299,0.19653299,0.45975513,138.04837,311.70175)">
+            <path
+               style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient31454);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+               d="m 367.75,440.75 1.75,-1.5 2.5,5.25 1.75,-1 -2.25,-5 2.5,0 -6.25,-6.25 z"
+               id="path45378-1-5-6-6-9"
+               sodipodi:nodetypes="cccccccc"
+               inkscape:connector-curvature="0" />
+            <rect
+               style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
+               id="rect45374-0-5-6-1-0"
+               width="16"
+               height="16"
+               x="362"
+               y="430" />
+            <path
+               style="fill:none;stroke:#000000;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+               d="m 367.5,431.5 7,7.25 -3,0 2.5,4.75 -1.75,1 -2.5,-5 -2.25,2.25 z"
+               id="path17835-7-5-7"
+               inkscape:connector-curvature="0"
+               sodipodi:nodetypes="cccccccc" />
+            <path
+               style="fill:none;stroke:#ffffff;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+               d="m 368.34375,433.75 0,5.75"
+               id="path17845-9-6-9"
+               inkscape:connector-curvature="0"
+               sodipodi:nodetypes="cc" />
+          </g>
+        </g>
       </g>
     </g>
     <g
diff --git a/release/datafiles/blender_icons16/icon16_restrict_color_off.dat b/release/datafiles/blender_icons16/icon16_restrict_color_off.dat
new file mode 100644 (file)
index 0000000..d313539
Binary files /dev/null and b/release/datafiles/blender_icons16/icon16_restrict_color_off.dat differ
diff --git a/release/datafiles/blender_icons16/icon16_restrict_color_on.dat b/release/datafiles/blender_icons16/icon16_restrict_color_on.dat
new file mode 100644 (file)
index 0000000..bb7782b
Binary files /dev/null and b/release/datafiles/blender_icons16/icon16_restrict_color_on.dat differ
diff --git a/release/datafiles/blender_icons32/icon32_restrict_color_off.dat b/release/datafiles/blender_icons32/icon32_restrict_color_off.dat
new file mode 100644 (file)
index 0000000..bbe5f61
Binary files /dev/null and b/release/datafiles/blender_icons32/icon32_restrict_color_off.dat differ
diff --git a/release/datafiles/blender_icons32/icon32_restrict_color_on.dat b/release/datafiles/blender_icons32/icon32_restrict_color_on.dat
new file mode 100644 (file)
index 0000000..46ba9e3
Binary files /dev/null and b/release/datafiles/blender_icons32/icon32_restrict_color_on.dat differ
index baa70ed08f5903705e49f53d5ad227d6d6688b47..b3d6107ccdb2d30e903602054bb98a42acbfdf6b 100644 (file)
@@ -136,7 +136,7 @@ class GreasePencilStrokeEditPanel:
     def draw(self, context):
         layout = self.layout
 
-        is_3d_view = context.space_data.type == 'VIEW_3D'
+        is_3d_view     = context.space_data.type == 'VIEW_3D'
 
         if not is_3d_view:
             layout.label(text="Select:")
@@ -151,18 +151,19 @@ class GreasePencilStrokeEditPanel:
             col.operator("gpencil.select_linked")
             col.operator("gpencil.select_more")
             col.operator("gpencil.select_less")
-
-            layout.separator()
+            col.operator("gpencil.palettecolor_select")
 
         layout.label(text="Edit:")
         row = layout.row(align=True)
         row.operator("gpencil.copy", text="Copy")
-        row.operator("gpencil.paste", text="Paste")
+        row.operator("gpencil.paste", text="Paste").type = 'COPY'
+        row.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE'
 
         col = layout.column(align=True)
-        col.operator("gpencil.delete", text="Delete")
+        col.operator("gpencil.delete")
         col.operator("gpencil.duplicate_move", text="Duplicate")
-        col.operator("transform.mirror", text="Mirror")
+        if is_3d_view:
+            col.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE'
 
         layout.separator()
 
@@ -176,9 +177,92 @@ class GreasePencilStrokeEditPanel:
 
         col = layout.column(align=True)
         col.operator("transform.bend", text="Bend")
+        col.operator("transform.mirror", text="Mirror")
         col.operator("transform.shear", text="Shear")
         col.operator("transform.tosphere", text="To Sphere")
 
+        layout.separator()
+        col = layout.column(align=True)
+        col.operator_menu_enum("gpencil.stroke_arrange", text="Arrange Strokes...", property="direction")
+        col.operator("gpencil.stroke_change_color", text="Move to Color")
+
+        layout.separator()
+        col = layout.column(align=True)
+        col.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
+        col.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
+        col.operator("gpencil.stroke_flip", text="Flip direction")
+
+        gpd = context.gpencil_data
+        if gpd:
+            col.prop(gpd, "show_stroke_direction", text="Show drawing direction")
+
+
+class GreasePencilBrushPanel:
+    # subclass must set
+    # bl_space_type = 'IMAGE_EDITOR'
+    bl_label = "Drawing Brushes"
+    bl_category = "Grease Pencil"
+    bl_region_type = 'TOOLS'
+
+    @staticmethod
+    def draw(self, context):
+        layout = self.layout
+
+        row = layout.row()
+        col = row.column()
+        ts = context.scene.tool_settings
+        if len(ts.gpencil_brushes) >= 2:
+            brows = 3
+        else:
+            brows = 2
+        col.template_list("GPENCIL_UL_brush", "", ts, "gpencil_brushes", ts.gpencil_brushes, "active_index", rows=brows)
+
+        col = row.column()
+
+        sub = col.column(align=True)
+        sub.operator("gpencil.brush_add", icon='ZOOMIN', text="")
+        sub.operator("gpencil.brush_remove", icon='ZOOMOUT', text="")
+        sub.menu("GPENCIL_MT_brush_specials", icon='DOWNARROW_HLT', text="")
+        brush = context.active_gpencil_brush
+        if brush:
+            if len(ts.gpencil_brushes) > 1:
+                col.separator()
+                sub = col.column(align=True)
+                sub.operator("gpencil.brush_move", icon='TRIA_UP', text="").type = 'UP'
+                sub.operator("gpencil.brush_move", icon='TRIA_DOWN', text="").type = 'DOWN'
+
+        # Brush details
+        if brush is not None:
+            row = layout.row()
+            row.prop(brush, "line_width")
+            row = layout.row(align=True)
+            row.prop(brush, "use_random_pressure", text='', icon='RNDCURVE')
+            row.prop(brush, "pen_sensitivity_factor", slider=True)
+            row.prop(brush, "use_pressure", text='', icon='STYLUS_PRESSURE')
+            row = layout.row(align=True)
+            row.prop(brush, "use_random_strength", text='', icon='RNDCURVE')
+            row.prop(brush, "strength", slider=True)
+            row.prop(brush, "use_strength_pressure", text='', icon='STYLUS_PRESSURE')
+            row = layout.row(align=True)
+            row.prop(brush, "random_press", slider=True)
+
+            row = layout.row(align=True)
+            row.prop(brush, "jitter", slider=True)
+            row.prop(brush, "use_jitter_pressure", text='', icon='STYLUS_PRESSURE')
+            row = layout.row()
+            row.prop(brush, "angle", slider=True)
+            row.prop(brush, "angle_factor", text="Factor", slider=True)
+
+            box = layout.box()
+            col = box.column(align=True)
+            col.label(text="Stroke Quality:")
+            col.prop(brush, "pen_smooth_factor")
+            col.prop(brush, "pen_smooth_steps")
+            col.separator()
+            row = col.row(align=False)
+            row.prop(brush, "pen_subdivision_steps")
+            row.prop(brush, "random_subdiv", text='Randomness', slider=True)
+
 
 class GreasePencilStrokeSculptPanel:
     # subclass must set
@@ -203,7 +287,7 @@ class GreasePencilStrokeSculptPanel:
         tool = settings.tool
         brush = settings.brush
 
-        layout.column().prop(settings, "tool", expand=True)
+        layout.column().prop(settings, "tool")
 
         col = layout.column()
         col.prop(brush, "size", slider=True)
@@ -211,6 +295,11 @@ class GreasePencilStrokeSculptPanel:
         row.prop(brush, "strength", slider=True)
         row.prop(brush, "use_pressure_strength", text="")
         col.prop(brush, "use_falloff")
+        if tool in {'SMOOTH', 'RANDOMIZE'}:
+            row = layout.row(align=True)
+            row.prop(settings, "affect_position", text="Position", icon='MESH_DATA', toggle=True)
+            row.prop(settings, "affect_strength", text="Strength", icon='COLOR', toggle=True)
+            row.prop(settings, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
 
         layout.separator()
 
@@ -220,18 +309,54 @@ class GreasePencilStrokeSculptPanel:
             row = layout.row(align=True)
             row.prop_enum(brush, "direction", 'ADD', text="Pinch")
             row.prop_enum(brush, "direction", 'SUBTRACT', text="Inflate")
-        elif tool == 'TWIST':
+        elif settings.tool == 'TWIST':
             row = layout.row(align=True)
             row.prop_enum(brush, "direction", 'SUBTRACT', text="CW")
             row.prop_enum(brush, "direction", 'ADD', text="CCW")
 
-        layout.separator()
-        layout.prop(settings, "use_select_mask")
+        row = layout.row(align=True)
+        row.prop(settings, "use_select_mask")
+        row = layout.row(align=True)
+        row.prop(settings, "selection_alpha", slider=True)
 
         if tool == 'SMOOTH':
             layout.prop(brush, "affect_pressure")
 
 
+class GreasePencilBrushCurvesPanel:
+    # subclass must set
+    # bl_space_type = 'IMAGE_EDITOR'
+    bl_label = "Grease Pencil Curves"
+    bl_category = "Grease Pencil"
+    bl_region_type = 'TOOLS'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        if context.active_gpencil_brush is None:
+            return False
+
+        brush = context.active_gpencil_brush
+        return bool(brush)
+
+    @staticmethod
+    def draw(self, context):
+        layout = self.layout
+        brush = context.active_gpencil_brush
+        # Brush
+        layout.label("Sensitivity")
+        box = layout.box()
+        box.template_curve_mapping(brush, "curve_sensitivity", brush=True)
+
+        layout.label("Strength")
+        box = layout.box()
+        box.template_curve_mapping(brush, "curve_strength", brush=True)
+
+        layout.label("Jitter")
+        box = layout.box()
+        box.template_curve_mapping(brush, "curve_jitter", brush=True)
+
+
 ###############################
 
 class GPENCIL_PIE_tool_palette(Menu):
@@ -282,6 +407,7 @@ class GPENCIL_PIE_tool_palette(Menu):
                 col.operator("gpencil.select_all", text="Select All", icon='PARTICLE_POINT')
                 col.operator("gpencil.select_all", text="Select Inverse", icon='BLANK1')
                 col.operator("gpencil.select_linked", text="Select Linked", icon='LINKED')
+                col.operator("gpencil.palettecolor_select", text="Select Color", icon='COLOR')
 
                 # NE - Select (Modal)
                 col = pie.column()
@@ -315,24 +441,47 @@ class GPENCIL_PIE_settings_palette(Menu):
         pie = layout.menu_pie()
         # gpd = context.gpencil_data
         gpl = context.active_gpencil_layer
+        palcolor = context.active_gpencil_palettecolor
+        brush = context.active_gpencil_brush
 
         # W - Stroke draw settings
         col = pie.column(align=True)
-        col.label(text="Stroke")
-        col.prop(gpl, "color", text="")
-        col.prop(gpl, "alpha", text="", slider=True)
+        if palcolor is not None:
+            col.label(text="Stroke")
+            col.prop(palcolor, "color", text="")
+            col.prop(palcolor, "alpha", text="", slider=True)
 
         # E - Fill draw settings
         col = pie.column(align=True)
-        col.label(text="Fill")
-        col.prop(gpl, "fill_color", text="")
-        col.prop(gpl, "fill_alpha", text="", slider=True)
+        if palcolor is not None:
+            col.label(text="Fill")
+            col.prop(palcolor, "fill_color", text="")
+            col.prop(palcolor, "fill_alpha", text="", slider=True)
 
-        # S - Layer settings
+        # S Brush settings
         col = pie.column()
-        col.prop(gpl, "line_width", slider=True)
-        # col.prop(gpl, "use_volumetric_strokes")
-        col.prop(gpl, "use_onion_skinning")
+        col.label("Active Brush:      ")
+
+        row = col.row()
+        row.operator_context = 'EXEC_REGION_WIN'
+        row.operator_menu_enum("gpencil.brush_change", "brush", text="", icon='BRUSH_DATA')
+        row.prop(brush, "name", text="")
+
+        col.prop(brush, "line_width", slider=True)
+        row = col.row(align=True)
+        row.prop(brush, "use_random_pressure", text='', icon='RNDCURVE')
+        row.prop(brush, "pen_sensitivity_factor", slider=True)
+        row.prop(brush, "use_pressure", text='', icon='STYLUS_PRESSURE')
+        row = col.row(align=True)
+        row.prop(brush, "use_random_strength", text='', icon='RNDCURVE')
+        row.prop(brush, "strength", slider=True)
+        row.prop(brush, "use_strength_pressure", text='', icon='STYLUS_PRESSURE')
+        row = col.row(align=True)
+        row.prop(brush, "jitter", slider=True)
+        row.prop(brush, "use_jitter_pressure", text='', icon='STYLUS_PRESSURE')
+        row = col.row()
+        row.prop(brush, "angle", slider=True)
+        row.prop(brush, "angle_factor", text="Factor", slider=True)
 
         # N - Active Layer
         col = pie.column()
@@ -347,6 +496,35 @@ class GPENCIL_PIE_settings_palette(Menu):
         row = col.row()
         row.prop(gpl, "lock")
         row.prop(gpl, "hide")
+        col.prop(gpl, "use_onion_skinning")
+
+        # NW - Move stroke Down
+        col = pie.column(align=True)
+        col.label("Arrange Strokes")
+        col.operator("gpencil.stroke_arrange", text="Send to Back").direction = 'BOTTOM'
+        col.operator("gpencil.stroke_arrange", text="Send Backward").direction = 'DOWN'
+
+        # NE - Move stroke Up
+        col = pie.column(align=True)
+        col.label("Arrange Strokes")
+        col.operator("gpencil.stroke_arrange", text="Bring to Front").direction = 'TOP'
+        col.operator("gpencil.stroke_arrange", text="Bring Forward").direction = 'UP'
+
+        # SW - Move stroke to color
+        col = pie.column(align=True)
+        col.operator("gpencil.stroke_change_color", text="Move to Color")
+
+        # SE - Join strokes
+        col = pie.column(align=True)
+        col.label("Join Strokes")
+        row = col.row()
+        row.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
+        row.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
+        col.operator("gpencil.stroke_flip", text="Flip direction")
+
+        gpd = context.gpencil_data
+        if gpd:
+            col.prop(gpd, "show_stroke_direction", text="Show drawing direction")
 
 
 class GPENCIL_PIE_tools_more(Menu):
@@ -411,6 +589,11 @@ class GPENCIL_PIE_sculpt(Menu):
         row.prop(brush, "strength", slider=True)
         # row.prop(brush, "use_pressure_strength", text="", icon_only=True)
         col.prop(brush, "use_falloff")
+        if settings.tool in {'SMOOTH', 'RANDOMIZE'}:
+            row = col.row(align=True)
+            row.prop(settings, "affect_position", text="Position", icon='MESH_DATA', toggle=True)
+            row.prop(settings, "affect_strength", text="Strength", icon='COLOR', toggle=True)
+            row.prop(settings, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
 
         # S - Change Brush Type Shortcuts
         row = pie.row()
@@ -422,6 +605,7 @@ class GPENCIL_PIE_sculpt(Menu):
         row = pie.row()
         row.prop_enum(settings, "tool", value='SMOOTH')
         row.prop_enum(settings, "tool", value='THICKNESS')
+        row.prop_enum(settings, "tool", value='STRENGTH')
         row.prop_enum(settings, "tool", value='RANDOMIZE')
 
 
@@ -448,6 +632,48 @@ class GPENCIL_MT_snap(Menu):
 ###############################
 
 
+class GPENCIL_UL_brush(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        # assert(isinstance(item, bpy.types.GPencilBrush)
+        brush = item
+
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            row = layout.row(align=True)
+            row.prop(brush, "name", text="", emboss=False, icon='BRUSH_DATA')
+        elif self.layout_type == 'GRID':
+            layout.alignment = 'CENTER'
+            layout.label(text="", icon_value=icon)
+
+
+class GPENCIL_UL_palettecolor(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        # assert(isinstance(item, bpy.types.PaletteColor)
+        palcolor = item
+
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            if palcolor.lock:
+                layout.active = False
+
+            split = layout.split(percentage=0.25)
+            row = split.row(align=True)
+            row.prop(palcolor, "color", text="", emboss=palcolor.is_stroke_visible)
+            row.prop(palcolor, "fill_color", text="", emboss=palcolor.is_fill_visible)
+            split.prop(palcolor, "info", text="", emboss=False)
+
+            row = layout.row(align=True)
+            row.prop(palcolor, "lock", text="", emboss=False)
+            row.prop(palcolor, "hide", text="", emboss=False)
+            if palcolor.ghost is True:
+                icon = 'GHOST_DISABLED'
+            else:
+                icon = 'GHOST_ENABLED'
+            row.prop(palcolor, "ghost", text="", icon=icon, emboss=False)
+
+        elif self.layout_type == 'GRID':
+            layout.alignment = 'CENTER'
+            layout.label(text="", icon_value=icon)
+
+
 class GPENCIL_UL_layer(UIList):
     def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
         # assert(isinstance(item, bpy.types.GPencilLayer)
@@ -457,15 +683,19 @@ class GPENCIL_UL_layer(UIList):
             if gpl.lock:
                 layout.active = False
 
-            split = layout.split(percentage=0.25)
-            row = split.row(align=True)
-            row.prop(gpl, "color", text="", emboss=gpl.is_stroke_visible)
-            row.prop(gpl, "fill_color", text="", emboss=gpl.is_fill_visible)
-            split.prop(gpl, "info", text="", emboss=False)
+            row = layout.row(align=True)
+            if gpl.is_parented:
+                icon = 'BONE_DATA'
+            else:
+                icon = 'BLANK1'
+
+            row.label(text="", icon=icon)
+            row.prop(gpl, "info", text="", emboss=False)
 
             row = layout.row(align=True)
             row.prop(gpl, "lock", text="", emboss=False)
             row.prop(gpl, "hide", text="", emboss=False)
+            row.prop(gpl, "unlock_color", text="", emboss=False)
         elif self.layout_type == 'GRID':
             layout.alignment = 'CENTER'
             layout.label(text="", icon_value=icon)
@@ -489,11 +719,40 @@ class GPENCIL_MT_layer_specials(Menu):
         layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All")
         layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="UnLock All")
 
+        layout.separator()
+
+        layout.operator("gpencil.layer_merge", icon='NLA', text="Merge Down")
+
+
+class GPENCIL_MT_brush_specials(Menu):
+    bl_label = "Layer"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.operator("gpencil.brush_copy", icon='PASTEDOWN', text="Copy current drawing brush")
+        layout.operator("gpencil.brush_presets_create", icon='HELP', text="Create a set of predefined brushes")
+
+
+class GPENCIL_MT_palettecolor_specials(Menu):
+    bl_label = "Layer"
+
+    def draw(self, context):
+        layout = self.layout
+
+        layout.operator("gpencil.palettecolor_reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
+        layout.operator("gpencil.palettecolor_hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True
+
+        layout.separator()
+
+        layout.operator("gpencil.palettecolor_lock_all", icon='LOCKED', text="Lock All")
+        layout.operator("gpencil.palettecolor_unlock_all", icon='UNLOCKED', text="UnLock All")
+        layout.operator("gpencil.palettecolor_copy", icon='PASTEDOWN', text="Copy Color")
+
 
 class GreasePencilDataPanel:
     # subclass must set
     # bl_space_type = 'IMAGE_EDITOR'
-    bl_label = "Grease Pencil"
+    bl_label = "Grease Pencil Layers"
     bl_region_type = 'UI'
 
     @staticmethod
@@ -553,46 +812,56 @@ class GreasePencilDataPanel:
                 col.separator()
 
                 sub = col.column(align=True)
-                sub.operator("gpencil.layer_isolate", icon='SOLO_OFF', text="").affect_visibility = False
+                sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
                 sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
 
         if gpl:
-            self.draw_layer(layout, gpl)
+            self.draw_layer(context, layout, gpl)
 
-    def draw_layer(self, layout, gpl):
+    def draw_layer(self, context, layout, gpl):
+        row = layout.row(align=True)
+        row.prop(gpl, "opacity", text="Opacity", slider=True)
         # layer settings
         split = layout.split(percentage=0.5)
         split.active = not gpl.lock
-
-        # Column 1 - Stroke
-        col = split.column(align=True)
-        col.label(text="Stroke:")
-        col.prop(gpl, "color", text="")
-        col.prop(gpl, "alpha", slider=True)
-
-        # Column 2 - Fill
-        col = split.column(align=True)
-        col.label(text="Fill:")
-        col.prop(gpl, "fill_color", text="")
-        col.prop(gpl, "fill_alpha", text="Opacity", slider=True)
-
         # Options
-        col = layout.column(align=True)
+        split = layout.split(percentage=0.5)
+        col = split.column(align=True)
         col.active = not gpl.lock
-        col.prop(gpl, "line_width", slider=True)
+        col.prop(gpl, "show_x_ray")
 
-        split = layout.split(percentage=0.5)
-        split.active = not gpl.lock
+        col.label("Tint")
+        col.prop(gpl, "tint_color", text="")
+        col.prop(gpl, "tint_factor", text="Factor", slider=True)
 
         col = split.column(align=True)
-        col.prop(gpl, "use_volumetric_strokes")
+        col.active = not gpl.lock
         col.prop(gpl, "show_points", text="Points")
+        # Full-Row - Parent
+        '''
+        row = layout.row()
+        if context.area.type == 'VIEW_3D' and not gpl.lock:
+            row.enabled = True
+        else:
+            row.enabled = False
+        '''
 
-        col = split.column(align=True)
-        col.prop(gpl, "use_hq_fill")
-        col.prop(gpl, "show_x_ray")
+        # col = row.column()
+        if context.space_data.type == 'VIEW_3D':
+            col.label(text="Parent:")
+            col.prop(gpl, "parent", text="")
 
-        layout.separator()
+            sub = col.column()
+            sub.prop(gpl, "parent_type", text="")
+            parent = gpl.parent
+            if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE':
+                sub.prop_search(gpl, "parent_bone", parent.data, "bones", text="")
+
+        # Full-Row - Thickness
+        row = layout.row(align=True)
+        row.active = not gpl.lock
+        row.prop(gpl, "line_change", text="Thickness change", slider=True)
+        row.operator("gpencil.stroke_apply_thickness", icon='STYLUS_PRESSURE', text="")
 
         # Full-Row - Frame Locking (and Delete Frame)
         row = layout.row(align=True)
@@ -606,8 +875,6 @@ class GreasePencilDataPanel:
         row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED')
         row.operator("gpencil.active_frame_delete", text="", icon='X')
 
-        layout.separator()
-
         # Onion skinning
         col = layout.column(align=True)
         col.active = not gpl.lock
@@ -633,14 +900,103 @@ class GreasePencilDataPanel:
         row.prop(gpl, "after_color", text="")
         sub.prop(gpl, "ghost_after_range", text="After")
 
-        # Smooth and subdivide new strokes
-        layout.separator()
-        col = layout.column(align=True)
-        col.label(text="New Stroke Quality:")
-        col.prop(gpl, "pen_smooth_factor")
-        col.prop(gpl, "pen_smooth_steps")
-        col.separator()
-        col.prop(gpl, "pen_subdivision_steps")
+
+class GreasePencilPaletteColorPanel:
+    # subclass must set
+    bl_label = "Grease Pencil Colors"
+    bl_region_type = 'UI'
+
+    @classmethod
+    def poll(cls, context):
+        if context.gpencil_data is None:
+            return False
+
+        gpd = context.gpencil_data
+        return bool(gpd.layers.active)
+
+    @staticmethod
+    def draw(self, context):
+        layout = self.layout
+        palette = context.active_gpencil_palette
+
+        if palette:
+            row = layout.row(align=True)
+            row.operator_context = 'EXEC_REGION_WIN'
+            row.operator_menu_enum("gpencil.palette_change", "palette", text="", icon='COLOR')
+            row.prop(palette, "name", text="")
+            row.operator("gpencil.palette_add", icon='ZOOMIN', text="")
+            row.operator("gpencil.palette_remove", icon='ZOOMOUT', text="")
+
+            # Palette colors
+            row = layout.row()
+            col = row.column()
+            if len(palette.colors) >= 2:
+                color_rows = 5
+            else:
+                color_rows = 2
+            col.template_list("GPENCIL_UL_palettecolor", "", palette, "colors", palette.colors, "active_index",
+                              rows=color_rows)
+
+            col = row.column()
+
+            sub = col.column(align=True)
+            sub.operator("gpencil.palettecolor_add", icon='ZOOMIN', text="")
+            sub.operator("gpencil.palettecolor_remove", icon='ZOOMOUT', text="")
+
+            palcol = context.active_gpencil_palettecolor
+            if palcol:
+                sub.menu("GPENCIL_MT_palettecolor_specials", icon='DOWNARROW_HLT', text="")
+
+            if len(palette.colors) > 1:
+                col.separator()
+
+                sub = col.column(align=True)
+                sub.operator("gpencil.palettecolor_move", icon='TRIA_UP', text="").direction = 'UP'
+                sub.operator("gpencil.palettecolor_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+
+                col.separator()
+                sub = col.column(align=True)
+                sub.operator("gpencil.palettecolor_isolate", icon='LOCKED', text="").affect_visibility = False
+                sub.operator("gpencil.palettecolor_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
+                sub.operator("gpencil.stroke_lock_color", icon='BORDER_RECT', text="")
+                sub.operator("gpencil.palette_lock_layer", icon='COLOR', text="")
+
+            pcolor = palette.colors.active
+            if pcolor:
+                self.draw_palettecolors(layout, pcolor)
+
+    # ----------------------------------------------
+    # Draw palette colors
+    # ----------------------------------------------
+    def draw_palettecolors(self, layout, pcolor):
+        # color settings
+        split = layout.split(percentage=0.5)
+        split.active = not pcolor.lock
+
+        # Column 1 - Stroke
+        col = split.column(align=True)
+        col.active = not pcolor.lock
+        col.label(text="Stroke:")
+        col.prop(pcolor, "color", text="")
+        col.prop(pcolor, "alpha", slider=True)
+
+        # Column 2 - Fill
+        col = split.column(align=True)
+        col.active = not pcolor.lock
+        col.label(text="Fill:")
+        col.prop(pcolor, "fill_color", text="")
+        col.prop(pcolor, "fill_alpha", text="Opacity", slider=True)
+
+        # Options
+        split = layout.split(percentage=0.5)
+        split.active = not pcolor.lock
+
+        col = split.column(align=True)
+        col.active = not pcolor.lock
+        col.prop(pcolor, "use_volumetric_strokes")
+        col = split.column(align=True)
+        col.active = not pcolor.lock
+        col.prop(pcolor, "use_hq_fill")
 
 
 class GreasePencilToolsPanel:
index 58bb956f653afa01d409ea8bbae35f5a54106e69..799f1e20dc673ee8c82e53f692488ac9d4909542 100644 (file)
@@ -25,8 +25,10 @@ from bl_ui.properties_grease_pencil_common import (
         GreasePencilDrawingToolsPanel,
         GreasePencilStrokeEditPanel,
         GreasePencilStrokeSculptPanel,
-        GreasePencilDataPanel
-        )
+        GreasePencilBrushPanel,
+        GreasePencilBrushCurvesPanel,
+        GreasePencilDataPanel,
+        GreasePencilPaletteColorPanel)
 
 
 class CLIP_UL_tracking_objects(UIList):
@@ -1126,6 +1128,16 @@ class CLIP_PT_grease_pencil(GreasePencilDataPanel, CLIP_PT_clip_view_panel, Pane
     # But, this should only be visible in "clip" view
 
 
+# Grease Pencil palette colors
+class CLIP_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, CLIP_PT_clip_view_panel, Panel):
+    bl_space_type = 'CLIP_EDITOR'
+    bl_region_type = 'UI'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    # NOTE: this is just a wrapper around the generic GP Panel
+    # But, this should only be visible in "clip" view
+
+
 # Grease Pencil drawing tools
 class CLIP_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
     bl_space_type = 'CLIP_EDITOR'
@@ -1141,6 +1153,15 @@ class CLIP_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
     bl_space_type = 'CLIP_EDITOR'
 
 
+# Grease Pencil drawing brushes
+class CLIP_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
+    bl_space_type = 'CLIP_EDITOR'
+
+
+# Grease Pencil drawing curves
+class CLIP_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
+    bl_space_type = 'CLIP_EDITOR'
+
 class CLIP_MT_view(Menu):
     bl_label = "View"
 
index 9f719bc793ed4aad64bff7c18ad84e0b5b62cbd4..bf6df05c2b2a4808e4ce52a5ccfd144a96ab4a7a 100644 (file)
@@ -29,7 +29,10 @@ from bl_ui.properties_grease_pencil_common import (
         GreasePencilDrawingToolsPanel,
         GreasePencilStrokeEditPanel,
         GreasePencilStrokeSculptPanel,
+        GreasePencilBrushPanel,
+        GreasePencilBrushCurvesPanel,
         GreasePencilDataPanel,
+        GreasePencilPaletteColorPanel
         )
 from bpy.app.translations import pgettext_iface as iface_
 
@@ -1187,6 +1190,14 @@ class IMAGE_PT_grease_pencil(GreasePencilDataPanel, Panel):
     # NOTE: this is just a wrapper around the generic GP Panel
 
 
+# Grease Pencil palette colors
+class IMAGE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
+    bl_space_type = 'IMAGE_EDITOR'
+    bl_region_type = 'UI'
+
+    # NOTE: this is just a wrapper around the generic GP Panel
+
+
 # Grease Pencil drawing tools
 class IMAGE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
     bl_space_type = 'IMAGE_EDITOR'
@@ -1202,5 +1213,15 @@ class IMAGE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
     bl_space_type = 'IMAGE_EDITOR'
 
 
+# Grease Pencil drawing brushes
+class IMAGE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
+    bl_space_type = 'IMAGE_EDITOR'
+
+
+# Grease Pencil drawing curves
+class IMAGE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
+    bl_space_type = 'IMAGE_EDITOR'
+
+
 if __name__ == "__main__":  # only for live edit.
     bpy.utils.register_module(__name__)
index ee342265f3d5a9de39aeea0a41be59c2903483ec..8821fa0ca58fd5a683c0fe3ec57269840c65e8f2 100644 (file)
@@ -25,8 +25,11 @@ from bl_ui.properties_grease_pencil_common import (
         GreasePencilDrawingToolsPanel,
         GreasePencilStrokeEditPanel,
         GreasePencilStrokeSculptPanel,
+        GreasePencilBrushPanel,
+        GreasePencilBrushCurvesPanel,
         GreasePencilDataPanel,
-        GreasePencilToolsPanel,
+        GreasePencilPaletteColorPanel,
+        GreasePencilToolsPanel
         )
 
 
@@ -464,6 +467,19 @@ class NODE_PT_grease_pencil(GreasePencilDataPanel, Panel):
         return snode is not None and snode.node_tree is not None
 
 
+# Grease Pencil palette colors
+class NODE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
+    bl_space_type = 'NODE_EDITOR'
+    bl_region_type = 'UI'
+
+    # NOTE: this is just a wrapper around the generic GP Panel
+
+    @classmethod
+    def poll(cls, context):
+        snode = context.space_data
+        return snode is not None and snode.node_tree is not None
+
+
 class NODE_PT_grease_pencil_tools(GreasePencilToolsPanel, Panel):
     bl_space_type = 'NODE_EDITOR'
     bl_region_type = 'UI'
@@ -494,6 +510,16 @@ class NODE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
     bl_space_type = 'NODE_EDITOR'
     bl_region_type = 'TOOLS'
 
+# Grease Pencil drawing brushes
+class NODE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
+    bl_space_type = 'NODE_EDITOR'
+    bl_region_type = 'TOOLS'
+
+# Grease Pencil drawing curves
+class NODE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
+    bl_space_type = 'NODE_EDITOR'
+    bl_region_type = 'TOOLS'
+
 # -----------------------------
 
 
index 4d1b91043446cbb433b3ce7d8cf764bd8b95d6eb..26136a8e024fcfc58f3e2f96fe1337a99f04e548 100644 (file)
 import bpy
 from bpy.types import Header, Menu, Panel
 from rna_prop_ui import PropertyPanel
-from bl_ui.properties_grease_pencil_common import GreasePencilDataPanel, GreasePencilToolsPanel
+from bl_ui.properties_grease_pencil_common import (
+        GreasePencilDataPanel,
+        GreasePencilPaletteColorPanel,
+        GreasePencilToolsPanel,
+        )
 from bpy.app.translations import pgettext_iface as iface_
 
 
@@ -1186,6 +1190,14 @@ class SEQUENCER_PT_grease_pencil(GreasePencilDataPanel, SequencerButtonsPanel_Ou
     # But, it should only show up when there are images in the preview region
 
 
+class SEQUENCER_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, SequencerButtonsPanel_Output, Panel):
+    bl_space_type = 'SEQUENCE_EDITOR'
+    bl_region_type = 'UI'
+
+    # NOTE: this is just a wrapper around the generic GP Panel
+    # But, it should only show up when there are images in the preview region
+
+
 class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsPanel_Output, Panel):
     bl_space_type = 'SEQUENCE_EDITOR'
     bl_region_type = 'UI'
index 681fa8e39aa2dcffde58875b9954e34c102dc006..5f16957b4355a395a96233cd3fe298e04e1690be 100644 (file)
 # <pep8 compliant>
 import bpy
 from bpy.types import Header, Menu, Panel
-from bl_ui.properties_grease_pencil_common import GreasePencilDataPanel
+from bl_ui.properties_grease_pencil_common import (
+        GreasePencilDataPanel,
+        GreasePencilPaletteColorPanel,
+        )
 from bl_ui.properties_paint_common import UnifiedPaintPanel
 from bpy.app.translations import contexts as i18n_contexts
 
@@ -139,7 +142,9 @@ class VIEW3D_HT_header(Header):
             # XXX: icon
             layout.prop(context.gpencil_data, "use_onion_skinning", text="Onion Skins", icon='PARTICLE_PATH')
 
-            layout.prop(context.tool_settings.gpencil_sculpt, "use_select_mask")
+            row = layout.row(align=True)
+            row.prop(context.tool_settings.gpencil_sculpt, "use_select_mask")
+            row.prop(context.tool_settings.gpencil_sculpt, "selection_alpha", slider=True)
 
 
 class VIEW3D_MT_editor_menus(Menu):
@@ -3079,6 +3084,13 @@ class VIEW3D_PT_grease_pencil(GreasePencilDataPanel, Panel):
     # NOTE: this is just a wrapper around the generic GP Panel
 
 
+class VIEW3D_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'UI'
+
+    # NOTE: this is just a wrapper around the generic GP Panel
+
+
 class VIEW3D_PT_view3d_properties(Panel):
     bl_space_type = 'VIEW_3D'
     bl_region_type = 'UI'
index e9f4a45c2c3b39d394d61da1eeaaf28b2a226c88..8019c8d2f3400e00a4f3dbadbfeaaa6dc821ecd6 100644 (file)
@@ -22,7 +22,9 @@ from bpy.types import Menu, Panel, UIList
 from bl_ui.properties_grease_pencil_common import (
         GreasePencilDrawingToolsPanel,
         GreasePencilStrokeEditPanel,
-        GreasePencilStrokeSculptPanel
+        GreasePencilStrokeSculptPanel,
+        GreasePencilBrushPanel,
+        GreasePencilBrushCurvesPanel
         )
 from bl_ui.properties_paint_common import (
         UnifiedPaintPanel,
@@ -1965,6 +1967,15 @@ class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel)
     bl_space_type = 'VIEW_3D'
 
 
+# Grease Pencil drawing brushes
+class VIEW3D_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
+    bl_space_type = 'VIEW_3D'
+
+# Grease Pencil drawingcurves
+class VIEW3D_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
+    bl_space_type = 'VIEW_3D'
+
+
 # Note: moved here so that it's always in last position in 'Tools' panels!
 class VIEW3D_PT_tools_history(View3DPanel, Panel):
     bl_category = "Tools"
index 618b36c5851585786cb72a86b70455b6766b4253..483fefbd89c9bd34a122304495b2278f8cecde2a 100644 (file)
@@ -28,7 +28,7 @@
  * and keep comment above the defines.
  * Use STRINGIFY() rather than defining with quotes */
 #define BLENDER_VERSION         277
-#define BLENDER_SUBVERSION      1
+#define BLENDER_SUBVERSION      3
 /* Several breakages with 270, e.g. constraint deg vs rad */
 #define BLENDER_MINVERSION      270
 #define BLENDER_MINSUBVERSION   6
index 65a68a4387cfe500a8d1810f179474c3cbeed5c3..30ac310c2df62ea8d6a041fd5e089cc6a70a50e1 100644 (file)
@@ -58,6 +58,9 @@ struct bPoseChannel;
 struct bGPdata;
 struct bGPDlayer;
 struct bGPDframe;
+struct bGPDpalette;
+struct bGPDpalettecolor;
+struct bGPDbrush;
 struct wmWindow;
 struct wmWindowManager;
 struct SpaceText;
@@ -283,6 +286,9 @@ int CTX_data_visible_pose_bones(const bContext *C, ListBase *list);
 struct bGPdata *CTX_data_gpencil_data(const bContext *C);
 struct bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C);
 struct bGPDframe *CTX_data_active_gpencil_frame(const bContext *C);
+struct bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C);
+struct bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C);
+struct bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C);
 int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list);
 int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list);
 int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list);
index e9e3cd3b16e489ed05e57907b5fda9f8638c7541..cbf167de25c99c2d41fb898d3c7db5e9825a40ce 100644 (file)
  *  \author Joshua Leung
  */
 
+struct ToolSettings;
 struct ListBase;
 struct bGPdata;
 struct bGPDlayer;
 struct bGPDframe;
 struct bGPDstroke;
+struct bGPDpalette;
+struct bGPDpalettecolor;
 struct Main;
 
 /* ------------ Grease-Pencil API ------------------ */
 
+void free_gpencil_stroke(struct bGPDstroke *gps);
 bool free_gpencil_strokes(struct bGPDframe *gpf);
 void free_gpencil_frames(struct bGPDlayer *gpl);
 void free_gpencil_layers(struct ListBase *list);
-void BKE_gpencil_free(struct bGPdata *gpd);
+void free_gpencil_brushes(struct ListBase *list);
+void free_gpencil_palettes(struct ListBase *list);
+void BKE_gpencil_free(struct bGPdata *gpd, bool free_palettes);
 
 void gpencil_stroke_sync_selection(struct bGPDstroke *gps);
 
@@ -52,17 +58,26 @@ struct bGPDframe *gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
 struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive);
 struct bGPdata *gpencil_data_addnew(const char name[]);
 
-struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src);
-struct bGPDlayer *gpencil_layer_duplicate(struct bGPDlayer *src);
+struct bGPDframe *gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
+struct bGPDlayer *gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
 struct bGPdata *gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy);
 
 void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local);
 
 void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
 
+struct bGPDpalette *gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive);
+struct bGPDpalette *gpencil_palette_duplicate(const struct bGPDpalette *palette_src);
+struct bGPDpalettecolor *gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive);
+
+struct bGPDbrush *gpencil_brush_addnew(struct ToolSettings *ts, const char *name, bool setactive);
+struct bGPDbrush *gpencil_brush_duplicate(const struct bGPDbrush *brush_src);
+void gpencil_brush_init_presets(struct ToolSettings *ts);
+
 
 /* Stroke and Fill - Alpha Visibility Threshold */
 #define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
+#define GPENCIL_STRENGTH_MIN 0.003f
 
 bool gpencil_layer_is_editable(const struct bGPDlayer *gpl);
 
@@ -87,4 +102,20 @@ struct bGPDlayer *gpencil_layer_getactive(struct bGPdata *gpd);
 void gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
 void gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
 
+struct bGPDbrush *gpencil_brush_getactive(struct ToolSettings *ts);
+void gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
+void gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *palette);
+
+struct bGPDpalette *gpencil_palette_getactive(struct bGPdata *gpd);
+void gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active);
+void gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette);
+void gpencil_palette_change_strokes(struct bGPdata *gpd);
+
+struct bGPDpalettecolor *gpencil_palettecolor_getactive(struct bGPDpalette *palette);
+void gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active);
+void gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor);
+struct bGPDpalettecolor *gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name);
+void gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname);
+void gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name);
+
 #endif /*  __BKE_GPENCIL_H__ */
index 5b7698544e0361f65b17e255aff43fc050bc3a09..9d5a95df8383e314380f6436abd277fef8b2fc62 100644 (file)
@@ -1112,6 +1112,21 @@ bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C)
        return ctx_data_pointer_get(C, "active_gpencil_layer");
 }
 
+bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C)
+{
+       return ctx_data_pointer_get(C, "active_gpencil_palette");
+}
+
+bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C)
+{
+       return ctx_data_pointer_get(C, "active_gpencil_palettecolor");
+}
+
+bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C)
+{
+       return ctx_data_pointer_get(C, "active_gpencil_brush");
+}
+
 bGPDframe *CTX_data_active_gpencil_frame(const bContext *C)
 {
        return ctx_data_pointer_get(C, "active_gpencil_frame");
index 8621da0d42e3fa0610408a6be61dae1ec88d3c43..083e0d050e6879718779ba74fd1135a60c5c66b1 100644 (file)
@@ -18,7 +18,7 @@
  * The Original Code is Copyright (C) 2008, Blender Foundation
  * This is a new part of Blender
  *
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
  *
  * ***** END GPL LICENSE BLOCK *****
  */
 
 #include "DNA_gpencil_types.h"
 #include "DNA_userdef_types.h"
+#include "DNA_scene_types.h"
 
 #include "BKE_animsys.h"
 #include "BKE_global.h"
 #include "BKE_gpencil.h"
+#include "BKE_colortools.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
 
 
 /* --------- Memory Management ------------ */
 
+/* free stroke, doesn't unlink from any listbase */
+void free_gpencil_stroke(bGPDstroke *gps)
+{
+       if (gps == NULL) {
+               return;
+       }
+
+       /* free stroke memory arrays, then stroke itself */
+       if (gps->points)
+               MEM_freeN(gps->points);
+       if (gps->triangles)
+               MEM_freeN(gps->triangles);
+
+       MEM_freeN(gps);
+}
+
 /* Free strokes belonging to a gp-frame */
 bool free_gpencil_strokes(bGPDframe *gpf)
 {
-       bGPDstroke *gps, *gpsn;
+       bGPDstroke *gps_next;
        bool changed = (BLI_listbase_is_empty(&gpf->strokes) == false);
 
        /* free strokes */
-       for (gps = gpf->strokes.first; gps; gps = gpsn) {
-               gpsn = gps->next;
-               
-               /* free stroke memory arrays, then stroke itself */
-               if (gps->points) MEM_freeN(gps->points);
-               if (gps->triangles) MEM_freeN(gps->triangles);
-               BLI_freelinkN(&gpf->strokes, gps);
+       for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps_next) {
+               gps_next = gps->next;
+               free_gpencil_stroke(gps);
        }
+       BLI_listbase_clear(&gpf->strokes);
 
        return changed;
 }
@@ -79,14 +94,14 @@ bool free_gpencil_strokes(bGPDframe *gpf)
 /* Free all of a gp-layer's frames */
 void free_gpencil_frames(bGPDlayer *gpl)
 {
-       bGPDframe *gpf, *gpfn;
+       bGPDframe *gpf_next;
        
        /* error checking */
        if (gpl == NULL) return;
        
        /* free frames */
-       for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
-               gpfn = gpf->next;
+       for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf_next) {
+               gpf_next = gpf->next;
                
                /* free strokes and their associated memory */
                free_gpencil_strokes(gpf);
@@ -95,17 +110,79 @@ void free_gpencil_frames(bGPDlayer *gpl)
        gpl->actframe = NULL;
 }
 
+/* Free all of a gp-colors */
+static void free_gpencil_colors(bGPDpalette *palette)
+{
+       /* error checking */
+       if (palette == NULL) {
+               return;
+       }
+
+       /* free colors */
+       BLI_freelistN(&palette->colors);
+}
+
+/* Free all of the gp-palettes and colors */
+void free_gpencil_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);
+}
+
+/* Free all of the gp-brushes for a viewport (list should be &gpd->brushes or so) */
+void free_gpencil_brushes(ListBase *list)
+{
+       bGPDbrush *brush_next;
+
+       /* error checking */
+       if (list == NULL) {
+               return;
+       }
+
+       /* delete brushes */
+       for (bGPDbrush *brush = list->first; brush; brush = brush_next) {
+               brush_next = brush->next;
+               /* free curves */
+               if (brush->cur_sensitivity) {
+                       curvemapping_free(brush->cur_sensitivity);
+               }
+               if (brush->cur_strength) {
+                       curvemapping_free(brush->cur_strength);
+               }
+               if (brush->cur_jitter) {
+                       curvemapping_free(brush->cur_jitter);
+               }
+
+               MEM_freeN(brush);
+       }
+       BLI_listbase_clear(list);
+}
+
 /* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
 void free_gpencil_layers(ListBase *list)
 {
-       bGPDlayer *gpl, *gpln;
+       bGPDlayer *gpl_next;
        
        /* error checking */
        if (list == NULL) return;
        
        /* delete layers */
-       for (gpl = list->first; gpl; gpl = gpln) {
-               gpln = gpl->next;
+       for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
+               gpl_next = gpl->next;
                
                /* free layers and their data */
                free_gpencil_frames(gpl);
@@ -113,14 +190,18 @@ void free_gpencil_layers(ListBase *list)
        }
 }
 
-/* Free all of GPencil datablock's related data, but not the block itself */
 /** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
-void BKE_gpencil_free(bGPdata *gpd)
+void BKE_gpencil_free(bGPdata *gpd, bool free_palettes)
 {
        BKE_animdata_free(&gpd->id, false);
 
        /* free layers */
        free_gpencil_layers(&gpd->layers);
+
+       /* free palettes */
+       if (free_palettes) {
+               free_gpencil_palettes(&gpd->palettes);
+       }
 }
 
 /* -------- Container Creation ---------- */
@@ -180,7 +261,7 @@ bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
 /* add a copy of the active gp-frame to the given layer */
 bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
 {
-       bGPDframe *new_frame, *gpf;
+       bGPDframe *new_frame;
        bool found = false;
        
        /* Error checking/handling */
@@ -197,7 +278,7 @@ bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
        new_frame = gpencil_frame_duplicate(gpl->actframe);
        
        /* Find frame to insert it before */
-       for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+       for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
                if (gpf->framenum > cframe) {
                        /* Add it here */
                        BLI_insertlinkbefore(&gpl->frames, gpf, new_frame);
@@ -249,8 +330,11 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
        
        /* set basic settings */
        copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
-       gpl->thickness = 3;
-       
+       /* Since GPv2 thickness must be 0 */
+       gpl->thickness = 0;
+
+       gpl->opacity = 1.0f;
+
        /* onion-skinning settings */
        if (gpd->flag & GP_DATA_SHOW_ONIONSKINS)
                gpl->flag |= GP_LAYER_ONIONSKIN;
@@ -263,9 +347,6 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
        /* high quality fill by default */
        gpl->flag |= GP_LAYER_HQ_FILL;
        
-       /* default smooth iterations */
-       gpl->draw_smoothlvl = 1;
-       
        /* auto-name */
        BLI_strncpy(gpl->info, name, sizeof(gpl->info));
        BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
@@ -278,6 +359,266 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
        return gpl;
 }
 
+/* add a new gp-palette and make it the active */
+bGPDpalette *gpencil_palette_addnew(bGPdata *gpd, const char *name, bool setactive)
+{
+       bGPDpalette *palette;
+
+       /* check that list is ok */
+       if (gpd == NULL) {
+               return NULL;
+       }
+
+       /* allocate memory and add to end of list */
+       palette = MEM_callocN(sizeof(bGPDpalette), "bGPDpalette");
+
+       /* add to datablock */
+       BLI_addtail(&gpd->palettes, palette);
+
+       /* set basic settings */
+       /* auto-name */
+       BLI_strncpy(palette->info, name, sizeof(palette->info));
+       BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
+                      sizeof(palette->info));
+
+       /* make this one the active one */
+       if (setactive) {
+               gpencil_palette_setactive(gpd, palette);
+       }
+
+       /* return palette */
+       return palette;
+}
+
+/* create a set of default drawing brushes with predefined presets */
+void gpencil_brush_init_presets(ToolSettings *ts)
+{
+       bGPDbrush *brush;
+       /* Basic brush */
+       brush = gpencil_brush_addnew(ts, "Basic", true);
+       brush->thickness = 3.0f;
+       brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
+       brush->draw_sensitivity = 1.0f;
+       brush->flag |= GP_BRUSH_USE_PRESSURE;
+
+       brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+       brush->draw_strength = 1.0f;
+       brush->flag |= ~GP_BRUSH_USE_STENGTH_PRESSURE;
+
+       brush->draw_random_press = 0.0f;
+
+       brush->draw_jitter = 0.0f;
+       brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+       brush->draw_angle = 0.0f;
+       brush->draw_angle_factor = 0.0f;
+
+       brush->draw_smoothfac = 0.0f;
+       brush->draw_smoothlvl = 1;
+       brush->sublevel = 0;
+       brush->draw_random_sub = 0.0f;
+
+       /* Pencil brush */
+       brush = gpencil_brush_addnew(ts, "Pencil", false);
+       brush->thickness = 7.0f;
+       brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
+       brush->draw_sensitivity = 1.0f;
+       brush->flag |= GP_BRUSH_USE_PRESSURE;
+
+       brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+       brush->draw_strength = 0.7f;
+       brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+       brush->draw_random_press = 0.0f;
+
+       brush->draw_jitter = 0.0f;
+       brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+       brush->draw_angle = 0.0f;
+       brush->draw_angle_factor = 0.0f;
+
+       brush->draw_smoothfac = 1.0f;
+       brush->draw_smoothlvl = 2;
+       brush->sublevel = 2;
+       brush->draw_random_sub = 0.0f;
+
+       /* Ink brush */
+       brush = gpencil_brush_addnew(ts, "Ink", false);
+       brush->thickness = 7.0f;
+       brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
+       brush->draw_sensitivity = 1.6f;
+       brush->flag |= GP_BRUSH_USE_PRESSURE;
+
+       brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+       brush->draw_strength = 1.0f;
+       brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
+
+       brush->draw_random_press = 0.0f;
+
+       brush->draw_jitter = 0.0f;
+       brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+       brush->draw_angle = 0.0f;
+       brush->draw_angle_factor = 0.0f;
+
+       brush->draw_smoothfac = 1.1f;
+       brush->draw_smoothlvl = 2;
+       brush->sublevel = 2;
+       brush->draw_random_sub = 0.0f;
+
+       /* Ink Noise brush */
+       brush = gpencil_brush_addnew(ts, "Ink noise", false);
+       brush->thickness = 6.0f;
+       brush->flag |= GP_BRUSH_USE_RANDOM_PRESSURE;
+       brush->draw_sensitivity = 1.611f;
+       brush->flag |= GP_BRUSH_USE_PRESSURE;
+
+       brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+       brush->draw_strength = 1.0f;
+       brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+       brush->draw_random_press = 1.0f;
+
+       brush->draw_jitter = 0.0f;
+       brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+       brush->draw_angle = 0.0f;
+       brush->draw_angle_factor = 0.0f;
+
+       brush->draw_smoothfac = 1.1f;
+       brush->draw_smoothlvl = 2;
+       brush->sublevel = 2;
+       brush->draw_random_sub = 0.0f;
+
+       /* Marker brush */
+       brush = gpencil_brush_addnew(ts, "Marker", false);
+       brush->thickness = 10.0f;
+       brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
+       brush->draw_sensitivity = 2.0f;
+       brush->flag &= ~GP_BRUSH_USE_PRESSURE;
+
+       brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+       brush->draw_strength = 1.0f;
+       brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
+
+       brush->draw_random_press = 0.0f;
+
+       brush->draw_jitter = 0.0f;
+       brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+       brush->draw_angle = M_PI_4; /* 45 degrees */
+       brush->draw_angle_factor = 1.0f;
+
+       brush->draw_smoothfac = 1.0f;
+       brush->draw_smoothlvl = 2;
+       brush->sublevel = 2;
+       brush->draw_random_sub = 0.0f;
+
+       /* Crayon brush */
+       brush = gpencil_brush_addnew(ts, "Crayon", false);
+       brush->thickness = 10.0f;
+       brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
+       brush->draw_sensitivity = 3.0f;
+       brush->flag &= ~GP_BRUSH_USE_PRESSURE;
+
+       brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
+       brush->draw_strength = 0.140f;
+       brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+       brush->draw_random_press = 0.0f;
+
+       brush->draw_jitter = 0.0f;
+       brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+       brush->draw_angle = 0.0f;
+       brush->draw_angle_factor = 0.0f;
+
+       brush->draw_smoothfac = 0.0f;
+       brush->draw_smoothlvl = 1;
+       brush->sublevel = 2;
+       brush->draw_random_sub = 0.5f;
+
+}
+
+/* add a new gp-brush and make it the active */
+bGPDbrush *gpencil_brush_addnew(ToolSettings *ts, const char *name, bool setactive)
+{
+       bGPDbrush *brush;
+
+       /* check that list is ok */
+       if (ts == NULL) {
+               return NULL;
+       }
+
+       /* allocate memory and add to end of list */
+       brush = MEM_callocN(sizeof(bGPDbrush), "bGPDbrush");
+
+       /* add to datablock */
+       BLI_addtail(&ts->gp_brushes, brush);
+
+       /* set basic settings */
+       brush->thickness = 3;
+       brush->draw_smoothlvl = 1;
+       brush->flag |= GP_BRUSH_USE_PRESSURE;
+       brush->draw_sensitivity = 1.0f;
+       brush->draw_strength = 1.0f;
+       brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+       brush->draw_jitter = 0.0f;
+       brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+       /* curves */
+       brush->cur_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+       brush->cur_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+       brush->cur_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+
+       /* auto-name */
+       BLI_strncpy(brush->info, name, sizeof(brush->info));
+       BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info));
+
+       /* make this one the active one */
+       if (setactive) {
+               gpencil_brush_setactive(ts, brush);
+       }
+
+       /* return brush */
+       return brush;
+}
+
+/* add a new gp-palettecolor and make it the active */
+bGPDpalettecolor *gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name, bool setactive)
+{
+       bGPDpalettecolor *palcolor;
+
+       /* check that list is ok */
+       if (palette == NULL) {
+               return NULL;
+       }
+
+       /* allocate memory and add to end of list */
+       palcolor = MEM_callocN(sizeof(bGPDpalettecolor), "bGPDpalettecolor");
+
+       /* add to datablock */
+       BLI_addtail(&palette->colors, palcolor);
+
+       /* set basic settings */
+       palcolor->flag |= PC_COLOR_HQ_FILL;
+       copy_v4_v4(palcolor->color, U.gpencil_new_layer_col);
+       ARRAY_SET_ITEMS(palcolor->fill, 1.0f, 1.0f, 1.0f);
+
+       /* auto-name */
+       BLI_strncpy(palcolor->info, name, sizeof(palcolor->info));
+       BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
+                      sizeof(palcolor->info));
+
+       /* make this one the active one */
+       if (setactive) {
+               gpencil_palettecolor_setactive(palette, palcolor);
+       }
+
+       /* return palette color */
+       return palcolor;
+}
+
 /* add a new gp-datablock */
 bGPdata *gpencil_data_addnew(const char name[])
 {
@@ -300,94 +641,157 @@ bGPdata *gpencil_data_addnew(const char name[])
 /* -------- Data Duplication ---------- */
 
 /* make a copy of a given gpencil frame */
-bGPDframe *gpencil_frame_duplicate(bGPDframe *src)
+bGPDframe *gpencil_frame_duplicate(const bGPDframe *gpf_src)
 {
-       bGPDstroke *gps, *gpsd;
-       bGPDframe *dst;
+       bGPDstroke *gps_dst;
+       bGPDframe *gpf_dst;
        
        /* error checking */
-       if (src == NULL)
+       if (gpf_src == NULL) {
                return NULL;
+       }
                
        /* make a copy of the source frame */
-       dst = MEM_dupallocN(src);
-       dst->prev = dst->next = NULL;
+       gpf_dst = MEM_dupallocN(gpf_src);
+       gpf_dst->prev = gpf_dst->next = NULL;
        
        /* copy strokes */
-       BLI_listbase_clear(&dst->strokes);
-       for (gps = src->strokes.first; gps; gps = gps->next) {
+       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, then adjust pointer to points too */
-               gpsd = MEM_dupallocN(gps);
-               gpsd->points = MEM_dupallocN(gps->points);
-               gpsd->triangles = MEM_dupallocN(gps->triangles);
-               gpsd->flag |= GP_STROKE_RECALC_CACHES;
-               BLI_addtail(&dst->strokes, gpsd);
+               gps_dst = MEM_dupallocN(gps_src);
+               gps_dst->points = MEM_dupallocN(gps_src->points);
+               gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
+               gps_dst->flag |= GP_STROKE_RECALC_CACHES;
+               BLI_addtail(&gpf_dst->strokes, gps_dst);
        }
        
        /* return new frame */
-       return dst;
+       return gpf_dst;
+}
+
+/* make a copy of a given gpencil brush */
+bGPDbrush *gpencil_brush_duplicate(const bGPDbrush *brush_src)
+{
+       bGPDbrush *brush_dst;
+
+       /* error checking */
+       if (brush_src == NULL) {
+               return NULL;
+       }
+
+       /* make a copy of source brush */
+       brush_dst = MEM_dupallocN(brush_src);
+       brush_dst->prev = brush_dst->next = NULL;
+       /* make a copy of curves */
+       brush_dst->cur_sensitivity = curvemapping_copy(brush_src->cur_sensitivity);
+       brush_dst->cur_strength = curvemapping_copy(brush_src->cur_strength);
+       brush_dst->cur_jitter = curvemapping_copy(brush_src->cur_jitter);
+
+       /* return new brush */
+       return brush_dst;
 }
 
+/* make a copy of a given gpencil palette */
+bGPDpalette *gpencil_palette_duplicate(const bGPDpalette *palette_src)
+{
+       bGPDpalette *palette_dst;
+       const bGPDpalettecolor *palcolor_src;
+       bGPDpalettecolor *palcolord_dst;
+
+       /* error checking */
+       if (palette_src == NULL) {
+               return NULL;
+       }
+
+       /* make a copy of source palette */
+       palette_dst = MEM_dupallocN(palette_src);
+       palette_dst->prev = palette_dst->next = NULL;
+
+       /* copy colors */
+       BLI_listbase_clear(&palette_dst->colors);
+       for (palcolor_src = palette_src->colors.first; palcolor_src; palcolor_src = palcolor_src->next) {
+               /* make a copy of source */
+               palcolord_dst = MEM_dupallocN(palcolor_src);
+               BLI_addtail(&palette_dst->colors, palcolord_dst);
+       }
+
+       /* return new palette */
+       return palette_dst;
+}
 /* make a copy of a given gpencil layer */
-bGPDlayer *gpencil_layer_duplicate(bGPDlayer *src)
+bGPDlayer *gpencil_layer_duplicate(const bGPDlayer *gpl_src)
 {
-       bGPDframe *gpf, *gpfd;
-       bGPDlayer *dst;
+       const bGPDframe *gpf_src;
+       bGPDframe *gpf_dst;
+       bGPDlayer *gpl_dst;
        
        /* error checking */
-       if (src == NULL)
+       if (gpl_src == NULL) {
                return NULL;
+       }
                
        /* make a copy of source layer */
-       dst = MEM_dupallocN(src);
-       dst->prev = dst->next = NULL;
+       gpl_dst = MEM_dupallocN(gpl_src);
+       gpl_dst->prev = gpl_dst->next = NULL;
        
        /* copy frames */
-       BLI_listbase_clear(&dst->frames);
-       for (gpf = src->frames.first; gpf; gpf = gpf->next) {
+       BLI_listbase_clear(&gpl_dst->frames);
+       for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
                /* make a copy of source frame */
-               gpfd = gpencil_frame_duplicate(gpf);
-               BLI_addtail(&dst->frames, gpfd);
+               gpf_dst = gpencil_frame_duplicate(gpf_src);
+               BLI_addtail(&gpl_dst->frames, gpf_dst);
                
                /* if source frame was the current layer's 'active' frame, reassign that too */
-               if (gpf == dst->actframe)
-                       dst->actframe = gpfd;
+               if (gpf_src == gpl_dst->actframe)
+                       gpl_dst->actframe = gpf_dst;
        }
        
        /* return new layer */
-       return dst;
+       return gpl_dst;
 }
 
 /* make a copy of a given gpencil datablock */
-bGPdata *gpencil_data_duplicate(Main *bmain, bGPdata *src, bool internal_copy)
+bGPdata *gpencil_data_duplicate(Main *bmain, bGPdata *gpd_src, bool internal_copy)
 {
-       bGPDlayer *gpl, *gpld;
-       bGPdata *dst;
-       
+       const bGPDlayer *gpl_src;
+       bGPDlayer *gpl_dst;
+       bGPdata *gpd_dst;
+
        /* error checking */
-       if (src == NULL)
+       if (gpd_src == NULL) {
                return NULL;
+       }
        
        /* make a copy of the base-data */
        if (internal_copy) {
                /* make a straight copy for undo buffers used during stroke drawing */
-               dst = MEM_dupallocN(src);
+               gpd_dst = MEM_dupallocN(gpd_src);
        }
        else {
                /* make a copy when others use this */
-               dst = BKE_libblock_copy(bmain, &src->id);
+               gpd_dst = BKE_libblock_copy(bmain, &gpd_src->id);
        }
        
        /* copy layers */
-       BLI_listbase_clear(&dst->layers);
-       for (gpl = src->layers.first; gpl; gpl = gpl->next) {
+       BLI_listbase_clear(&gpd_dst->layers);
+       for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
                /* make a copy of source layer and its data */
-               gpld = gpencil_layer_duplicate(gpl);
-               BLI_addtail(&dst->layers, gpld);
+               gpl_dst = gpencil_layer_duplicate(gpl_src);
+               BLI_addtail(&gpd_dst->layers, gpl_dst);
+       }
+       if (!internal_copy) {
+               /* copy palettes */
+               bGPDpalette *palette_src, *palette_dst;
+               BLI_listbase_clear(&gpd_dst->palettes);
+               for (palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) {
+                       palette_dst = gpencil_palette_duplicate(palette_src);
+                       BLI_addtail(&gpd_dst->palettes, palette_dst);
+               }
        }
        
        /* return new */
-       return dst;
+       return gpd_dst;
 }
 
 void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
@@ -458,7 +862,7 @@ bool gpencil_layer_is_editable(const bGPDlayer *gpl)
                /* Opacity must be sufficiently high that it is still "visible"
                 * Otherwise, it's not really "visible" to the user, so no point editing...
                 */
-               if ((gpl->color[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH)) {
+               if (gpl->opacity > GPENCIL_ALPHA_OPACITY_THRESH) {
                        return true;
                }
        }
@@ -685,3 +1089,243 @@ void gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
 }
 
 /* ************************************************** */
+/* get the active gp-brush for editing */
+bGPDbrush *gpencil_brush_getactive(ToolSettings *ts)
+{
+       bGPDbrush *brush;
+
+       /* error checking */
+       if (ELEM(NULL, ts, ts->gp_brushes.first)) {
+               return NULL;
+       }
+
+       /* loop over brushes until found (assume only one active) */
+       for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
+               if (brush->flag & GP_BRUSH_ACTIVE) {
+                       return brush;
+               }
+       }
+
+       /* no active brush found */
+       return NULL;
+}
+
+/* set the active gp-brush */
+void gpencil_brush_setactive(ToolSettings *ts, bGPDbrush *active)
+{
+       bGPDbrush *brush;
+
+       /* error checking */
+       if (ELEM(NULL, ts, ts->gp_brushes.first, active)) {
+               return;
+       }
+
+       /* loop over brushes deactivating all */
+       for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
+               brush->flag &= ~GP_BRUSH_ACTIVE;
+       }
+
+       /* set as active one */
+       active->flag |= GP_BRUSH_ACTIVE;
+}
+
+/* delete the active gp-brush */
+void gpencil_brush_delete(ToolSettings *ts, bGPDbrush *brush)
+{
+       /* error checking */
+       if (ELEM(NULL, ts, brush)) {
+               return;
+       }
+
+       /* free curves */
+       if (brush->cur_sensitivity) {
+               curvemapping_free(brush->cur_sensitivity);
+       }
+       if (brush->cur_strength) {
+               curvemapping_free(brush->cur_strength);
+       }
+       if (brush->cur_jitter) {
+               curvemapping_free(brush->cur_jitter);
+       }
+
+       /* free */
+       BLI_freelinkN(&ts->gp_brushes, brush);
+}
+
+/* ************************************************** */
+/* get the active gp-palette for editing */
+bGPDpalette *gpencil_palette_getactive(bGPdata *gpd)
+{
+       bGPDpalette *palette;
+
+       /* error checking */
+       if (ELEM(NULL, gpd, gpd->palettes.first)) {
+               return NULL;
+       }
+
+       /* loop over palettes until found (assume only one active) */
+       for (palette = gpd->palettes.first; palette; palette = palette->next) {
+               if (palette->flag & PL_PALETTE_ACTIVE)
+                       return palette;
+       }
+
+       /* no active palette found */
+       return NULL;
+}
+
+/* set the active gp-palette */
+void gpencil_palette_setactive(bGPdata *gpd, bGPDpalette *active)
+{
+       bGPDpalette *palette;
+
+       /* error checking */
+       if (ELEM(NULL, gpd, gpd->palettes.first, active)) {
+               return;
+       }
+
+       /* loop over palettes deactivating all */
+       for (palette = gpd->palettes.first; palette; palette = palette->next) {
+               palette->flag &= ~PL_PALETTE_ACTIVE;
+       }
+
+       /* set as active one */
+       active->flag |= PL_PALETTE_ACTIVE;
+       /* force color recalc */
+       gpencil_palette_change_strokes(gpd);
+}
+
+/* delete the active gp-palette */
+void gpencil_palette_delete(bGPdata *gpd, bGPDpalette *palette)
+{
+       /* error checking */
+       if (ELEM(NULL, gpd, palette)) {
+               return;
+       }
+
+       /* free colors */
+       free_gpencil_colors(palette);
+       BLI_freelinkN(&gpd->palettes, palette);
+       /* force color recalc */
+       gpencil_palette_change_strokes(gpd);
+}
+
+/* Set all strokes to recalc the palette color */
+void gpencil_palette_change_strokes(bGPdata *gpd)
+{
+       bGPDlayer *gpl;
+       bGPDframe *gpf;
+       bGPDstroke *gps;
+
+       for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+               for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+                       for (gps = gpf->strokes.first; gps; gps = gps->next) {
+                               gps->flag |= GP_STROKE_RECALC_COLOR;
+                       }
+               }
+       }
+}
+
+
+/* get the active gp-palettecolor for editing */
+bGPDpalettecolor *gpencil_palettecolor_getactive(bGPDpalette *palette)
+{
+       bGPDpalettecolor *palcolor;
+
+       /* error checking */
+       if (ELEM(NULL, palette, palette->colors.first)) {
+               return NULL;
+       }
+
+       /* loop over colors until found (assume only one active) */
+       for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+               if (palcolor->flag & PC_COLOR_ACTIVE) {
+                       return palcolor;
+               }
+       }
+
+       /* no active color found */
+       return NULL;
+}
+/* get the gp-palettecolor looking for name */
+bGPDpalettecolor *gpencil_palettecolor_getbyname(bGPDpalette *palette, char *name)
+{
+       /* error checking */
+       if (ELEM(NULL, palette, name)) {
+               return NULL;
+       }
+
+       return BLI_findstring(&palette->colors, name, offsetof(bGPDpalettecolor, info));
+}
+
+/* Change color name in all strokes */
+void gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char *newname)
+{
+       bGPDlayer *gpl;
+       bGPDframe *gpf;
+       bGPDstroke *gps;
+
+       for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+               for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+                       for (gps = gpf->strokes.first; gps; gps = gps->next) {
+                               if (STREQ(gps->colorname, oldname)) {
+                                       strcpy(gps->colorname, newname);
+                               }
+                       }
+               }
+       }
+               
+}
+
+/* Delete all strokes of the color */
+void gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name)
+{
+       bGPDlayer *gpl;
+       bGPDframe *gpf;
+       bGPDstroke *gps, *gpsn;
+
+       for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+               for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+                       for (gps = gpf->strokes.first; gps; gps = gpsn) {
+                               gpsn = gps->next;
+
+                               if (STREQ(gps->colorname, name)) {
+                                       if (gps->points) MEM_freeN(gps->points);
+                                       if (gps->triangles) MEM_freeN(gps->triangles);
+                                       BLI_freelinkN(&gpf->strokes, gps);
+                               }
+                       }
+               }
+       }
+
+}
+
+/* set the active gp-palettecolor */
+void gpencil_palettecolor_setactive(bGPDpalette *palette, bGPDpalettecolor *active)
+{
+       bGPDpalettecolor *palcolor;
+
+       /* error checking */
+       if (ELEM(NULL, palette, palette->colors.first, active)) {
+               return;
+       }
+
+       /* loop over colors deactivating all */
+       for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+               palcolor->flag &= ~PC_COLOR_ACTIVE;
+       }
+
+       /* set as active one */
+       active->flag |= PC_COLOR_ACTIVE;
+}
+
+/* delete the active gp-palettecolor */
+void gpencil_palettecolor_delete(bGPDpalette *palette, bGPDpalettecolor *palcolor)
+{
+       /* error checking */
+       if (ELEM(NULL, palette, palcolor)) {
+               return;
+       }
+
+       /* free */
+       BLI_freelinkN(&palette->colors, palcolor);
+}
index 74b3b1b6c184df106ae4466606bc8e433dc51398..a7b93cf3cb1afe4ef4145c258209b5eddfae38ad 100644 (file)
@@ -795,7 +795,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
                                free_windowmanager_cb(NULL, (wmWindowManager *)id);
                        break;
                case ID_GD:
-                       BKE_gpencil_free((bGPdata *)id);
+                       BKE_gpencil_free((bGPdata *)id, true);
                        break;
                case ID_MC:
                        BKE_movieclip_free((MovieClip *)id);
index 3e37ee83ceab35919df4efc817eaca46adbb4e43..4a1d279545e87fd30641230d2a56f90a469f7604 100644 (file)
@@ -49,6 +49,7 @@
 #include "DNA_space_types.h"
 #include "DNA_view3d_types.h"
 #include "DNA_windowmanager_types.h"
+#include "DNA_gpencil_types.h"
 
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
@@ -286,6 +287,13 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
                ts->imapaint.paintcursor = NULL;
                id_us_plus((ID *)ts->imapaint.stencil);
                ts->particle.paintcursor = NULL;
+               /* duplicate Grease Pencil Drawing Brushes */
+               BLI_listbase_clear(&ts->gp_brushes);
+               for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
+                       bGPDbrush *newbrush = gpencil_brush_duplicate(brush);
+                       BLI_addtail(&ts->gp_brushes, newbrush);
+               }
+
        }
        
        /* make a private copy of the avicodecdata */
@@ -432,6 +440,10 @@ void BKE_scene_free(Scene *sce)
                        BKE_paint_free(&sce->toolsettings->uvsculpt->paint);
                        MEM_freeN(sce->toolsettings->uvsculpt);
                }
+               /* free Grease Pencil Drawing Brushes */
+               free_gpencil_brushes(&sce->toolsettings->gp_brushes);
+               BLI_freelistN(&sce->toolsettings->gp_brushes);
+
                BKE_paint_free(&sce->toolsettings->imapaint.paint);
 
                MEM_freeN(sce->toolsettings);
@@ -764,6 +776,11 @@ void BKE_scene_init(Scene *sce)
                gp_brush->strength = 0.5f;
                gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
                
+               gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
+               gp_brush->size = 25;
+               gp_brush->strength = 0.5f;
+               gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
                gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
                gp_brush->size = 50;
                gp_brush->strength = 0.3f;
index 7eabcd18fb8281dff8cb2396902db866a3ba767f..52ca8520b4682fa5cc817185b8f48d216062bad2 100644 (file)
 #include "BKE_sequencer.h"
 #include "BKE_outliner_treehash.h"
 #include "BKE_sound.h"
-
+#include "BKE_colortools.h"
 
 #include "NOD_common.h"
 #include "NOD_socket.h"
@@ -5872,6 +5872,22 @@ static void direct_link_scene(FileData *fd, Scene *sce)
                        sce->toolsettings->wpaint->wpaint_prev = NULL;
                        sce->toolsettings->wpaint->tot = 0;
                }
+               /* relink grease pencil drawing brushes */
+               link_list(fd, &sce->toolsettings->gp_brushes);
+               for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
+                       brush->cur_sensitivity = newdataadr(fd, brush->cur_sensitivity);
+                       if (brush->cur_sensitivity) {
+                               direct_link_curvemapping(fd, brush->cur_sensitivity);
+                       }
+                       brush->cur_strength = newdataadr(fd, brush->cur_strength);
+                       if (brush->cur_strength) {
+                               direct_link_curvemapping(fd, brush->cur_strength);
+                       }
+                       brush->cur_jitter = newdataadr(fd, brush->cur_jitter);
+                       if (brush->cur_jitter) {
+                               direct_link_curvemapping(fd, brush->cur_jitter);
+                       }
+               }
        }
 
        if (sce->ed) {
@@ -6154,7 +6170,8 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
        bGPDlayer *gpl;
        bGPDframe *gpf;
        bGPDstroke *gps;
-       
+       bGPDpalette *palette;
+
        /* we must firstly have some grease-pencil data to link! */
        if (gpd == NULL)
                return;
@@ -6162,11 +6179,19 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
        /* relink animdata */
        gpd->adt = newdataadr(fd, gpd->adt);
        direct_link_animdata(fd, gpd->adt);
-       
+
+       /* relink palettes */
+       link_list(fd, &gpd->palettes);
+       for (palette = gpd->palettes.first; palette; palette = palette->next) {
+               link_list(fd, &palette->colors);
+       }
+
        /* relink layers */
        link_list(fd, &gpd->layers);
        
        for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+               /* parent */
+               gpl->parent = newlibadr(fd, gpd->id.lib, gpl->parent);
                /* relink frames */
                link_list(fd, &gpl->frames);
                gpl->actframe = newdataadr(fd, gpl->actframe);
@@ -6179,9 +6204,12 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
                                gps->points = newdataadr(fd, gps->points);
                                
                                /* the triangulation is not saved, so need to be recalculated */
-                               gps->flag |= GP_STROKE_RECALC_CACHES;
                                gps->triangles = NULL;
                                gps->tot_triangles = 0;
+                               gps->flag |= GP_STROKE_RECALC_CACHES;
+                               /* the color pointer is not saved, so need to be recalculated using the color name */
+                               gps->palcolor = NULL;
+                               gps->flag |= GP_STROKE_RECALC_COLOR;
                        }
                }
        }
index 3e6b0d34ba68b5031906c21d63751b85fb3bcbeb..c4fec3ed8244e18122f0664ccf7516df27a8ca08 100644 (file)
@@ -63,6 +63,7 @@
 #include "BKE_scene.h"
 #include "BKE_sequencer.h"
 #include "BKE_screen.h"
+#include "BKE_gpencil.h"
 
 #include "BLI_math.h"
 #include "BLI_listbase.h"
@@ -1075,15 +1076,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
                        }
                }
 
-               /* init grease pencil smooth level iterations */
-               for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
-                       for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
-                               if (gpl->draw_smoothlvl == 0) {
-                                       gpl->draw_smoothlvl = 1;
-                               }
-                       }
-               }
-
                for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
                        for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
                                for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
@@ -1192,7 +1184,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
 
                for (Camera *camera = main->camera.first; camera != NULL; camera = camera->id.next) {
                        if (camera->stereo.pole_merge_angle_from == 0.0f &&
-                           camera->stereo.pole_merge_angle_to == 0.0f)
+                               camera->stereo.pole_merge_angle_to == 0.0f)
                        {
                                camera->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
                                camera->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
@@ -1251,4 +1243,82 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
                        }
                }
        }
+
+       if (!MAIN_VERSION_ATLEAST(main, 277, 3)) {
+               /* ------- init of grease pencil initialization --------------- */
+               if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "bGPDpalettecolor", "palcolor")) {
+                       for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+                               ToolSettings *ts = scene->toolsettings;
+                               /* initialize use position for sculpt brushes */
+                               ts->gp_sculpt.flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
+                               /* initialize  selected vertices alpha factor */
+                               ts->gp_sculpt.alpha = 1.0f;
+
+                               /* new strength sculpt brush */
+                               if (ts->gp_sculpt.brush[0].size >= 11) {
+                                       GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
+                                       GP_EditBrush_Data *brush;
+
+                                       brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
+                                       brush->size = 25;
+                                       brush->strength = 0.5f;
+                                       brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+                               }
+                       }
+                       /* create a default grease pencil drawing brushes set */
+                       if (!BLI_listbase_is_empty(&main->gpencil)) {
+                               for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+                                       ToolSettings *ts = scene->toolsettings;
+                                       if (BLI_listbase_is_empty(&ts->gp_brushes)) {
+                                               gpencil_brush_init_presets(ts);
+                                       }
+                               }
+                       }
+                       /* Convert Grease Pencil to new palettes/brushes
+                        * Loop all strokes and create the palette and all colors
+                        */
+                       for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
+                               if (BLI_listbase_is_empty(&gpd->palettes)) {
+                                       /* create palette */
+                                       bGPDpalette *palette = gpencil_palette_addnew(gpd, "GP_Palette", true);
+                                       for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+                                               /* create color using layer name */
+                                               bGPDpalettecolor *palcolor = gpencil_palettecolor_addnew(palette, gpl->info, true);
+                                               if (palcolor != NULL) {
+                                                       /* set color attributes */
+                                                       copy_v4_v4(palcolor->color, gpl->color);
+                                                       copy_v4_v4(palcolor->fill, gpl->fill);
+                                                       palcolor->flag = gpl->flag;
+                                                       /* set layer opacity to 1 */
+                                                       gpl->opacity = 1.0f;
+                                                       /* set tint color */
+                                                       ARRAY_SET_ITEMS(gpl->tintcolor, 0.0f, 0.0f, 0.0f, 0.0f);
+
+                                                       for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+                                                               for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+                                                                       /* set stroke to palette and force recalculation */
+                                                                       strcpy(gps->colorname, gpl->info);
+                                                                       gps->palcolor = NULL;
+                                                                       gps->flag |= GP_STROKE_RECALC_COLOR;
+                                                                       gps->thickness = gpl->thickness;
+                                                                       /* set alpha strength to 1 */
+                                                                       for (int i = 0; i < gps->totpoints; i++) {
+                                                                               gps->points[i].strength = 1.0f;
+                                                                       }
+
+                                                               }
+                                                       }
+                                               }
+                                               /* set thickness to 0 (now it is a factor to override stroke thickness) */
+                                               gpl->thickness = 0.0f;
+                                       }
+                                       /* set first color as active */
+                                       if (palette->colors.first)
+                                               gpencil_palettecolor_setactive(palette, palette->colors.first);
+                               }
+                       }
+               }
+               /* ------- end of grease pencil initialization --------------- */
+       }
+
 }
index 0ed7a397e0b957ec4ca21fc2063e6aee765b774a..ec817b9b26180d1397c3336a4a1712075a0625de 100644 (file)
@@ -108,6 +108,11 @@ void BLO_update_defaults_startup_blend(Main *bmain)
                                brush->strength = 0.5f;
                                brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
                                
+                               brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
+                               brush->size = 25;
+                               brush->strength = 0.5f;
+                               brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
                                brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
                                brush->size = 50;
                                brush->strength = 0.3f;
index ba783e08b39e6e10796826e6813f63283c503231..fb31cd227ba02f719cb9496fc7f98c51d4161c44 100644 (file)
@@ -2673,6 +2673,20 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
                        writestruct(wd, DATA, UvSculpt, 1, tos->uvsculpt);
                        write_paint(wd, &tos->uvsculpt->paint);
                }
+               /* write grease-pencil drawing brushes to file */
+               writelist(wd, DATA, bGPDbrush, &tos->gp_brushes);
+               for (bGPDbrush *brush = tos->gp_brushes.first; brush; brush = brush->next) {
+                       if (brush->cur_sensitivity) {
+                               write_curvemapping(wd, brush->cur_sensitivity);
+                       }
+                       if (brush->cur_strength) {
+                               write_curvemapping(wd, brush->cur_strength);
+                       }
+                       if (brush->cur_jitter) {
+                               write_curvemapping(wd, brush->cur_jitter);
+                       }
+               }
+               
 
                write_paint(wd, &tos->imapaint.paint);
 
@@ -2835,6 +2849,7 @@ static void write_gpencils(WriteData *wd, ListBase *lb)
        bGPDlayer *gpl;
        bGPDframe *gpf;
        bGPDstroke *gps;
+       bGPDpalette *palette;
 
        for (gpd = lb->first; gpd; gpd = gpd->id.next) {
                if (gpd->id.us > 0 || wd->current) {
@@ -2861,6 +2876,11 @@ static void write_gpencils(WriteData *wd, ListBase *lb)
                                        }
                                }
                        }
+                       /* write grease-pencil palettes */
+                       writelist(wd, DATA, bGPDpalette, &gpd->palettes);
+                       for (palette = gpd->palettes.first; palette; palette = palette->next) {
+                               writelist(wd, DATA, bGPDpalettecolor, &palette->colors);
+                       }
                }
        }
 
index ea2f7fc5588f4d0046065df7256882b1fdf7ac9c..752544f65e1cdf57decacb3e85efd7b3ab37b7f1 100644 (file)
@@ -4208,6 +4208,8 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
                        offset += ICON_WIDTH; 
                }
                else if (ale->type == ANIMTYPE_GPLAYER) {
+#if 0
+                       /* XXX: Maybe need a better design */
                        /* color swatch for layer color */
                        bGPDlayer *gpl = (bGPDlayer *)ale->data;
                        PointerRNA ptr;
@@ -4216,7 +4218,6 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
                        RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, &ptr);
                        
                        UI_block_align_begin(block);
-                       
                        UI_block_emboss_set(block, RNA_boolean_get(&ptr, "is_stroke_visible") ? UI_EMBOSS : UI_EMBOSS_NONE);
                        uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset, yminc, w, ICON_WIDTH, 
                                  &ptr, "color", -1, 
@@ -4226,11 +4227,11 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
                        uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset + w, yminc, w, ICON_WIDTH, 
                                  &ptr, "fill_color", -1, 
                                  0, 0, 0, 0, gpl->info);
-                       
                        UI_block_emboss_set(block, UI_EMBOSS_NONE);
                        UI_block_align_end(block);
-                       
+
                        offset += ICON_WIDTH;
+#endif
                }
        }
        
index 79a2c4942392d223506495f000d4530e42da97cf..bd09616243b53045d40a5db07863593f5a8d9630 100644 (file)
@@ -18,7 +18,7 @@
  * The Original Code is Copyright (C) 2008, Blender Foundation
  * This is a new part of Blender
  *
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
  *
  * ***** END GPL LICENSE BLOCK *****
  */
@@ -52,6 +52,7 @@
 #include "DNA_space_types.h"
 #include "DNA_view3d_types.h"
 #include "DNA_userdef_types.h"
+#include "DNA_object_types.h"
 
 #include "BKE_context.h"
 #include "BKE_global.h"
@@ -94,9 +95,32 @@ typedef enum eDrawStrokeFlags {
 #define GP_DRAWTHICKNESS_SPECIAL    3
 
 /* ----- Tool Buffer Drawing ------ */
+/* helper function to set color of buffer point */
+static void gp_set_tpoint_color(tGPspoint *pt, float ink[4])
+{
+       float alpha = ink[3] * pt->strength;
+       CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
+       glColor4f(ink[0], ink[1], ink[2], alpha);
+}
+
+/* helper function to set color of point */
+static void gp_set_point_color(bGPDspoint *pt, float ink[4])
+{
+       float alpha = ink[3] * pt->strength;
+       CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
+       glColor4f(ink[0], ink[1], ink[2], alpha);
+}
+
+/* helper function to set color and point */
+static void gp_set_color_and_tpoint(tGPspoint *pt, float ink[4])
+{
+       gp_set_tpoint_color(pt, ink);
+       glVertex2iv(&pt->x);
+}
 
 /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
-static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickness, short dflag, short sflag)
+static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickness,
+                                  short dflag, short sflag, float ink[4])
 {
        tGPspoint *pt;
        int i;
@@ -113,7 +137,8 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
                /* if drawing a single point, draw it larger */
                glPointSize((float)(thickness + 2) * points->pressure);
                glBegin(GL_POINTS);
-               glVertex2iv(&points->x);
+
+               gp_set_color_and_tpoint(points, ink);
                glEnd();
        }
        else if (sflag & GP_STROKE_ERASER) {
@@ -138,15 +163,18 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
                                glBegin(GL_LINE_STRIP);
                                
                                /* need to roll-back one point to ensure that there are no gaps in the stroke */
-                               if (i != 0) glVertex2iv(&(pt - 1)->x);
+                               if (i != 0) { 
+                                       gp_set_color_and_tpoint((pt - 1), ink);
+                               }
                                
                                /* now the point we want... */
-                               glVertex2iv(&pt->x);
+                               gp_set_color_and_tpoint(pt, ink);
                                
                                oldpressure = pt->pressure;
                        }
-                       else
-                               glVertex2iv(&pt->x);
+                       else {
+                               gp_set_color_and_tpoint(pt, ink);
+                       }
                }
                glEnd();
 
@@ -155,37 +183,35 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
 }
 
 /* --------- 2D Stroke Drawing Helpers --------- */
-
-/* helper function to calculate x-y drawing coordinates for 2D points */
-static void gp_calc_2d_stroke_xy(bGPDspoint *pt, short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
+/* change in parameter list */
+static void gp_calc_2d_stroke_fxy(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->x;
-               r_co[1] = pt->y;
+               r_co[0] = pt[0];
+               r_co[1] = pt[1];
        }
        else if (sflag & GP_STROKE_2DIMAGE) {
-               const float x = (float)((pt->x * winx) + offsx);
-               const float y = (float)((pt->y * winy) + offsy);
-               
+               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->x / 100 * winx) + offsx;
-               const float y = (float)(pt->y / 100 * winy) + offsy;
-               
+               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 buffer stroke in "volumetric" style
  * NOTE: the stroke buffer doesn't have any coordinate offsets/transforms
  */
 static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, short thickness,
-                                             short dflag, short UNUSED(sflag))
+                                             short dflag, short UNUSED(sflag), float ink[4])
 {
        GLUquadricObj *qobj = gluNewQuadric();
        float modelview[4][4];
@@ -216,6 +242,7 @@ static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, s
                glLoadMatrixf((float *)modelview);
                
                /* draw the disk using the current state... */
+               gp_set_tpoint_color(pt, ink);
                gluDisk(qobj, 0.0,  pt->pressure * thickness, 32, 1);
                
                
@@ -229,7 +256,8 @@ static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, s
 /* draw a 2D strokes in "volumetric" style */
 static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, short thickness,
                                          short dflag, short sflag,
-                                         int offsx, int offsy, int winx, int winy)
+                                         int offsx, int offsy, int winx, int winy,
+                                         float diff_mat[4][4], float ink[4])
 {
        GLUquadricObj *qobj = gluNewQuadric();
        float modelview[4][4];
@@ -238,7 +266,7 @@ static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, shor
        
        bGPDspoint *pt;
        int i;
-       
+       float fpt[3];
        
        /* HACK: We need a scale factor for the drawing in the image editor,
         * which seems to use 1 unit as it's maximum size, whereas everything
@@ -256,10 +284,14 @@ static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, shor
        glPushMatrix();
        
        for (i = 0, pt = points; i < totpoints; i++, pt++) {
+               /* color of point */
+               gp_set_point_color(pt, ink);
+
                /* set the transformed position */
                float co[2];
                
-               gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
+               mul_v3_m4v3(fpt, diff_mat, &pt->x);
+               gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
                translate_m4(modelview, co[0], co[1], 0.0f);
                
                glLoadMatrixf((float *)modelview);
@@ -276,8 +308,9 @@ static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, shor
 }
 
 /* draw a 3D stroke in "volumetric" style */
-static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, short thickness,
-                                         short UNUSED(dflag), short UNUSED(sflag))
+static void gp_draw_stroke_volumetric_3d(
+        bGPDspoint *points, int totpoints, short thickness,
+        short UNUSED(dflag), short UNUSED(sflag), float diff_mat[4][4], float ink[4])
 {
        GLUquadricObj *qobj = gluNewQuadric();
        
@@ -286,7 +319,7 @@ static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, shor
        
        bGPDspoint *pt;
        int i;
-       
+       float fpt[3];
        
        /* Get the basic modelview matrix we use for performing calculations */
        glGetFloatv(GL_MODELVIEW_MATRIX, (float *)base_modelview);
@@ -305,8 +338,13 @@ static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, shor
        glPushMatrix();
        
        for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
+               /* color of point */
+               gp_set_point_color(pt, ink);
+
+               mul_v3_m4v3(fpt, diff_mat, &pt->x);
+
                /* apply translation to base_modelview, so that the translated point is put in the right place */
-               translate_m4(base_modelview, pt->x, pt->y, pt->z);
+               translate_m4(base_modelview, fpt[0], fpt[1], fpt[2]);
                
                /* copy the translation component to the billboard matrix we're going to use,
                 * then reset the base matrix to the original values so that we can do the same
@@ -378,9 +416,9 @@ static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d
 static void gp_triangulate_stroke_fill(bGPDstroke *gps)
 {
        BLI_assert(gps->totpoints >= 3);
-       gps->tot_triangles = gps->totpoints - 2;
-
+       
        /* allocate memory for temporary areas */
+       gps->tot_triangles = gps->totpoints - 2;
        unsigned int (*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");
        
@@ -390,6 +428,8 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
        gp_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
        BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)gps->totpoints, direction, (unsigned int(*)[3])tmp_triangles);
 
+       /* Number of triangles */
+       gps->tot_triangles = gps->totpoints - 2;
        /* save triangulation data in stroke cache */
        if (gps->tot_triangles > 0) {
                if (gps->triangles == NULL) {
@@ -399,9 +439,7 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
                        gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
                }
                
-               int i;
-               
-               for (i = 0; i < gps->tot_triangles; i++) {
+               for (int i = 0; i < gps->tot_triangles; i++) {
                        bGPDtriangle *stroke_triangle = &gps->triangles[i];
                        stroke_triangle->v1 = tmp_triangles[i][0];
                        stroke_triangle->v2 = tmp_triangles[i][1];
@@ -428,21 +466,27 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
 
 
 /* draw fills for shapes */
-static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short dflag, int offsx, int offsy, int winx, int winy)
+static void gp_draw_stroke_fill(
+        bGPdata *gpd, bGPDstroke *gps,
+        int offsx, int offsy, int winx, int winy, float diff_mat[4][4])
 {
+       bGPDpalettecolor *palcolor;
+       int i;
+       float fpt[3];
+
        BLI_assert(gps->totpoints >= 3);
-       
+
+       palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+
        /* Triangulation fill if high quality flag is enabled */
-       if (dflag & GP_DRAWDATA_HQ_FILL) {
+       if (palcolor->flag & PC_COLOR_HQ_FILL) {
                bGPDtriangle *stroke_triangle;
                bGPDspoint *pt;
-               int i;
-               
+
                /* Calculate triangles cache for filling area (must be done only after changes) */
                if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
                        gp_triangulate_stroke_fill(gps);
                }
-               
                /* Draw all triangles for filling the polygon (cache must be calculated before) */
                BLI_assert(gps->tot_triangles >= 1);
                glBegin(GL_TRIANGLES);
@@ -450,32 +494,33 @@ static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short
                        if (gps->flag & GP_STROKE_3DSPACE) {
                                /* vertex 1 */
                                pt = &gps->points[stroke_triangle->v1];
-                               glVertex3fv(&pt->x);
-                               
+                               mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                               glVertex3fv(fpt);
                                /* vertex 2 */
                                pt = &gps->points[stroke_triangle->v2];
-                               glVertex3fv(&pt->x);
-                               
+                               mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                               glVertex3fv(fpt);
                                /* vertex 3 */
                                pt = &gps->points[stroke_triangle->v3];
-                               glVertex3fv(&pt->x);
+                               mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                               glVertex3fv(fpt);
                        }
                        else {
                                float co[2];
-                               
                                /* vertex 1 */
                                pt = &gps->points[stroke_triangle->v1];
-                               gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+                               mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                               gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
                                glVertex2fv(co);
-                               
                                /* vertex 2 */
                                pt = &gps->points[stroke_triangle->v2];
-                               gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+                               mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                               gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
                                glVertex2fv(co);
-                               
                                /* vertex 3 */
                                pt = &gps->points[stroke_triangle->v3];
-                               gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+                               mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                               gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
                                glVertex2fv(co);
                        }
                }
@@ -483,30 +528,31 @@ static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short
        }
        else {
                /* As an initial implementation, we use the OpenGL filled polygon drawing
-                * here since it's the easiest option to implement for this case. It does
-                * come with limitations (notably for concave shapes), though it works well
-                * enough for many simple situations.
-                *
-                * We keep this legacy implementation around despite now having the high quality
-                * fills, as this is necessary for keeping everything working nicely for files
-                * created using old versions of Blender which may have depended on the artifacts
-                * the old fills created.
-                */
+               * here since it's the easiest option to implement for this case. It does
+               * come with limitations (notably for concave shapes), though it shouldn't
+               * be much of an issue in most cases.
+               *
+               * We keep this legacy implementation around despite now having the high quality
+               * fills, as this is necessary for keeping everything working nicely for files
+               * created using old versions of Blender which may have depended on the artifacts
+               * the old fills created.
+               */
                bGPDspoint *pt;
-               int i;
-               
+
                glBegin(GL_POLYGON);
                for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
                        if (gps->flag & GP_STROKE_3DSPACE) {
-                               glVertex3fv(&pt->x);
+                               mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                               glVertex3fv(fpt);
                        }
                        else {
                                float co[2];
-                               
-                               gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+                               mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                               gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
                                glVertex2fv(co);
                        }
                }
+
                glEnd();
        }
 }
@@ -514,23 +560,33 @@ static void gp_draw_stroke_fill(bGPDstroke *gps, short UNUSED(thickness), short
 /* ----- Existing Strokes Drawing (3D and Point) ------ */
 
 /* draw a given stroke - just a single dot (only one point) */
-static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dflag, short sflag,
-                                 int offsx, int offsy, int winx, int winy)
+static void gp_draw_stroke_point(
+        bGPDspoint *points, short thickness, short dflag, short sflag,
+        int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4])
 {
+       float fpt[3];
+       bGPDspoint *pt = &points[0];
+
+       /* color of point */
+       gp_set_point_color(pt, ink);
+
        /* set point thickness (since there's only one of these) */
        glPointSize((float)(thickness + 2) * points->pressure);
        
+       /* get final position using parent matrix */
+       mul_v3_m4v3(fpt, diff_mat, &pt->x);
+
        /* draw point */
        if (sflag & GP_STROKE_3DSPACE) {
                glBegin(GL_POINTS);
-               glVertex3fv(&points->x);
+               glVertex3fv(fpt);
                glEnd();
        }
        else {
                float co[2];
                
                /* get coordinates of point */
-               gp_calc_2d_stroke_xy(points, sflag, offsx, offsy, winx, winy, co);
+               gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
                
                /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok
                 *  - also mandatory in if Image Editor 'image-based' dot
@@ -559,16 +615,21 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla
 }
 
 /* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
-static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug, short UNUSED(sflag))
+static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug,
+                              short UNUSED(sflag), float diff_mat[4][4], float ink[4], bool cyclic)
 {
-       bGPDspoint *pt;
+       bGPDspoint *pt, *pt2;
        float curpressure = points[0].pressure;
        int i;
-       
+       float fpt[3];
+       float cyclic_fpt[3];
+
        /* draw stroke curve */
        glLineWidth(max_ff(curpressure * thickness, 1.0f));
        glBegin(GL_LINE_STRIP);
        for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
+               gp_set_point_color(pt, ink);
+
                /* 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.
@@ -580,15 +641,29 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
                        glBegin(GL_LINE_STRIP);
                        
                        /* need to roll-back one point to ensure that there are no gaps in the stroke */
-                       if (i != 0) glVertex3fv(&(pt - 1)->x);
+                       if (i != 0) { 
+                               pt2 = pt - 1;
+                               mul_v3_m4v3(fpt, diff_mat, &pt2->x);
+                               glVertex3fv(fpt);
+                       }
                        
                        /* now the point we want... */
-                       glVertex3fv(&pt->x);
+                       mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                       glVertex3fv(fpt);
                }
                else {
-                       glVertex3fv(&pt->x);
+                       mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                       glVertex3fv(fpt);
+               }
+               /* saves first point to use in cyclic */
+               if (i == 0) {
+                       copy_v3_v3(cyclic_fpt, fpt);
                }
        }
+       /* if cyclic draw line to first point */
+       if (cyclic) {
+               glVertex3fv(cyclic_fpt);
+       }
        glEnd();
 
        /* draw debug points of curve on top? */
@@ -597,9 +672,12 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
                glPointSize((float)(thickness + 2));
                
                glBegin(GL_POINTS);
-               for (i = 0, pt = points; i < totpoints && pt; i++, pt++)
-                       glVertex3fv(&pt->x);
+               for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
+                       mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                       glVertex3fv(fpt);
+               }
                glEnd();
+
        }
 }
 
@@ -607,7 +685,7 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
 
 /* draw a given stroke in 2d */
 static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
-                              bool debug, int offsx, int offsy, int winx, int winy)
+                              bool debug, int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4])
 {
        /* otherwise thickness is twice that of the 3D view */
        float thickness = (float)thickness_s * 0.5f;
@@ -625,6 +703,7 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
                bGPDspoint *pt1, *pt2;
                float pm[2];
                int i;
+               float fpt[3];
                
                glShadeModel(GL_FLAT);
                glBegin(GL_QUADS);
@@ -635,10 +714,13 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
                        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 points */
-                       gp_calc_2d_stroke_xy(pt1, sflag, offsx, offsy, winx, winy, s0);
-                       gp_calc_2d_stroke_xy(pt2, sflag, offsx, offsy, winx, winy, s1);
+                       mul_v3_m4v3(fpt, diff_mat, &pt1->x);
+                       gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
+
+                       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];
@@ -650,6 +732,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
                        /* always use pressure from first point here */
                        pthick = (pt1->pressure * thickness * scalefac);
                        
+                       /* color of point */
+                       gp_set_point_color(pt1, ink);
+
                        /* if the first segment, start of segment is segment's normal */
                        if (i == 0) {
                                /* draw start cap first
@@ -725,6 +810,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
                                /* 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_color(pt2, ink);
+
                                /* calculate points for end of segment */
                                mt[0] = m2[0] * pthick;
                                mt[1] = m2[1] * pthick;
@@ -770,14 +858,15 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
        if (debug) {
                bGPDspoint *pt;
                int i;
-               
+               float fpt[3];
+
                glPointSize((float)(thickness_s + 2));
                
                glBegin(GL_POINTS);
                for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
                        float co[2];
-                       
-                       gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
+                       mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                       gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
                        glVertex2fv(co);
                }
                glEnd();
@@ -818,26 +907,45 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
 }
 
 /* draw a set of strokes */
-static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
-                            bool debug, short lthick, const float color[4], const float fill_color[4])
+static void gp_draw_strokes(
+        bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
+        bool debug, short lthick, const float opacity, const float tintcolor[4],
+        const bool onion, const bool custonion, float diff_mat[4][4])
 {
        bGPDstroke *gps;
-       
+       float tcolor[4];
+       float tfill[4];
+       short sthickness;
+       float ink[4];
+
        for (gps = gpf->strokes.first; gps; gps = gps->next) {
                /* check if stroke can be drawn */
-               if (gp_can_draw_stroke(gps, dflag) == false)
+               if (gp_can_draw_stroke(gps, dflag) == false) {
                        continue;
-               
+               }
+               /* check if the color is visible */
+               bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+               if ((palcolor == NULL) ||
+                   (palcolor->flag & PC_COLOR_HIDE) ||
+                   /* if onion and ghost flag do not draw*/
+                   (onion && (palcolor->flag & PC_COLOR_ONIONSKIN)))
+               {
+                       continue;
+               }
+
+               /* calculate thickness */
+               sthickness = gps->thickness + lthick;
+
                /* 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);
                                glEnable(GL_DEPTH_TEST);
-                               
+
                                /* first arg is normally rv3d->dist, but this isn't
                                 * available here and seems to work quite well without */
                                bglPolygonOffset(1.0f, 1.0f);
@@ -846,34 +954,65 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
                                glPolygonOffset(-1.0f, -1.0f);
 #endif
                        }
-                       
+
                        /* 3D Fill */
-                       if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
-                               glColor4fv(fill_color);
-                               gp_draw_stroke_fill(gps, lthick, dflag, offsx, offsy, winx, winy);
+                       //if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
+                       if (gps->totpoints >= 3) {
+                               /* set color using palette, tint color and opacity */
+                               interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
+                               tfill[3] = palcolor->fill[3] * opacity;
+                               if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
+                                       if (!onion) {
+                                               glColor4fv(tfill);
+                                       }
+                                       else {
+                                               if (custonion) {
+                                                       glColor4fv(tintcolor);
+                                               }
+                                               else {
+                                                       ARRAY_SET_ITEMS(tfill, UNPACK3(palcolor->fill), tintcolor[3]);
+                                                       glColor4fv(tfill);
+                                               }
+                                       }
+                                       gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
+                               }
                        }
-                       
+
                        /* 3D Stroke */
-                       glColor4fv(color);
-                       
-                       if (dflag & GP_DRAWDATA_VOLUMETRIC) {
+                       /* set color using palette, tint color and opacity */
+                       if (!onion) {
+                               interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]);
+                               tcolor[3] = palcolor->color[3] * opacity;
+                               copy_v4_v4(ink, tcolor);
+                       }
+                       else {
+                               if (custonion) {
+                                       copy_v4_v4(ink, tintcolor);
+                               }
+                               else {
+                                       ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
+                                       copy_v4_v4(ink, tcolor);
+                               }
+                       }
+                       if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
                                /* volumetric stroke drawing */
-                               gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, lthick, dflag, gps->flag);
+                               gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, diff_mat, ink);
                        }
                        else {
                                /* 3D Lines - OpenGL primitives-based */
                                if (gps->totpoints == 1) {
-                                       gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+                                       gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
+                                                            diff_mat, ink);
                                }
                                else {
-                                       gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug, gps->flag);
+                                       gp_draw_stroke_3d(gps->points, gps->totpoints, sthickness, debug, gps->flag,
+                                                         diff_mat, ink, gps->flag & GP_STROKE_CYCLIC);
                                }
                        }
-                       
                        if (no_xray) {
                                glDepthMask(mask_orig);
                                glDisable(GL_DEPTH_TEST);
-                               
+
                                bglPolygonOffset(0.0, 0.0);
 #if 0
                                glDisable(GL_POLYGON_OFFSET_LINE);
@@ -883,25 +1022,58 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
                }
                else {
                        /* 2D - Fill */
-                       if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
-                               glColor4fv(fill_color);
-                               gp_draw_stroke_fill(gps, lthick, dflag, offsx, offsy, winx, winy);
+                       if (gps->totpoints >= 3) {
+                               /* set color using palette, tint color and opacity */
+                               interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
+                               tfill[3] = palcolor->fill[3] * opacity;
+                               if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
+                                       if (!onion) {
+                                               glColor4fv(tfill);
+                                       }
+                                       else {
+                                               if (custonion) {
+                                                       glColor4fv(tintcolor);
+                                               }
+                                               else {
+                                                       ARRAY_SET_ITEMS(tfill, palcolor->fill[0], palcolor->fill[1], palcolor->fill[2],
+                                                                       tintcolor[3]);
+                                                       glColor4fv(tfill);
+                                               }
+                                       }
+                                       gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
+                               }
                        }
-                       
+
                        /* 2D Strokes... */
-                       glColor4fv(color);
-                       
-                       if (dflag & GP_DRAWDATA_VOLUMETRIC) {
+                       /* set color using palette, tint color and opacity */
+                       if (!onion) {
+                               interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]);
+                               tcolor[3] = palcolor->color[3] * opacity;
+                               copy_v4_v4(ink, tcolor);
+                       }
+                       else {
+                               if (custonion) {
+                                       copy_v4_v4(ink, tintcolor);
+                               }
+                               else {
+                                       ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
+                                       copy_v4_v4(ink, tcolor);
+                               }
+                       }
+                       if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
                                /* blob/disk-based "volumetric" drawing */
-                               gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+                               gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag,
+                                                            offsx, offsy, winx, winy, diff_mat, ink);
                        }
                        else {
                                /* normal 2D strokes */
                                if (gps->totpoints == 1) {
-                                       gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+                                       gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
+                                                            diff_mat, ink);
                                }
                                else {
-                                       gp_draw_stroke_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy);
+                                       gp_draw_stroke_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, debug,
+                                                         offsx, offsy, winx, winy, diff_mat, ink);
                                }
                        }
                }
@@ -909,13 +1081,19 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
 }
 
 /* Draw selected verts for strokes being edited */
-static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, const float tcolor[3])
+static void gp_draw_strokes_edit(
+        bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag,
+        short lflag, float diff_mat[4][4], float alpha)
 {
        bGPDstroke *gps;
        
+       /* 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) {
@@ -939,7 +1117,8 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
                bGPDspoint *pt;
                float vsize, bsize;
                int i;
-               
+               float fpt[3];
+
                /* check if stroke can be drawn */
                if (gp_can_draw_stroke(gps, dflag) == false)
                        continue;
@@ -951,6 +1130,19 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
                if ((gps->flag & GP_STROKE_SELECT) == 0)
                        continue;
                
+               /* verify palette color lock */
+               {
+                       bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+                       if (palcolor != NULL) {
+                               if (palcolor->flag & PC_COLOR_HIDE) {
+                                       continue;
+                               }
+                               if (((lflag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED)) {
+                                       continue;
+                               }
+                       }
+               }
+
                /* Get size of verts:
                 * - The selected state needs to be larger than the unselected state so that
                 *   they stand out more.
@@ -966,25 +1158,23 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
                }
                
                /* First Pass: Draw all the verts (i.e. these become the unselected state) */
-               if (tcolor != NULL) {
-                       /* for now, we assume that the base color of the points is not too close to the real color */
-                       glColor3fv(tcolor);
-               }
-               else {
-                       /* this doesn't work well with the default theme and black strokes... */
-                       UI_ThemeColor(TH_GP_VERTEX);
-               }
+               /* for now, we assume that the base color of the points is not too close to the real color */
+               /* set color using palette */
+               bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+               glColor3fv(palcolor->color);
+
                glPointSize(bsize);
                
                glBegin(GL_POINTS);
                for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
                        if (gps->flag & GP_STROKE_3DSPACE) {
-                               glVertex3fv(&pt->x);
+                               mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                               glVertex3fv(fpt);
                        }
                        else {
                                float co[2];
-                               
-                               gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+                               mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                               gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
                                glVertex2fv(co);
                        }
                }
@@ -992,24 +1182,54 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
                
                
                /* Second Pass: Draw only verts which are selected */
-               UI_ThemeColor(TH_GP_VERTEX_SELECT);
+               float curColor[4];
+               UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, curColor);
+               glColor4f(curColor[0], curColor[1], curColor[2], alpha);
+
                glPointSize(vsize);
                
                glBegin(GL_POINTS);
                for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
                        if (pt->flag & GP_SPOINT_SELECT) {
                                if (gps->flag & GP_STROKE_3DSPACE) {
-                                       glVertex3fv(&pt->x);
+                                       mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                                       glVertex3fv(fpt);
                                }
                                else {
                                        float co[2];
                                        
-                                       gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+                                       mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                                       gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
                                        glVertex2fv(co);
                                }
                        }
                }
                glEnd();
+
+               /* Draw start and end point if enabled stroke direction hint */
+               if ((gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1)) {
+                       bGPDspoint *p;
+                       
+                       glPointSize(vsize + 4);
+                       glBegin(GL_POINTS);
+
+                       /* start point in green bigger */
+                       glColor3f(0.0f, 1.0f, 0.0f);
+                       p = &gps->points[0];
+                       mul_v3_m4v3(fpt, diff_mat, &p->x);
+                       glVertex3fv(fpt);
+                       glEnd();
+
+                       /* end point in red smaller */
+                       glPointSize(vsize + 1);
+                       glBegin(GL_POINTS);
+
+                       glColor3f(1.0f, 0.0f, 0.0f);
+                       p = &gps->points[gps->totpoints - 1];
+                       mul_v3_m4v3(fpt, diff_mat, &p->x);
+                       glVertex3fv(fpt);
+                       glEnd();
+               }
        }
        
        
@@ -1031,18 +1251,20 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
 /* ----- General Drawing ------ */
 
 /* draw onion-skinning for a layer */
-static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
-                               int UNUSED(cfra), int dflag, bool debug, short lthick)
+static void gp_draw_onionskins(
+        bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
+        int UNUSED(cfra), int dflag, bool debug, float diff_mat[4][4])
 {
-       const float alpha = gpl->color[3];
+       const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)};
+       const float alpha = 1.0f;
        float color[4];
-       
+
        /* 1) Draw Previous Frames First */
        if (gpl->flag & GP_LAYER_GHOST_PREVCOL) {
                copy_v3_v3(color, gpl->gcolor_prev);
        }
        else {
-               copy_v3_v3(color, gpl->color);
+               copy_v3_v3(color, default_color);
        }
        
        if (gpl->gstep > 0) {
@@ -1056,7 +1278,8 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
                                /* 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(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+                               gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
+                                               true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
                        }
                        else
                                break;
@@ -1066,7 +1289,8 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
                /* 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(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+                       gp_draw_strokes(gpd, gpf->prev, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
+                                       true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
                }
        }
        else {
@@ -1079,7 +1303,7 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
                copy_v3_v3(color, gpl->gcolor_next);
        }
        else {
-               copy_v3_v3(color, gpl->color);
+               copy_v3_v3(color, default_color);
        }
        
        if (gpl->gstep_next > 0) {
@@ -1093,7 +1317,8 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
                                /* 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(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+                               gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
+                                               true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
                        }
                        else
                                break;
@@ -1103,27 +1328,31 @@ static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int of
                /* 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(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+                       gp_draw_strokes(gpd, gpf->next, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
+                                       true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
                }
        }
        else {
                /* don't draw - disabled */
        }
        
-       /* 3) restore alpha */
-       glColor4fv(gpl->color);
 }
 
 /* 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)
+static void gp_draw_data_layers(
+        bGPDbrush *brush, float alpha, bGPdata *gpd,
+        int offsx, int offsy, int winx, int winy, int cfra, int dflag)
 {
        bGPDlayer *gpl;
-       
+       float diff_mat[4][4];
+
        for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
                bGPDframe *gpf;
-               
+               /* calculate parent position */
+               ED_gpencil_parent_location(gpl, diff_mat);
+
                bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false;
-               short lthick = gpl->thickness;
+               short lthick = brush->thickness + gpl->thickness;
                
                /* don't draw layer if hidden */
                if (gpl->flag & GP_LAYER_HIDE)
@@ -1155,9 +1384,6 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
                /* HQ fills... */
                GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_HQ_FILL), GP_DRAWDATA_HQ_FILL);
 
-               /* fill strokes... */
-               // XXX: this is not a very good limit
-               GP_DRAWFLAG_APPLY((gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH), GP_DRAWDATA_FILL);
 #undef GP_DRAWFLAG_APPLY
                
                /* draw 'onionskins' (frame left + right) */
@@ -1165,11 +1391,12 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
                        /* Drawing method - only immediately surrounding (gstep = 0),
                         * or within a frame range on either side (gstep > 0)
                         */
-                       gp_draw_onionskins(gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, lthick);
+                       gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, diff_mat);
                }
                
                /* draw the strokes already in active frame */
-               gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, gpl->color, gpl->fill);
+               gp_draw_strokes(gpd, gpf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness,
+                               gpl->opacity, gpl->tintcolor, false, false, diff_mat);
                
                /* Draw verts of selected strokes
                 *  - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
@@ -1183,8 +1410,7 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
                    (gpl->flag & GP_LAYER_LOCKED) == 0 &&
                    (gpd->flag & GP_DATA_STROKE_EDITMODE))
                {
-                       gp_draw_strokes_edit(gpf, offsx, offsy, winx, winy, dflag,
-                                            (gpl->color[3] < 0.95f) ? gpl->color : NULL);
+                       gp_draw_strokes_edit(gpd, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, diff_mat, alpha);
                }
                
                /* Check if may need to draw the active stroke cache, only if this layer is the active layer
@@ -1194,7 +1420,7 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
                    (gpf->flag & GP_FRAME_PAINT))
                {
                        /* Set color for drawing buffer stroke - since this may not be set yet */
-                       glColor4fv(gpl->color);
+                       // glColor4fv(gpl->color);
                        
                        /* Buffer stroke needs to be drawn with a different linestyle
                         * to help differentiate them from normal strokes.
@@ -1202,11 +1428,12 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
                         * It should also be noted that sbuffer contains temporary point types
                         * i.e. tGPspoints NOT bGPDspoints
                         */
-                       if (gpl->flag & GP_LAYER_VOLUMETRIC) {
-                               gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
+                       if (gpd->sflag & PC_COLOR_VOLUMETRIC) {
+                               gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick,
+                                                                dflag, gpd->sbuffer_sflag, gpd->scolor);
                        }
                        else {
-                               gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
+                               gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor);
                        }
                }
        }
@@ -1258,7 +1485,9 @@ static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
 }
 
 /* draw grease-pencil datablock */
-static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
+static void gp_draw_data(
+        bGPDbrush *brush, float alpha, bGPdata *gpd,
+        int offsx, int offsy, int winx, int winy, int cfra, int dflag)
 {
        /* reset line drawing style (in case previous user didn't reset) */
        setlinestyle(0);
@@ -1276,7 +1505,7 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy,
        glEnable(GL_BLEND);
        
        /* draw! */
-       gp_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag);
+       gp_draw_data_layers(brush, alpha, gpd, offsx, offsy, winx, winy, cfra, dflag);
        
        /* turn off alpha blending, then smooth lines */
        glDisable(GL_BLEND); // alpha blending
@@ -1303,14 +1532,25 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
                }
                
                if (gpd_source) {
-                       gp_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag);
+                       ToolSettings *ts = scene->toolsettings;
+                       bGPDbrush *brush = gpencil_brush_getactive(ts);
+                       if (brush != NULL) {
+                               gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source,
+                                            offsx, offsy, winx, winy, cfra, dflag);
+                       }
+                       
                }
        }
        
        /* 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);
+               ToolSettings *ts = scene->toolsettings;
+               bGPDbrush *brush = gpencil_brush_getactive(ts);
+               if (brush != NULL) {
+                       gp_draw_data(brush, ts->gp_sculpt.alpha, gpd,
+                                    offsx, offsy, winx, winy, cfra, dflag);
+               }
        }
 }
 
@@ -1479,6 +1719,7 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, AReg
        
        /* draw it! */
        gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
+       
 }
 
 void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
index 0271afd6827ebfc5700b2e6dee217aada7c72196..1bb3b7e1ae77046df070a8d6315a67febe4b83cd 100644 (file)
@@ -18,7 +18,7 @@
  * The Original Code is Copyright (C) 2015, Blender Foundation
  * This is a new part of Blender
  *
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
  *
  * ***** END GPL LICENSE BLOCK *****
  *
@@ -51,6 +51,7 @@
 #include "DNA_space_types.h"
 #include "DNA_view3d_types.h"
 #include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
 
 #include "BKE_context.h"
 #include "BKE_global.h"
@@ -223,9 +224,26 @@ static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i
        GP_EditBrush_Data *brush = gso->brush;
        float inf = gp_brush_influence_calc(gso, radius, co);
        bool affect_pressure = (brush->flag & GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE) != 0;
-       
+       /* need one flag enabled by default */
+       if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION |
+                                   GP_BRUSHEDIT_FLAG_APPLY_STRENGTH |
+                                   GP_BRUSHEDIT_FLAG_APPLY_THICKNESS)) == 0)
+       {
+               gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
+       }
+
        /* perform smoothing */
-       return gp_smooth_stroke(gps, i, inf, affect_pressure);
+       if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_POSITION) {
+               gp_smooth_stroke(gps, i, inf, affect_pressure);
+       }
+       if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_STRENGTH) {
+               gp_smooth_stroke_strength(gps, i, inf);
+       }
+       if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_THICKNESS) {
+               gp_smooth_stroke_thickness(gps, i, inf);
+       }
+       
+       return true;
 }
 
 /* ----------------------------------------------- */
@@ -267,6 +285,41 @@ static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
 }
 
 
+/* ----------------------------------------------- */
+/* 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 i,
+        const int radius, const int co[2])
+{
+       bGPDspoint *pt = gps->points + i;
+       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->strength -= inf;
+       }
+       else {
+               /* make line thicker - increase stroke pressure */
+               pt->strength += inf;
+       }
+
+       /* Strength should stay within [0.0, 1.0] */
+       CLAMP(pt->strength, 0.0f, 1.0f);
+
+       return true;
+}
+
+
 /* ----------------------------------------------- */
 /* Grab Brush */
 
@@ -373,11 +426,12 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
 }
 
 /* Apply grab transform to all relevant points of the affected strokes */
-static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso, bGPDstroke *gps)
+static void gp_brush_grab_apply_cached(
+        tGP_BrushEditData *gso, bGPDstroke *gps, bool parented, 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]];
@@ -385,9 +439,23 @@ static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso, bGPDstroke *gps)
                
                /* adjust the amount of displacement to apply */
                mul_v3_v3fl(delta, gso->dvec, data->weights[i]);
+               if (!parented) {
+                       /* apply */
+                       add_v3_v3(&pt->x, delta);
+               }
+               else {
+                       float fpt[3];
+                       /* apply transformation */
+                       mul_v3_m4v3(fpt, diff_mat, &pt->x);
+                       /* apply */
+                       add_v3_v3(fpt, delta);
+                       copy_v3_v3(&pt->x, fpt);
+                       /* 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);
+               }
                
-               /* apply */
-               add_v3_v3(&pt->x, delta);
        }
 }
 
@@ -592,62 +660,92 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
         */
        const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f;
        const float fac = BLI_frand() * inf;
-       
-       /* 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
-        *   viewspace 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];
-       
-       //printf("svec = %f %f, ", svec[0], svec[1]);
-       
-       /* scale the displacement by the random displacement, and apply */
-       if (BLI_frand() > 0.5f) {
-               mul_v2_fl(svec, -fac);
-       }
-       else {
-               mul_v2_fl(svec, fac);
+       /* need one flag enabled by default */
+       if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION |
+                                   GP_BRUSHEDIT_FLAG_APPLY_STRENGTH |
+                                   GP_BRUSHEDIT_FLAG_APPLY_THICKNESS)) == 0)
+       {
+               gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
        }
-       
-       //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);
+
+       /* apply random to position */
+       if (gso->settings->flag & GP_BRUSHEDIT_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
+                *   viewspace 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_frand() > 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);
+                               }
+                       }
+                       else {
+                               /* ERROR */
+                               BLI_assert("3D stroke being sculpted in non-3D view");
                        }
                }
                else {
-                       /* ERROR */
-                       BLI_assert("3D stroke being sculpted in non-3D view");
+                       /* 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);
                }
        }
-       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_BRUSHEDIT_FLAG_APPLY_STRENGTH) {
+               if (BLI_frand() > 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_BRUSHEDIT_FLAG_APPLY_THICKNESS) {
+               if (BLI_frand() > 0.5f) {
+                       pt->pressure += fac;
+               }
+               else {
+                       pt->pressure -= fac;
+               }
+               /* only limit lower value */
+               CLAMP_MIN(pt->pressure, 0.0f);
+       }
+
        /* done */
        return true;
 }
@@ -1099,7 +1197,9 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
 /* Apply ----------------------------------------------- */
 
 /* Apply brush operation to points in this stroke */
-static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, GP_BrushApplyCb apply)
+static bool gpsculpt_brush_do_stroke(
+        tGP_BrushEditData *gso, bGPDstroke *gps, bool parented,
+        float diff_mat[4][4], GP_BrushApplyCb apply)
 {
        GP_SpaceConversion *gsc = &gso->gsc;
        rcti *rect = &gso->brush_rect;
@@ -1111,9 +1211,16 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, GP
        int i;
        bool include_last = false;
        bool changed = false;
-       
+
        if (gps->totpoints == 1) {
-               gp_point_to_xy(gsc, gps, gps->points, &pc1[0], &pc1[1]);
+               if (!parented) {
+                       gp_point_to_xy(gsc, gps, gps->points, &pc1[0], &pc1[1]);
+               }
+               else {
+                       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])) {
@@ -1140,10 +1247,20 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, GP
                                        continue;
                                }
                        }
-                       
-                       gp_point_to_xy(gsc, gps, pt1, &pc1[0], &pc1[1]);
-                       gp_point_to_xy(gsc, gps, pt2, &pc2[0], &pc2[1]);
-                       
+                       if (!parented) {
+                               gp_point_to_xy(gsc, gps, pt1, &pc1[0], &pc1[1]);
+                               gp_point_to_xy(gsc, gps, pt2, &pc2[0], &pc2[1]);
+                       }
+                       else {
+                               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])))
@@ -1228,76 +1345,105 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
        
        
        /* Find visible strokes, and perform operations on those if hit */
-       CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+       float diff_mat[4][4];
+       bool parented = false;
+
+       CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
        {
-               switch (gso->brush_type) {
-                       case GP_EDITBRUSH_TYPE_SMOOTH: /* Smooth strokes */
-                       {
-                               changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_smooth_apply);
-                               break;
-                       }
-                       
-                       case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */
-                       {
-                               changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_thickness_apply);
-                               break;
+               /* calculate difference matrix if parent object */
+               if (gpl->parent != NULL) {
+                       ED_gpencil_parent_location(gpl, diff_mat);
+                       parented = true;
+               }
+               else {
+                       parented = false;
+               }
+
+               bGPDframe *gpf = gpl->actframe;
+               bGPDstroke *gps;
+               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;
+                       /* check if the color is editable */
+                       if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+                               continue;
                        }
-                       
-                       case GP_EDITBRUSH_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, gp_brush_grab_store_points);
+
+                       switch (gso->brush_type) {
+                               case GP_EDITBRUSH_TYPE_SMOOTH: /* Smooth strokes */
+                               {
+                                       changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_smooth_apply);
+                                       break;
                                }
-                               else {
-                                       /* Apply effect to the stored points */
-                                       gp_brush_grab_apply_cached(gso, gps);
-                                       changed |= true;
+
+                               case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */
+                               {
+                                       changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_thickness_apply);
+                                       break;
                                }
-                               break;
-                       }
-                       
-                       case GP_EDITBRUSH_TYPE_PUSH: /* Push points */
-                       {
-                               changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_push_apply);
-                               break;
-                       }
-                       
-                       case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */
-                       {
-                               changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_pinch_apply);
-                               break;
-                       }
-                       
-                       case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */
-                       {
-                               changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_twist_apply);
-                               break;
+
+                               case GP_EDITBRUSH_TYPE_STRENGTH: /* Adjust stroke color strength */
+                               {
+                                       changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_strength_apply);
+                                       break;
+                               }
+
+                               case GP_EDITBRUSH_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, parented, diff_mat, gp_brush_grab_store_points);
+                                       }
+                                       else {
+                                               /* Apply effect to the stored points */
+                                               gp_brush_grab_apply_cached(gso, gps, parented, diff_mat);
+                                               changed |= true;
+                                       }
+                                       break;
+                               }
+
+                               case GP_EDITBRUSH_TYPE_PUSH: /* Push points */
+                               {
+                                       changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_push_apply);
+                                       break;
+                               }
+
+                               case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */
+                               {
+                                       changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_pinch_apply);
+                                       break;
+                               }
+
+                               case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */
+                               {
+                                       changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_twist_apply);
+                                       break;
+                               }
+
+                               case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */
+                               {
+                                       changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_randomize_apply);
+                                       break;
+                               }
+
+                               default:
+                                       printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
+                                       break;
                        }
-                       
-                       case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */
-                       {
-                               changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_randomize_apply);
-                               break;
+                       /* Triangulation must be calculated if changed */
+                       if (changed) {
+                               gps->flag |= GP_STROKE_RECALC_CACHES;
+                               gps->tot_triangles = 0;
                        }
-                       
-                       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_CACHES;
-                       gps->tot_triangles = 0;
                }
        }
        CTX_DATA_END;
-       
+
        return changed;
 }
 
@@ -1441,6 +1587,11 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve
                        needs_timer = true;
                        break;
                        
+               case GP_EDITBRUSH_TYPE_STRENGTH:
+                       brush_rate = 0.01f; // XXX: hardcoded
+                       needs_timer = true;
+                       break;
+
                case GP_EDITBRUSH_TYPE_PINCH:
                        brush_rate = 0.001f; // XXX: hardcoded
                        needs_timer = true;
index c47985ebc1b6ab9cf49ca8575e6de6eede0db317..95ea13c399a34f3fbe46ffa7a786f1528d0924a0 100644 (file)
@@ -142,12 +142,31 @@ static EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRN
 /* 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, bGPDstroke *gps, bGPDspoint *pt, float p3d[3], rctf *subrect)
+static void gp_strokepoint_convertcoords(
+        bContext *C, 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);
-       
+       bGPDspoint mypt, *pt;
+
+       float diff_mat[4][4];
+       pt = &mypt;
+
+       /* calculate difference matrix if parent object */
+       if (gpl->parent == NULL) {
+               copy_v3_v3(&pt->x, &source_pt->x);
+       }
+       else {
+               /* apply parent transform */
+               float fpt[3];
+               ED_gpencil_parent_location(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);
@@ -628,7 +647,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
                bp = &nu->bp[old_nbp - 1];
                
                /* First point */
-               gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
+               gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
                if (prev_bp) {
                        interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
                        if (do_gtd) {
@@ -649,7 +668,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
                /* Second point */
                /* Note dt2 is always negative, which marks the gap. */
                if (gps->totpoints > 1) {
-                       gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
+                       gp_strokepoint_convertcoords(C, 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);
@@ -670,9 +689,9 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
                float p[3], next_p[3];
                float dt = 0.0f;
                
-               gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
+               gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
                if (gps->totpoints > 1) {
-                       gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
+                       gp_strokepoint_convertcoords(C, 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);
@@ -701,10 +720,10 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
             i++, pt++, bp++)
        {
                float p[3];
-               float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
+               float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC;
                
                /* get coordinates to add at */
-               gp_strokepoint_convertcoords(C, gps, pt, p, subrect);
+               gp_strokepoint_convertcoords(C, 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);
@@ -816,12 +835,12 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
        /* get initial coordinates */
        pt = gps->points;
        if (tot) {
-               gp_strokepoint_convertcoords(C, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
+               gp_strokepoint_convertcoords(C, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
                if (tot > 1) {
-                       gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
+                       gp_strokepoint_convertcoords(C, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
                }
                if (stitch && tot > 2) {
-                       gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
+                       gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
                }
        }
        
@@ -940,7 +959,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
        
        /* add points */
        for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
-               float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
+               float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC;
                
                if (i || old_nbezt) {
                        interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
@@ -964,7 +983,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
                copy_v3_v3(p3d_cur, p3d_next);
                
                if (i + 2 < tot) {
-                       gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
+                       gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
                }
                
                prev_bezt = bezt;
index 746497f0ff5e2e8f804495b64b5b4f40fa3f9216..e915446e46184b3d2b4c5ebe9a07aea5a560cfc2 100644 (file)
@@ -18,7 +18,7 @@
  * The Original Code is Copyright (C) 2008, Blender Foundation, Joshua Leung
  * This is a new part of Blender
  *
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
  *
  * ***** END GPL LICENSE BLOCK *****
  *
@@ -40,6 +40,8 @@
 
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
 
 #include "BLT_translation.h"
 
@@ -57,6 +59,7 @@
 #include "BKE_report.h"
 #include "BKE_scene.h"
 #include "BKE_screen.h"
+#include "BKE_colortools.h"
 
 #include "UI_interface.h"
 #include "UI_resources.h"
@@ -72,6 +75,8 @@
 
 #include "gpencil_intern.h"
 
+/* maximum sizes of gp-session buffer */
+#define GP_STROKE_BUFFER_MAX    5000
 
 /* ************************************************ */
 /* Datablock Operators */
@@ -596,6 +601,61 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot)
                        "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_current = gpencil_layer_getactive(gpd);
+       bGPDlayer *gpl_next = gpl_current->next;
+
+       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, SET_INT_IN_POINTER(gpf->framenum), gpf);
+       }
+
+       /* read all frames from next layer */
+       for (bGPDframe *gpf = gpl_next->frames.first; gpf; gpf = gpf->next) {
+               /* try to find frame in active layer */
+               bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, SET_INT_IN_POINTER(gpf->framenum));
+               if (!frame) {
+                       /* nothing found, create new */
+                       frame = gpencil_frame_addnew(gpl_current, gpf->framenum);
+               }
+               /* add to tail all strokes */
+               BLI_movelisttolist(&frame->strokes, &gpf->strokes);
+       }
+       /* Now delete next layer */
+       gpencil_layer_delete(gpd, gpl_next);
+       BLI_ghash_free(gh_frames_cur, NULL, NULL);
+
+       /* notifiers */
+       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";
+
+       /* callbacks */
+       ot->exec = gp_merge_layer_exec;
+       ot->poll = gp_active_layer_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
 /* ********************** Change Layer ***************************** */
 
 static int gp_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
@@ -663,3 +723,1740 @@ 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
+};
+
+static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+       bGPDstroke *gps;
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd, gpl, gpl->actframe)) {
+               return OPERATOR_CANCELLED;
+       }
+
+       bGPDframe *gpf = gpl->actframe;
+       /* temp listbase to store selected strokes */
+       ListBase selected = {NULL};
+       const int direction = RNA_enum_get(op->ptr, "type");
+
+       /* 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(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) {
+                                       BKE_report(op->reports, RPT_ERROR, "Some selected stroke is already on top");
+                                       return OPERATOR_CANCELLED;
+                               }
+                       }
+                       /* some stroke is already at botom */
+                       if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) {
+                               if (gps == gpf->strokes.first) {
+                                       BKE_report(op->reports, RPT_ERROR, "Some selected stroke is already on bottom");
+                                       return OPERATOR_CANCELLED;
+                               }
+                       }
+                       /* add to list */
+                       BLI_addtail(&selected, BLI_genericNodeN(gps));
+               }
+       }
+
+       /* Now do the movement of the stroke */
+       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_insertlinkafter(&gpf->strokes, gpf->strokes.last, gps);
+                       }
+                       break;
+               /* Bring Forward */
+               case GP_STROKE_MOVE_UP:
+                       for (LinkData *link = selected.last; link; link = link->prev) {
+                               gps = link->data;
+                               BLI_remlink(&gpf->strokes, gps);
+                               BLI_insertlinkafter(&gpf->strokes, gps->next, gps);
+                       }
+                       break;
+                       /* Send Backward */
+               case GP_STROKE_MOVE_DOWN:
+                       for (LinkData *link = selected.first; link; link = link->next) {
+                               gps = link->data;
+                               BLI_remlink(&gpf->strokes, gps);
+                               BLI_insertlinkbefore(&gpf->strokes, gps->prev, gps);
+                       }
+                       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_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
+                       }
+                       break;
+               default:
+                       BLI_assert(0);
+                       break;
+       }
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_arrange(wmOperatorType *ot)
+{
+       static 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";
+
+       /* api callbacks */
+       ot->exec = gp_stroke_arrange_exec;
+       ot->poll = gp_active_layer_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       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 *UNUSED(op))
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDpalette *palette;
+       bGPDpalettecolor *color;
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd)) {
+               return OPERATOR_CANCELLED;
+       }
+
+       palette = gpencil_palette_getactive(gpd);
+       color = gpencil_palettecolor_getactive(palette);
+       if (ELEM(NULL, palette, color)) {
+               return OPERATOR_CANCELLED;
+       }
+
+       /* loop all strokes */
+       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;
+                                       /* check if the color is editable */
+                                       if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+                                               continue;
+
+                                       /* asign new color (only if different) */
+                                       if (STREQ(gps->colorname, color->info) == false) {
+                                               strcpy(gps->colorname, color->info);
+                                               gps->flag |= GP_STROKE_RECALC_COLOR;
+                                       }
+                               }
+                       }
+               }
+       }
+       /* notifiers */
+       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 color";
+
+       /* api callbacks */
+       ot->exec = gp_stroke_change_color_exec;
+       ot->poll = gp_active_layer_poll;
+}
+
+/* ******************* 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);
+       bGPDpalette *palette;
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd))
+               return OPERATOR_CANCELLED;
+
+       palette = gpencil_palette_getactive(gpd);
+       if (ELEM(NULL, palette))
+               return OPERATOR_CANCELLED;
+
+       /* first lock all colors */
+       for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+               palcolor->flag |= PC_COLOR_LOCKED;
+       }
+
+       /* 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 */
+                                       if (gps->palcolor != NULL) {
+                                               gps->palcolor->flag &= ~PC_COLOR_LOCKED;
+                                       }
+                               }
+                       }
+               }
+       }
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       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";
+
+       /* api callbacks */
+       ot->exec = gp_stroke_lock_color_exec;
+       ot->poll = gp_active_layer_poll;
+}
+
+/* ******************* 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 = 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 */
+                       gps->thickness = gps->thickness + gpl->thickness;
+               }
+       }
+       /* clear value */
+       gpl->thickness = 0.0f;
+
+       /* notifiers */
+       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;
+}
+
+/* ******************* Close Strokes ************************** */
+
+enum {
+       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);
+       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)
+       {
+               for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+                       bGPDpalettecolor *palcolor = gps->palcolor;
+
+                       /* 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 (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_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 */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+/**
+ * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
+ * option to force opened/closed strokes instead of just toggle behavior.
+ */
+void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
+{
+       static 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;
+
+       ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", "");
+}
+
+/* ******************* Stroke join ************************** */
+
+/* Helper: flip stroke */
+static void gpencil_flip_stroke(bGPDstroke *gps)
+{
+       bGPDspoint pt, *point, *point2;
+       int end = gps->totpoints - 1;
+
+       for (int i = 0; i < gps->totpoints / 2; i++) {
+               /* 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, float delta[3],
+                                      float pressure, float strength, float deltatime)
+{
+       bGPDspoint *newpoint;
+
+       gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (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;
+}
+
+/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */
+static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b)
+{
+       bGPDspoint point, *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);
+       }
+
+       /* 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, 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, 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, delta, pt->pressure, pt->strength, deltatime);
+               }
+       }
+}
+
+enum {
+       GP_STROKE_JOIN = -1,
+       GP_STROKE_JOINCOPY = 1
+};
+
+static int gp_stroke_join_exec(bContext *C, wmOperator *op)
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDlayer *activegpl = gpencil_layer_getactive(gpd);
+       bGPDstroke *gps, *gpsn;
+       bGPDpalette *palette = gpencil_palette_getactive(gpd);
+       bGPDpalettecolor *palcolor = gpencil_palettecolor_getactive(palette);
+
+       bGPDframe *gpf_a = NULL;
+       bGPDstroke *stroke_a = NULL;
+       bGPDstroke *stroke_b = NULL;
+       bGPDstroke *new_stroke = NULL;
+
+       int type = RNA_enum_get(op->ptr, "type");
+
+       /* 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;
+               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(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);
+                                               new_stroke->triangles = NULL;
+                                               new_stroke->tot_triangles = 0;
+                                               new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+                                               /* if new, set current color */
+                                               if (type == GP_STROKE_JOINCOPY) {
+                                                       new_stroke->palcolor = palcolor;
+                                                       strcpy(new_stroke->colorname, palcolor->info);
+                                                       new_stroke->flag |= GP_STROKE_RECALC_COLOR;
+                                               }
+                                       }
+                                       /* join new_stroke and stroke B. New stroke will contain all the previous data */
+                                       gpencil_stroke_join_strokes(new_stroke, stroke_b);
+
+                                       /* 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);
+                                                       free_gpencil_stroke(stroke_a);
+                                                       stroke_a = NULL;
+                                               }
+                                               if (stroke_b) {
+                                                       BLI_remlink(&gpf->strokes, stroke_b);
+                                                       free_gpencil_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 = gpencil_frame_addnew(activegpl, gpf_a->framenum);
+
+                       BLI_addtail(&activegpl->actframe->strokes, new_stroke);
+               }
+       }
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_join(wmOperatorType *ot)
+{
+       static 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;
+
+       ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", "");
+}
+
+/* ******************* Stroke flip ************************** */
+
+static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(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;
+               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(gpl, gps) == false) {
+                                       continue;
+                               }
+                               /* flip stroke */
+                               gpencil_flip_stroke(gps);
+                       }
+               }
+       }
+       CTX_DATA_END;
+
+       /* notifiers */
+       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 drawing direction of selected strokes";
+
+       /* api callbacks */
+       ot->exec = gp_stroke_flip_exec;
+       ot->poll = gp_active_layer_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ************************************************ */
+/* Drawing Brushes Operators */
+
+/* ******************* Add New Brush ************************ */
+
+/* add new brush - wrapper around API */
+static int gp_brush_add_exec(bContext *C, wmOperator *op)
+{
+       ToolSettings *ts = CTX_data_tool_settings(C);
+
+       /* if there's no existing container */
+       if (ts == NULL) {
+               BKE_report(op->reports, RPT_ERROR, "Nowhere for brush data to go");
+               return OPERATOR_CANCELLED;
+       }
+       /* add new brush now */
+       gpencil_brush_addnew(ts, DATA_("GP_Brush"), true);
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_add(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Add Brush";
+       ot->idname = "GPENCIL_OT_brush_add";
+       ot->description = "Add new Grease Pencil drawing brush for the active Grease Pencil datablock";
+
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* callbacks */
+       ot->exec = gp_brush_add_exec;
+       ot->poll = gp_add_poll;
+}
+
+/* ******************* Remove Active Brush ************************* */
+
+static int gp_brush_remove_exec(bContext *C, wmOperator *op)
+{
+       ToolSettings *ts = CTX_data_tool_settings(C);
+       bGPDbrush *brush = gpencil_brush_getactive(ts);
+
+       /* sanity checks */
+       if (ELEM(NULL, ts, brush))
+               return OPERATOR_CANCELLED;
+
+       if (BLI_listbase_count(&ts->gp_brushes) < 2) {
+               BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a brush. Unable to delete brush");
+               return OPERATOR_CANCELLED;
+       }
+
+
+       /* make the brush before this the new active brush
+        * - use the one after if this is the first
+        * - if this is the only brush, this naturally becomes NULL
+        */
+       if (brush->prev)
+               gpencil_brush_setactive(ts, brush->prev);
+       else
+               gpencil_brush_setactive(ts, brush->next);
+
+       /* delete the brush now... */
+       gpencil_brush_delete(ts, brush);
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_remove(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Remove brush";
+       ot->idname = "GPENCIL_OT_brush_remove";
+       ot->description = "Remove active Grease Pencil drawing brush";
+
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* callbacks */
+       ot->exec = gp_brush_remove_exec;
+       ot->poll = gp_active_brush_poll;
+}
+
+/* ********************** Change Brush ***************************** */
+
+static int gp_brush_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
+{
+       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_brush_change", "brush");
+       UI_popup_menu_end(C, pup);
+
+       return OPERATOR_INTERFACE;
+}
+
+static int gp_brush_change_exec(bContext *C, wmOperator *op)
+{
+       ToolSettings *ts = CTX_data_tool_settings(C);
+       bGPDbrush *brush = NULL;
+       int brush_num = RNA_enum_get(op->ptr, "brush");
+
+       /* Get brush or create new one */
+       if (brush_num == -1) {
+               /* Create brush */
+               brush = gpencil_brush_addnew(ts, DATA_("GP_Brush"), true);
+       }
+       else {
+               /* Try to get brush */
+               brush = BLI_findlink(&ts->gp_brushes, brush_num);
+
+               if (brush == NULL) {
+                       BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent brush (index = %d)", brush_num);
+                       return OPERATOR_CANCELLED;
+               }
+       }
+
+       /* Set active brush */
+       gpencil_brush_setactive(ts, brush);
+
+       /* updates */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_change(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Change Brush";
+       ot->idname = "GPENCIL_OT_brush_change";
+       ot->description = "Change active Grease Pencil drawing brush";
+
+       /* callbacks */
+       ot->invoke = gp_brush_change_invoke;
+       ot->exec = gp_brush_change_exec;
+       ot->poll = gp_active_brush_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* gp brush to use (dynamic enum) */
+       ot->prop = RNA_def_enum(ot->srna, "brush", DummyRNA_DEFAULT_items, 0, "Grease Pencil Brush", "");
+       RNA_def_enum_funcs(ot->prop, ED_gpencil_brushes_enum_itemf);
+}
+
+/* ******************* Move Brush Up/Down ************************** */
+
+enum {
+       GP_BRUSH_MOVE_UP = -1,
+       GP_BRUSH_MOVE_DOWN = 1
+};
+
+static int gp_brush_move_exec(bContext *C, wmOperator *op)
+{
+       ToolSettings *ts = CTX_data_tool_settings(C);
+       bGPDbrush *brush = gpencil_brush_getactive(ts);
+
+       int direction = RNA_enum_get(op->ptr, "type");
+
+       /* sanity checks */
+       if (ELEM(NULL, ts, brush)) {
+               return OPERATOR_CANCELLED;
+       }
+
+       /* up or down? */
+       if (direction == GP_BRUSH_MOVE_UP) {
+               /* up */
+               BLI_remlink(&ts->gp_brushes, brush);
+               BLI_insertlinkbefore(&ts->gp_brushes, brush->prev, brush);
+       }
+       else if (direction == GP_BRUSH_MOVE_DOWN) {
+               /* down */
+               BLI_remlink(&ts->gp_brushes, brush);
+               BLI_insertlinkafter(&ts->gp_brushes, brush->next, brush);
+       }
+       else {
+               BLI_assert(0);
+       }
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_move(wmOperatorType *ot)
+{
+       static EnumPropertyItem slot_move[] = {
+               {GP_BRUSH_MOVE_UP, "UP", 0, "Up", ""},
+               {GP_BRUSH_MOVE_DOWN, "DOWN", 0, "Down", ""},
+               {0, NULL, 0, NULL, NULL }
+       };
+
+       /* identifiers */
+       ot->name = "Move Brush";
+       ot->idname = "GPENCIL_OT_brush_move";
+       ot->description = "Move the active Grease Pencil drawing brush up/down in the list";
+
+       /* api callbacks */
+       ot->exec = gp_brush_move_exec;
+       ot->poll = gp_active_brush_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       ot->prop = RNA_def_enum(ot->srna, "type", slot_move, GP_BRUSH_MOVE_UP, "Type", "");
+}
+
+/* ******************* Brush create presets ************************** */
+
+static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       ToolSettings *ts = CTX_data_tool_settings(C);
+       gpencil_brush_init_presets(ts);
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       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";
+
+       /* api callbacks */
+       ot->exec = gp_brush_presets_create_exec;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+}
+
+/* ***************** Copy Brush ************************ */
+
+static int gp_brush_copy_exec(bContext *C, wmOperator *op)
+{
+       ToolSettings *ts = CTX_data_tool_settings(C);
+
+       /* if there's no existing container */
+       if (ts == NULL) {
+               BKE_report(op->reports, RPT_ERROR, "Nowhere for brush data to go");
+               return OPERATOR_CANCELLED;
+       }
+
+       bGPDbrush *brush = gpencil_brush_getactive(ts);
+       bGPDbrush *newbrush;
+
+       /* sanity checks */
+       if (ELEM(NULL, brush))
+               return OPERATOR_CANCELLED;
+
+       /* create a brush and duplicate data */
+       newbrush = gpencil_brush_addnew(ts, brush->info, true);
+       newbrush->thickness = brush->thickness;
+       newbrush->draw_smoothfac = brush->draw_smoothfac;
+       newbrush->draw_smoothlvl = brush->draw_smoothlvl;
+       newbrush->sublevel = brush->sublevel;
+       newbrush->flag = brush->flag;
+       newbrush->draw_sensitivity = brush->draw_sensitivity;
+       newbrush->draw_strength = brush->draw_strength;
+       newbrush->draw_jitter = brush->draw_jitter;
+       newbrush->draw_angle = brush->draw_angle;
+       newbrush->draw_angle_factor = brush->draw_angle_factor;
+       newbrush->draw_random_press = brush->draw_random_press;
+       newbrush->draw_random_sub = brush->draw_random_sub;
+
+       /* free automatic curves created by default (replaced by copy) */
+       curvemapping_free(newbrush->cur_sensitivity);
+       curvemapping_free(newbrush->cur_strength);
+       curvemapping_free(newbrush->cur_jitter);
+
+       /* make a copy of curves */
+       newbrush->cur_sensitivity = curvemapping_copy(brush->cur_sensitivity);
+       newbrush->cur_strength = curvemapping_copy(brush->cur_strength);
+       newbrush->cur_jitter = curvemapping_copy(brush->cur_jitter);
+
+       gpencil_brush_setactive(ts, newbrush);
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_copy(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Copy Brush";
+       ot->idname = "GPENCIL_OT_brush_copy";
+       ot->description = "Copy current Grease Pencil drawing brush";
+
+       /* callbacks */
+       ot->exec = gp_brush_copy_exec;
+       ot->poll = gp_active_brush_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ***************** Select Brush ************************ */
+
+static int gp_brush_select_exec(bContext *C, wmOperator *op)
+{
+       ToolSettings *ts = CTX_data_tool_settings(C);
+
+       /* if there's no existing container */
+       if (ts == NULL) {
+               BKE_report(op->reports, RPT_ERROR, "Nowhere to go");
+               return OPERATOR_CANCELLED;
+       }
+
+       const int index = RNA_int_get(op->ptr, "index");
+       bGPDbrush *brush = BLI_findlink(&ts->gp_brushes, index);
+       /* sanity checks */
+       if (ELEM(NULL, brush)) {
+               return OPERATOR_CANCELLED;
+       }
+
+       gpencil_brush_setactive(ts, brush);
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_select(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Select Brush";
+       ot->idname = "GPENCIL_OT_brush_select";
+       ot->description = "Select a Grease Pencil drawing brush";
+
+       /* callbacks */
+       ot->exec = gp_brush_select_exec;
+       ot->poll = gp_active_brush_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Drawing Brush", 0, INT_MAX);
+}
+
+/* ************************************************ */
+/* Palette Operators */
+
+/* ******************* Add New Palette ************************ */
+
+/* add new palette - wrapper around API */
+static int gp_palette_add_exec(bContext *C, wmOperator *op)
+{
+       bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+       /* 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)
+               *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+
+       /* add new palette now */
+       gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true);
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palette_add(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Add Palette";
+       ot->idname = "GPENCIL_OT_palette_add";
+       ot->description = "Add new Grease Pencil palette for the active Grease Pencil datablock";
+
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* callbacks */
+       ot->exec = gp_palette_add_exec;
+       ot->poll = gp_add_poll;
+}
+
+/* ******************* Remove Active Palette ************************* */
+
+static int gp_palette_remove_exec(bContext *C, wmOperator *op)
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDpalette *palette = gpencil_palette_getactive(gpd);
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd, palette))
+               return OPERATOR_CANCELLED;
+
+       if (BLI_listbase_count(&gpd->palettes) < 2) {
+               BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette. Unable to delete palette");
+               return OPERATOR_CANCELLED;
+       }
+
+
+       /* make the palette before this the new active palette
+        * - use the one after if this is the first
+        * - if this is the only palette, this naturally becomes NULL
+        */
+       if (palette->prev)
+               gpencil_palette_setactive(gpd, palette->prev);
+       else
+               gpencil_palette_setactive(gpd, palette->next);
+
+       /* delete the palette now... */
+       gpencil_palette_delete(gpd, palette);
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palette_remove(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Remove palette";
+       ot->idname = "GPENCIL_OT_palette_remove";
+       ot->description = "Remove active Grease Pencil palette";
+
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* callbacks */
+       ot->exec = gp_palette_remove_exec;
+       ot->poll = gp_active_palette_poll;
+}
+
+/* ********************** Change Palette ***************************** */
+
+static int gp_palette_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
+{
+       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_palette_change", "palette");
+       UI_popup_menu_end(C, pup);
+
+       return OPERATOR_INTERFACE;
+}
+
+static int gp_palette_change_exec(bContext *C, wmOperator *op)
+{
+       bGPdata *gpd = CTX_data_gpencil_data(C);
+       bGPDpalette *palette = NULL;
+       int palette_num = RNA_enum_get(op->ptr, "palette");
+
+       /* Get palette or create new one */
+       if (palette_num == -1) {
+               /* Create palette */
+               palette = gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
+       }
+       else {
+               /* Try to get palette */
+               palette = BLI_findlink(&gpd->palettes, palette_num);
+
+               if (palette == NULL) {
+                       BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent palette (index = %d)", palette_num);
+                       return OPERATOR_CANCELLED;
+               }
+       }
+
+       /* Set active palette */
+       gpencil_palette_setactive(gpd, palette);
+
+       /* updates */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palette_change(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Change Palette";
+       ot->idname = "GPENCIL_OT_palette_change";
+       ot->description = "Change active Grease Pencil palette";
+
+       /* callbacks */
+       ot->invoke = gp_palette_change_invoke;
+       ot->exec = gp_palette_change_exec;
+       ot->poll = gp_active_palette_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* gp palette to use (dynamic enum) */
+       ot->prop = RNA_def_enum(ot->srna, "palette", DummyRNA_DEFAULT_items, 0, "Grease Pencil Palette", "");
+       RNA_def_enum_funcs(ot->prop, ED_gpencil_palettes_enum_itemf);
+}
+
+/* ******************* Lock and hide any color non used in current layer ************************** */
+
+static int gp_palette_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDpalette *palette;
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd))
+               return OPERATOR_CANCELLED;
+
+       palette = gpencil_palette_getactive(gpd);
+       if (ELEM(NULL, palette))
+               return OPERATOR_CANCELLED;
+
+       /* first lock and hide all colors */
+       for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+               palcolor->flag |= PC_COLOR_LOCKED;
+               palcolor->flag |= PC_COLOR_HIDE;
+       }
+
+       /* 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;
+
+                               /* unlock/unhide color if not unlocked before */
+                               if (gps->palcolor != NULL) {
+                                       gps->palcolor->flag &= ~PC_COLOR_LOCKED;
+                                       gps->palcolor->flag &= ~PC_COLOR_HIDE;
+                               }
+                       }
+               }
+       }
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palette_lock_layer(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Disable Unused Layer Colors";
+       ot->idname = "GPENCIL_OT_palette_lock_layer";
+       ot->description = "Lock and hide any color not used in any layer";
+
+       /* api callbacks */
+       ot->exec = gp_palette_lock_layer_exec;
+       ot->poll = gp_active_layer_poll;
+}
+
+/* ************************************************ */
+/* Palette Colors Operators */
+
+/* ******************* Add New Palette ************************ */
+
+/* add new palette - wrapper around API */
+static int gp_palettecolor_add_exec(bContext *C, wmOperator *op)
+{
+       bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+       /* 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)
+               *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+
+       /* verify palette */
+       bGPDpalette *palette = gpencil_palette_getactive(*gpd_ptr);
+       if (palette == NULL)
+               palette = gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true);
+
+       /* add new palette color now */
+       gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_add(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Add Palette Color";
+       ot->idname = "GPENCIL_OT_palettecolor_add";
+       ot->description = "Add new Grease Pencil palette color for the active Grease Pencil datablock";
+
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* callbacks */
+       ot->exec = gp_palettecolor_add_exec;
+       ot->poll = gp_add_poll;
+}
+
+/* ******************* Remove Active Palette color ************************* */
+
+static int gp_palettecolor_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDpalette *palette = gpencil_palette_getactive(gpd);
+       bGPDpalettecolor *color = gpencil_palettecolor_getactive(palette);
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd, palette, color))
+               return OPERATOR_CANCELLED;
+
+       /* make the palette color before this the new active color
+        * - use the one after if this is the first
+        * - if this is the only color, this naturally becomes NULL
+        */
+       if (color->prev)
+               gpencil_palettecolor_setactive(palette, color->prev);
+       else
+               gpencil_palettecolor_setactive(palette, color->next);
+
+       /* delete the strokes */
+       gpencil_palettecolor_delete_strokes(gpd, color->info);
+
+       /* delete the palette color now... */
+       gpencil_palettecolor_delete(palette, color);
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_remove(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Remove palette color";
+       ot->idname = "GPENCIL_OT_palettecolor_remove";
+       ot->description = "Remove active Grease Pencil palette color";
+
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* callbacks */
+       ot->exec = gp_palettecolor_remove_exec;
+       ot->poll = gp_active_palettecolor_poll;
+}
+
+/* ********************** Isolate palette color **************************** */
+
+static int gp_isolate_palettecolor_exec(bContext *C, wmOperator *op)
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDpalette *palette = gpencil_palette_getactive(gpd);
+       bGPDpalettecolor *active_color = gpencil_palettecolor_getactive(palette);
+       bGPDpalettecolor *palcolor;
+
+       int flags = PC_COLOR_LOCKED;
+       bool isolate = false;
+
+       if (RNA_boolean_get(op->ptr, "affect_visibility"))
+               flags |= PC_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 */
+       for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+               /* Skip if this is the active one */
+               if (palcolor == active_color)
+                       continue;
+
+               /* If the flags aren't set, that means that the color is
+                * not alone, so we have some colors to isolate still
+                */
+               if ((palcolor->flag & flags) == 0) {
+                       isolate = true;
+                       break;
+               }
+       }
+
+       /* Set/Clear flags as appropriate */
+       if (isolate) {
+               /* Set flags on all "other" colors */
+               for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+                       if (palcolor == active_color)
+                               continue;
+                       else
+                               palcolor->flag |= flags;
+               }
+       }
+       else {
+               /* Clear flags - Restore everything else */
+               for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+                       palcolor->flag &= ~flags;
+               }
+       }
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_isolate(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Isolate Palette Color";
+       ot->idname = "GPENCIL_OT_palettecolor_isolate";
+       ot->description = "Toggle whether the active color is the only one that is editable and/or visible";
+
+       /* callbacks */
+       ot->exec = gp_isolate_palettecolor_exec;
+       ot->poll = gp_active_palettecolor_poll;
+
+       /* 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");
+}
+
+/* *********************** Hide Palette colors ******************************** */
+
+static int gp_palettecolor_hide_exec(bContext *C, wmOperator *op)
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDpalette *palette = gpencil_palette_getactive(gpd);
+       bGPDpalettecolor *palcolor = gpencil_palettecolor_getactive(palette);
+
+       bool unselected = RNA_boolean_get(op->ptr, "unselected");
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd, palette, palcolor))
+               return OPERATOR_CANCELLED;
+
+       if (unselected) {
+               bGPDpalettecolor *color;
+
+               /* hide unselected */
+               for (color = palette->colors.first; color; color = color->next) {
+                       if (color != palcolor) {
+                               color->flag |= PC_COLOR_HIDE;
+                       }
+               }
+       }
+       else {
+               /* hide selected/active */
+               palcolor->flag |= PC_COLOR_HIDE;
+       }
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_hide(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Hide Color(s)";
+       ot->idname = "GPENCIL_OT_palettecolor_hide";
+       ot->description = "Hide selected/unselected Grease Pencil colors";
+
+       /* callbacks */
+       ot->exec = gp_palettecolor_hide_exec;
+       ot->poll = gp_active_palettecolor_poll; /* NOTE: we need an active color to play with */
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* props */
+       RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected colors");
+}
+
+/* ********************** Show All Colors ***************************** */
+
+/* poll callback for showing colors */
+static int gp_palettecolor_reveal_poll(bContext *C)
+{
+       return ED_gpencil_data_get_active(C) != NULL;
+}
+
+static int gp_palettecolor_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDpalette *palette = gpencil_palette_getactive(gpd);
+       bGPDpalettecolor *palcolor;
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd, palette))
+               return OPERATOR_CANCELLED;
+
+       /* make all colors visible */
+       for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+               palcolor->flag &= ~PC_COLOR_HIDE;
+       }
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_reveal(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Show All Colors";
+       ot->idname = "GPENCIL_OT_palettecolor_reveal";
+       ot->description = "Unhide all hidden Grease Pencil palette colors";
+
+       /* callbacks */
+       ot->exec = gp_palettecolor_reveal_exec;
+       ot->poll = gp_palettecolor_reveal_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ***************** Lock/Unlock All Palette colors ************************ */
+
+static int gp_palettecolor_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDpalette *palette = gpencil_palette_getactive(gpd);
+       bGPDpalettecolor *palcolor;
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd, palette))
+               return OPERATOR_CANCELLED;
+
+       /* make all layers non-editable */
+       for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+               palcolor->flag |= PC_COLOR_LOCKED;
+       }
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_lock_all(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Lock All Colors";
+       ot->idname = "GPENCIL_OT_palettecolor_lock_all";
+       ot->description = "Lock all Grease Pencil colors to prevent them from being accidentally modified";
+
+       /* callbacks */
+       ot->exec = gp_palettecolor_lock_all_exec;
+       ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* -------------------------- */
+
+static int gp_palettecolor_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDpalette *palette = gpencil_palette_getactive(gpd);
+       bGPDpalettecolor *palcolor;
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd, palette))
+               return OPERATOR_CANCELLED;
+
+       /* make all layers editable again*/
+       for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+               palcolor->flag &= ~PC_COLOR_LOCKED;
+       }
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_unlock_all(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Unlock All Colors";
+       ot->idname = "GPENCIL_OT_palettecolor_unlock_all";
+       ot->description = "Unlock all Grease Pencil colors so that they can be edited";
+
+       /* callbacks */
+       ot->exec = gp_palettecolor_unlock_all_exec;
+       ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************* Move Color Up/Down ************************** */
+
+enum {
+       GP_COLOR_MOVE_UP = -1,
+       GP_COLOR_MOVE_DOWN = 1
+};
+
+static int gp_palettecolor_move_exec(bContext *C, wmOperator *op)
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDpalette *palette = gpencil_palette_getactive(gpd);
+       bGPDpalettecolor *palcolor = gpencil_palettecolor_getactive(palette);
+
+       int direction = RNA_enum_get(op->ptr, "direction");
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd, palette, palcolor))
+               return OPERATOR_CANCELLED;
+
+       /* up or down? */
+       if (direction == GP_COLOR_MOVE_UP) {
+               /* up */
+               BLI_remlink(&palette->colors, palcolor);
+               BLI_insertlinkbefore(&palette->colors, palcolor->prev, palcolor);
+       }
+       else if (direction == GP_COLOR_MOVE_DOWN) {
+               /* down */
+               BLI_remlink(&palette->colors, palcolor);
+               BLI_insertlinkafter(&palette->colors, palcolor->next, palcolor);
+       }
+       else {
+               BLI_assert(0);
+       }
+
+       /* notifiers */
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_palettecolor_move(wmOperatorType *ot)
+{
+       static EnumPropertyItem slot_move[] = {
+               {GP_COLOR_MOVE_UP, "UP", 0, "Up", ""},
+               {GP_COLOR_MOVE_DOWN, "DOWN", 0, "Down", ""},
+               {0, NULL, 0, NULL, NULL}
+       };
+
+       /* identifiers */
+       ot->name = "Move Palette color";
+       ot->idname = "GPENCIL_OT_palettecolor_move";
+       ot->description = "Move the active Grease Pencil palette color up/down in the list";
+
+       /* api callbacks */
+       ot->exec = gp_palettecolor_move_exec;
+       ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_COLOR_MOVE_UP, "Direction", "");
+}
+
+/* ***************** Select all strokes using Palette color ************************ */
+
+static int gp_palettecolor_select_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       bGPdata *gpd = ED_gpencil_data_get_active(C);
+       bGPDpalette *palette = gpencil_palette_getactive(gpd);
+       bGPDpalettecolor *palcolor = gpencil_palettecolor_getactive(palette);
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd, palette, palcolor))
+               return OPERATOR_CANCELLED;
+
+       /* read all strokes and select*/
+       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)) {
+                       /* verify something to do */
+                       for (bGPDstroke *gps = gpl->actframe->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(gpl, gps) == false)
+                                       continue;
+
+                               /* select */
+                               if (strcmp(palcolor->info, gps->colorname) == 0) {
+                               &n