Grease Pencil v2 Branch

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
This commit is contained in:
2016-08-03 23:31:48 +02:00
committed by Julian Eisel
parent 9d4ea84277
commit eaea4ea51f
58 changed files with 7245 additions and 784 deletions

View File

@@ -30957,6 +30957,93 @@
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"
@@ -30968,16 +31055,16 @@
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"
@@ -91590,8 +91677,7 @@
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"
@@ -91602,8 +91688,7 @@
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)"
@@ -91819,8 +91904,7 @@
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"
@@ -91831,8 +91915,7 @@
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)"
@@ -91942,6 +92025,382 @@
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

Before

Width:  |  Height:  |  Size: 4.4 MiB

After

Width:  |  Height:  |  Size: 4.4 MiB

View 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)
col.active = not gpl.lock
col.prop(gpl, "line_width", slider=True)
split = layout.split(percentage=0.5)
split.active = not gpl.lock
col = split.column(align=True)
col.prop(gpl, "use_volumetric_strokes")
col.prop(gpl, "show_points", text="Points")
col = split.column(align=True)
col.prop(gpl, "use_hq_fill")
col.active = not gpl.lock
col.prop(gpl, "show_x_ray")
layout.separator()
col.label("Tint")
col.prop(gpl, "tint_color", text="")
col.prop(gpl, "tint_factor", text="Factor", slider=True)
col = split.column(align=True)
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 = row.column()
if context.space_data.type == 'VIEW_3D':
col.label(text="Parent:")
col.prop(gpl, "parent", text="")
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:

View 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"

View 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__)

View 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'
# -----------------------------

View File

@@ -20,7 +20,11 @@
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'

View File

@@ -19,7 +19,10 @@
# <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'

View 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"

View 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

View 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);

View File

@@ -31,19 +31,25 @@
* \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__ */

View 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");

View 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 *****
*/
@@ -44,10 +44,12 @@
#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"
@@ -57,21 +59,34 @@
/* --------- 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,7 +330,10 @@ 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)
@@ -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 layer */
bGPDlayer *gpencil_layer_duplicate(bGPDlayer *src)
/* make a copy of a given gpencil brush */
bGPDbrush *gpencil_brush_duplicate(const bGPDbrush *brush_src)
{
bGPDframe *gpf, *gpfd;
bGPDlayer *dst;
bGPDbrush *brush_dst;
/* error checking */
if (src == NULL)
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(const bGPDlayer *gpl_src)
{
const bGPDframe *gpf_src;
bGPDframe *gpf_dst;
bGPDlayer *gpl_dst;
/* error checking */
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);
}

View 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);

View 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;

View File

@@ -144,7 +144,7 @@
#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,6 +6170,7 @@ 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)
@@ -6163,10 +6180,18 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
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;
}
}
}

View 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 --------------- */
}
}

View 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;

View 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);
}
}
}

View 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
}
}

File diff suppressed because it is too large Load Diff

View 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,7 +426,8 @@ 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;
@@ -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,60 +660,90 @@ 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]);
/* 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];
/* 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);
/* 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 */
@@ -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;
@@ -1113,7 +1213,14 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, GP
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,9 +1247,19 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, GP
continue;
}
}
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]);
}
gp_point_to_xy(gsc, gps, pt1, &pc1[0], &pc1[1]);
gp_point_to_xy(gsc, gps, pt2, &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])) ||
@@ -1228,72 +1345,101 @@ 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;
}
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);
}
else {
/* Apply effect to the stored points */
gp_brush_grab_apply_cached(gso, gps);
changed |= true;
}
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_RANDOMIZE: /* Apply jitter */
{
changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_randomize_apply);
break;
}
default:
printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
break;
/* calculate difference matrix if parent object */
if (gpl->parent != NULL) {
ED_gpencil_parent_location(gpl, diff_mat);
parented = true;
}
else {
parented = false;
}
/* Triangulation must be calculated if changed */
if (changed) {
gps->flag |= GP_STROKE_RECALC_CACHES;
gps->tot_triangles = 0;
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;
}
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;
}
case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */
{
changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_thickness_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;
}
/* Triangulation must be calculated if changed */
if (changed) {
gps->flag |= GP_STROKE_RECALC_CACHES;
gps->tot_triangles = 0;
}
}
}
CTX_DATA_END;
@@ -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;

View File

@@ -142,11 +142,30 @@ 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 */
@@ -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;

File diff suppressed because it is too large Load Diff

View File

@@ -125,10 +125,48 @@ static int gp_stroke_edit_poll(bContext *C)
return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
}
/* ************ Stroke Hide selection Toggle ************** */
static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
ToolSettings *ts = CTX_data_tool_settings(C);
if (ts == NULL)
return OPERATOR_CANCELLED;
/* Just toggle alpha... */
if (ts->gp_sculpt.alpha > 0.0f) {
ts->gp_sculpt.alpha = 0.0f;
}
else {
ts->gp_sculpt.alpha = 1.0f;
}
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
return OPERATOR_FINISHED;
}
void GPENCIL_OT_selection_opacity_toggle(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Hide Selection";
ot->idname = "GPENCIL_OT_selection_opacity_toggle";
ot->description = "Hide/Unhide selected points for Grease Pencil strokes setting alpha factor";
/* callbacks */
ot->exec = gpencil_hideselect_toggle_exec;
ot->poll = gp_stroke_edit_poll;
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
}
/* ************** Duplicate Selected Strokes **************** */
/* Make copies of selected point segments in a selected stroke */
static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes)
static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, const char *layername)
{
bGPDspoint *pt;
int i;
@@ -169,6 +207,7 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes)
/* make a stupid copy first of the entire stroke (to get the flags too) */
gpsd = MEM_dupallocN(gps);
strcpy(gpsd->tmp_layerinfo, layername); /* saves original layer name */
/* initialize triangle memory - will be calculated on next redraw */
gpsd->triangles = NULL;
@@ -216,8 +255,9 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
/* make copies of selected strokes, and deselect these once we're done */
for (gps = gpf->strokes.first; gps; gps = gps->next) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false)
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
if (gps->flag & GP_STROKE_SELECT) {
if (gps->totpoints == 1) {
@@ -226,6 +266,7 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
/* make direct copies of the stroke and its points */
gpsd = MEM_dupallocN(gps);
strcpy(gpsd->tmp_layerinfo, gpl->info);
gpsd->points = MEM_dupallocN(gps->points);
/* triangle information - will be calculated on next redraw */
@@ -238,7 +279,7 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
}
else {
/* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
gp_duplicate_points(gps, &new_strokes);
gp_duplicate_points(gps, &new_strokes, gpl->info);
}
/* deselect original stroke, or else the originals get moved too
@@ -345,6 +386,7 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
/* make direct copies of the stroke and its points */
gpsd = MEM_dupallocN(gps);
strcpy(gpsd->tmp_layerinfo, gpl->info); /* saves original layer name */
gpsd->points = MEM_dupallocN(gps->points);
/* triangles cache - will be recalculated on next redraw */
@@ -358,7 +400,7 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
}
else {
/* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
gp_duplicate_points(gps, &gp_strokes_copypastebuf);
gp_duplicate_points(gps, &gp_strokes_copypastebuf, gpl->info);
}
}
}
@@ -395,13 +437,20 @@ static int gp_strokes_paste_poll(bContext *C)
return (CTX_data_active_gpencil_layer(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf));
}
enum {
GP_COPY_ONLY = -1,
GP_COPY_MERGE = 1
};
static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only use active for copy merge */
bGPDframe *gpf;
int type = RNA_enum_get(op->ptr, "type");
/* check for various error conditions */
if (gpd == NULL) {
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
@@ -415,7 +464,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
/* no active layer - let's just create one */
gpl = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
}
else if (gpencil_layer_is_editable(gpl) == false) {
else if ((gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_MERGE)) {
BKE_report(op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked");
return OPERATOR_CANCELLED;
}
@@ -463,26 +512,34 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
* we are obliged to add a new frame if one
* doesn't exist already
*/
gpf = gpencil_layer_getframe(gpl, CFRA, true);
if (gpf) {
bGPDstroke *gps;
/* Copy each stroke into the layer */
for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use(C, gps)) {
bGPDstroke *new_stroke = MEM_dupallocN(gps);
/* need to verify if layer exist nad frame */
if (type != GP_COPY_MERGE) {
gpl = BLI_findstring(&gpd->layers, gps->tmp_layerinfo, offsetof(bGPDlayer, info));
if (gpl == NULL) {
/* no layer - use active (only if layer deleted before paste) */
gpl = CTX_data_active_gpencil_layer(C);
}
}
gpf = gpencil_layer_getframe(gpl, CFRA, true);
if (gpf) {
bGPDstroke *new_stroke = MEM_dupallocN(gps);
new_stroke->tmp_layerinfo[0] = '\0';
new_stroke->points = MEM_dupallocN(gps->points);
new_stroke->points = MEM_dupallocN(gps->points);
new_stroke->flag |= GP_STROKE_RECALC_CACHES;
new_stroke->triangles = NULL;
new_stroke->flag |= GP_STROKE_RECALC_CACHES;
new_stroke->triangles = NULL;
new_stroke->next = new_stroke->prev = NULL;
BLI_addtail(&gpf->strokes, new_stroke);
new_stroke->next = new_stroke->prev = NULL;
BLI_addtail(&gpf->strokes, new_stroke);
}
}
}
}
/* updates */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -492,10 +549,16 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_paste(wmOperatorType *ot)
{
static EnumPropertyItem copy_type[] = {
{GP_COPY_ONLY, "COPY", 0, "Copy", ""},
{GP_COPY_MERGE, "MERGE", 0, "Merge", ""},
{0, NULL, 0, NULL, NULL}
};
/* identifiers */
ot->name = "Paste Strokes";
ot->idname = "GPENCIL_OT_paste";
ot->description = "Paste previously copied strokes into active layer";
ot->description = "Paste previously copied strokes or copy and merge in active layer";
/* callbacks */
ot->exec = gp_strokes_paste_exec;
@@ -503,6 +566,8 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ot->prop = RNA_def_enum(ot->srna, "type", copy_type, 0, "Type", "");
}
/* ******************* Move To Layer ****************************** */
@@ -1069,7 +1134,7 @@ void GPENCIL_OT_delete(wmOperatorType *ot)
};
/* identifiers */
ot->name = "Delete...";
ot->name = "Delete";
ot->idname = "GPENCIL_OT_delete";
ot->description = "Delete selected Grease Pencil strokes, vertices, or frames";
@@ -1124,25 +1189,65 @@ static int gp_snap_poll(bContext *C)
static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
{
RegionView3D *rv3d = CTX_wm_region_data(C);
float gridf = rv3d->gridview;
const float gridf = rv3d->gridview;
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
bGPDspoint *pt;
int i;
bGPdata *gpd = ED_gpencil_data_get_active(C);
float diff_mat[4][4];
// TOOD: if entire stroke is selected, offset entire stroke by same amount?
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)) {
/* calculate difference matrix if parent object */
if (gpl->parent != NULL) {
ED_gpencil_parent_location(gpl, diff_mat);
}
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;
}
bGPDspoint *pt;
int i;
// TOOD: if entire stroke is selected, offset entire stroke by same amount?
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
/* only if point is selected.. */
if (pt->flag & GP_SPOINT_SELECT) {
if (gpl->parent == NULL) {
pt->x = gridf * floorf(0.5f + pt->x / gridf);
pt->y = gridf * floorf(0.5f + pt->y / gridf);
pt->z = gridf * floorf(0.5f + pt->z / gridf);
}
else {
/* apply parent transformations */
float fpt[3];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf);
fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf);
fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf);
/* return data */
copy_v3_v3(&pt->x, fpt);
gp_apply_parent_point(gpl, pt);
}
}
}
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
/* only if point is selected.. */
if (pt->flag & GP_SPOINT_SELECT) {
pt->x = gridf * floorf(0.5f + pt->x / gridf);
pt->y = gridf * floorf(0.5f + pt->y / gridf);
pt->z = gridf * floorf(0.5f + pt->z / gridf);
}
}
}
CTX_DATA_END;
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1173,37 +1278,64 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
const float *cursor_global = ED_view3d_cursor3d_get(scene, v3d);
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
bGPDspoint *pt;
int i;
bGPdata *gpd = ED_gpencil_data_get_active(C);
float diff_mat[4][4];
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
if ((gps->flag & GP_STROKE_SELECT) == 0)
continue;
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)) {
if (use_offset) {
float offset[3];
/* compute offset from first point of stroke to cursor */
/* TODO: Allow using midpoint instead? */
sub_v3_v3v3(offset, cursor_global, &gps->points->x);
/* apply offset to all points in the stroke */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
add_v3_v3(&pt->x, offset);
/* calculate difference matrix if parent object */
if (gpl->parent != NULL) {
ED_gpencil_parent_location(gpl, diff_mat);
}
}
else {
/* affect each selected point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
copy_v3_v3(&pt->x, cursor_global);
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;
}
bGPDspoint *pt;
int i;
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
if ((gps->flag & GP_STROKE_SELECT) == 0)
continue;
if (use_offset) {
float offset[3];
/* compute offset from first point of stroke to cursor */
/* TODO: Allow using midpoint instead? */
sub_v3_v3v3(offset, cursor_global, &gps->points->x);
/* apply offset to all points in the stroke */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
add_v3_v3(&pt->x, offset);
}
}
else {
/* affect each selected point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
copy_v3_v3(&pt->x, cursor_global);
if (gpl->parent != NULL) {
gp_apply_parent_point(gpl, pt);
}
}
}
}
}
}
}
CTX_DATA_END;
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1243,24 +1375,57 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
INIT_MINMAX(min, max);
/* calculate midpoints from selected points */
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
bGPDspoint *pt;
int i;
bGPdata *gpd = ED_gpencil_data_get_active(C);
float diff_mat[4][4];
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
if ((gps->flag & GP_STROKE_SELECT) == 0)
continue;
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)) {
/* calculate difference matrix if parent object */
if (gpl->parent != NULL) {
ED_gpencil_parent_location(gpl, diff_mat);
}
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;
}
bGPDspoint *pt;
int i;
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
if ((gps->flag & GP_STROKE_SELECT) == 0)
continue;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
if (gpl->parent == NULL) {
add_v3_v3(centroid, &pt->x);
minmax_v3v3_v3(min, max, &pt->x);
}
else {
/* apply parent transformations */
float fpt[3];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
add_v3_v3(centroid, fpt);
minmax_v3v3_v3(min, max, fpt);
}
count++;
}
}
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
add_v3_v3(centroid, &pt->x);
minmax_v3v3_v3(min, max, &pt->x);
count++;
}
}
}
CTX_DATA_END;
if (v3d->around == V3D_AROUND_CENTER_MEAN && count) {
mul_v3_fl(centroid, 1.0f / (float)count);

View File

@@ -100,6 +100,23 @@ void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct bGPDspoint *pt,
int *r_x, int *r_y);
/**
* Convert point to parent space
*
* \param pt Original point
* \param diff_mat Matrix with the difference between original parent matrix
* \param[out] r_pt Pointer to new point after apply matrix
*/
void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt);
/**
* Change points position relative to parent object
*/
void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps);
/**
* Change point position relative to parent object
*/
void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt);
/**
* Convert a screenspace point to a 3D Grease Pencil coordinate.
*
@@ -116,6 +133,10 @@ bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, struct Scene *scene, const float
int gp_add_poll(struct bContext *C);
int gp_active_layer_poll(struct bContext *C);
int gp_active_brush_poll(struct bContext *C);
int gp_active_palette_poll(struct bContext *C);
int gp_active_palettecolor_poll(struct bContext *C);
int gp_brush_crt_presets_poll(bContext *C);
/* Copy/Paste Buffer --------------------------------- */
/* gpencil_edit.c */
@@ -136,6 +157,22 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke
*/
bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure);
/**
* Apply smooth for strength to stroke point
* \param gps Stroke to smooth
* \param i Point index
* \param inf Amount of smoothing to apply
*/
bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf);
/**
* Apply smooth for thickness to stroke point (use pressure)
* \param gps Stroke to smooth
* \param i Point index
* \param inf Amount of smoothing to apply
*/
bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf);
/**
* Subdivide a stroke once, by adding points at the midpoint between each pair of points
* \param gps Stroke data
@@ -143,11 +180,25 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure);
*/
void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints);
/**
* Add randomness to stroke
* \param gps Stroke data
* \param brsuh Brush data
*/
void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush);
/* Layers Enums -------------------------------------- */
struct EnumPropertyItem *ED_gpencil_layers_enum_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
/* Enums of GP Brushes */
EnumPropertyItem *ED_gpencil_brushes_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
bool *r_free);
/* Enums of GP palettes */
EnumPropertyItem *ED_gpencil_palettes_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
bool *r_free);
/* ***************************************************** */
/* Operator Defines */
@@ -166,6 +217,7 @@ typedef enum eGPencil_PaintModes {
/* stroke editing ----- */
void GPENCIL_OT_editmode_toggle(struct wmOperatorType *ot);
void GPENCIL_OT_selection_opacity_toggle(struct wmOperatorType *ot);
void GPENCIL_OT_select(struct wmOperatorType *ot);
void GPENCIL_OT_select_all(struct wmOperatorType *ot);
@@ -216,12 +268,45 @@ void GPENCIL_OT_lock_all(struct wmOperatorType *ot);
void GPENCIL_OT_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot);
void GPENCIL_OT_layer_merge(struct wmOperatorType *ot);
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_arrange(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_change_color(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_lock_color(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_apply_thickness(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_cyclical_set(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_join(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_flip(struct wmOperatorType *ot);
void GPENCIL_OT_brush_add(struct wmOperatorType *ot);
void GPENCIL_OT_brush_remove(struct wmOperatorType *ot);
void GPENCIL_OT_brush_change(struct wmOperatorType *ot);
void GPENCIL_OT_brush_move(struct wmOperatorType *ot);
void GPENCIL_OT_brush_presets_create(struct wmOperatorType *ot);
void GPENCIL_OT_brush_copy(struct wmOperatorType *ot);
void GPENCIL_OT_brush_select(struct wmOperatorType *ot);
void GPENCIL_OT_palette_add(struct wmOperatorType *ot);
void GPENCIL_OT_palette_remove(struct wmOperatorType *ot);
void GPENCIL_OT_palette_change(struct wmOperatorType *ot);
void GPENCIL_OT_palette_lock_layer(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_add(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_remove(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_isolate(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_hide(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_reveal(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_lock_all(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_move(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_select(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_copy(struct wmOperatorType *ot);
/* undo stack ---------- */
void gpencil_undo_init(struct bGPdata *gpd);
@@ -273,4 +358,39 @@ typedef enum ACTCONT_TYPES {
ACTCONT_GPENCIL
} ACTCONT_TYPES;
/**
* Iterate over all editable strokes in the current context,
* stopping on each usable layer + stroke pair (i.e. gpl and gps)
* to perform some operations on the stroke.
*
* \param gpl The identifier to use for the layer of the stroke being processed.
* Choose a suitable value to avoid name clashes.
* \param gps The identifier to use for current stroke being processed.
* Choose a suitable value to avoid name clashes.
*/
#define GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) \
{ \
CTX_DATA_BEGIN(C, bGPDlayer*, gpl, editable_gpencil_layers) \
{ \
if (gpl->actframe == NULL) \
continue; \
/* calculate difference matrix if parent object */ \
float diff_mat[4][4]; \
ED_gpencil_parent_location(gpl, diff_mat); \
/* loop over strokes */ \
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; \
/* ... Do Stuff With Strokes ... */
#define GP_EDITABLE_STROKES_END \
} \
} \
CTX_DATA_END; \
} (void)0
#endif /* __GPENCIL_INTERN_H__ */

View File

@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2009, 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 *****
*/
@@ -140,8 +140,8 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
* that the only data being edited is that of the Grease Pencil strokes
*/
/* FKEY = Eraser Radius */
kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
/* CTRL + FKEY = Eraser Radius */
kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius");
@@ -169,8 +169,8 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0);
RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength");
/* Ctrl-FKEY = Sculpt Brush Size */
kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
/* FKEY = Sculpt Brush Size */
kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size");
@@ -267,12 +267,35 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "unselected", true);
WM_keymap_add_item(keymap, "GPENCIL_OT_selection_opacity_toggle", HKEY, KM_PRESS, KM_CTRL, 0);
/* Isolate Layer */
WM_keymap_add_item(keymap, "GPENCIL_OT_layer_isolate", PADASTERKEY, KM_PRESS, 0, 0);
/* Move to Layer */
WM_keymap_add_item(keymap, "GPENCIL_OT_move_to_layer", MKEY, KM_PRESS, 0, 0);
/* Select drawing brush using index */
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", ONEKEY, KM_PRESS, 0, 0);
RNA_int_set(kmi->ptr, "index", 0);
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", TWOKEY, KM_PRESS, 0, 0);
RNA_int_set(kmi->ptr, "index", 1);
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", THREEKEY, KM_PRESS, 0, 0);
RNA_int_set(kmi->ptr, "index", 2);
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", FOURKEY, KM_PRESS, 0, 0);
RNA_int_set(kmi->ptr, "index", 3);
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", FIVEKEY, KM_PRESS, 0, 0);
RNA_int_set(kmi->ptr, "index", 4);
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", SIXKEY, KM_PRESS, 0, 0);
RNA_int_set(kmi->ptr, "index", 5);
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", SEVENKEY, KM_PRESS, 0, 0);
RNA_int_set(kmi->ptr, "index", 6);
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", EIGHTKEY, KM_PRESS, 0, 0);
RNA_int_set(kmi->ptr, "index", 7);
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", NINEKEY, KM_PRESS, 0, 0);
RNA_int_set(kmi->ptr, "index", 8);
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_select", ZEROKEY, KM_PRESS, 0, 0);
RNA_int_set(kmi->ptr, "index", 9);
/* Transform Tools */
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
@@ -318,6 +341,7 @@ void ED_operatortypes_gpencil(void)
/* Editing (Strokes) ------------ */
WM_operatortype_append(GPENCIL_OT_editmode_toggle);
WM_operatortype_append(GPENCIL_OT_selection_opacity_toggle);
WM_operatortype_append(GPENCIL_OT_select);
WM_operatortype_append(GPENCIL_OT_select_all);
@@ -362,12 +386,44 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_lock_all);
WM_operatortype_append(GPENCIL_OT_unlock_all);
WM_operatortype_append(GPENCIL_OT_layer_isolate);
WM_operatortype_append(GPENCIL_OT_layer_merge);
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
WM_operatortype_append(GPENCIL_OT_convert);
WM_operatortype_append(GPENCIL_OT_stroke_arrange);
WM_operatortype_append(GPENCIL_OT_stroke_change_color);
WM_operatortype_append(GPENCIL_OT_stroke_lock_color);
WM_operatortype_append(GPENCIL_OT_stroke_apply_thickness);
WM_operatortype_append(GPENCIL_OT_stroke_cyclical_set);
WM_operatortype_append(GPENCIL_OT_stroke_join);
WM_operatortype_append(GPENCIL_OT_stroke_flip);
WM_operatortype_append(GPENCIL_OT_palette_add);
WM_operatortype_append(GPENCIL_OT_palette_remove);
WM_operatortype_append(GPENCIL_OT_palette_change);
WM_operatortype_append(GPENCIL_OT_palette_lock_layer);
WM_operatortype_append(GPENCIL_OT_palettecolor_add);
WM_operatortype_append(GPENCIL_OT_palettecolor_remove);
WM_operatortype_append(GPENCIL_OT_palettecolor_isolate);
WM_operatortype_append(GPENCIL_OT_palettecolor_hide);
WM_operatortype_append(GPENCIL_OT_palettecolor_reveal);
WM_operatortype_append(GPENCIL_OT_palettecolor_lock_all);
WM_operatortype_append(GPENCIL_OT_palettecolor_unlock_all);
WM_operatortype_append(GPENCIL_OT_palettecolor_move);
WM_operatortype_append(GPENCIL_OT_palettecolor_select);
WM_operatortype_append(GPENCIL_OT_palettecolor_copy);
WM_operatortype_append(GPENCIL_OT_brush_add);
WM_operatortype_append(GPENCIL_OT_brush_remove);
WM_operatortype_append(GPENCIL_OT_brush_change);
WM_operatortype_append(GPENCIL_OT_brush_move);
WM_operatortype_append(GPENCIL_OT_brush_presets_create);
WM_operatortype_append(GPENCIL_OT_brush_copy);
WM_operatortype_append(GPENCIL_OT_brush_select);
/* Editing (Time) --------------- */
}

View 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 *****
*/
@@ -39,21 +39,26 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_rand.h"
#include "BLT_translation.h"
#include "PIL_time.h"
#include "BKE_main.h"
#include "BKE_paint.h"
#include "BKE_gpencil.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
#include "BKE_colortools.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_brush_types.h"
#include "DNA_windowmanager_types.h"
#include "UI_view2d.h"
@@ -151,6 +156,10 @@ typedef struct tGPsdata {
float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */
void *erasercursor; /* radial cursor data for drawing eraser */
bGPDpalettecolor *palettecolor; /* current palette color */
bGPDbrush *brush; /* current drawing brush */
short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */
} tGPsdata;
/* ------ */
@@ -333,10 +342,90 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3]
}
}
/* apply jitter to stroke */
static void gp_brush_jitter(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const int mval[2], int r_mval[2])
{
float pressure = pt->pressure;
float tmp_pressure = pt->pressure;
if (brush->draw_jitter > 0.0f) {
float curvef = curvemapping_evaluateF(brush->cur_jitter, 0, pressure);
tmp_pressure = curvef * brush->draw_sensitivity;
}
const float exfactor = (brush->draw_jitter + 2.0f) * (brush->draw_jitter + 2.0f); /* exponential value */
const float fac = BLI_frand() * exfactor * tmp_pressure;
/* Jitter is applied perpendicular to the mouse movement vector (2D space) */
float mvec[2], svec[2];
/* mouse movement in ints -> floats */
if (gpd->sbuffer_size > 1) {
mvec[0] = (float)(mval[0] - (pt - 1)->x);
mvec[1] = (float)(mval[1] - (pt - 1)->y);
normalize_v2(mvec);
}
else {
mvec[0] = 0.0f;
mvec[1] = 0.0f;
}
/* rotate mvec by 90 degrees... */
svec[0] = -mvec[1];
svec[1] = mvec[0];
/* scale the displacement by the random, and apply */
if (BLI_frand() > 0.5f) {
mul_v2_fl(svec, -fac);
}
else {
mul_v2_fl(svec, fac);
}
r_mval[0] = mval[0] + svec[0];
r_mval[1] = mval[1] + svec[1];
}
/* apply pressure change depending of the angle of the stroke to simulate a pen with shape */
static void gp_brush_angle(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const int mval[2])
{
float mvec[2];
float sen = brush->draw_angle_factor; /* sensitivity */;
float fac;
float mpressure;
float angle = brush->draw_angle; /* default angle of brush in radians */;
float v0[2] = { cos(angle), sin(angle) }; /* angle vector of the brush with full thickness */
/* Apply to first point (only if there are 2 points because before no data to do it ) */
if (gpd->sbuffer_size == 1) {
mvec[0] = (float)(mval[0] - (pt - 1)->x);
mvec[1] = (float)(mval[1] - (pt - 1)->y);
normalize_v2(mvec);
/* uses > 1.0f to get a smooth transition in first point */
fac = 1.4f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
(pt - 1)->pressure = (pt - 1)->pressure - (sen * fac);
CLAMP((pt - 1)->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
}
/* apply from second point */
if (gpd->sbuffer_size >= 1) {
mvec[0] = (float)(mval[0] - (pt - 1)->x);
mvec[1] = (float)(mval[1] - (pt - 1)->y);
normalize_v2(mvec);
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
/* interpolate with previous point for smoother transitions */
mpressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
pt->pressure = mpressure;
CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
}
}
/* add current stroke-point to buffer (returns whether point was successfully added) */
static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure, double curtime)
{
bGPdata *gpd = p->gpd;
bGPDbrush *brush = p->brush;
tGPspoint *pt;
/* check painting mode */
@@ -349,6 +438,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* store settings */
copy_v2_v2_int(&pt->x, mval);
pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
pt->strength = 1.0f;
pt->time = (float)(curtime - p->inittime);
/* increment buffer size */
@@ -363,6 +453,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* store settings */
copy_v2_v2_int(&pt->x, mval);
pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
pt->strength = 1.0f;
pt->time = (float)(curtime - p->inittime);
/* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
@@ -381,8 +472,65 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
pt = ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
/* store settings */
copy_v2_v2_int(&pt->x, mval);
pt->pressure = pressure;
/* pressure */
if (brush->flag & GP_BRUSH_USE_PRESSURE) {
float curvef = curvemapping_evaluateF(brush->cur_sensitivity, 0, pressure);
pt->pressure = curvef * brush->draw_sensitivity;
}
else {
pt->pressure = 1.0f;
}
/* Apply jitter to position */
if (brush->draw_jitter > 0.0f) {
int r_mval[2];
gp_brush_jitter(gpd, brush, pt, mval, r_mval);
copy_v2_v2_int(&pt->x, r_mval);
}
else {
copy_v2_v2_int(&pt->x, mval);
}
/* apply randomness to pressure */
if ((brush->draw_random_press > 0.0f) && (brush->flag & GP_BRUSH_USE_RANDOM_PRESSURE)) {
float curvef = curvemapping_evaluateF(brush->cur_sensitivity, 0, pressure);
float tmp_pressure = curvef * brush->draw_sensitivity;
if (BLI_frand() > 0.5f) {
pt->pressure -= tmp_pressure * brush->draw_random_press * BLI_frand();
}
else {
pt->pressure += tmp_pressure * brush->draw_random_press * BLI_frand();
}
CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f);
}
/* apply angle of stroke to brush size */
if (brush->draw_angle_factor > 0.0f) {
gp_brush_angle(gpd, brush, pt, mval);
}
/* color strength */
if (brush->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
float curvef = curvemapping_evaluateF(brush->cur_strength, 0, pressure);
float tmp_pressure = curvef * brush->draw_sensitivity;
pt->strength = tmp_pressure * brush->draw_strength;
}
else {
pt->strength = brush->draw_strength;
}
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
/* apply randomness to color strength */
if ((brush->draw_random_press > 0.0f) && (brush->flag & GP_BRUSH_USE_RANDOM_STRENGTH)) {
if (BLI_frand() > 0.5f) {
pt->strength -= pt->strength * brush->draw_random_press * BLI_frand();
}
else {
pt->strength += pt->strength * brush->draw_random_press * BLI_frand();
}
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
/* point time */
pt->time = (float)(curtime - p->inittime);
/* increment counters */
@@ -395,12 +543,15 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
return GP_STROKEADD_NORMAL;
}
else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
/* get pointer to destination point */
pt = (tGPspoint *)(gpd->sbuffer);
/* store settings */
copy_v2_v2_int(&pt->x, mval);
pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
pt->strength = 1.0f;
pt->time = (float)(curtime - p->inittime);
/* if there's stroke for this poly line session add (or replace last) point
@@ -433,10 +584,16 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
/* if parented change position relative to parent object */
if (gpl->parent != NULL) {
gp_apply_parent_point(gpl, pts);
}
/* copy pressure and time */
pts->pressure = pt->pressure;
pts->strength = pt->strength;
pts->time = pt->time;
/* force fill recalc */
gps->flag |= GP_STROKE_RECALC_CACHES;
}
/* increment counters */
@@ -534,6 +691,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
bGPDstroke *gps;
bGPDspoint *pt;
tGPspoint *ptc;
bGPDbrush *brush = p->brush;
int i, totelem;
/* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
@@ -569,7 +727,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* copy appropriate settings for stroke */
gps->totpoints = totelem;
gps->thickness = p->gpl->thickness;
gps->thickness = brush->thickness;
gps->flag = gpd->sbuffer_sflag;
gps->inittime = p->inittime;
@@ -577,7 +735,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
gps->flag |= GP_STROKE_RECALC_CACHES;
/* allocate enough memory for a continuous array for storage points */
int sublevel = gpl->sublevel;
int sublevel = brush->sublevel;
int new_totpoints = gps->totpoints;
for (i = 0; i < sublevel; i++) {
@@ -600,9 +758,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
/* if parented change position relative to parent object */
if (gpl->parent != NULL) {
gp_apply_parent_point(gpl, pt);
}
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
pt++;
@@ -614,9 +777,15 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
/* if parented change position relative to parent object */
if (gpl->parent != NULL) {
gp_apply_parent_point(gpl, pt);
}
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
}
}
@@ -626,9 +795,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
/* if parented change position relative to parent object */
if (gpl->parent != NULL) {
gp_apply_parent_point(gpl, pt);
}
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
}
else {
@@ -703,6 +877,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
}
@@ -716,25 +892,38 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
gp_subdivide_stroke(gps, totpoints);
}
}
/* apply randomness to stroke */
if (brush->draw_random_sub > 0.0f) {
gp_randomize_stroke(gps, brush);
}
/* smooth stroke after subdiv - only if there's something to do
* for each iteration, the factor is reduced to get a better smoothing without changing too much
* the original stroke
*/
if (gpl->draw_smoothfac > 0.0f) {
if (brush->draw_smoothfac > 0.0f) {
float reduce = 0.0f;
for (int r = 0; r < gpl->draw_smoothlvl; ++r) {
for (int r = 0; r < brush->draw_smoothlvl; ++r) {
for (i = 0; i < gps->totpoints; i++) {
/* NOTE: No pressure smoothing, or else we get annoying thickness changes while drawing... */
gp_smooth_stroke(gps, i, gpl->draw_smoothfac - reduce, false);
gp_smooth_stroke(gps, i, brush->draw_smoothfac - reduce, false);
}
reduce += 0.25f; // reduce the factor
}
}
/* if parented change position relative to parent object */
if (gpl->parent != NULL) {
gp_apply_parent(gpl, gps);
}
if (depth_arr)
MEM_freeN(depth_arr);
}
/* Save palette color */
bGPDpalette *palette = gpencil_palette_getactive(p->gpd);
bGPDpalettecolor *palcolor = gpencil_palettecolor_getactive(palette);
gps->palcolor = palcolor;
strcpy(gps->colorname, palcolor->info);
/* add stroke to frame */
BLI_addtail(&p->gpf->strokes, gps);
@@ -761,12 +950,21 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, cons
(p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH))
{
RegionView3D *rv3d = p->ar->regiondata;
bGPDlayer *gpl = p->gpl;
const int mval[2] = {x, y};
float mval_3d[3];
float fpt[3];
float diff_mat[4][4];
/* calculate difference matrix if parent object */
ED_gpencil_parent_location(gpl, diff_mat);
if (ED_view3d_autodist_simple(p->ar, mval, mval_3d, 0, NULL)) {
const float depth_mval = view3d_point_depth(rv3d, mval_3d);
const float depth_pt = view3d_point_depth(rv3d, &pt->x);
mul_v3_m4v3(fpt, diff_mat, &pt->x);
const float depth_pt = view3d_point_depth(rv3d, fpt);
if (depth_pt > depth_mval) {
return true;
@@ -804,6 +1002,12 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
int pc1[2] = {0};
int pc2[2] = {0};
int i;
float diff_mat[4][4];
/* calculate difference matrix if parent object */
if (gpl->parent != NULL) {
ED_gpencil_parent_location(gpl, diff_mat);
}
if (gps->totpoints == 0) {
/* just free stroke */
@@ -816,8 +1020,14 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
else if (gps->totpoints == 1) {
/* only process if it hasn't been masked out... */
if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
if (gpl->parent == NULL) {
gp_point_to_xy(&p->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(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
}
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
@@ -826,7 +1036,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
// XXX: pressure sensitive eraser should apply here too?
MEM_freeN(gps->points);
if (gps->triangles)
MEM_freeN(gps->triangles);
MEM_freeN(gps->triangles);
BLI_freelinkN(&gpf->strokes, gps);
}
}
@@ -836,7 +1046,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* Pressure threshold at which stroke should be culled: Calculated as pressure value
* below which we would have invisible strokes
*/
const float cull_thresh = (gpl->thickness) ? 1.0f / ((float)gpl->thickness) : 1.0f;
const float cull_thresh = (gps->thickness) ? 1.0f / ((float)gps->thickness) : 1.0f;
/* Amount to decrease the pressure of each point with each stroke */
// TODO: Fetch from toolsettings, or compute based on thickness instead?
@@ -870,9 +1080,18 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
continue;
/* get coordinates of point in screenspace */
gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
if (gpl->parent == NULL) {
gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
}
else {
bGPDspoint npt;
gp_point_to_parent_space(pt1, diff_mat, &npt);
gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
gp_point_to_parent_space(pt2, diff_mat, &npt);
gp_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
}
/* Check that point segment of the boundbox of the eraser stroke */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
@@ -955,7 +1174,10 @@ static void gp_stroke_doeraser(tGPsdata *p)
/* loop over strokes, checking segments for intersections */
for (gps = gpf->strokes.first; gps; gps = gpn) {
gpn = gps->next;
/* check if the color is editable */
if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
continue;
}
/* Not all strokes in the datablock may be valid in the current editor/context
* (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
*/
@@ -994,6 +1216,78 @@ static void gp_session_validatebuffer(tGPsdata *p)
p->inittime = 0.0;
}
/* create a new palette color */
static bGPDpalettecolor *gp_create_new_color(bGPDpalette *palette)
{
bGPDpalettecolor *palcolor;
palcolor = gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
return palcolor;
}
/* initialize a drawing brush */
static void gp_init_drawing_brush(ToolSettings *ts, tGPsdata *p)
{
bGPDbrush *brush;
/* if not exist, create a new one */
if (BLI_listbase_is_empty(&ts->gp_brushes)) {
/* create new brushes */
gpencil_brush_init_presets(ts);
brush = gpencil_brush_getactive(ts);
}
else {
/* Use the current */
brush = gpencil_brush_getactive(ts);
}
/* be sure curves are initializated */
curvemapping_initialize(brush->cur_sensitivity);
curvemapping_initialize(brush->cur_strength);
curvemapping_initialize(brush->cur_jitter);
/* asign to temp tGPsdata */
p->brush = brush;
}
/* initialize a paint palette brush and a default color if not exist */
static void gp_init_palette(tGPsdata *p)
{
bGPdata *gpd;
bGPDpalette *palette;
bGPDpalettecolor *palcolor;
gpd = p->gpd;
/* if not exist, create a new palette */
if (BLI_listbase_is_empty(&gpd->palettes)) {
/* create new palette */
palette = gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
/* now create a default color */
palcolor = gp_create_new_color(palette);
}
else {
/* Use the current palette and color */
palette = gpencil_palette_getactive(gpd);
/* the palette needs one color */
if (BLI_listbase_is_empty(&palette->colors)) {
palcolor = gp_create_new_color(palette);
}
else {
palcolor = gpencil_palettecolor_getactive(palette);
}
/* in some situations can be null, so use first */
if (palcolor == NULL) {
gpencil_palettecolor_setactive(palette, palette->colors.first);
palcolor = palette->colors.first;
}
}
/* asign to temp tGPsdata */
p->palettecolor = palcolor;
}
/* (re)init new painting data */
static bool gp_session_initdata(bContext *C, tGPsdata *p)
{
@@ -1158,6 +1452,15 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* clear out buffer (stored in gp-data), in case something contaminated it */
gp_session_validatebuffer(p);
/* set brush and create a new one if null */
gp_init_drawing_brush(ts, p);
/* set palette info and create a new one if null */
gp_init_palette(p);
/* set palette colors */
bGPDpalettecolor *palcolor = p->palettecolor;
bGPdata *pdata = p->gpd;
copy_v4_v4(pdata->scolor, palcolor->color);
pdata->sflag = palcolor->flag;
return 1;
}
@@ -1495,7 +1798,6 @@ static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
/* ------------------------------- */
static void gpencil_draw_exit(bContext *C, wmOperator *op)
{
tGPsdata *p = op->customdata;
@@ -1600,7 +1902,7 @@ static void gpencil_draw_status_indicators(tGPsdata *p)
break;
case GP_PAINTMODE_DRAW:
ED_area_headerprint(p->sa, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | "
"ESC/Enter to end (or click outside this area)"));
"E/ESC/Enter to end (or click outside this area)"));
break;
case GP_PAINTMODE_DRAW_POLY:
ED_area_headerprint(p->sa, IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | "
@@ -1691,6 +1993,31 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
*/
p->mval[0] = event->mval[0] + 1;
p->mval[1] = event->mval[1] + 1;
/* verify key status for straight lines */
if ((event->ctrl > 0) || (event->alt > 0)) {
if (p->straight[0] == 0) {
int dx = abs(p->mval[0] - p->mvalo[0]);
int dy = abs(p->mval[1] - p->mvalo[1]);
if ((dx > 0) || (dy > 0)) {
/* check mouse direction to replace the other coordinate with previous values */
if (dx >= dy) {
/* horizontal */
p->straight[0] = 1;
p->straight[1] = p->mval[1]; /* save y */
}
else {
/* vertical */
p->straight[0] = 2;
p->straight[1] = p->mval[0]; /* save x */
}
}
}
}
else {
p->straight[0] = 0;
}
p->curtime = PIL_check_seconds_timer();
/* handle pressure sensitivity (which is supplied by tablets) */
@@ -1725,6 +2052,8 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
p->mvalo[1] = p->mval[1];
p->opressure = p->pressure;
p->inittime = p->ocurtime = p->curtime;
p->straight[0] = 0;
p->straight[1] = 0;
/* special exception here for too high pressure values on first touch in
* windows for some tablets, then we just skip first touch...
@@ -1733,6 +2062,18 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
return;
}
/* check if alt key is pressed and limit to straight lines */
if (p->straight[0] != 0) {
if (p->straight[0] == 1) {
/* horizontal */
p->mval[1] = p->straight[1]; /* replace y */
}
else {
/* vertical */
p->mval[0] = p->straight[1]; /* replace x */
}
}
/* fill in stroke data (not actually used directly by gpencil_draw_apply) */
RNA_collection_add(op->ptr, "stroke", &itemptr);
@@ -1855,7 +2196,6 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
if (p->paintmode == GP_PAINTMODE_ERASER) {
gpencil_draw_toggle_eraser_cursor(C, p, true);
}
/* set cursor
* NOTE: This may change later (i.e. intentionally via brush toggle,
* or unintentionally if the user scrolls outside the area)...
@@ -1870,6 +2210,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
/* handle the initial drawing - i.e. for just doing a simple dot */
gpencil_draw_apply_event(op, event);
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
else {
/* toolbar invoked - don't start drawing yet... */
@@ -1976,6 +2317,10 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* is essential for ensuring that they can quickly return to that view
*/
}
else if ((ELEM(event->type, DKEY)) && (event->val == KM_RELEASE)) {
/* enable continuous if release D key in mid drawing */
p->scene->toolsettings->gpencil_flags |= GP_TOOL_FLAG_PAINTSESSIONS_ON;
}
else {
estate = OPERATOR_RUNNING_MODAL;
}
@@ -1986,7 +2331,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* exit painting mode (and/or end current stroke)
* NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647]
*/
if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) {
if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) {
/* exit() ends the current stroke before cleaning up */
/* printf("\t\tGP - end of paint op + end of stroke\n"); */
p->status = GP_STATUS_DONE;
@@ -2045,6 +2390,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
else {
/* printf("\t\tGP - end of stroke + op\n"); */
/* disable paint session */
p->scene->toolsettings->gpencil_flags &= ~GP_TOOL_FLAG_PAINTSESSIONS_ON;
p->status = GP_STATUS_DONE;
estate = OPERATOR_FINISHED;
}
@@ -2074,6 +2422,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
in_bounds = true;
}
else {
/* disable paint session */
p->scene->toolsettings->gpencil_flags &= ~GP_TOOL_FLAG_PAINTSESSIONS_ON;
/* Out of bounds, or invalid in some other way */
p->status = GP_STATUS_ERROR;
estate = OPERATOR_CANCELLED;
@@ -2090,6 +2441,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
}
else {
/* disable paint session */
p->scene->toolsettings->gpencil_flags &= ~GP_TOOL_FLAG_PAINTSESSIONS_ON;
/* No region */
p->status = GP_STATUS_ERROR;
estate = OPERATOR_CANCELLED;
@@ -2117,6 +2471,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
p = gpencil_stroke_begin(C, op);
if (p->status == GP_STATUS_ERROR) {
/* disable paint session */
p->scene->toolsettings->gpencil_flags &= ~GP_TOOL_FLAG_PAINTSESSIONS_ON;
estate = OPERATOR_CANCELLED;
}
}
@@ -2125,6 +2482,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* NOTE: Don't eter this case if an error occurred while finding the
* region (as above)
*/
/* disable paint session */
p->scene->toolsettings->gpencil_flags &= ~GP_TOOL_FLAG_PAINTSESSIONS_ON;
p->status = GP_STATUS_DONE;
estate = OPERATOR_FINISHED;
}

View File

@@ -43,6 +43,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_object_types.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
@@ -616,9 +617,10 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
/* NOTE: Code here is adapted (i.e. copied directly) from gpencil_paint.c::gp_stroke_eraser_dostroke()
* It would be great to de-duplicate the logic here sometime, but that can wait...
*/
static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
const int mx, const int my, const int radius,
const bool select, rcti *rect)
static bool gp_stroke_do_circle_sel(
bGPDstroke *gps, GP_SpaceConversion *gsc,
const int mx, const int my, const int radius,
const bool select, rcti *rect, const bool parented, float diff_mat[4][4])
{
bGPDspoint *pt1, *pt2;
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
@@ -626,7 +628,14 @@ static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
bool changed = false;
if (gps->totpoints == 1) {
gp_point_to_xy(gsc, gps, gps->points, &x0, &y0);
if (!parented) {
gp_point_to_xy(gsc, gps, gps->points, &x0, &y0);
}
else {
bGPDspoint pt_temp;
gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0);
}
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
@@ -654,9 +663,18 @@ static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
/* get points to work with */
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
if (!parented) {
gp_point_to_xy(gsc, gps, pt1, &x0, &y0);
gp_point_to_xy(gsc, gps, pt2, &x1, &y1);
}
else {
bGPDspoint npt;
gp_point_to_parent_space(pt1, diff_mat, &npt);
gp_point_to_xy(gsc, gps, &npt, &x0, &y0);
gp_point_to_xy(gsc, gps, pt1, &x0, &y0);
gp_point_to_xy(gsc, gps, pt2, &x1, &y1);
gp_point_to_parent_space(pt2, diff_mat, &npt);
gp_point_to_xy(gsc, gps, &npt, &x1, &y1);
}
/* check that point segment of the boundbox of the selection stroke */
if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
@@ -733,11 +751,13 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
/* find visible strokes, and select if hit */
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
changed |= gp_stroke_do_circle_sel(gps, &gsc, mx, my, radius, select, &rect);
changed |= gp_stroke_do_circle_sel(
gps, &gsc, mx, my, radius, select, &rect,
(gpl->parent != NULL), diff_mat);
}
CTX_DATA_END;
GP_EDITABLE_STROKES_END;
/* updates */
if (changed) {
@@ -818,8 +838,9 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op)
WM_operator_properties_border_to_rcti(op, &rect);
/* select/deselect points */
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
bGPDspoint *pt;
int i;
@@ -827,7 +848,14 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op)
int x0, y0;
/* convert point coords to screenspace */
gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
if (gpl->parent == NULL) {
gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
}
else {
bGPDspoint pt2;
gp_point_to_parent_space(pt, diff_mat, &pt2);
gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0);
}
/* test if in selection rect */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0)) {
@@ -845,7 +873,7 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op)
/* Ensure that stroke selection is in sync with its points */
gpencil_stroke_sync_selection(gps);
}
CTX_DATA_END;
GP_EDITABLE_STROKES_END;
/* updates */
if (changed) {
@@ -920,7 +948,7 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
}
/* select/deselect points */
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
bGPDspoint *pt;
int i;
@@ -929,11 +957,17 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
int x0, y0;
/* convert point coords to screenspace */
gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
if (gpl->parent == NULL) {
gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
}
else {
bGPDspoint pt2;
gp_point_to_parent_space(pt, diff_mat, &pt2);
gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0);
}
/* test if in lasso boundbox + within the lasso noose */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0) &&
BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX))
BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX))
{
if (select) {
pt->flag |= GP_SPOINT_SELECT;
@@ -949,7 +983,7 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
/* Ensure that stroke selection is in sync with its points */
gpencil_stroke_sync_selection(gps);
}
CTX_DATA_END;
GP_EDITABLE_STROKES_END;
/* cleanup */
MEM_freeN((void *)mcords);
@@ -1020,7 +1054,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* First Pass: Find stroke point which gets hit */
/* XXX: maybe we should go from the top of the stack down instead... */
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
{
bGPDspoint *pt;
int i;
@@ -1029,7 +1063,14 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int xy[2];
gp_point_to_xy(&gsc, gps, pt, &xy[0], &xy[1]);
if (gpl->parent == NULL) {
gp_point_to_xy(&gsc, gps, pt, &xy[0], &xy[1]);
}
else {
bGPDspoint pt2;
gp_point_to_parent_space(pt, diff_mat, &pt2);
gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]);
}
/* do boundbox check first */
if (!ELEM(V2D_IS_CLIPPED, xy[0], xy[1])) {
@@ -1040,14 +1081,14 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* only use this point if it is a better match than the current hit - T44685 */
if (pt_distance < hit_distance) {
hit_stroke = gps;
hit_point = pt;
hit_point = pt;
hit_distance = pt_distance;
}
}
}
}
}
CTX_DATA_END;
GP_EDITABLE_STROKES_END;
/* Abort if nothing hit... */
if (ELEM(NULL, hit_stroke, hit_point)) {

View File

@@ -142,7 +142,7 @@ void gpencil_undo_push(bGPdata *gpd)
*/
undo_node->gpd->adt = NULL;
BKE_gpencil_free(undo_node->gpd);
BKE_gpencil_free(undo_node->gpd, false);
MEM_freeN(undo_node->gpd);
BLI_freelinkN(&undo_nodes, undo_node);
@@ -170,7 +170,7 @@ void gpencil_undo_finish(void)
*/
undo_node->gpd->adt = NULL;
BKE_gpencil_free(undo_node->gpd);
BKE_gpencil_free(undo_node->gpd, false);
MEM_freeN(undo_node->gpd);
undo_node = undo_node->next;

View File

@@ -17,7 +17,7 @@
*
* The Original Code is Copyright (C) 2014, Blender Foundation
*
* Contributor(s): Joshua Leung
* Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -32,9 +32,13 @@
#include <stddef.h>
#include <math.h>
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "BLI_rand.h"
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
@@ -46,6 +50,7 @@
#include "BKE_context.h"
#include "BKE_gpencil.h"
#include "BKE_tracking.h"
#include "BKE_action.h"
#include "WM_api.h"
@@ -269,6 +274,34 @@ int gp_active_layer_poll(bContext *C)
return (gpl != NULL);
}
/* poll callback for checking if there is an active brush */
int gp_active_brush_poll(bContext *C)
{
ToolSettings *ts = CTX_data_tool_settings(C);
bGPDbrush *brush = gpencil_brush_getactive(ts);
return (brush != NULL);
}
/* poll callback for checking if there is an active palette */
int gp_active_palette_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDpalette *palette = gpencil_palette_getactive(gpd);
return (palette != NULL);
}
/* poll callback for checking if there is an active palette color */
int gp_active_palettecolor_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDpalette *palette = gpencil_palette_getactive(gpd);
bGPDpalettecolor *palcolor = gpencil_palettecolor_getactive(palette);
return (palcolor != NULL);
}
/* ******************************************************** */
/* Dynamic Enums of GP Layers */
/* NOTE: These include an option to create a new layer and use that... */
@@ -412,6 +445,60 @@ bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
return ED_gpencil_stroke_can_use_direct(sa, gps);
}
/* Check whether given stroke can be edited for the current color */
bool ED_gpencil_stroke_color_use(const bGPDlayer *gpl, const bGPDstroke *gps)
{
/* check if the color is editable */
bGPDpalettecolor *palcolor = gps->palcolor;
if (palcolor != NULL) {
if (palcolor->flag & PC_COLOR_HIDE)
return false;
if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED))
return false;
}
return true;
}
/* Get palette color or create a new one */
bGPDpalettecolor *ED_gpencil_stroke_getcolor(bGPdata *gpd, bGPDstroke *gps)
{
bGPDpalette *palette;
bGPDpalettecolor *palcolor;
if ((gps->palcolor != NULL) && ((gps->flag & GP_STROKE_RECALC_COLOR) == 0))
return gps->palcolor;
/* get palette */
palette = gpencil_palette_getactive(gpd);
if (palette == NULL) {
palette = gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
}
/* get color */
palcolor = gpencil_palettecolor_getbyname(palette, gps->colorname);
if (palcolor == NULL) {
if (gps->palcolor == NULL) {
palcolor = gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
/* set to a different color */
ARRAY_SET_ITEMS(palcolor->color, 1.0f, 0.0f, 1.0f, 0.9f);
}
else {
palcolor = gpencil_palettecolor_addnew(palette, gps->colorname, true);
/* set old color and attributes */
bGPDpalettecolor *gpscolor = gps->palcolor;
copy_v4_v4(palcolor->color, gpscolor->color);
copy_v4_v4(palcolor->fill, gpscolor->fill);
palcolor->flag = gpscolor->flag;
}
}
/* clear flag and set pointer */
gps->flag &= ~GP_STROKE_RECALC_COLOR;
gps->palcolor = palcolor;
return palcolor;
}
/* ******************************************************** */
/* Space Conversion */
@@ -451,6 +538,50 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
}
}
/* convert point to parent space */
void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt)
{
float fpt[3];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
copy_v3_v3(&r_pt->x, fpt);
}
/* Change position relative to parent object */
void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt;
int i;
/* undo matrix */
float diff_mat[4][4];
float inverse_diff_mat[4][4];
float fpt[3];
ED_gpencil_parent_location(gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
for (i = 0; i < gps->totpoints; i++) {
pt = &gps->points[i];
mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
copy_v3_v3(&pt->x, fpt);
}
}
/* Change point position relative to parent object */
void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt)
{
/* undo matrix */
float diff_mat[4][4];
float inverse_diff_mat[4][4];
float fpt[3];
ED_gpencil_parent_location(gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
copy_v3_v3(&pt->x, fpt);
}
/* Convert Grease Pencil points to screen-space values
* WARNING: This assumes that the caller has already checked whether the stroke in question can be drawn
@@ -591,20 +722,102 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure)
madd_v3_v3fl(sco, &pt1->x, average_fac);
madd_v3_v3fl(sco, &pt2->x, average_fac);
#if 0
/* XXX: Disabled because get weird result */
/* do pressure too? */
if (affect_pressure) {
pressure += pt1->pressure * average_fac;
pressure += pt2->pressure * average_fac;
}
#endif
}
}
/* Based on influence factor, blend between original and optimal smoothed coordinate */
interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
#if 0
/* XXX: Disabled because get weird result */
if (affect_pressure) {
pt->pressure = pressure;
}
#endif
return true;
}
/**
* Apply smooth for strength to stroke point
* \param gps Stroke to smooth
* \param i Point index
* \param inf Amount of smoothing to apply
*/
bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf)
{
bGPDspoint *ptb = &gps->points[i];
/* Do nothing if not enough points */
if (gps->totpoints <= 2) {
return false;
}
/* Compute theoretical optimal value using distances */
bGPDspoint *pta, *ptc;
int before = i - 1;
int after = i + 1;
CLAMP_MIN(before, 0);
CLAMP_MAX(after, gps->totpoints - 1);
pta = &gps->points[before];
ptc = &gps->points[after];
/* the optimal value is the corresponding to the interpolation of the strength
* at the distance of point b
*/
const float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength;
/* Based on influence factor, blend between original and optimal */
ptb->strength = (1.0f - inf) * ptb->strength + inf * optimal;
return true;
}
/**
* Apply smooth for thickness to stroke point (use pressure)
* \param gps Stroke to smooth
* \param i Point index
* \param inf Amount of smoothing to apply
*/
bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf)
{
bGPDspoint *ptb = &gps->points[i];
/* Do nothing if not enough points */
if (gps->totpoints <= 2) {
return false;
}
/* Compute theoretical optimal value using distances */
bGPDspoint *pta, *ptc;
int before = i - 1;
int after = i + 1;
CLAMP_MIN(before, 0);
CLAMP_MAX(after, gps->totpoints - 1);
pta = &gps->points[before];
ptc = &gps->points[after];
/* the optimal value is the corresponding to the interpolation of the pressure
* at the distance of point b
*/
float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
float optimal = (1.0f - fac) * pta->pressure + fac * ptc->pressure;
/* Based on influence factor, blend between original and optimal */
ptb->pressure = (1.0f - inf) * ptb->pressure + inf * optimal;
return true;
}
@@ -633,16 +846,99 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints)
interp_v3_v3v3(&pt->x, &prev->x, &next->x, 0.5f);
pt->pressure = interpf(prev->pressure, next->pressure, 0.5f);
pt->time = interpf(prev->time, next->time, 0.5f);
pt->strength = interpf(prev->strength, next->strength, 0.5f);
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = interpf(prev->time, next->time, 0.5f);
}
/* Update to new total number of points */
gps->totpoints = new_totpoints;
}
/**
* Add randomness to stroke
* \param gps Stroke data
* \param brsuh Brush data
*/
void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush)
{
bGPDspoint *pt1, *pt2, *pt3;
float v1[3];
float v2[3];
if (gps->totpoints < 3) {
return;
}
/* get two vectors using 3 points */
pt1 = &gps->points[0];
pt2 = &gps->points[1];
pt3 = &gps->points[(int)(gps->totpoints * 0.75)];
sub_v3_v3v3(v1, &pt2->x, &pt1->x);
sub_v3_v3v3(v2, &pt3->x, &pt2->x);
normalize_v3(v1);
normalize_v3(v2);
/* get normal vector to plane created by two vectors */
float normal[3];
cross_v3_v3v3(normal, v1, v2);
normalize_v3(normal);
/* get orthogonal vector to plane to rotate random effect */
float ortho[3];
cross_v3_v3v3(ortho, v1, normal);
normalize_v3(ortho);
/* Read all points and apply shift vector (first and last point not modified) */
for (int i = 1; i < gps->totpoints - 1; ++i) {
bGPDspoint *pt = &gps->points[i];
/* get vector with shift (apply a division because random is too sensitive */
const float fac = BLI_frand() * (brush->draw_random_sub / 10.0f);
float svec[3];
copy_v3_v3(svec, ortho);
if (BLI_frand() > 0.5f) {
mul_v3_fl(svec, -fac);
}
else {
mul_v3_fl(svec, fac);
}
/* apply shift */
add_v3_v3(&pt->x, svec);
}
}
/* calculate difference matrix */
void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4])
{
Object *ob = gpl->parent;
if (ob == NULL) {
unit_m4(diff_mat);
return;
}
else {
if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
mul_m4_m4m4(diff_mat, ob->obmat, gpl->inverse);
return;
}
else if (gpl->partype == PARBONE) {
bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, gpl->parsubstr);
if (pchan) {
float tmp_mat[4][4];
mul_m4_m4m4(tmp_mat, ob->obmat, pchan->pose_mat);
mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse);
}
else {
mul_m4_m4m4(diff_mat, ob->obmat, gpl->inverse); /* if bone not found use object (armature) */
}
return;
}
else {
unit_m4(diff_mat); /* not defined type */
}
}
}
/* ******************************************************** */
bool ED_gpencil_stroke_minmax(
const bGPDstroke *gps, const bool use_select,
float r_min[3], float r_max[3])
@@ -659,3 +955,74 @@ bool ED_gpencil_stroke_minmax(
}
return changed;
}
/* Dynamic Enums of GP Brushes */
EnumPropertyItem *ED_gpencil_brushes_enum_itemf(
bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
bool *r_free)
{
ToolSettings *ts = CTX_data_tool_settings(C);
bGPDbrush *brush;
EnumPropertyItem *item = NULL, item_tmp = { 0 };
int totitem = 0;
int i = 0;
if (ELEM(NULL, C, ts)) {
return DummyRNA_DEFAULT_items;
}
/* Existing brushes */
for (brush = ts->gp_brushes.first; brush; brush = brush->next, i++) {
item_tmp.identifier = brush->info;
item_tmp.name = brush->info;
item_tmp.value = i;
if (brush->flag & GP_BRUSH_ACTIVE)
item_tmp.icon = ICON_BRUSH_DATA;
else
item_tmp.icon = ICON_NONE;
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
/* Dynamic Enums of GP Palettes */
EnumPropertyItem *ED_gpencil_palettes_enum_itemf(
bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
bool *r_free)
{
bGPdata *gpd = CTX_data_gpencil_data(C);
bGPDpalette *palette;
EnumPropertyItem *item = NULL, item_tmp = { 0 };
int totitem = 0;
int i = 0;
if (ELEM(NULL, C, gpd)) {
return DummyRNA_DEFAULT_items;
}
/* Existing palettes */
for (palette = gpd->palettes.first; palette; palette = palette->next, i++) {
item_tmp.identifier = palette->info;
item_tmp.name = palette->info;
item_tmp.value = i;
if (palette->flag & PL_PALETTE_ACTIVE)
item_tmp.icon = ICON_COLOR;
else
item_tmp.icon = ICON_NONE;
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
/* ******************************************************** */

View File

@@ -41,6 +41,8 @@ struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
struct bGPDpalette;
struct bGPDpalettecolor;
struct bAnimContext;
struct KeyframeEditData;
struct PointerRNA;
@@ -57,6 +59,7 @@ struct wmKeyConfig;
typedef struct tGPspoint {
int x, y; /* x and y coordinates of cursor (in relative to area) */
float pressure; /* pressure of tablet at this point */
float strength; /* pressure of tablet at this point for alpha factor */
float time; /* Time relative to stroke start (used when converting to path) */
} tGPspoint;
@@ -86,6 +89,9 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr
bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps);
bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
bool ED_gpencil_stroke_color_use(const struct bGPDlayer *gpl, const struct bGPDstroke *gps);
struct bGPDpalettecolor *ED_gpencil_stroke_getcolor(struct bGPdata *gpd, struct bGPDstroke *gps);
bool ED_gpencil_stroke_minmax(
const struct bGPDstroke *gps, const bool use_select,
@@ -142,4 +148,10 @@ bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mod
int ED_gpencil_session_active(void);
int ED_undo_gpencil_step(struct bContext *C, int step, const char *name);
/* ------------ Transformation Utilities ------------ */
/* get difference matrix using parent */
void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]);
#endif /* __ED_GPENCIL_H__ */

View File

@@ -320,9 +320,9 @@ DEF_ICON(OUTLINER_OB_SPEAKER)
DEF_ICON(BLANK123)
DEF_ICON(BLANK124)
DEF_ICON(BLANK125)
DEF_ICON(BLANK126)
DEF_ICON(BLANK127)
#endif
DEF_ICON(RESTRICT_COLOR_OFF)
DEF_ICON(RESTRICT_COLOR_ON)
DEF_ICON(RESTRICT_VIEW_OFF)
DEF_ICON(RESTRICT_VIEW_ON)
DEF_ICON(RESTRICT_SELECT_OFF)

View File

@@ -48,6 +48,7 @@
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
#include "DNA_actuator_types.h"
#include "DNA_gpencil_types.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -1145,10 +1146,22 @@ static int object_delete_exec(bContext *C, wmOperator *op)
}
else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) {
BKE_reportf(op->reports, RPT_WARNING,
"Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
base->object->id.name + 2, scene->id.name + 2);
"Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
base->object->id.name + 2, scene->id.name + 2);
continue;
}
/* remove from Grease Pencil parent */
for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
if (gpl->parent != NULL) {
Object *ob = gpl->parent;
Object *curob = base->object;
if (ob == curob) {
gpl->parent = NULL;
}
}
}
}
/* deselect object -- it could be used in other scenes */
base->object->flag &= ~SELECT;

View File

@@ -48,6 +48,7 @@
#include "DNA_world_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
#include "DNA_gpencil_types.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -1762,6 +1763,14 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
else {
/* copy already clears */
}
/* remap gpencil parenting */
bGPdata *gpd = scene->gpd;
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
if (gpl->parent == ob) {
gpl->parent = obn;
}
}
base->flag = obn->flag;
id_us_min(&ob->id);

View File

@@ -43,6 +43,7 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
#include "BKE_camera.h"
#include "BKE_context.h"
@@ -414,6 +415,99 @@ static void screen_opengl_render_write(OGLRender *oglrender)
else printf("OpenGL Render failed to write '%s'\n", name);
}
static void addAlphaOverFloat(float dest[4], const float source[4])
{
/* d = s + (1-alpha_s)d*/
float mul;
mul = 1.0f - source[3];
dest[0] = (mul * dest[0]) + source[0];
dest[1] = (mul * dest[1]) + source[1];
dest[2] = (mul * dest[2]) + source[2];
dest[3] = (mul * dest[3]) + source[3];
}
/* add renderlayer and renderpass for each grease pencil layer for using in composition */
static void add_gpencil_renderpass(OGLRender *oglrender, RenderResult *rr, RenderView *rv)
{
bGPdata *gpd = oglrender->scene->gpd;
Scene *scene = oglrender->scene;
/* sanity checks */
if (gpd == NULL) {
return;
}
if (scene == NULL) {
return;
}
if (BLI_listbase_is_empty(&gpd->layers)) {
return;
}
/* save old alpha mode */
short oldalphamode = scene->r.alphamode;
/* set alpha transparent for gp */
scene->r.alphamode = R_ALPHAPREMUL;
/* saves layer status */
short *oldsts = MEM_mallocN(BLI_listbase_count(&gpd->layers) * sizeof(short), "temp_gplayers_flag");
int i = 0;
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
oldsts[i] = gpl->flag;
++i;
}
/* loop all layers to create separate render */
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* dont draw layer if hidden */
if (gpl->flag & GP_LAYER_HIDE)
continue;
/* hide all layer except current */
for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) {
if (gpl != gph) {
gph->flag |= GP_LAYER_HIDE;
}
}
/* render this gp layer */
screen_opengl_render_doit(oglrender, rr);
/* add RendePass composite */
RenderPass *rp = RE_create_gp_pass(rr, gpl->info, rv->name);
/* copy image data from rectf */
float *src = RE_RenderViewGetById(rr, oglrender->view_id)->rectf;
float *dest = rp->rect;
float *pixSrc, *pixDest;
int x, y, rectx, recty;
rectx = rr->rectx;
recty = rr->recty;
for (y = 0; y < recty; y++) {
for (x = 0; x < rectx; x++) {
pixSrc = src + 4 * (rectx * y + x);
if (pixSrc[3] > 0.0) {
pixDest = dest + 4 * (rectx * y + x);
addAlphaOverFloat(pixDest, pixSrc);
}
}
}
/* back layer status */
i = 0;
for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) {
gph->flag = oldsts[i];
++i;
}
}
/* free memory */
MEM_freeN(oldsts);
/* back default alpha mode */
scene->r.alphamode = oldalphamode;
}
static void screen_opengl_render_apply(OGLRender *oglrender)
{
RenderResult *rr;
@@ -449,6 +543,9 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
BLI_assert(view_id < oglrender->views_len);
RE_SetActiveRenderView(oglrender->re, rv->name);
oglrender->view_id = view_id;
/* add grease pencil passes */
add_gpencil_renderpass(oglrender, rr, rv);
/* render composite */
screen_opengl_render_doit(oglrender, rr);
}

View File

@@ -85,7 +85,8 @@ const char *screen_context_dir[] = {
"sequences", "selected_sequences", "selected_editable_sequences", /* sequencer */
"gpencil_data", "gpencil_data_owner", /* grease pencil data */
"visible_gpencil_layers", "editable_gpencil_layers", "editable_gpencil_strokes",
"active_gpencil_layer", "active_gpencil_frame",
"active_gpencil_layer", "active_gpencil_frame", "active_gpencil_palette",
"active_gpencil_palettecolor", "active_gpencil_brush",
"active_operator",
NULL};
@@ -474,6 +475,44 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
}
else if (CTX_data_equals(member, "active_gpencil_palette")) {
/* XXX: see comment for gpencil_data case... */
bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
if (gpd) {
bGPDpalette *palette = gpencil_palette_getactive(gpd);
if (palette) {
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilPalette, palette);
return 1;
}
}
}
else if (CTX_data_equals(member, "active_gpencil_palettecolor")) {
/* XXX: see comment for gpencil_data case... */
bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
if (gpd) {
bGPDpalette *palette = gpencil_palette_getactive(gpd);
if (palette) {
bGPDpalettecolor *palcolor = gpencil_palettecolor_getactive(palette);
if (palcolor) {
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilPaletteColor, palcolor);
return 1;
}
}
}
}
else if (CTX_data_equals(member, "active_gpencil_brush")) {
/* XXX: see comment for gpencil_data case... */
bGPDbrush *brush = gpencil_brush_getactive(scene->toolsettings);
if (brush) {
CTX_data_pointer_set(result, NULL, &RNA_GPencilBrush, brush);
return 1;
}
}
else if (CTX_data_equals(member, "active_gpencil_frame")) {
/* XXX: see comment for gpencil_data case... */
bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
@@ -533,6 +572,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
for (gps = gpf->strokes.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use_direct(sa, gps)) {
/* check if the color is editable */
if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
continue;
}
CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps);
}
}

View File

@@ -1002,7 +1002,7 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
}
static void tselem_draw_gp_icon_uibut(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl)
static void UNUSED_FUNCTION(tselem_draw_gp_icon_uibut)(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl)
{
/* restrict column clip - skip it for now... */
if (arg->x >= arg->xmax) {
@@ -1233,9 +1233,12 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
else
UI_icon_draw(x, y, RNA_struct_ui_icon(te->rnaptr.type));
break;
/* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */
#if 0
case TSE_GP_LAYER:
tselem_draw_gp_icon_uibut(&arg, tselem->id, te->directdata);
break;
#endif
default:
UI_icon_draw(x, y, ICON_DOT); break;
}

View File

@@ -327,6 +327,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
for (j = 0; j < 3; j++) {
copy_v3_v3(&pt->x, ruler_item->co[j]);
pt->pressure = 1.0f;
pt->strength = 1.0f;
pt++;
}
}
@@ -336,6 +337,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
for (j = 0; j < 3; j += 2) {
copy_v3_v3(&pt->x, ruler_item->co[j]);
pt->pressure = 1.0f;
pt->strength = 1.0f;
pt++;
}
}

View File

@@ -7687,6 +7687,10 @@ static void createTransGPencil(bContext *C, TransInfo *t)
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;
}
if (is_prop_edit) {
/* Proportional Editing... */
@@ -7735,6 +7739,15 @@ static void createTransGPencil(bContext *C, TransInfo *t)
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf = gpl->actframe;
bGPDstroke *gps;
float diff_mat[4][4];
float inverse_diff_mat[4][4];
/* calculate difference matrix if parent object */
if (gpl->parent != NULL) {
ED_gpencil_parent_location(gpl, diff_mat);
/* undo matrix */
invert_m4_m4(inverse_diff_mat, diff_mat);
}
/* Make a new frame to work on if the layer's frame and the current scene frame don't match up
* - This is useful when animating as it saves that "uh-oh" moment when you realize you've
@@ -7743,6 +7756,10 @@ static void createTransGPencil(bContext *C, TransInfo *t)
// XXX: should this be allowed when framelock is enabled?
if (gpf->framenum != cfra) {
gpf = gpencil_frame_addcopy(gpl, cfra);
/* in some weird situations (framelock enabled) return NULL */
if (gpf == NULL) {
continue;
}
}
/* Loop over strokes, adding TransData for points as needed... */
@@ -7755,7 +7772,10 @@ static void createTransGPencil(bContext *C, TransInfo *t)
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;
}
/* What we need to include depends on proportional editing settings... */
if (is_prop_edit) {
if (is_prop_edit_connected) {
@@ -7824,9 +7844,18 @@ static void createTransGPencil(bContext *C, TransInfo *t)
/* screenspace */
td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
copy_m3_m4(td->smtx, t->persmat);
copy_m3_m4(td->mtx, t->persinv);
unit_m3(td->axismtx);
/* apply parent transformations */
if (gpl->parent == NULL) {
copy_m3_m4(td->smtx, t->persmat);
copy_m3_m4(td->mtx, t->persinv);
unit_m3(td->axismtx);
}
else {
/* apply matrix transformation relative to parent */
copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
copy_m3_m4(td->mtx, diff_mat); /* display position */
copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
}
}
else {
/* configure 2D dataspace points so that they don't play up... */
@@ -7835,9 +7864,18 @@ static void createTransGPencil(bContext *C, TransInfo *t)
// XXX: matrices may need to be different?
}
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
unit_m3(td->axismtx); // XXX?
/* apply parent transformations */
if (gpl->parent == NULL) {
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
unit_m3(td->axismtx); // XXX?
}
else {
/* apply matrix transformation relative to parent */
copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
copy_m3_m4(td->mtx, diff_mat); /* display position */
copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
}
}
/* Triangulation must be calculated again, so save the stroke for recalc function */
td->extra = gps;

View File

@@ -975,7 +975,9 @@ static void recalcData_gpencil_strokes(TransInfo *t)
TransData *td = t->data;
for (int i = 0; i < t->total; i++, td++) {
bGPDstroke *gps = td->extra;
gps->flag |= GP_STROKE_RECALC_CACHES;
if (gps != NULL) {
gps->flag |= GP_STROKE_RECALC_CACHES;
}
}
}

View File

@@ -58,6 +58,7 @@
#include "BKE_pointcache.h"
#include "BKE_editmesh.h"
#include "BKE_lattice.h"
#include "BKE_gpencil.h"
#include "BIF_gl.h"
@@ -68,6 +69,7 @@
#include "ED_curve.h"
#include "ED_particle.h"
#include "ED_view3d.h"
#include "ED_gpencil.h"
#include "UI_resources.h"
@@ -288,23 +290,48 @@ static int calc_manipulator_stats(const bContext *C)
zero_v3(scene->twcent);
if (is_gp_edit) {
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
/* we're only interested in selected points here... */
if (gps->flag & GP_STROKE_SELECT) {
bGPDspoint *pt;
int i;
float diff_mat[4][4];
float fpt[3];
/* Change selection status of all points, then make the stroke match */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
calc_tw_center(scene, &pt->x);
totsel++;
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)) {
/* calculate difference matrix if parent object */
if (gpl->parent != NULL) {
ED_gpencil_parent_location(gpl, diff_mat);
}
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;
}
/* we're only interested in selected points here... */
if (gps->flag & GP_STROKE_SELECT) {
bGPDspoint *pt;
int i;
/* Change selection status of all points, then make the stroke match */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
if (gpl->parent == NULL) {
calc_tw_center(scene, &pt->x);
totsel++;
}
else {
mul_v3_m4v3(fpt, diff_mat, &pt->x);
calc_tw_center(scene, fpt);
totsel++;
}
}
}
}
}
}
}
CTX_DATA_END;
/* selection center */
if (totsel) {

View 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 *****
*/
@@ -32,9 +32,10 @@
#include "DNA_listBase.h"
#include "DNA_ID.h"
#include "DNA_brush_types.h"
struct AnimData;
struct CurveMapping;
/* Grease-Pencil Annotations - 'Stroke Point'
* -> Coordinates may either be 2d or 3d depending on settings at the time
@@ -44,6 +45,7 @@ struct AnimData;
typedef struct bGPDspoint {
float x, y, z; /* co-ordinates of point (usually 2d, but can be 3d as well) */
float pressure; /* pressure of input device (from 0 to 1) at this point */
float strength; /* color strength (used for alpha factor) */
float time; /* seconds since start of stroke */
int flag; /* additional options (NOTE: can shrink this field down later if needed) */
} bGPDspoint;
@@ -65,24 +67,113 @@ typedef struct bGPDtriangle {
int v1, v2, v3; /* indices for tesselated triangle used for GP Fill */
} bGPDtriangle;
/* GP brush (used for new strokes) */
typedef struct bGPDbrush {
struct bGPDbrush *next, *prev;
char info[64]; /* Brush name. Must be unique. */
short thickness; /* thickness to apply to strokes */
short flag;
float draw_smoothfac; /* amount of smoothing to apply to newly created strokes */
short draw_smoothlvl; /* number of times to apply smooth factor to new strokes */
short sublevel; /* number of times to subdivide new strokes */
float draw_sensitivity; /* amount of sensivity to apply to newly created strokes */
float draw_strength; /* amount of alpha strength to apply to newly created strokes */
float draw_jitter; /* amount of jitter to apply to newly created strokes */
float draw_angle; /* angle when the brush has full thickness */
float draw_angle_factor; /* factor to apply when angle change (only 90 degrees) */
float draw_random_press; /* factor of randomness for sensitivity and strength */
float draw_random_sub; /* factor of randomness for subdivision */
struct CurveMapping *cur_sensitivity;
struct CurveMapping *cur_strength;
struct CurveMapping *cur_jitter;
} bGPDbrush;
/* bGPDbrush->flag */
typedef enum eGPDbrush_Flag {
/* brush is active */
GP_BRUSH_ACTIVE = (1 << 0),
/* brush use pressure */
GP_BRUSH_USE_PRESSURE = (1 << 1),
/* brush use pressure for alpha factor */
GP_BRUSH_USE_STENGTH_PRESSURE = (1 << 2),
/* brush use pressure for alpha factor */
GP_BRUSH_USE_JITTER_PRESSURE = (1 << 3),
/* brush use random for pressure */
GP_BRUSH_USE_RANDOM_PRESSURE = (1 << 4),
/* brush use random for strength */
GP_BRUSH_USE_RANDOM_STRENGTH = (1 << 5)
} eGPDbrush_Flag;
/* color of palettes */
typedef struct bGPDpalettecolor {
struct bGPDpalettecolor *next, *prev;
char info[64]; /* Color name. Must be unique. */
float color[4];
float fill[4]; /* color that should be used for drawing "fills" for strokes */
short flag; /* settings for palette color */
char pad[6]; /* padding for compiler alignment error */
} bGPDpalettecolor;
/* bGPDpalettecolor->flag */
typedef enum eGPDpalettecolor_Flag {
/* color is active */
PC_COLOR_ACTIVE = (1 << 0),
/* don't display color */
PC_COLOR_HIDE = (1 << 1),
/* protected from further editing */
PC_COLOR_LOCKED = (1 << 2),
/* do onion skinning */
PC_COLOR_ONIONSKIN = (1 << 3),
/* "volumetric" strokes (i.e. GLU Quadric discs in 3D) */
PC_COLOR_VOLUMETRIC = (1 << 4),
/* Use High quality fill */
PC_COLOR_HQ_FILL = (1 << 5)
} eGPDpalettecolor_Flag;
/* palette of colors */
typedef struct bGPDpalette {
struct bGPDpalette *next, *prev;
/* pointer to individual colours */
ListBase colors;
char info[64]; /* Palette name. Must be unique. */
short flag;
char pad[6]; /* padding for compiler alignment error */
} bGPDpalette;
/* bGPDpalette->flag */
typedef enum eGPDpalette_Flag {
/* palette is active */
PL_PALETTE_ACTIVE = (1 << 0)
} eGPDpalette_Flag;
/* Grease-Pencil Annotations - 'Stroke'
* -> A stroke represents a (simplified version) of the curve
* drawn by the user in one 'mousedown'->'mouseup' operation
*/
typedef struct bGPDstroke {
struct bGPDstroke *next, *prev;
bGPDspoint *points; /* array of data-points for stroke */
void *pad; /* keep 4 pointers at the beginning, padding for 'inittime' is tricky 64/32bit */
int totpoints; /* number of data-points in array */
short thickness; /* thickness of stroke (currently not used) */
short flag; /* various settings about this stroke */
bGPDtriangle *triangles;/* tesselated triangles for GP Fill */
int totpoints; /* number of data-points in array */
int tot_triangles; /* number of triangles in array */
int pad1, *pad2;
short thickness; /* thickness of stroke */
short flag, pad[2]; /* various settings about this stroke */
double inittime; /* Init time of stroke */
/* The pointer to color is only used during drawing, but not saved
* colorname is the join with the palette, but when draw, the pointer is update if the value is NULL
* to speed up the drawing
*/
char colorname[128]; /* color name */
bGPDpalettecolor *palcolor; /* current palette color */
/* temporary layer name only used during copy/paste to put the stroke in the original layer */
char tmp_layerinfo[128];
} bGPDstroke;
/* bGPDstroke->flag */
@@ -97,6 +188,10 @@ typedef enum eGPDstroke_Flag {
GP_STROKE_SELECT = (1 << 3),
/* Recalculate triangulation for high quality fill (when true, force a new recalc) */
GP_STROKE_RECALC_CACHES = (1 << 4),
/* Recalculate the color pointer using the name as index (true force a new recalc) */
GP_STROKE_RECALC_COLOR = (1 << 5),
/* Flag used to indicate that stroke is closed and draw edge between last and first point */
GP_STROKE_CYCLIC = (1 << 7),
/* only for use with stroke-buffer (while drawing eraser) */
GP_STROKE_ERASER = (1 << 15)
} eGPDstroke_Flag;
@@ -139,16 +234,18 @@ typedef struct bGPDlayer {
float gcolor_prev[3]; /* optional color for ghosts before the active frame */
float gcolor_next[3]; /* optional color for ghosts after the active frame */
float color[4]; /* color that should be used to draw all the strokes in this layer */
float fill[4]; /* color that should be used for drawing "fills" for strokes */
float color[4]; /* Color for strokes in layers (replaced by palettecolor). Only used for ruler (which uses GPencil internally) */
float fill[4]; /* Fill color for strokes in layers. Not used and replaced by palettecolor fill */
char info[128]; /* optional reference info about this layer (i.e. "director's comments, 12/3")
* this is used for the name of the layer too and kept unique. */
float draw_smoothfac; /* amount of smoothing to apply to newly created strokes */
short draw_smoothlvl; /* number of times to apply smooth factor to new strokes */
short sublevel; /* number of times to subdivide new strokes */
short pad[4]; /* padding for compiler error */
struct Object *parent; /* parent object */
float inverse[4][4]; /* inverse matrix (only used if parented) */
char parsubstr[64]; /* String describing subobject info, MAX_ID_NAME-2 */
short partype, pad;
float tintcolor[4]; /* Color used to tint layer, alpha value is used as factor */
float opacity; /* Opacity of the layer */
} bGPDlayer;
/* bGPDlayer->flag */
@@ -176,7 +273,9 @@ typedef enum eGPDlayer_Flag {
/* "volumetric" strokes (i.e. GLU Quadric discs in 3D) */
GP_LAYER_VOLUMETRIC = (1 << 10),
/* Use high quality fill (instead of buggy legacy OpenGL Fill) */
GP_LAYER_HQ_FILL = (1 << 11)
GP_LAYER_HQ_FILL = (1 << 11),
/* Unlock color */
GP_LAYER_UNLOCK_COLOR = (1 << 12)
} eGPDlayer_Flag;
/* Grease-Pencil Annotations - 'DataBlock' */
@@ -195,6 +294,13 @@ typedef struct bGPdata {
short sbuffer_size; /* number of elements currently in cache */
short sbuffer_sflag; /* flags for stroke that cache represents */
void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */
float scolor[4]; /* buffer color using palettes */
char pad[6]; /* padding for compiler alignment error */
short sflag; /* settings for palette color */
/* saved paletes and brushes */
ListBase palettes;
//ListBase brushes;
} bGPdata;
/* bGPdata->flag */
@@ -229,7 +335,9 @@ typedef enum eGPdata_Flag {
GP_DATA_STROKE_EDITMODE = (1 << 8),
/* Convenience/cache flag to make it easier to quickly toggle onion skinning on/off */
GP_DATA_SHOW_ONIONSKINS = (1 << 9)
GP_DATA_SHOW_ONIONSKINS = (1 << 9),
/* Draw a green and red point to indicate start and end of the stroke */
GP_DATA_SHOW_DIRECTION = (1 << 10)
} eGPdata_Flag;
#endif /* __DNA_GPENCIL_TYPES_H__ */

View File

@@ -62,6 +62,7 @@ struct AnimData;
struct Editing;
struct SceneStats;
struct bGPdata;
struct bGPDbrush;
struct MovieClip;
struct ColorSpace;
@@ -1117,12 +1118,12 @@ typedef enum eGP_EditBrush_Types {
GP_EDITBRUSH_TYPE_SUBDIVIDE = 7,
GP_EDITBRUSH_TYPE_SIMPLIFY = 8,
GP_EDITBRUSH_TYPE_CLONE = 9,
GP_EDITBRUSH_TYPE_STRENGTH = 10,
/* !!! Update GP_EditBrush_Data brush[###]; below !!! */
TOT_GP_EDITBRUSH_TYPES
} eGP_EditBrush_Types;
/* Settings for a GPencil Stroke Sculpting Brush */
typedef struct GP_EditBrush_Data {
short size; /* radius of brush */
@@ -1148,17 +1149,26 @@ typedef enum eGP_EditBrush_Flag {
/* GPencil Stroke Sculpting Settings */
typedef struct GP_BrushEdit_Settings {
GP_EditBrush_Data brush[10]; /* TOT_GP_EDITBRUSH_TYPES */
GP_EditBrush_Data brush[11]; /* TOT_GP_EDITBRUSH_TYPES */
void *paintcursor; /* runtime */
int brushtype; /* eGP_EditBrush_Types */
int flag; /* eGP_BrushEdit_SettingsFlag */
char pad[4];
float alpha; /* alpha factor for selection color */
} GP_BrushEdit_Settings;
/* GP_BrushEdit_Settings.flag */
typedef enum eGP_BrushEdit_SettingsFlag {
/* only affect selected points */
GP_BRUSHEDIT_FLAG_SELECT_MASK = (1 << 0)
GP_BRUSHEDIT_FLAG_SELECT_MASK = (1 << 0),
/* apply brush to position */
GP_BRUSHEDIT_FLAG_APPLY_POSITION = (1 << 1),
/* apply brush to strength */
GP_BRUSHEDIT_FLAG_APPLY_STRENGTH = (1 << 2),
/* apply brush to thickness */
GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3)
} eGP_BrushEdit_SettingsFlag;
/* *************************************************************** */
@@ -1378,6 +1388,9 @@ typedef struct ToolSettings {
/* Grease Pencil Sculpt */
struct GP_BrushEdit_Settings gp_sculpt;
/* Grease Pencil Drawing Brushes (bGPDbrush) */
ListBase gp_brushes;
/* Image Paint (8 byttse aligned please!) */
struct ImagePaintSettings imapaint;

View File

@@ -257,6 +257,9 @@ extern StructRNA RNA_FreestyleSettings;
extern StructRNA RNA_Function;
extern StructRNA RNA_GPencilFrame;
extern StructRNA RNA_GPencilLayer;
extern StructRNA RNA_GPencilPalette;
extern StructRNA RNA_GPencilPaletteColor;
extern StructRNA RNA_GPencilBrush;
extern StructRNA RNA_GPencilStroke;
extern StructRNA RNA_GPencilStrokePoint;
extern StructRNA RNA_GPencilSculptSettings;

View File

@@ -15,7 +15,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Blender Foundation (2009), Joshua Leung
* Contributor(s): Blender Foundation (2009), Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -41,6 +41,17 @@
#include "rna_internal.h"
#include "WM_types.h"
#include "DNA_object_types.h"
#include "ED_gpencil.h"
/* parent type */
static EnumPropertyItem parent_type_items[] = {
{PAROBJECT, "OBJECT", 0, "Object", "The layer is parented to an object"},
{PARSKEL, "ARMATURE", 0, "Armature", ""},
{PARBONE, "BONE", 0, "Bone", "The layer is parented to a bone"},
{0, NULL, 0, NULL, NULL}
};
#ifdef RNA_RUNTIME
@@ -49,8 +60,7 @@
#include "WM_api.h"
#include "BKE_gpencil.h"
#include "DNA_object_types.h"
#include "BKE_action.h"
static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
@@ -90,6 +100,16 @@ static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, Pointer
rna_GPencil_update(bmain, scene, ptr);
}
static void rna_GPencil_stroke_colorname_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bGPDstroke *gps = (bGPDstroke *)ptr->data;
gps->flag |= GP_STROKE_RECALC_COLOR;
gps->palcolor = NULL;
/* Now do standard updates... */
rna_GPencil_update(bmain, scene, ptr);
}
static char *rna_GPencilLayer_path(PointerRNA *ptr)
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
@@ -123,38 +143,140 @@ static void rna_GPencilLayer_line_width_range(PointerRNA *ptr, int *min, int *ma
* it's relatively hard to test for that. So, for now, only volumetric strokes
* get to be larger...
*/
/* From GP v2 this value is used to increase or decrease the thickness of the stroke */
if (gpl->flag & GP_LAYER_VOLUMETRIC) {
*min = 1;
*min = -300;
*max = 300;
*softmin = 1;
*softmin = -100;
*softmax = 100;
}
else {
*min = 1;
*min = -10;
*max = 10;
*softmin = 1;
*softmin = -10;
*softmax = 10;
}
}
static int rna_GPencilLayer_is_stroke_visible_get(PointerRNA *ptr)
/* set parent */
static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char *substr)
{
/* see drawgpencil.c -> gp_draw_data_layers() for more details
* about this limit for showing/not showing
*/
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
return (gpl->color[3] > GPENCIL_ALPHA_OPACITY_THRESH);
if (type == PAROBJECT) {
invert_m4_m4(gpl->inverse, par->obmat);
gpl->parent = par;
gpl->partype |= PAROBJECT;
gpl->parsubstr[0] = 0;
}
else if (type == PARSKEL) {
invert_m4_m4(gpl->inverse, par->obmat);
gpl->parent = par;
gpl->partype |= PARSKEL;
gpl->parsubstr[0] = 0;
}
else if (type == PARBONE) {
bPoseChannel *pchan = BKE_pose_channel_find_name(par->pose, substr);
if (pchan) {
float tmp_mat[4][4];
mul_m4_m4m4(tmp_mat, par->obmat, pchan->pose_mat);
invert_m4_m4(gpl->inverse, tmp_mat);
gpl->parent = par;
gpl->partype |= PARBONE;
BLI_strncpy(gpl->parsubstr, substr, sizeof(gpl->parsubstr));
}
}
}
static int rna_GPencilLayer_is_fill_visible_get(PointerRNA *ptr)
/* set parent object and inverse matrix */
static void rna_GPencilLayer_parent_set(PointerRNA *ptr, PointerRNA value)
{
/* see drawgpencil.c -> gp_draw_data_layers() for more details
* about this limit for showing/not showing
*/
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
return (gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH);
Object *par = (Object *)value.data;
if (par != NULL) {
set_parent(gpl, par, gpl->partype, gpl->parsubstr);
}
else {
/* keep strokes in the same place, so apply current transformation */
if (gpl->parent != NULL) {
bGPDspoint *pt;
int i;
float diff_mat[4][4];
/* calculate difference matrix */
ED_gpencil_parent_location(gpl, diff_mat);
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
mul_m4_v3(diff_mat, &pt->x);
}
}
}
}
/* clear parent */
gpl->parent = NULL;
}
}
/* set parent type */
static void rna_GPencilLayer_parent_type_set(PointerRNA *ptr, int value)
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
Object *par = gpl->parent;
gpl->partype = value;
if (par != NULL) {
set_parent(gpl, par, value, gpl->parsubstr);
}
}
/* set parent bone */
static void rna_GPencilLayer_parent_bone_set(PointerRNA *ptr, const char *value)
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
Object *par = gpl->parent;
gpl->partype = PARBONE;
if (par != NULL) {
set_parent(gpl, par, gpl->partype, value);
}
}
/* parent types enum */
static EnumPropertyItem *rna_Object_parent_type_itemf(
bContext *UNUSED(C), PointerRNA *ptr,
PropertyRNA *UNUSED(prop), bool *r_free)
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
EnumPropertyItem *item = NULL;
int totitem = 0;
RNA_enum_items_add_value(&item, &totitem, parent_type_items, PAROBJECT);
if (gpl->parent) {
Object *par = gpl->parent;
if (par->type == OB_ARMATURE) {
/* special hack: prevents this being overrided */
RNA_enum_items_add_value(&item, &totitem, &parent_type_items[1], PARSKEL);
RNA_enum_items_add_value(&item, &totitem, parent_type_items, PARBONE);
}
}
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
static int rna_GPencilLayer_is_parented_get(PointerRNA *ptr)
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
return (gpl->parent != NULL);
}
static PointerRNA rna_GPencil_active_layer_get(PointerRNA *ptr)
@@ -357,10 +479,12 @@ static void rna_GPencil_stroke_point_pop(bGPDstroke *stroke, ReportList *reports
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame)
static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame, const char *colorname)
{
bGPDstroke *stroke = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
strcpy(stroke->colorname, colorname);
stroke->palcolor = NULL;
stroke->flag |= GP_STROKE_RECALC_COLOR;
BLI_addtail(&frame->strokes, stroke);
return stroke;
@@ -490,6 +614,239 @@ static void rna_GPencil_clear(bGPdata *gpd)
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
/* Palettes */
static bGPDpalette *rna_GPencil_palette_new(bGPdata *gpd, const char *name, int setactive)
{
bGPDpalette *palette = gpencil_palette_addnew(gpd, name, setactive != 0);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return palette;
}
static void rna_GPencil_palette_remove(bGPdata *gpd, ReportList *reports, PointerRNA *palette_ptr)
{
bGPDpalette *palette = palette_ptr->data;
if (BLI_findindex(&gpd->palettes, palette) == -1) {
BKE_report(reports, RPT_ERROR, "Palette not found in grease pencil data");
return;
}
gpencil_palette_delete(gpd, palette);
RNA_POINTER_INVALIDATE(palette_ptr);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
static PointerRNA rna_GPencil_active_palette_get(PointerRNA *ptr)
{
bGPdata *gpd = ptr->id.data;
if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */
bGPDpalette *palette;
for (palette = gpd->palettes.first; palette; palette = palette->next) {
if (palette->flag & PL_PALETTE_ACTIVE) {
break;
}
}
if (palette) {
return rna_pointer_inherit_refine(ptr, &RNA_GPencilPalette, palette);
}
}
return rna_pointer_inherit_refine(ptr, NULL, NULL);
}
static void rna_GPencil_active_palette_set(PointerRNA *ptr, PointerRNA value)
{
bGPdata *gpd = ptr->id.data;
if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */
bGPDpalette *palette;
for (palette = gpd->palettes.first; palette; palette = palette->next) {
if (palette == value.data) {
palette->flag |= PL_PALETTE_ACTIVE;
}
else {
palette->flag &= ~PL_PALETTE_ACTIVE;
}
}
/* force color recalc */
gpencil_palette_change_strokes(gpd);
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
}
static int rna_GPencilPalette_index_get(PointerRNA *ptr)
{
bGPdata *gpd = (bGPdata *)ptr->id.data;
bGPDpalette *palette = gpencil_palette_getactive(gpd);
return BLI_findindex(&gpd->palettes, palette);
}
static void rna_GPencilPalette_index_set(PointerRNA *ptr, int value)
{
bGPdata *gpd = (bGPdata *)ptr->id.data;
bGPDpalette *palette = BLI_findlink(&gpd->palettes, value);
gpencil_palette_setactive(gpd, palette);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
static void rna_GPencilPalette_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
{
bGPdata *gpd = (bGPdata *)ptr->id.data;
*min = 0;
*max = max_ii(0, BLI_listbase_count(&gpd->palettes) - 1);
*softmin = *min;
*softmax = *max;
}
/* Palette colors */
static bGPDpalettecolor *rna_GPencilPalette_color_new(bGPDpalette *palette)
{
bGPDpalettecolor *color = gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
return color;
}
static void rna_GPencilPalette_color_remove(bGPDpalette *palette, ReportList *reports, PointerRNA *color_ptr)
{
bGPDpalettecolor *color = color_ptr->data;
if (BLI_findindex(&palette->colors, color) == -1) {
BKE_reportf(reports, RPT_ERROR, "Palette '%s' does not contain color given", palette->info + 2);
return;
}
gpencil_palettecolor_delete(palette, color);
RNA_POINTER_INVALIDATE(color_ptr);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
static PointerRNA rna_GPencilPalette_active_color_get(PointerRNA *ptr)
{
bGPDpalette *palette = (bGPDpalette *)ptr->data;
bGPDpalettecolor *color;
for (color = palette->colors.first; color; color = color->next) {
if (color->flag & PC_COLOR_ACTIVE) {
break;
}
}
if (color) {
return rna_pointer_inherit_refine(ptr, &RNA_GPencilPaletteColor, color);
}
return rna_pointer_inherit_refine(ptr, NULL, NULL);
}
static void rna_GPencilPalette_active_color_set(PointerRNA *ptr, PointerRNA value)
{
bGPDpalette *palette = (bGPDpalette *)ptr->data;
bGPDpalettecolor *color = value.data;
gpencil_palettecolor_setactive(palette, color);
}
static void rna_GPencilPalette_info_set(PointerRNA *ptr, const char *value)
{
bGPdata *gpd = ptr->id.data;
bGPDpalette *palette = ptr->data;
/* copy the new name into the name slot */
BLI_strncpy_utf8(palette->info, value, sizeof(palette->info));
BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
sizeof(palette->info));
}
static char *rna_GPencilPalette_color_path(PointerRNA *ptr)
{
bGPdata *gpd = ptr->id.data;
bGPDpalette *palette = gpencil_palette_getactive(gpd);
bGPDpalettecolor *palcolor = ptr->data;
char name_palette[sizeof(palette->info) * 2];
char name_color[sizeof(palcolor->info) * 2];
BLI_strescape(name_palette, palette->info, sizeof(name_palette));
BLI_strescape(name_color, palcolor->info, sizeof(name_color));
return BLI_sprintfN("palettes[\"%s\"].colors[\"%s\"]", name_palette, name_color);
}
static void rna_GPencilPaletteColor_info_set(PointerRNA *ptr, const char *value)
{
bGPdata *gpd = ptr->id.data;
bGPDpalette *palette = gpencil_palette_getactive(gpd);
bGPDpalettecolor *palcolor = ptr->data;
/* rename all strokes */
gpencil_palettecolor_changename(gpd, palcolor->info, value);
/* copy the new name into the name slot */
BLI_strncpy_utf8(palcolor->info, value, sizeof(palcolor->info));
BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
sizeof(palcolor->info));
}
static void rna_GPencilStrokeColor_info_set(PointerRNA *ptr, const char *value)
{
bGPDstroke *gps = ptr->data;
/* copy the new name into the name slot */
BLI_strncpy_utf8(gps->colorname, value, sizeof(gps->colorname));
}
static int rna_GPencilPaletteColor_is_stroke_visible_get(PointerRNA *ptr)
{
bGPDpalettecolor *pcolor = (bGPDpalettecolor *)ptr->data;
return (pcolor->color[3] > GPENCIL_ALPHA_OPACITY_THRESH);
}
static int rna_GPencilPaletteColor_is_fill_visible_get(PointerRNA *ptr)
{
bGPDpalettecolor *pcolor = (bGPDpalettecolor *)ptr->data;
return (pcolor->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH);
}
static int rna_GPencilPaletteColor_index_get(PointerRNA *ptr)
{
bGPDpalette *palette = (bGPDpalette *)ptr->data;
bGPDpalettecolor *pcolor = gpencil_palettecolor_getactive(palette);
return BLI_findindex(&palette->colors, pcolor);
}
static void rna_GPencilPaletteColor_index_set(PointerRNA *ptr, int value)
{
bGPDpalette *palette = (bGPDpalette *)ptr->data;
bGPDpalettecolor *pcolor = BLI_findlink(&palette->colors, value);
gpencil_palettecolor_setactive(palette, pcolor);
}
static void rna_GPencilPaletteColor_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
{
bGPDpalette *palette = (bGPDpalette *)ptr->data;
*min = 0;
*max = max_ii(0, BLI_listbase_count(&palette->colors) - 1);
*softmin = *min;
*softmax = *max;
}
#else
static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
@@ -513,6 +870,12 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Pressure", "Pressure of tablet at point when drawing it");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "strength");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Strength", "Color intensity (alpha factor)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SPOINT_SELECT);
RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_point_select_set");
@@ -542,6 +905,35 @@ static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_int(func, "index", -1, INT_MIN, INT_MAX, "Index", "point index", INT_MIN, INT_MAX);
}
/* This information is read only and it can be used by add-ons */
static void rna_def_gpencil_triangle(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "GPencilTriangle", NULL);
RNA_def_struct_sdna(srna, "bGPDtriangle");
RNA_def_struct_ui_text(srna, "Triangle", "Triangulation data for HQ fill");
/* point v1 */
prop = RNA_def_property(srna, "v1", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "v1");
RNA_def_property_ui_text(prop, "v1", "First triangle vertice index");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* point v2 */
prop = RNA_def_property(srna, "v2", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "v2");
RNA_def_property_ui_text(prop, "v2", "Second triangle vertice index");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* point v3 */
prop = RNA_def_property(srna, "v3", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "v3");
RNA_def_property_ui_text(prop, "v3", "Third triangle vertice index");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_gpencil_stroke(BlenderRNA *brna)
{
StructRNA *srna;
@@ -566,6 +958,19 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Stroke Points", "Stroke data points");
rna_def_gpencil_stroke_points_api(brna, prop);
/* Triangles */
prop = RNA_def_property(srna, "triangles", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "triangles", "tot_triangles");
RNA_def_property_struct_type(prop, "GPencilTriangle");
RNA_def_property_ui_text(prop, "Triangles", "Triangulation data for HQ fill");
/* Color */
prop = RNA_def_property(srna, "color", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPencilPaletteColor");
RNA_def_property_pointer_sdna(prop, NULL, "palcolor");
RNA_def_property_ui_text(prop, "Palette Color", "Color from palette used in Stroke");
RNA_def_property_update(prop, 0, "rna_GPencil_update");
/* Settings */
prop = RNA_def_property(srna, "draw_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
@@ -578,6 +983,27 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_select_set");
RNA_def_property_ui_text(prop, "Select", "Stroke is selected for viewport editing");
RNA_def_property_update(prop, 0, "rna_GPencil_update");
/* Color Name */
prop = RNA_def_property(srna, "colorname", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilStrokeColor_info_set");
RNA_def_property_ui_text(prop, "Color Name", "Palette color name");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_colorname_update");
/* Cyclic: Draw a line from end to start point */
prop = RNA_def_property(srna, "draw_cyclic", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STROKE_CYCLIC);
RNA_def_property_ui_text(prop, "Cyclic", "Enable cyclic drawing, closing the stroke");
RNA_def_property_update(prop, 0, "rna_GPencil_update");
/* Line Thickness */
prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "thickness");
RNA_def_property_range(prop, 1, 300);
RNA_def_property_ui_range(prop, 1, 10, 1, 0);
RNA_def_property_ui_text(prop, "Thickness", "Thickness of stroke (in pixels)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
}
static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop)
@@ -594,6 +1020,7 @@ static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_GPencil_stroke_new");
RNA_def_function_ui_description(func, "Add a new grease pencil stroke");
parm = RNA_def_string(func, "colorname", 0, MAX_NAME, "Color", "Name of the color");
parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "", "The newly created stroke");
RNA_def_function_return(func, parm);
@@ -721,45 +1148,33 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Volumetric Strokes", "Draw strokes as a series of circular blobs, resulting in a volumetric effect");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Use High Quality Fill */
prop = RNA_def_property(srna, "use_hq_fill", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HQ_FILL);
RNA_def_property_ui_text(prop, "High Quality Fill", "Fill strokes using high quality method to avoid glitches (slower fps during animation playback)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Stroke Drawing Color */
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Color", "Color for all strokes in this layer");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "color[3]");
prop = RNA_def_property(srna, "opacity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "opacity");
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_text(prop, "Opacity", "Layer Opacity");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Fill Drawing Color */
prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "fill");
/* Tint Color */
prop = RNA_def_property(srna, "tint_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "tintcolor");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Fill Color", "Color for filling region bounded by each stroke");
RNA_def_property_ui_text(prop, "Tint Color", "Color for tinting stroke colors");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "fill_alpha", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "fill[3]");
/* Tint factor */
prop = RNA_def_property(srna, "tint_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "tintcolor[3]");
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_text(prop, "Fill Opacity", "Opacity for filling region bounded by each stroke");
RNA_def_property_ui_text(prop, "Tint Factor", "Factor of tinting color");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Line Thickness */
prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL);
/* Line Thickness change */
prop = RNA_def_property(srna, "line_change", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "thickness");
//RNA_def_property_range(prop, 1, 10); /* 10 px limit comes from Windows OpenGL limits for natively-drawn strokes */
RNA_def_property_int_funcs(prop, NULL, NULL, "rna_GPencilLayer_line_width_range");
RNA_def_property_ui_text(prop, "Thickness", "Thickness of strokes (in pixels)");
RNA_def_property_ui_text(prop, "Thickness", "Thickness change to apply current strokes (in pixels)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Onion-Skinning */
@@ -803,31 +1218,6 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Smoothing factor for new strokes */
prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac");
RNA_def_property_range(prop, 0.0, 2.0f);
RNA_def_property_ui_text(prop, "Smooth",
"Amount of smoothing to apply to newly created strokes, to reduce jitter/noise");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Iterations of the Smoothing factor */
prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl");
RNA_def_property_range(prop, 1, 3);
RNA_def_property_ui_text(prop, "Iterations",
"Number of times to smooth newly created strokes "
"(smoothing strength is halved on each successive round of smoothing)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Subdivision level for new strokes */
prop = RNA_def_property(srna, "pen_subdivision_steps", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "sublevel");
RNA_def_property_range(prop, 0, 3);
RNA_def_property_ui_text(prop, "Subdivision Steps",
"Number of times to subdivide newly created strokes, for less jagged strokes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Flags */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE);
@@ -847,6 +1237,15 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Frame Locked", "Lock current frame displayed by layer");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Unlock colors */
prop = RNA_def_property(srna, "unlock_color", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_UNLOCK_COLOR);
RNA_def_property_ui_icon(prop, ICON_RESTRICT_COLOR_OFF, 1);
RNA_def_property_ui_text(prop, "Unlock color", "Unprotect colors selected from further editing "
"and/or frame changes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* expose as layers.active */
#if 0
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
@@ -873,17 +1272,41 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "X Ray", "Make the layer draw in front of objects");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Parent object */
prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_funcs(prop, NULL, "rna_GPencilLayer_parent_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
RNA_def_property_ui_text(prop, "Parent", "Parent Object");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Read-only state props (for simpler UI code) */
prop = RNA_def_property(srna, "is_stroke_visible", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_GPencilLayer_is_stroke_visible_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Is Stroke Visible", "True when opacity of stroke is set high enough to be visible");
/* parent type */
prop = RNA_def_property(srna, "parent_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "partype");
RNA_def_property_enum_items(prop, parent_type_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_GPencilLayer_parent_type_set", "rna_Object_parent_type_itemf");
RNA_def_property_ui_text(prop, "Parent Type", "Type of parent relation");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "is_fill_visible", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_GPencilLayer_is_fill_visible_get", NULL);
/* parent bone */
prop = RNA_def_property(srna, "parent_bone", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "parsubstr");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilLayer_parent_bone_set");
RNA_def_property_ui_text(prop, "Parent Bone", "Name of parent bone in case of a bone parenting relation");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* matrix */
prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "inverse");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "MatrixInverse", "Parent inverse transformation matrix");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* read only parented flag */
prop = RNA_def_property(srna, "is_parented", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_GPencilLayer_is_parented_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Is Fill Visible", "True when opacity of fill is set high enough to be visible");
RNA_def_property_ui_text(prop, "Is Parented", "True when the layer parent object is set");
/* Layers API */
func = RNA_def_function(srna, "clear", "rna_GPencil_layer_clear");
@@ -933,6 +1356,207 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_ui_text(prop, "Active Layer Index", "Index of active grease pencil layer");
}
static void rna_def_gpencil_palettecolor(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "GPencilPaletteColor", NULL);
RNA_def_struct_sdna(srna, "bGPDpalettecolor");
RNA_def_struct_ui_text(srna, "Grease Pencil Palette color", "Collection of related colors");
RNA_def_struct_path_func(srna, "rna_GPencilPalette_color_path");
/* Stroke Drawing Color */
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "color");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Color", "Color for strokes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "color[3]");
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_text(prop, "Opacity", "Color Opacity");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Name */
prop = RNA_def_property(srna, "info", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Info", "Color name");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilPaletteColor_info_set");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Fill Drawing Color */
prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "fill");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Fill Color", "Color for filling region bounded by each stroke");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Fill alpha */
prop = RNA_def_property(srna, "fill_alpha", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "fill[3]");
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_text(prop, "Fill Opacity", "Opacity for filling region bounded by each stroke");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Flags */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_HIDE);
RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
RNA_def_property_ui_text(prop, "Hide", "Set color Visibility");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_LOCKED);
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
RNA_def_property_ui_text(prop, "Locked", "Protect color from further editing and/or frame changes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_ONIONSKIN);
RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0);
RNA_def_property_ui_text(prop, "Ghost", "Display the color in onion skinning");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Draw Style */
prop = RNA_def_property(srna, "use_volumetric_strokes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_VOLUMETRIC);
RNA_def_property_ui_text(prop, "Volumetric Strokes", "Draw strokes as a series of circular blobs, resulting in "
"a volumetric effect");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Use High quality fill */
prop = RNA_def_property(srna, "use_hq_fill", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_HQ_FILL);
RNA_def_property_ui_text(prop, "High Quality Fill", "Fill strokes using high quality to avoid glitches "
"(slower fps during animation play)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Read-only state props (for simpler UI code) */
prop = RNA_def_property(srna, "is_stroke_visible", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_GPencilPaletteColor_is_stroke_visible_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Is Stroke Visible", "True when opacity of stroke is set high enough to be visible");
prop = RNA_def_property(srna, "is_fill_visible", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_GPencilPaletteColor_is_fill_visible_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Is Fill Visible", "True when opacity of fill is set high enough to be visible");
}
/* palette colors api */
static void rna_def_gpencil_palettecolors_api(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
PropertyRNA *prop;
FunctionRNA *func;
PropertyRNA *parm;
RNA_def_property_srna(cprop, "GPencilPaletteColors");
srna = RNA_def_struct(brna, "GPencilPaletteColors", NULL);
RNA_def_struct_sdna(srna, "bGPDpalette");
RNA_def_struct_ui_text(srna, "Palette colors", "Collection of palette colors");
func = RNA_def_function(srna, "new", "rna_GPencilPalette_color_new");
RNA_def_function_ui_description(func, "Add a new color to the palette");
parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The newly created color");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_GPencilPalette_color_remove");
RNA_def_function_ui_description(func, "Remove a color from the palette");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The color to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPencilPaletteColor");
RNA_def_property_pointer_funcs(prop, "rna_GPencilPalette_active_color_get", "rna_GPencilPalette_active_color_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active Palette Color", "Current active color");
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop,
"rna_GPencilPaletteColor_index_get",
"rna_GPencilPaletteColor_index_set",
"rna_GPencilPaletteColor_index_range");
RNA_def_property_ui_text(prop, "Active color Index", "Index of active palette color");
}
static void rna_def_gpencil_palette(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "GPencilPalette", NULL);
RNA_def_struct_sdna(srna, "bGPDpalette");
RNA_def_struct_ui_text(srna, "Grease Pencil Palette", "Collection of related palettes");
RNA_def_struct_ui_icon(srna, ICON_COLOR);
/* Name */
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "info");
RNA_def_property_ui_text(prop, "Name", "Palette name");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilPalette_info_set");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Colors */
prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "colors", NULL);
RNA_def_property_struct_type(prop, "GPencilPaletteColor");
RNA_def_property_ui_text(prop, "Colors", "Colors of the palette");
rna_def_gpencil_palettecolors_api(brna, prop);
}
static void rna_def_gpencil_palettes_api(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
PropertyRNA *prop;
FunctionRNA *func;
PropertyRNA *parm;
RNA_def_property_srna(cprop, "GreasePencilPalettes");
srna = RNA_def_struct(brna, "GreasePencilPalettes", NULL);
RNA_def_struct_sdna(srna, "bGPdata");
RNA_def_struct_ui_text(srna, "Grease Pencil Palettes", "Collection of grease pencil palettes");
func = RNA_def_function(srna, "new", "rna_GPencil_palette_new");
RNA_def_function_ui_description(func, "Add a new grease pencil palette");
parm = RNA_def_string(func, "name", "GPencilPalette", MAX_NAME, "Name", "Name of the palette");
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_boolean(func, "set_active", 0, "Set Active", "Activate the newly created palette");
parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The newly created palette");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_GPencil_palette_remove");
RNA_def_function_ui_description(func, "Remove a grease pencil palette");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The palette to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPencilPalette");
RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_palette_get", "rna_GPencil_active_palette_set",
NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active Palette", "Current active palette");
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop,
"rna_GPencilPalette_index_get",
"rna_GPencilPalette_index_set",
"rna_GPencilPalette_index_range");
RNA_def_property_ui_text(prop, "Active Palette Index", "Index of active palette");
}
static void rna_def_gpencil_data(BlenderRNA *brna)
{
StructRNA *srna;
@@ -951,6 +1575,13 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layers", "");
rna_def_gpencil_layers_api(brna, prop);
/* Palettes */
prop = RNA_def_property(srna, "palettes", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "palettes", NULL);
RNA_def_property_struct_type(prop, "GPencilPalette");
RNA_def_property_ui_text(prop, "Palettes", "");
rna_def_gpencil_palettes_api(brna, prop);
/* Animation Data */
rna_def_animdata_common(srna);
@@ -967,6 +1598,12 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
"Show ghosts of the frames before and after the current frame, toggle to enable on active layer or disable all");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
prop = RNA_def_property(srna, "show_stroke_direction", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_SHOW_DIRECTION);
RNA_def_property_ui_text(prop, "Show Direction", "Show stroke drawing direction with a bigger green dot (start) "
"and smaller red dot (end) points");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* API Functions */
func = RNA_def_function(srna, "clear", "rna_GPencil_clear");
RNA_def_function_ui_description(func, "Remove all the grease pencil data");
@@ -980,8 +1617,12 @@ void RNA_def_gpencil(BlenderRNA *brna)
rna_def_gpencil_layer(brna);
rna_def_gpencil_frame(brna);
rna_def_gpencil_triangle(brna);
rna_def_gpencil_stroke(brna);
rna_def_gpencil_stroke_point(brna);
rna_def_gpencil_palette(brna);
rna_def_gpencil_palettecolor(brna);
}
#endif

View File

@@ -35,6 +35,7 @@
#include "DNA_linestyle_types.h"
#include "DNA_userdef_types.h"
#include "DNA_world_types.h"
#include "DNA_gpencil_types.h"
#include "IMB_imbuf_types.h"
@@ -437,6 +438,7 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
#include "BKE_sequencer.h"
#include "BKE_animsys.h"
#include "BKE_freestyle.h"
#include "BKE_gpencil.h"
#include "ED_info.h"
#include "ED_node.h"
@@ -449,6 +451,108 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
#include "FRS_freestyle.h"
#endif
/* Grease pencil Drawing Brushes */
static bGPDbrush *rna_GPencil_brush_new(ToolSettings *ts, const char *name, int setactive)
{
bGPDbrush *brush = gpencil_brush_addnew(ts, name, setactive != 0);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return brush;
}
static void rna_GPencil_brush_remove(ToolSettings *ts, ReportList *reports, PointerRNA *brush_ptr)
{
bGPDbrush *brush = brush_ptr->data;
if (BLI_findindex(&ts->gp_brushes, brush) == -1) {
BKE_report(reports, RPT_ERROR, "Brush not found in grease pencil data");
return;
}
gpencil_brush_delete(ts, brush);
RNA_POINTER_INVALIDATE(brush_ptr);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
static PointerRNA rna_GPencil_active_brush_get(PointerRNA *ptr)
{
ToolSettings *ts = (ToolSettings *) ptr->data;
bGPDbrush *brush;
for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
if (brush->flag & GP_BRUSH_ACTIVE) {
break;
}
}
if (brush) {
return rna_pointer_inherit_refine(ptr, &RNA_GPencilBrush, brush);
}
return rna_pointer_inherit_refine(ptr, NULL, NULL);
}
static void rna_GPencil_active_brush_set(PointerRNA *ptr, PointerRNA value)
{
ToolSettings *ts = (ToolSettings *) ptr->data;
bGPDbrush *brush;
for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
if (brush == value.data) {
brush->flag |= GP_BRUSH_ACTIVE;
}
else {
brush->flag &= ~GP_BRUSH_ACTIVE;
}
}
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
static int rna_GPencilBrush_index_get(PointerRNA *ptr)
{
ToolSettings *ts = (ToolSettings *) ptr->data;
bGPDbrush *brush = gpencil_brush_getactive(ts);
return BLI_findindex(&ts->gp_brushes, brush);
}
static void rna_GPencilBrush_index_set(PointerRNA *ptr, int value)
{
ToolSettings *ts = (ToolSettings *) ptr->data;
bGPDbrush *brush = BLI_findlink(&ts->gp_brushes, value);
gpencil_brush_setactive(ts, brush);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
static void rna_GPencilBrush_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
{
ToolSettings *ts = (ToolSettings *) ptr->data;
*min = 0;
*max = max_ii(0, BLI_listbase_count(&ts->gp_brushes) - 1);
*softmin = *min;
*softmax = *max;
}
static void rna_GPencilBrush_name_set(PointerRNA *ptr, const char *value)
{
ToolSettings *ts = (ToolSettings *) ptr->data;
bGPDbrush *brush = ptr->data;
/* copy the new name into the name slot */
BLI_strncpy_utf8(brush->info, value, sizeof(brush->info));
BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info));
}
/* ----------------- end of Grease pencil drawing brushes ------------*/
static void rna_SpaceImageEditor_uv_sculpt_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
{
ED_space_image_uv_sculpt_update(bmain->wm.first, scene);
@@ -1991,6 +2095,202 @@ static int rna_gpu_is_hq_supported_get(PointerRNA *UNUSED(ptr))
#else
/* Grease Pencil Drawing Brushes */
static void rna_def_gpencil_brush(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "GPencilBrush", NULL);
RNA_def_struct_sdna(srna, "bGPDbrush");
RNA_def_struct_ui_text(srna, "Grease Pencil Brush", "Collection of brushes being used to control the "
"line style of new strokes");
RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA);
/* Name */
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "info");
RNA_def_property_ui_text(prop, "Name", "Brush name");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilBrush_name_set");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Line Thickness */
prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "thickness");
RNA_def_property_range(prop, 1, 300);
RNA_def_property_ui_range(prop, 1, 10, 1, 0);
RNA_def_property_ui_text(prop, "Thickness", "Thickness of strokes (in pixels)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Sensitivity factor for new strokes */
prop = RNA_def_property(srna, "pen_sensitivity_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "draw_sensitivity");
RNA_def_property_range(prop, 0.1f, 3.0f);
RNA_def_property_ui_text(prop, "Sensitivity", "Pressure sensitivity factor for new strokes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Strength factor for new strokes */
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "draw_strength");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Strength", "Color strength for new strokes (affect alpha factor of color)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Jitter factor for new strokes */
prop = RNA_def_property(srna, "jitter", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "draw_jitter");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Jitter", "Jitter factor for new strokes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Randomnes factor for sensitivity and strength */
prop = RNA_def_property(srna, "random_press", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "draw_random_press");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Randomness", "Randomness factor for pressure and strength in new strokes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Randomnes factor for subdivision */
prop = RNA_def_property(srna, "random_subdiv", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "draw_random_sub");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Random Subdivision", "Randomness factor for new strokes after subdivision");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Angle when brush is full size */
prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "draw_angle");
RNA_def_property_range(prop, 0.0f, M_PI_2);
RNA_def_property_ui_text(prop, "Angle", "Angle of drawing when brush has full size");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Factor to change brush size depending of angle */
prop = RNA_def_property(srna, "angle_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "draw_angle_factor");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Angle Factor", "Factor to apply when the brush rotate of its full size");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Smoothing factor for new strokes */
prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac");
RNA_def_property_range(prop, 0.0, 2.0f);
RNA_def_property_ui_text(prop, "Smooth", "Amount of smoothing to apply to newly created strokes, to "
"reduce jitter/noise");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Iterations of the Smoothing factor */
prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl");
RNA_def_property_range(prop, 1, 3);
RNA_def_property_ui_text(prop, "Iterations", "Number of times to smooth newly created strokes [+ reason/effect "
"of using higher values of this property]");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Subdivision level for new strokes */
prop = RNA_def_property(srna, "pen_subdivision_steps", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "sublevel");
RNA_def_property_range(prop, 0, 3);
RNA_def_property_ui_text(prop, "Subdivision Steps", "Number of times to subdivide newly created strokes, for "
"less jagged strokes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Curves for pressure */
prop = RNA_def_property(srna, "curve_sensitivity", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "cur_sensitivity");
RNA_def_property_struct_type(prop, "CurveMapping");
RNA_def_property_ui_text(prop, "Curve Sensitivity", "Curve used for the sensitivity");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
prop = RNA_def_property(srna, "curve_strength", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "cur_strength");
RNA_def_property_struct_type(prop, "CurveMapping");
RNA_def_property_ui_text(prop, "Curve Strength", "Curve used for the strength");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
prop = RNA_def_property(srna, "curve_jitter", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "cur_jitter");
RNA_def_property_struct_type(prop, "CurveMapping");
RNA_def_property_ui_text(prop, "Curve Jitter", "Curve used for the jitter effect");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Flags */
prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
RNA_def_property_ui_text(prop, "Use Pressure", "Use tablet pressure");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
prop = RNA_def_property(srna, "use_strength_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_STENGTH_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
RNA_def_property_ui_text(prop, "Use Pressure Strength", "Use tablet pressure for color strength");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
prop = RNA_def_property(srna, "use_jitter_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_JITTER_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
RNA_def_property_ui_text(prop, "Use Pressure Jitter", "Use tablet pressure for jitter");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
prop = RNA_def_property(srna, "use_random_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_RANDOM_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_PARTICLES, 0);
RNA_def_property_ui_text(prop, "Random Pressure", "Use random value for pressure");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
prop = RNA_def_property(srna, "use_random_strength", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_RANDOM_STRENGTH);
RNA_def_property_ui_icon(prop, ICON_PARTICLES, 0);
RNA_def_property_ui_text(prop, "Random Strength", "Use random value for strength");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
}
/* Grease Pencil Drawing Brushes API */
static void rna_def_gpencil_brushes_api(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
PropertyRNA *prop;
FunctionRNA *func;
PropertyRNA *parm;
RNA_def_property_srna(cprop, "GreasePencilBrushes");
srna = RNA_def_struct(brna, "GreasePencilBrushes", NULL);
RNA_def_struct_sdna(srna, "ToolSettings");
RNA_def_struct_ui_text(srna, "Grease Pencil Brushes", "Collection of grease pencil brushes");
func = RNA_def_function(srna, "new", "rna_GPencil_brush_new");
RNA_def_function_ui_description(func, "Add a new grease pencil brush");
parm = RNA_def_string(func, "name", "GPencilBrush", MAX_NAME, "Name", "Name of the brush");
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_boolean(func, "set_active", 0, "Set Active", "Set the newly created brush to the active brush");
parm = RNA_def_pointer(func, "palette", "GPencilBrush", "", "The newly created brush");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_GPencil_brush_remove");
RNA_def_function_ui_description(func, "Remove a grease pencil brush");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "brush", "GPencilBrush", "", "The brush to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPencilBrush");
RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_brush_get", "rna_GPencil_active_brush_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active Brush", "Current active brush");
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop,
"rna_GPencilBrush_index_get",
"rna_GPencilBrush_index_set",
"rna_GPencilBrush_index_range");
RNA_def_property_ui_text(prop, "Active brush Index", "Index of active brush");
}
static void rna_def_transform_orientation(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2323,6 +2623,13 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "GPencilSculptSettings");
RNA_def_property_ui_text(prop, "Grease Pencil Sculpt", "");
/* Grease Pencil - Drawing brushes */
prop = RNA_def_property(srna, "gpencil_brushes", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "gp_brushes", NULL);
RNA_def_property_struct_type(prop, "GPencilBrush");
RNA_def_property_ui_text(prop, "Grease Pencil Brushes", "Grease Pencil drawing brushes");
rna_def_gpencil_brushes_api(brna, prop);
/* Grease Pencil - 3D View Stroke Placement */
prop = RNA_def_property(srna, "gpencil_stroke_placement_view3d", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_v3d_align");
@@ -6839,6 +7146,7 @@ void RNA_def_scene(BlenderRNA *brna)
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
rna_def_tool_settings(brna);
rna_def_gpencil_brush(brna);
rna_def_unified_paint_settings(brna);
rna_def_curve_paint_settings(brna);
rna_def_statvis(brna);

View File

@@ -63,7 +63,8 @@ static EnumPropertyItem particle_edit_hair_brush_items[] = {
EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = {
{GP_EDITBRUSH_TYPE_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth stroke points"},
{GP_EDITBRUSH_TYPE_THICKNESS, "THICKNESS", 0, "Thickness", "Adjust thickness of strokes"},
{GP_EDITBRUSH_TYPE_GRAB, "GRAB", 0, "Grab", "Translate the set of points initially within the brush circle"},
{ GP_EDITBRUSH_TYPE_STRENGTH, "STRENGTH", 0, "Strength", "Adjust color strength of strokes" },
{ GP_EDITBRUSH_TYPE_GRAB, "GRAB", 0, "Grab", "Translate the set of points initially within the brush circle" },
{GP_EDITBRUSH_TYPE_PUSH, "PUSH", 0, "Push", "Move points out of the way, as if combing them"},
{GP_EDITBRUSH_TYPE_TWIST, "TWIST", 0, "Twist", "Rotate points around the midpoint of the brush"},
{GP_EDITBRUSH_TYPE_PINCH, "PINCH", 0, "Pinch", "Pull points towards the midpoint of the brush"},
@@ -71,7 +72,7 @@ EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = {
//{GP_EDITBRUSH_TYPE_SUBDIVIDE, "SUBDIVIDE", 0, "Subdivide", "Increase point density for higher resolution strokes when zoomed in"},
//{GP_EDITBRUSH_TYPE_SIMPLIFY, "SIMPLIFY", 0, "Simplify", "Reduce density of stroke points"},
{GP_EDITBRUSH_TYPE_CLONE, "CLONE", 0, "Clone", "Paste copies of the strokes stored on the clipboard"},
{0, NULL, 0, NULL, NULL}
{ 0, NULL, 0, NULL, NULL }
};
EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
@@ -100,6 +101,11 @@ EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
#include "ED_particle.h"
static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
static EnumPropertyItem particle_edit_disconnected_hair_brush_items[] = {
{PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush"},
{PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb hairs"},
@@ -1016,6 +1022,27 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_VERTEXSEL, 0); // FIXME: this needs a custom icon
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "affect_position", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_POSITION);
RNA_def_property_ui_text(prop, "Affect position", "The brush affects the position of the point");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "affect_strength", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_STRENGTH);
RNA_def_property_ui_text(prop, "Affect strength", "The brush affects the color strength of the point");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "affect_thickness", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_THICKNESS);
RNA_def_property_ui_text(prop, "Affect thickness", "The brush affects the thickness of the point");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "selection_alpha", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "alpha");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Alpha", "Alpha value for selected vertices");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update");
/* brush */
srna = RNA_def_struct(brna, "GPencilSculptBrush", NULL);
RNA_def_struct_sdna(srna, "GP_EditBrush_Data");

View File

@@ -238,6 +238,9 @@ void RE_render_result_rect_from_ibuf(
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname);
/* add passes for grease pencil */
struct RenderPass *RE_create_gp_pass(struct RenderResult *rr, const char *layername, const char *viewname);
/* obligatory initialize call, disprect is optional */
void RE_InitState(struct Render *re, struct Render *source, struct RenderData *rd,
struct SceneRenderLayer *srl,

View File

@@ -83,6 +83,9 @@ void render_result_save_empty_result_tiles(struct Render *re);
void render_result_exr_file_begin(struct Render *re);
void render_result_exr_file_end(struct Render *re);
/* render pass wrapper for gpencil */
struct RenderPass *gp_add_pass(struct RenderResult *rr, struct RenderLayer *rl, int channels, int passtype, const char *viewname);
void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart, const char *viewname);
void render_result_exr_file_path(struct Scene *scene, const char *layname, int sample, char *filepath);

View File

@@ -4018,3 +4018,31 @@ RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const c
}
return rp;
}
/* create a renderlayer and renderpass for grease pencil layer */
RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const char *viewname)
{
RenderLayer *rl = BLI_findstring(&rr->layers, layername, offsetof(RenderLayer, name));
/* only create render layer if not exist */
if (!rl) {
rl = MEM_callocN(sizeof(RenderLayer), layername);
BLI_addtail(&rr->layers, rl);
BLI_strncpy(rl->name, layername, sizeof(rl->name));
rl->lay = 0;
rl->layflag = SCE_LAY_SOLID;
rl->passflag = SCE_PASS_COMBINED;
rl->rectx = rr->rectx;
rl->recty = rr->recty;
}
/* clear previous pass if exist or the new image will be over previous one*/
RenderPass *rp = RE_pass_find_by_type(rl, SCE_PASS_COMBINED, viewname);
if (rp) {
if (rp->rect) {
MEM_freeN(rp->rect);
}
BLI_freelinkN(&rl->passes, rp);
}
/* create a totally new pass */
return gp_add_pass(rr, rl, 4, SCE_PASS_COMBINED, viewname);
}

View File

@@ -540,6 +540,11 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int
return rpass;
}
/* wrapper called from render_opengl */
RenderPass *gp_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname)
{
return render_layer_add_pass(rr, rl, channels, passtype, viewname);
}
#ifdef WITH_CYCLES_DEBUG
const char *RE_debug_pass_name_get(int debug_type)

View File

@@ -111,6 +111,7 @@ struct bConstraint;
struct bConstraintOb;
struct bConstraintTarget;
struct bContextDataResult;
struct bGPDlayer;
struct bNode;
struct bNodeType;
struct bNodeSocket;
@@ -153,6 +154,7 @@ struct wmWindowManager;
#include "../blender/editors/include/ED_clip.h"
#include "../blender/editors/include/ED_curve.h"
#include "../blender/editors/include/ED_fileselect.h"
#include "../blender/editors/include/ED_gpencil.h"
#include "../blender/editors/include/ED_image.h"
#include "../blender/editors/include/ED_info.h"
#include "../blender/editors/include/ED_keyframes_edit.h"
@@ -350,6 +352,7 @@ void *ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const stru
void *ED_region_draw_cb_customdata(void *handle) RET_ZERO /* XXX This one looks wrong also */
void ED_region_draw_cb_exit(struct ARegionType *art, void *handle) RET_NONE
void ED_area_headerprint(struct ScrArea *sa, const char *str) RET_NONE
void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]) RET_NONE
void UI_view2d_region_to_view(struct View2D *v2d, float x, float y, float *viewx, float *viewy) RET_NONE
bool UI_view2d_view_to_region_clip(struct View2D *v2d, float x, float y, int *regionx, int *regiony) RET_ZERO
void UI_view2d_view_to_region(struct View2D *v2d, float x, float y, int *regionx, int *region_y) RET_NONE