WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 358 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
123 changed files with 1487 additions and 569 deletions
Showing only changes of commit d4d58418be - Show all commits

View File

@ -141,9 +141,9 @@ set(OPENCOLLADA_HASH ee7dae874019fea7be11613d07567493)
set(OPENCOLLADA_HASH_TYPE MD5)
set(OPENCOLLADA_FILE opencollada-${OPENCOLLADA_VERSION}.tar.gz)
set(OPENCOLORIO_VERSION 2.3.0)
set(OPENCOLORIO_VERSION 2.3.2)
set(OPENCOLORIO_URI https://github.com/AcademySoftwareFoundation/OpenColorIO/archive/v${OPENCOLORIO_VERSION}.tar.gz)
set(OPENCOLORIO_HASH c05f24a516fe82d381c4b0d471e12ad5)
set(OPENCOLORIO_HASH 8af74fcb8c4820ab21204463a06ba490)
set(OPENCOLORIO_HASH_TYPE MD5)
set(OPENCOLORIO_FILE OpenColorIO-${OPENCOLORIO_VERSION}.tar.gz)

View File

@ -115,9 +115,6 @@ ccl_device_inline void path_state_next(KernelGlobals kg,
flag |= PATH_RAY_TERMINATE_ON_NEXT_SURFACE;
}
if (!kernel_data.integrator.transparent_shadows)
flag |= PATH_RAY_MIS_SKIP;
INTEGRATOR_STATE_WRITE(state, path, flag) = flag;
INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = transparent_bounce;
/* Random number generator next bounce. */

View File

@ -211,14 +211,14 @@ static bool angle_close(float a, float b)
* value shifting etc.
* Note that this code is much more forgiving than the spec. For example, in type A and B,
* the range of vertical angles officially must be either exactly 0°-90° or -90°-90°.
* However, in practise, IES files are all over the place. Therefore, the handling is as
* However, in practice, IES files are all over the place. Therefore, the handling is as
* flexible as possible, and tries to turn any input into something useful. */
void IESFile::process_type_b()
{
/* According to the standard, Type B defines a different coordinate system where the polar axis
* is horizontal, not vertical.
* To avoid overcomplicating the conversion logic, we just transpose the angles and use the
* To avoid over complicating the conversion logic, we just transpose the angles and use the
* regular Type A/C coordinate system. Users can just rotate the light to get the "proper"
* orientation. */
vector<vector<float>> newintensity;

View File

@ -41,16 +41,16 @@
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-width="1837"
inkscape:window-height="962"
id="namedview34335"
showgrid="false"
inkscape:zoom="32.000001"
inkscape:cx="386.92187"
inkscape:cy="586.82811"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:zoom="2"
inkscape:cx="256"
inkscape:cy="185"
inkscape:window-x="56"
inkscape:window-y="31"
inkscape:window-maximized="0"
inkscape:current-layer="layer8"
inkscape:showpageshadow="2"
inkscape:deskcolor="#808080"
@ -13847,26 +13847,6 @@
style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
id="path10313" />
</g>
<g
id="g12836"
style="display:inline;fill:#ffffff;enable-background:new"
transform="translate(-123,459)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:label="M-26">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 540.5,263 c -2.47936,0 -4.5,2.02064 -4.5,4.5 0,2.47936 2.02064,4.5 4.5,4.5 2.47936,0 4.5,-2.02064 4.5,-4.5 0,-2.47936 -2.02064,-4.5 -4.5,-4.5 z m 0,1 c 1.93892,0 3.5,1.56108 3.5,3.5 0,1.40621 -0.82672,2.60476 -2.01758,3.16211 -0.16784,-2.48561 -2.15892,-4.47669 -4.64453,-4.64453 C 537.89524,264.82672 539.09379,264 540.5,264 Z"
transform="translate(123,-459)"
id="path12830"
inkscape:connector-curvature="0" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 657.50195,-192.93359 a 0.50004997,0.50004997 0 0 0 -0.22656,0.0508 c -2.27231,1.07327 -3.57921,3.51034 -3.21484,5.99609 0.36436,2.48575 2.31598,4.44563 4.80078,4.82227 2.48479,0.37663 4.92837,-0.91763 6.01367,-3.1836 a 0.50013262,0.50013262 0 1 0 -0.90234,-0.43164 c -0.89704,1.8729 -2.90867,2.93833 -4.96289,2.62696 -2.05422,-0.31138 -3.6598,-1.92406 -3.96094,-3.97852 -0.30115,-2.05446 0.77387,-4.06001 2.65234,-4.94727 a 0.50004997,0.50004997 0 0 0 -0.19922,-0.95507 z"
id="path12834"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
id="g22255"
@ -17439,7 +17419,7 @@
sodipodi:nodetypes="cccccccsccccccccc" />
</g>
<g
transform="translate(-0.389343,-189.06)"
transform="translate(-0.389343,-189.14839)"
style="display:inline;enable-background:new"
id="g4917"
inkscape:label="E-6">
@ -17459,6 +17439,22 @@
d="m 122.93095,287.85344 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z m 0,1 c -1.11049,0 -2,0.88951 -2,2 0,1.11049 0.88951,2 2,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
transform="translate(83.289453,-189.18163)"
style="display:inline;enable-background:new"
id="g4917-5"
inkscape:label="E-6">
<path
inkscape:connector-curvature="0"
id="circle14295-0-3-0-1-6"
d="m 115.59493,291.64794 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z m 0,1 c -1.11049,0 -2,0.88951 -2,2 0,1.11049 0.88951,2 2,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
inkscape:connector-curvature="0"
id="circle14295-0-3-6-4"
d="m 122.93095,287.85344 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z m 0,1 c -1.11049,0 -2,0.88951 -2,2 0,1.11049 0.88951,2 2,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
transform="translate(-0.389343,-189.06)"
style="display:inline;enable-background:new"
@ -19273,6 +19269,112 @@
id="path20467-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
<g
id="g4304-7"
style="display:inline;enable-background:new"
inkscape:label="H-17"
transform="translate(188.99437,104.97791)">
<path
inkscape:connector-curvature="0"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 342.5,158 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 13 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 6.5,3 c 2.20237,0 4,1.79764 4,4 0,2.20237 -1.79763,4 -4,4 -2.20236,0 -4,-1.79763 -4,-4 0,-2.20236 1.79764,-4 4,-4 z"
id="rect13348-1" />
</g>
<g
style="display:inline;fill:none;enable-background:new"
id="g12"
transform="translate(405.99511,10.009244)"
inkscape:label="A-21">
<path
d="m 6,10 c -0.55228,0 -1,0.4477 -1,1 0,0.3701 0.2011,0.6933 0.5,0.8662 V 13 c 0,0.2761 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.2239 0.5,-0.5 V 11.8662 C 6.7989,11.6933 7,11.3701 7,11 7,10.4477 6.55228,10 6,10 Z"
fill="#ffffff"
id="path1-6" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M 6,1 C 3.79086,1 2,2.79086 2,5 v 2 h 9.5 C 11.7761,7 12,7.22386 12,7.5 v 8 C 12,15.7761 11.7761,16 11.5,16 H 0.5 C 0.223858,16 0,15.7761 0,15.5 v -8 C 0,7.22386 0.223858,7 0.5,7 H 1 V 5 C 1,2.23858 3.23858,0 6,0 8.2179,0 10.0985,1.44407 10.7529,3.44327 10.8321,3.68519 10.6888,3.93708 10.4473,4.01757 10.1662,4.11127 9.86854,3.93654 9.76912,3.65743 9.2174,2.10867 7.73817,1 6,1 Z M 1,8 v 7 H 11 V 8 Z"
fill="#ffffff"
id="path2-9" />
</g>
<g
style="display:inline;fill:none;enable-background:new"
id="g2-6"
transform="translate(427.02199,10.010043)"
inkscape:label="A-19">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M 1,7 V 5 C 1,2.23858 3.23858,0 6,0 c 2.76142,0 5,2.23858 5,5 v 2 h 0.5 C 11.7761,7 12,7.22386 12,7.5 v 8 C 12,15.7761 11.7761,16 11.5,16 H 0.5 C 0.223858,16 0,15.7761 0,15.5 v -8 C 0,7.22386 0.223858,7 0.5,7 Z M 2,5 C 2,2.79086 3.79086,1 6,1 8.20914,1 10,2.79086 10,5 V 7 H 2 Z m 4,5 c -0.55228,0 -1,0.4477 -1,1 0,0.3701 0.2011,0.6933 0.5,0.8662 V 13 c 0,0.2761 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.2239 0.5,-0.5 V 11.8662 C 6.7989,11.6933 7,11.3701 7,11 7,10.4477 6.55228,10 6,10 Z"
fill="#ffffff"
id="path1-4" />
</g>
<g
style="display:inline;fill:none;enable-background:new"
id="g15"
transform="translate(383.03883,10.007582)"
inkscape:label="A-21">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M 4,12 V 10.5 C 4,10.2239 4.22386,10 4.5,10 h 6 c 0.2761,0 0.5,0.2239 0.5,0.5 v 5 C 11,15.7761 10.7761,16 10.5,16 H 5.70711 C 5.5745,16 5.44732,15.9473 5.35355,15.8536 L 4.14645,14.6464 C 4.05268,14.5527 4,14.4255 4,14.2929 V 13 H 3 v 0.5 C 3,13.7761 2.77614,14 2.5,14 2.22386,14 2,13.7761 2,13.5 v -2 C 2,11.2239 2.22386,11 2.5,11 2.77614,11 3,11.2239 3,11.5 V 12 Z M 5.91421,15 5,14.0858 V 11 h 5 v 4 z"
fill="#ffffff"
id="path1-52" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M 13.2154,13.5 15,14.5917 v -2.1834 z m 1.931,2.3536 C 15.2369,15.944 15.3619,16 15.5,16 15.7761,16 16,15.7761 16,15.5 v -4 C 16,11.2239 15.7761,11 15.5,11 c -0.1381,0 -0.2631,0.056 -0.3536,0.1464 l -3.1022,1.8978 C 11.8707,13.1226 11.75,13.2972 11.75,13.5 c 0,0.2028 0.1207,0.3774 0.2942,0.4558 z"
fill="#ffffff"
id="path2-5" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M 6.3849,4.22363 C 6.02407,4.30023 5.65038,4.17199 5.41263,3.88997 4.95248,3.34412 4.26691,3 3.5,3 2.11929,3 1,4.11929 1,5.5 1,6.88071 2.11929,8 3.5,8 h 7 C 12.433,8 14,6.433 14,4.5 14,2.567 12.433,1 10.5,1 8.90711,1 7.56034,2.06492 7.13771,3.5237 7.03507,3.878 6.74572,4.14702 6.3849,4.22363 Z M 6.60573,2.2436 C 6.42451,2.5557 6.27972,2.89159 6.17721,3.24543 5.94409,2.96889 5.6689,2.72898 5.36151,2.53555 4.82233,2.19626 4.18409,2 3.5,2 1.567,2 0,3.56701 0,5.5 0,7.43299 1.567,9 3.5,9 h 7 C 12.9853,9 15,6.98528 15,4.5 15,2.01472 12.9853,0 10.5,0 8.83701,0 7.38471,0.902078 6.60573,2.2436 Z"
fill="#ffffff"
id="path3-6" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M 10.5,5 C 10.7761,5 11,4.77614 11,4.5 11,4.22386 10.7761,4 10.5,4 10.2239,4 10,4.22386 10,4.5 10,4.77614 10.2239,5 10.5,5 Z m 0,1 C 11.3284,6 12,5.32843 12,4.5 12,3.67157 11.3284,3 10.5,3 9.67157,3 9,3.67157 9,4.5 9,5.32843 9.67157,6 10.5,6 Z"
fill="#ffffff"
id="path4-7" />
<path
d="m 4.5,5.5 c 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55228 0.44772,-1 1,-1 0.55228,0 1,0.44772 1,1 z"
fill="#ffffff"
id="path5-0" />
</g>
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="circle13367-9-8"
d="m 197.49219,94.596621 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,2.999999 -3,2.999999 -1.65093,0 -3,-1.349069 -3,-2.999999 0,-1.65093 1.34907,-3 3,-3 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<g
id="g56">
<g
id="g165467-7"
style="display:inline;enable-background:new"
inkscape:label="I-3"
transform="translate(440.99177,20.983957)">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 52.49219,179.00781 c -0.1326,4e-5 -0.25976,0.0527 -0.35352,0.1465 l -2.980087,2.96444 c -0.12064,0.11597 -0.14648,0.22852 -0.14648,0.35352 v 2.53315 h 1 l 0.003,-2.32915 2.684077,-2.66846 h 8.29297 v 8.29298 l -2.730276,2.69699 -2.262334,0.003 v 1 h 2.466854 c 0.11717,0 0.23766,-0.0261 0.3457,-0.13867 l 3.033606,-3.00033 c 0.0938,-0.0938 0.14646,-0.22091 0.14649,-0.35352 v -9 c -3e-5,-0.27612 -0.22387,-0.49996 -0.5,-0.5 z"
id="path5236-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccscccccccccscccccc" />
</g>
<g
id="g19381-2"
style="display:inline;enable-background:new"
inkscape:label="F-1"
transform="translate(483.00515,84.044245)">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 6.4818091,122.96135 c -0.1592654,-10e-4 -0.516986,0.087 -0.4960937,0.48465 l -0.00781,6.03971 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 6.0356916 c 0.235331,0.002 0.481037,-0.17264 0.475555,-0.49925 -0.0029,-0.17416 -0.0016,-1.65682 3.16e-4,-1.94881 0.0029,-0.44725 -0.236518,-0.47226 -0.460246,-0.47182 -0.223728,4.4e-4 -3.5227115,-0.004 -3.5227115,-0.004 0,0 -0.00434,-2.02425 0.00601,-3.62304 0.00284,-0.43846 -0.2571116,-0.47024 -0.5021009,-0.4681 -0.6989961,0.007 -1.4515221,-0.005 -2.0286105,-0.009 z"
id="path13927-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sccccsszcssss" />
</g>
</g>
</g>
<g
inkscape:groupmode="layer"

Before

Width:  |  Height:  |  Size: 2.6 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

View File

@ -69,7 +69,7 @@ def _paths_with_extension_repos():
for repo in _preferences.filepaths.extension_repos:
if not repo.enabled:
continue
dirpath = repo.directory_or_default
dirpath = repo.directory
if not os.path.isdir(dirpath):
continue
addon_paths.append((dirpath, "%s.%s" % (_ext_base_pkg_idname, repo.module)))
@ -774,7 +774,7 @@ def _extension_dirpath_from_preferences():
for repo in _preferences.filepaths.extension_repos:
if not repo.enabled:
continue
repos_dict[repo.module] = repo.directory_or_default
repos_dict[repo.module] = repo.directory
return repos_dict

View File

@ -1316,10 +1316,10 @@ class UserExtensionRepo(StructRNA):
__slots__ = ()
@property
def directory_or_default(self):
def directory(self):
"""Return ``directory`` or a default path derived from the users scripts path."""
if directory := self.directory:
return directory
if self.use_custom_directory:
return self.custom_directory
import os
import bpy
return os.path.join(bpy.utils.user_resource('SCRIPTS', path="extensions"), self.module)

View File

@ -669,7 +669,7 @@ class GPENCIL_UL_layer(UIList):
row = layout.row(align=True)
icon_mask = 'MOD_MASK' if gpl.use_mask_layer else 'LAYER_ACTIVE'
icon_mask = 'CLIPUV_DEHLT' if gpl.use_mask_layer else 'CLIPUV_HLT'
row.prop(gpl, "use_mask_layer", text="", icon=icon_mask, emboss=False)

View File

@ -240,23 +240,37 @@ class DOPESHEET_HT_editor_buttons:
# Layer management
if st.mode == 'GPENCIL':
ob = context.active_object
enable_but = ob is not None and ob.type == 'GPENCIL'
row = layout.row(align=True)
row.enabled = enable_but
row.operator("gpencil.layer_add", icon='ADD', text="")
row.operator("gpencil.layer_remove", icon='REMOVE', text="")
row.menu("GPENCIL_MT_layer_context_menu", icon='DOWNARROW_HLT', text="")
if context.preferences.experimental.use_grease_pencil_version3:
enable_but = ob is not None and ob.type == 'GREASEPENCIL'
row = layout.row(align=True)
row.enabled = enable_but
row.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
row.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
row = layout.row(align=True)
row.enabled = enable_but
row.operator("grease_pencil.layer_add", icon='ADD', text="")
row.operator("grease_pencil.layer_remove", icon='REMOVE', text="")
row.menu("GREASE_PENCIL_MT_grease_pencil_add_layer_extra", icon='DOWNARROW_HLT', text="")
row = layout.row(align=True)
row.enabled = enable_but
row.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_ON', text="").affect_visibility = True
row.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
row = layout.row(align=True)
row.enabled = enable_but
row.operator("anim.channels_move", icon='TRIA_UP', text="").direction = 'UP'
row.operator("anim.channels_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
else:
enable_but = ob is not None and ob.type == 'GPENCIL'
row = layout.row(align=True)
row.enabled = enable_but
row.operator("gpencil.layer_add", icon='ADD', text="")
row.operator("gpencil.layer_remove", icon='REMOVE', text="")
row.menu("GPENCIL_MT_layer_context_menu", icon='DOWNARROW_HLT', text="")
row = layout.row(align=True)
row.enabled = enable_but
row.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
row.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
row = layout.row(align=True)
row.enabled = enable_but
row.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_ON', text="").affect_visibility = True
row.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
layout.separator_spacer()

View File

@ -157,7 +157,7 @@ class TOPBAR_PT_gpencil_layers(Panel):
srow = col.row(align=True)
srow.prop(gpl, "opacity", text="Opacity", slider=True)
srow.prop(gpl, "use_mask_layer", text="",
icon='MOD_MASK' if gpl.use_mask_layer else 'LAYER_ACTIVE')
icon='CLIPUV_DEHLT' if gpl.use_mask_layer else 'CLIPUV_HLT')
srow = col.row(align=True)
srow.prop(gpl, "use_lights", text="Lights")

View File

@ -1122,6 +1122,7 @@ class USERPREF_PT_theme_text_style(ThemePanel, CenterAlignMixIn, Panel):
layout.label(text="Widget")
self._ui_font_style(layout, style.widget)
class USERPREF_PT_theme_bone_color_sets(ThemePanel, CenterAlignMixIn, Panel):
bl_label = "Bone Color Sets"
bl_options = {'DEFAULT_CLOSED'}
@ -1602,6 +1603,15 @@ class USERPREF_UL_extension_repos(UIList):
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.prop(repo, "name", text="", emboss=False)
# Show an error icon if this repository has unusable settings.
if repo.enabled:
if (
(repo.use_custom_directory and repo.custom_directory == "") or
(repo.use_remote_path and repo.remote_path == "")
):
layout.label(text="", icon='ERROR')
layout.prop(repo, "enabled", text="", emboss=False, icon='CHECKBOX_HLT' if repo.enabled else 'CHECKBOX_DEHLT')
@ -2048,8 +2058,8 @@ class USERPREF_PT_extensions_repos(Panel):
)
col = row.column(align=True)
col.operator("preferences.extension_repo_add", text="", icon='ADD')
props = col.operator("preferences.extension_repo_remove", text="", icon='REMOVE')
col.operator_menu_enum("preferences.extension_repo_add", "type", text="", icon='ADD')
props = col.operator_menu_enum("preferences.extension_repo_remove", "type", text="", icon='REMOVE')
props.index = active_library_index
try:
@ -2062,10 +2072,29 @@ class USERPREF_PT_extensions_repos(Panel):
layout.separator()
layout.prop(active_repo, "remote_path")
layout.prop(active_repo, "use_remote_path", text="Use Remote URL")
row = layout.row()
if active_repo.use_remote_path:
if active_repo.remote_path == "":
row.alert = True
else:
row.active = False
row.prop(active_repo, "remote_path", text="")
if layout_panel := self._panel_layout_kludge(layout, text="Advanced"):
layout_panel.prop(active_repo, "directory")
layout_panel.prop(active_repo, "use_custom_directory")
row = layout_panel.row()
if active_repo.use_custom_directory:
if active_repo.custom_directory == "":
row.alert = True
else:
row.active = False
row.prop(active_repo, "custom_directory", text="")
layout_panel.separator()
row = layout_panel.row()
row.prop(active_repo, "use_cache")
row.prop(active_repo, "module")

View File

@ -949,7 +949,7 @@ class VIEW3D_HT_header(Header):
layout.popover(
panel="VIEW3D_PT_gpencil_sculpt_automasking",
text="",
icon='MOD_MASK',
icon=VIEW3D_HT_header._gpencil_sculpt_automasking_icon(tool_settings.gpencil_sculpt)
)
elif object_mode == 'SCULPT':
@ -975,7 +975,7 @@ class VIEW3D_HT_header(Header):
layout.popover(
panel="VIEW3D_PT_sculpt_automasking",
text="",
icon='MOD_MASK',
icon=VIEW3D_HT_header._sculpt_automasking_icon(tool_settings.sculpt)
)
elif object_mode == 'VERTEX_PAINT':
@ -1080,6 +1080,29 @@ class VIEW3D_HT_header(Header):
# sub.enabled = shading.type != 'RENDERED'
sub.popover(panel="VIEW3D_PT_shading", text="")
@staticmethod
def _sculpt_automasking_icon(sculpt):
automask_enabled = (sculpt.use_automasking_topology or
sculpt.use_automasking_face_sets or
sculpt.use_automasking_boundary_edges or
sculpt.use_automasking_boundary_face_sets or
sculpt.use_automasking_cavity or
sculpt.use_automasking_cavity_inverted or
sculpt.use_automasking_start_normal or
sculpt.use_automasking_view_normal)
return "CLIPUV_DEHLT" if automask_enabled else "CLIPUV_HLT"
@staticmethod
def _gpencil_sculpt_automasking_icon(gpencil_sculpt):
automask_enabled = (gpencil_sculpt.use_automasking_stroke or
gpencil_sculpt.use_automasking_layer_stroke or
gpencil_sculpt.use_automasking_material_stroke or
gpencil_sculpt.use_automasking_material_active or
gpencil_sculpt.use_automasking_layer_active)
return "CLIPUV_DEHLT" if automask_enabled else "CLIPUV_HLT"
class VIEW3D_MT_editor_menus(Menu):
bl_label = ""

View File

@ -256,6 +256,11 @@ void ANIM_armature_refresh_solo_active(bArmature *armature);
bool ANIM_armature_bonecoll_is_visible_effectively(const bArmature *armature,
const BoneCollection *bcoll);
/**
* Expand or collapse a bone collection in the tree view.
*/
void ANIM_armature_bonecoll_is_expanded_set(BoneCollection *bcoll, bool is_expanded);
/**
* Assign the bone to the bone collection.
*
@ -381,6 +386,16 @@ bool armature_bonecoll_is_descendant_of(const bArmature *armature,
bool bonecoll_has_children(const BoneCollection *bcoll);
/**
* For each bone collection in the destination armature, copy its #BONE_COLLECTION_EXPANDED flag
* from the corresponding bone collection in the source armature.
*
* This is used in the handling of undo steps, to ensure that undo'ing does _not_
* modify this flag.
*/
void bonecolls_copy_expanded_flag(Span<BoneCollection *> bcolls_dest,
Span<const BoneCollection *> bcolls_source);
/**
* Move a bone collection from one parent to another.
*

View File

@ -22,4 +22,4 @@ float evaluate_driver_from_rna_pointer(const AnimationEvalContext *anim_eval_con
PropertyRNA *prop,
const FCurve *fcu);
} // namespace blender::animrig
} // namespace blender::animrig

View File

@ -711,9 +711,11 @@ void ANIM_armature_bonecoll_remove(bArmature *armature, BoneCollection *bcoll)
armature_bonecoll_find_index(armature, bcoll));
}
BoneCollection *ANIM_armature_bonecoll_get_by_name(bArmature *armature, const char *name)
template<typename MaybeConstBoneCollection>
static MaybeConstBoneCollection *bonecolls_get_by_name(
blender::Span<MaybeConstBoneCollection *> bonecolls, const char *name)
{
for (BoneCollection *bcoll : armature->collections_span()) {
for (MaybeConstBoneCollection *bcoll : bonecolls) {
if (STREQ(bcoll->name, name)) {
return bcoll;
}
@ -721,6 +723,11 @@ BoneCollection *ANIM_armature_bonecoll_get_by_name(bArmature *armature, const ch
return nullptr;
}
BoneCollection *ANIM_armature_bonecoll_get_by_name(bArmature *armature, const char *name)
{
return bonecolls_get_by_name(armature->collections_span(), name);
}
int ANIM_armature_bonecoll_get_index_by_name(bArmature *armature, const char *name)
{
for (int index = 0; index < armature->collection_array_num; index++) {
@ -846,6 +853,16 @@ bool ANIM_armature_bonecoll_is_visible_effectively(const bArmature *armature,
return bcoll->is_visible_with_ancestors();
}
void ANIM_armature_bonecoll_is_expanded_set(BoneCollection *bcoll, bool is_expanded)
{
if (is_expanded) {
bcoll->flags |= BONE_COLLECTION_EXPANDED;
}
else {
bcoll->flags &= ~BONE_COLLECTION_EXPANDED;
}
}
/* Store the bone's membership on the collection. */
static void add_membership(BoneCollection *bcoll, Bone *bone)
{
@ -1237,6 +1254,45 @@ bool bonecoll_has_children(const BoneCollection *bcoll)
return bcoll->child_count > 0;
}
void bonecolls_copy_expanded_flag(Span<BoneCollection *> bcolls_dest,
Span<const BoneCollection *> bcolls_source)
{
/* Try to preserve the bone collection expanded/collapsed states. These are UI
* changes that shouldn't impact undo steps. Care has to be taken to match the
* old and the new bone collections, though, as they may have been reordered
* or renamed.
*
* Reordering is handled by looking up collections by name.
* Renames are handled by skipping those that cannot be found by name. */
auto find_old = [bcolls_source](const char *name, const int index) -> const BoneCollection * {
/* Only check index when it's valid in the old armature. */
if (index < bcolls_source.size()) {
const BoneCollection *bcoll = bcolls_source[index];
if (STREQ(bcoll->name, name)) {
/* Index and name matches, let's use */
return bcoll;
}
}
/* Try to find by name as a last resort. This function only works with
* non-const pointers, hence the const_cast. */
const BoneCollection *bcoll = bonecolls_get_by_name(bcolls_source, name);
return bcoll;
};
for (int i = 0; i < bcolls_dest.size(); i++) {
BoneCollection *bcoll_new = bcolls_dest[i];
const BoneCollection *bcoll_old = find_old(bcoll_new->name, i);
if (!bcoll_old) {
continue;
}
ANIM_armature_bonecoll_is_expanded_set(bcoll_new, bcoll_old->is_expanded());
}
}
int armature_bonecoll_move_to_parent(bArmature *armature,
const int from_bcoll_index,
int to_child_num,

View File

@ -26,4 +26,4 @@ float evaluate_driver_from_rna_pointer(const AnimationEvalContext *anim_eval_con
return evaluate_driver(&anim_rna, fcu->driver, fcu->driver, anim_eval_context);
}
} // namespace blender::animrig
} // namespace blender::animrig

View File

@ -17,6 +17,12 @@ namespace blender::bke::bake {
*/
class BakeItem {
public:
/**
* User-defined name. This is not necessarily unique and might change over time. It's purpose is
* to make bakes more inspectable.
*/
std::string name;
virtual ~BakeItem() = default;
};

View File

@ -24,6 +24,8 @@ struct BakeSocketConfig {
* for some socket types).
*/
Vector<AttrDomain> domains;
/** User-defined name of every socket. */
Vector<StringRef> names;
/**
* Determines which geometries a field socket should be evaluated on. This can be used to
* implement rules like a field should only be evaluated on the preceding or on all geometries.

View File

@ -234,6 +234,18 @@ struct bContextPollMsgDyn_Params {
};
const char *CTX_wm_operator_poll_msg_get(bContext *C, bool *r_free);
/**
* Set a message to be shown when the operator is disabled in the UI.
*
* \note even though the function name does not include the word "disabled", the
* message is only shown when the operator (in the UI) is in fact disabled.
*
* \note even though the function name suggests this is limited to situations
* when the poll function returns false, this is not the case. Even when the
* operator is disabled because it is added to a disabled uiLayout, this message
* will show.
*/
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg);
void CTX_wm_operator_poll_msg_set_dynamic(bContext *C, const bContextPollMsgDyn_Params *params);
void CTX_wm_operator_poll_msg_clear(bContext *C);

View File

@ -31,4 +31,4 @@ void clear_vertex_groups(GreasePencil &grease_pencil);
/** Select or deselect vertices assigned to this group. */
void select_from_group(GreasePencil &grease_pencil, StringRef name, bool select);
} // namespace blender::bke::greasepencil
} // namespace blender::bke::greasepencil

View File

@ -518,8 +518,7 @@ void BKE_image_ensure_gpu_texture(struct Image *image, struct ImageUser *iuser);
/**
* Get the #GPUTexture for a given `Image`.
*
* `iuser` and `ibuf` are mutual exclusive parameters. The caller can pass the `ibuf` when already
* available. It is also required when requesting the #GPUTexture for a render result.
*
*
* The requested GPU texture will be cached for subsequent calls, but only a single layer, pass,
* and view can be cached at a time, so the cache should be invalidated in operators and RNA
@ -530,11 +529,26 @@ void BKE_image_ensure_gpu_texture(struct Image *image, struct ImageUser *iuser);
* calling BKE_image_ensure_gpu_texture. This is a workaround until image can support a more
* complete caching system.
*/
struct GPUTexture *BKE_image_get_gpu_texture(struct Image *image,
struct ImageUser *iuser,
struct ImBuf *ibuf);
struct GPUTexture *BKE_image_get_gpu_tiles(struct Image *image, struct ImageUser *iuser);
struct GPUTexture *BKE_image_get_gpu_tilemap(struct Image *image, struct ImageUser *iuser);
struct GPUTexture *BKE_image_get_gpu_texture(struct Image *image, struct ImageUser *iuser);
/*
* Like BKE_image_get_gpu_texture, but can also get render or compositing result.
*/
struct GPUTexture *BKE_image_get_gpu_viewer_texture(struct Image *image, struct ImageUser *iuser);
/*
* Like BKE_image_get_gpu_texture, but can also return array and tile mapping texture for UDIM
* tiles as used in material shaders.
*/
typedef struct ImageGPUTextures {
struct GPUTexture *texture;
struct GPUTexture *tile_mapping;
} ImageGPUTextures;
ImageGPUTextures BKE_image_get_gpu_material_texture(struct Image *image,
struct ImageUser *iuser,
const bool use_tile_mapping);
/**
* Is the alpha of the `GPUTexture` for a given image/ibuf premultiplied.
*/

View File

@ -82,7 +82,7 @@ void BKE_preferences_asset_library_default_add(struct UserDef *userdef) ATTR_NON
bUserExtensionRepo *BKE_preferences_extension_repo_add(UserDef *userdef,
const char *name,
const char *module,
const char *dirpath);
const char *custom_dirpath);
void BKE_preferences_extension_repo_remove(UserDef *userdef, bUserExtensionRepo *repo);
void BKE_preferences_extension_repo_name_set(UserDef *userdef,
@ -92,7 +92,11 @@ void BKE_preferences_extension_repo_module_set(UserDef *userdef,
bUserExtensionRepo *repo,
const char *module);
void BKE_preferences_extension_repo_path_set(bUserExtensionRepo *repo, const char *path);
void BKE_preferences_extension_repo_custom_dirpath_set(bUserExtensionRepo *repo, const char *path);
void BKE_preferences_extension_repo_dirpath_get(const bUserExtensionRepo *repo,
char *dirpath,
int dirpath_maxncpy);
bUserExtensionRepo *BKE_preferences_extension_repo_find_index(const UserDef *userdef, int index);
bUserExtensionRepo *BKE_preferences_extension_repo_find_by_module(const UserDef *userdef,
const char *module);

View File

@ -25,6 +25,7 @@
#include "BLI_math_vector.h"
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@ -63,6 +64,8 @@
#include "CLG_log.h"
using namespace blender;
/* -------------------------------------------------------------------- */
/** \name Prototypes
* \{ */
@ -461,6 +464,14 @@ static void armature_blend_read_data(BlendDataReader *reader, ID *id)
ANIM_armature_runtime_refresh(arm);
}
static void armature_undo_preserve(BlendLibReader * /*reader*/, ID *id_new, ID *id_old)
{
bArmature *arm_new = (bArmature *)id_new;
bArmature *arm_old = (bArmature *)id_old;
animrig::bonecolls_copy_expanded_flag(arm_new->collections_span(), arm_old->collections_span());
}
IDTypeInfo IDType_ID_AR = {
/*id_code*/ ID_AR,
/*id_filter*/ FILTER_ID_AR,
@ -485,7 +496,7 @@ IDTypeInfo IDType_ID_AR = {
/*blend_read_data*/ armature_blend_read_data,
/*blend_read_after_liblink*/ nullptr,
/*blend_read_undo_preserve*/ nullptr,
/*blend_read_undo_preserve*/ armature_undo_preserve,
/*lib_override_apply_post*/ nullptr,
};
@ -3190,5 +3201,9 @@ bool BoneCollection::is_solo() const
{
return this->flags & BONE_COLLECTION_SOLO;
}
bool BoneCollection::is_expanded() const
{
return this->flags & BONE_COLLECTION_EXPANDED;
}
/** \} */

View File

@ -587,7 +587,6 @@ bool CustomDataAttributeProvider::try_delete(void *owner, const AttributeIDRef &
return false;
}
const int element_num = custom_data_access_.get_element_num(owner);
;
for (const int i : IndexRange(custom_data->totlayer)) {
const CustomDataLayer &layer = custom_data->layers[i];
if (this->type_is_supported((eCustomDataType)layer.type) &&

View File

@ -1010,6 +1010,9 @@ static void serialize_bake_item(const BakeItem &item,
BlobSharing &blob_sharing,
DictionaryValue &r_io_item)
{
if (!item.name.empty()) {
r_io_item.append_str("name", item.name);
}
if (const auto *geometry_state_item = dynamic_cast<const GeometryBakeItem *>(&item)) {
r_io_item.append_str("type", "GEOMETRY");

View File

@ -101,6 +101,12 @@ Array<std::unique_ptr<BakeItem>> move_socket_values_to_bake_items(const Span<voi
GeometryBakeItem::prepare_geometry_for_bake(geometry, data_block_map);
}
for (const int i : bake_items.index_range()) {
if (std::unique_ptr<BakeItem> &item = bake_items[i]) {
item->name = config.names[i];
}
}
return bake_items;
}

View File

@ -351,13 +351,15 @@ void BKE_image_ensure_gpu_texture(Image *image, ImageUser *image_user)
}
}
static GPUTexture *image_get_gpu_texture(Image *ima,
ImageUser *iuser,
ImBuf *ibuf,
eGPUTextureTarget textarget)
static ImageGPUTextures image_get_gpu_texture(Image *ima,
ImageUser *iuser,
const bool use_viewers,
const bool use_tile_mapping)
{
ImageGPUTextures result = {};
if (ima == nullptr) {
return nullptr;
return result;
}
/* Free any unused GPU textures, since we know we are in a thread with OpenGL
@ -396,6 +398,11 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
/* Tag as in active use for garbage collector. */
BKE_image_tag_time(ima);
/* Test if we need to get a tiled array texture. */
eGPUTextureTarget textarget = (use_tile_mapping && ima->source == IMA_SRC_TILED) ?
TEXTARGET_2D_ARRAY :
TEXTARGET_2D;
/* Test if we already have a texture. */
int current_view = iuser ? iuser->multi_index : 0;
if (current_view >= 2) {
@ -403,7 +410,9 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, current_view);
if (*tex) {
return *tex;
result.texture = *tex;
result.tile_mapping = *get_image_gpu_texture_ptr(ima, TEXTARGET_TILE_MAPPING, current_view);
return result;
}
/* Check if we have a valid image. If not, we return a dummy
@ -411,32 +420,38 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
ImageTile *tile = BKE_image_get_tile(ima, 0);
if (tile == nullptr) {
*tex = image_gpu_texture_error_create(textarget);
return *tex;
result.texture = *tex;
return result;
}
/* check if we have a valid image buffer */
ImBuf *ibuf_intern = ibuf;
if (ibuf_intern == nullptr) {
ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, nullptr);
if (ibuf_intern == nullptr) {
*tex = image_gpu_texture_error_create(textarget);
return *tex;
}
void *lock;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, (use_viewers) ? &lock : nullptr);
if (ibuf == nullptr) {
BKE_image_release_ibuf(ima, ibuf, (use_viewers) ? &lock : nullptr);
*tex = image_gpu_texture_error_create(textarget);
result.texture = *tex;
return result;
}
if (textarget == TEXTARGET_2D_ARRAY) {
*tex = gpu_texture_create_tile_array(ima, ibuf_intern);
}
else if (textarget == TEXTARGET_TILE_MAPPING) {
*tex = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0);
/* For materials, array and tile mapping in case there are UDIM tiles. */
*tex = gpu_texture_create_tile_array(ima, ibuf);
result.texture = *tex;
GPUTexture **tile_mapping_tex = get_image_gpu_texture_ptr(
ima, TEXTARGET_TILE_MAPPING, current_view);
*tile_mapping_tex = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0);
result.tile_mapping = *tile_mapping_tex;
}
else {
/* Single image texture. */
const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH);
const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima,
ibuf_intern);
const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
*tex = IMB_create_gpu_texture(
ima->id.name + 2, ibuf_intern, use_high_bitdepth, store_premultiplied);
*tex = IMB_create_gpu_texture(ima->id.name + 2, ibuf, use_high_bitdepth, store_premultiplied);
result.texture = *tex;
if (*tex) {
GPU_texture_extend_mode(*tex, GPU_SAMPLER_EXTEND_MODE_REPEAT);
@ -455,29 +470,29 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
if (*tex) {
GPU_texture_original_size_set(*tex, ibuf_intern->x, ibuf_intern->y);
GPU_texture_original_size_set(*tex, ibuf->x, ibuf->y);
}
if (ibuf != ibuf_intern) {
BKE_image_release_ibuf(ima, ibuf_intern, nullptr);
}
BKE_image_release_ibuf(ima, ibuf, (use_viewers) ? &lock : nullptr);
return *tex;
return result;
}
GPUTexture *BKE_image_get_gpu_texture(Image *image, ImageUser *iuser, ImBuf *ibuf)
GPUTexture *BKE_image_get_gpu_texture(Image *image, ImageUser *iuser)
{
return image_get_gpu_texture(image, iuser, ibuf, TEXTARGET_2D);
return image_get_gpu_texture(image, iuser, false, false).texture;
}
GPUTexture *BKE_image_get_gpu_tiles(Image *image, ImageUser *iuser)
GPUTexture *BKE_image_get_gpu_viewer_texture(Image *image, ImageUser *iuser)
{
return image_get_gpu_texture(image, iuser, nullptr, TEXTARGET_2D_ARRAY);
return image_get_gpu_texture(image, iuser, true, false).texture;
}
GPUTexture *BKE_image_get_gpu_tilemap(Image *image, ImageUser *iuser)
ImageGPUTextures BKE_image_get_gpu_material_texture(Image *image,
ImageUser *iuser,
const bool use_tile_mapping)
{
return image_get_gpu_texture(image, iuser, nullptr, TEXTARGET_TILE_MAPPING);
return image_get_gpu_texture(image, iuser, false, use_tile_mapping);
}
/** \} */

View File

@ -159,7 +159,7 @@ static size_t strncpy_py_module(char *dst, const char *src, const size_t dst_max
bUserExtensionRepo *BKE_preferences_extension_repo_add(UserDef *userdef,
const char *name,
const char *module,
const char *dirpath)
const char *custom_dirpath)
{
bUserExtensionRepo *repo = DNA_struct_default_alloc(bUserExtensionRepo);
BLI_addtail(&userdef->extension_repos, repo);
@ -171,9 +171,9 @@ bUserExtensionRepo *BKE_preferences_extension_repo_add(UserDef *userdef,
BKE_preferences_extension_repo_module_set(userdef, repo, module);
/* Set the directory. */
STRNCPY(repo->dirpath, dirpath);
BLI_path_normalize(repo->dirpath);
BLI_path_slash_rstrip(repo->dirpath);
STRNCPY(repo->custom_dirpath, custom_dirpath);
BLI_path_normalize(repo->custom_dirpath);
BLI_path_slash_rstrip(repo->custom_dirpath);
/* While not a strict rule, ignored paths that already exist, *
* pointing to the same path is going to logical problems with package-management. */
@ -181,8 +181,8 @@ bUserExtensionRepo *BKE_preferences_extension_repo_add(UserDef *userdef,
if (repo == repo_iter) {
continue;
}
if (BLI_path_cmp(repo->dirpath, repo_iter->dirpath) == 0) {
repo->dirpath[0] = '\0';
if (BLI_path_cmp(repo->custom_dirpath, repo_iter->custom_dirpath) == 0) {
repo->custom_dirpath[0] = '\0';
break;
}
}
@ -228,9 +228,29 @@ void BKE_preferences_extension_repo_module_set(UserDef *userdef,
sizeof(repo->module));
}
void BKE_preferences_extension_repo_path_set(bUserExtensionRepo *repo, const char *path)
void BKE_preferences_extension_repo_custom_dirpath_set(bUserExtensionRepo *repo, const char *path)
{
STRNCPY(repo->dirpath, path);
STRNCPY(repo->custom_dirpath, path);
}
void BKE_preferences_extension_repo_dirpath_get(const bUserExtensionRepo *repo,
char *dirpath,
const int dirpath_maxncpy)
{
if (repo->flag & USER_EXTENSION_REPO_FLAG_USE_CUSTOM_DIRECTORY) {
BLI_strncpy(dirpath, repo->custom_dirpath, dirpath_maxncpy);
return;
}
char subdir[16 + sizeof(bUserExtensionRepo::module)];
BLI_string_join(subdir, sizeof(subdir), "extensions", SEP_STR, repo->module);
const std::optional<std::string> path = BKE_appdir_folder_id(BLENDER_USER_SCRIPTS, subdir);
if (path.has_value()) {
BLI_strncpy(dirpath, path.value().c_str(), dirpath_maxncpy);
}
else {
dirpath[0] = '\0';
}
}
bUserExtensionRepo *BKE_preferences_extension_repo_find_index(const UserDef *userdef, int index)

View File

@ -1316,7 +1316,7 @@ static void tracking_stabilize_frame_interpolation_cb(void *__restrict userdata,
for (int x = 0; x < tmpibuf->x; x++, dst++) {
vec[0] = float(x);
mul_v3_m4v3(rvec, mat, vec);
*dst = imbuf::interpolate_bilinear_fl(ibuf, rvec[0], rvec[1]);
*dst = imbuf::interpolate_bilinear_border_fl(ibuf, rvec[0], rvec[1]);
}
}
else if (data->tracking_filter == TRACKING_FILTER_BICUBIC) {
@ -1342,7 +1342,7 @@ static void tracking_stabilize_frame_interpolation_cb(void *__restrict userdata,
for (int x = 0; x < tmpibuf->x; x++, dst++) {
vec[0] = float(x);
mul_v3_m4v3(rvec, mat, vec);
*dst = imbuf::interpolate_bilinear_byte(ibuf, rvec[0], rvec[1]);
*dst = imbuf::interpolate_bilinear_border_byte(ibuf, rvec[0], rvec[1]);
}
}
else if (data->tracking_filter == TRACKING_FILTER_BICUBIC) {

View File

@ -142,7 +142,7 @@ inline void interpolate_nearest_wrap_fl(
}
/**
* Bilinear sampling.
* Bilinear sampling (with black border).
*
* Takes four image samples at floor(u,v) and floor(u,v)+1, and blends them
* based on fractional parts of u,v. Samples outside the image are turned
@ -152,6 +152,26 @@ inline void interpolate_nearest_wrap_fl(
* to get proper filtering.
*/
[[nodiscard]] uchar4 interpolate_bilinear_border_byte(
const uchar *buffer, int width, int height, float u, float v);
[[nodiscard]] float4 interpolate_bilinear_border_fl(
const float *buffer, int width, int height, float u, float v);
void interpolate_bilinear_border_fl(
const float *buffer, float *output, int width, int height, int components, float u, float v);
/**
* Bilinear sampling.
*
* Takes four image samples at floor(u,v) and floor(u,v)+1, and blends them
* based on fractional parts of u,v.
* Samples outside the image are clamped to texels at image edge.
*
* Note that you probably want to subtract 0.5 from u,v before this function,
* to get proper filtering.
*/
[[nodiscard]] uchar4 interpolate_bilinear_byte(
const uchar *buffer, int width, int height, float u, float v);

View File

@ -30,3 +30,9 @@
#else
# define BLI_HAVE_SSE2 0
#endif
#if defined(__SSE4_1__) || (defined(__ARM_NEON) && defined(WITH_SSE2NEON))
# define BLI_HAVE_SSE4 1
#else
# define BLI_HAVE_SSE4 0
#endif

View File

@ -389,7 +389,7 @@ BLI_INLINE bool bchunk_data_compare_unchecked(const BChunk *chunk,
const size_t data_base_len,
const size_t offset)
{
BLI_assert(offset + (size_t)chunk->data_len <= data_base_len);
BLI_assert(offset + size_t(chunk->data_len) <= data_base_len);
UNUSED_VARS_NDEBUG(data_base_len);
return (memcmp(&data_base[offset], chunk->data, chunk->data_len) == 0);
}
@ -399,7 +399,7 @@ static bool bchunk_data_compare(const BChunk *chunk,
const size_t data_base_len,
const size_t offset)
{
if (offset + (size_t)chunk->data_len <= data_base_len) {
if (offset + size_t(chunk->data_len) <= data_base_len) {
return bchunk_data_compare_unchecked(chunk, data_base, data_base_len, offset);
}
return false;
@ -974,7 +974,7 @@ static const BChunkRef *table_lookup(const BArrayInfo *info,
const hash_key *table_hash_array)
{
const hash_key key = table_hash_array[((offset - i_table_start) / info->chunk_stride)];
const uint key_index = (uint)(key % (hash_key)table_len);
const uint key_index = uint(key % (hash_key)table_len);
const BTableRef *tref = table[key_index];
if (tref != nullptr) {
const size_t size_left = data_len - offset;
@ -1041,7 +1041,7 @@ static const BChunkRef *table_lookup(const BArrayInfo *info,
const size_t size_left = data_len - offset;
const hash_key key = hash_data(&data[offset], std::min(data_hash_len, size_left));
const uint key_index = (uint)(key % (hash_key)table_len);
const uint key_index = uint(key % (hash_key)table_len);
for (BTableRef *tref = table[key_index]; tref; tref = tref->next) {
const BChunkRef *cref = tref->cref;
# ifdef USE_HASH_TABLE_KEY_CACHE
@ -1331,7 +1331,7 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info,
hash_store_len
#endif
);
const uint key_index = (uint)(key % (hash_key)table_len);
const uint key_index = uint(key % (hash_key)table_len);
BTableRef *tref_prev = table[key_index];
BLI_assert(table_ref_stack_n < chunk_list_reference_remaining_len);
#ifdef USE_HASH_TABLE_DEDUPLICATE
@ -1532,7 +1532,7 @@ BArrayStore *BLI_array_store_create(uint stride, uint chunk_count)
bs->info.accum_read_ahead_bytes = bs->info.accum_read_ahead_len * stride;
#else
bs->info.accum_read_ahead_bytes = std::min((size_t)BCHUNK_HASH_LEN, chunk_count) * stride;
bs->info.accum_read_ahead_bytes = std::min(size_t(BCHUNK_HASH_LEN), chunk_count) * stride;
#endif
bs->memory.chunk_list = BLI_mempool_create(sizeof(BChunkList), 0, 512, BLI_MEMPOOL_NOP);
@ -1805,7 +1805,7 @@ bool BLI_array_store_is_valid(BArrayStore *bs)
goto user_finally;
}
}
if (!(BLI_mempool_len(bs->memory.chunk_list) == (int)BLI_ghash_len(chunk_list_map))) {
if (!(BLI_mempool_len(bs->memory.chunk_list) == int(BLI_ghash_len(chunk_list_map)))) {
ok = false;
goto user_finally;
}
@ -1819,7 +1819,7 @@ bool BLI_array_store_is_valid(BArrayStore *bs)
totrefs += 1;
}
}
if (!(BLI_mempool_len(bs->memory.chunk) == (int)BLI_ghash_len(chunk_map))) {
if (!(BLI_mempool_len(bs->memory.chunk) == int(BLI_ghash_len(chunk_map)))) {
ok = false;
goto user_finally;
}

View File

@ -536,7 +536,7 @@ void BLI_get_short_name(char short_name[256], const char *filepath)
GetShortPathNameW(filepath_16, short_name_16, 256);
for (i = 0; i < 256; i++) {
short_name[i] = (char)short_name_16[i];
short_name[i] = char(short_name_16[i]);
}
UTF16_UN_ENCODE(filepath);

View File

@ -17,6 +17,8 @@
#include "BLI_simd.h"
#include "BLI_strict_flags.h"
namespace blender::math {
enum class eCubicFilter {
BSpline,
Mitchell,
@ -24,7 +26,7 @@ enum class eCubicFilter {
/* Calculate cubic filter coefficients, for samples at -1,0,+1,+2.
* f is 0..1 offset from texel center in pixel space. */
template<enum eCubicFilter filter> static blender::float4 cubic_filter_coefficients(float f)
template<enum eCubicFilter filter> static float4 cubic_filter_coefficients(float f)
{
float f2 = f * f;
float f3 = f2 * f;
@ -35,7 +37,7 @@ template<enum eCubicFilter filter> static blender::float4 cubic_filter_coefficie
float w0 = -w3 + f2 * 0.5f - f * 0.5f + 1.0f / 6.0f;
float w1 = f3 * 0.5f - f2 * 1.0f + 2.0f / 3.0f;
float w2 = 1.0f - w0 - w1 - w3;
return blender::float4(w0, w1, w2, w3);
return float4(w0, w1, w2, w3);
}
else if constexpr (filter == eCubicFilter::Mitchell) {
/* Cubic Mitchell-Netravali filter with B=1/3, C=1/3 parameters. */
@ -43,7 +45,7 @@ template<enum eCubicFilter filter> static blender::float4 cubic_filter_coefficie
float w1 = 7.0f / 6.0f * f3 - 2.0f * f2 + 8.0f / 9.0f;
float w2 = -7.0f / 6.0f * f3 + 3.0f / 2.0f * f2 + 0.5f * f + 1.0f / 18.0f;
float w3 = 7.0f / 18.0f * f3 - 1.0f / 3.0f * f2;
return blender::float4(w0, w1, w2, w3);
return float4(w0, w1, w2, w3);
}
}
@ -54,13 +56,11 @@ template<enum eCubicFilter filter> static blender::float4 cubic_filter_coefficie
BLI_INLINE __m128 floor_simd(__m128 v)
{
# if defined(__SSE4_1__) || defined(__ARM_NEON) && defined(WITH_SSE2NEON)
/* If we're on SSE4 or ARM NEON, just use the simple floor() way. */
# if BLI_HAVE_SSE4
__m128 v_floor = _mm_floor_ps(v);
# else
/* The hard way: truncate, for negative inputs this will round towards zero.
* Then compare with input, and subtract 1 for the inputs that were
* negative. */
/* Truncate, for negative inputs this will round towards zero. Then compare
* with input, and subtract 1 for the inputs that were negative. */
__m128 v_trunc = _mm_cvtepi32_ps(_mm_cvttps_epi32(v));
__m128 v_neg = _mm_cmplt_ps(v, v_trunc);
__m128 v_floor = _mm_sub_ps(v_trunc, _mm_and_ps(v_neg, _mm_set1_ps(1.0f)));
@ -68,6 +68,30 @@ BLI_INLINE __m128 floor_simd(__m128 v)
return v_floor;
}
BLI_INLINE __m128i min_i_simd(__m128i a, __m128i b)
{
# if BLI_HAVE_SSE4
return _mm_min_epi32(a, b);
# else
__m128i cmp = _mm_cmplt_epi32(a, b);
a = _mm_and_si128(cmp, a);
b = _mm_andnot_si128(cmp, b);
return _mm_or_si128(a, b);
# endif
}
BLI_INLINE __m128i max_i_simd(__m128i a, __m128i b)
{
# if BLI_HAVE_SSE4
return _mm_max_epi32(a, b);
# else
__m128i cmp = _mm_cmplt_epi32(b, a);
a = _mm_and_si128(cmp, a);
b = _mm_andnot_si128(cmp, b);
return _mm_or_si128(a, b);
# endif
}
template<eCubicFilter filter>
BLI_INLINE void bicubic_interpolation_uchar_simd(
const uchar *src_buffer, uchar *output, int width, int height, float u, float v)
@ -90,8 +114,8 @@ BLI_INLINE void bicubic_interpolation_uchar_simd(
__m128 frac_uv = _mm_sub_ps(uv, uv_floor);
/* Calculate pixel weights. */
blender::float4 wx = cubic_filter_coefficients<filter>(_mm_cvtss_f32(frac_uv));
blender::float4 wy = cubic_filter_coefficients<filter>(
float4 wx = cubic_filter_coefficients<filter>(_mm_cvtss_f32(frac_uv));
float4 wy = cubic_filter_coefficients<filter>(
_mm_cvtss_f32(_mm_shuffle_ps(frac_uv, frac_uv, 1)));
/* Read 4x4 source pixels and blend them. */
@ -134,8 +158,6 @@ template<typename T, eCubicFilter filter>
static void bicubic_interpolation(
const T *src_buffer, T *output, int width, int height, int components, float u, float v)
{
using namespace blender;
BLI_assert(src_buffer && output);
#if BLI_HAVE_SSE2
@ -147,8 +169,8 @@ static void bicubic_interpolation(
}
#endif
int iu = (int)floor(u);
int iv = (int)floor(v);
int iu = int(floor(u));
int iv = int(floor(v));
/* Sample area entirely outside image? */
if (iu + 1 < 0 || iu > width - 1 || iv + 1 < 0 || iv > height - 1) {
@ -156,8 +178,8 @@ static void bicubic_interpolation(
return;
}
float frac_u = u - (float)iu;
float frac_v = v - (float)iv;
float frac_u = u - float(iu);
float frac_v = v - float(iv);
float4 out{0.0f};
@ -234,6 +256,7 @@ static void bicubic_interpolation(
}
}
template<bool border>
BLI_INLINE void bilinear_fl_impl(const float *buffer,
float *output,
int width,
@ -259,7 +282,7 @@ BLI_INLINE void bilinear_fl_impl(const float *buffer,
float uf = floorf(u);
float vf = floorf(v);
x1 = (int)uf;
x1 = int(uf);
x2 = x1 + 1;
y1 = int(vf);
y2 = y1 + 1;
@ -288,33 +311,23 @@ BLI_INLINE void bilinear_fl_impl(const float *buffer,
return;
}
/* Sample including outside of edges of image. */
if (x1 < 0 || y1 < 0) {
row1 = empty;
/* Sample locations. */
if constexpr (border) {
row1 = (x1 < 0 || y1 < 0) ? empty : buffer + (int64_t(width) * y1 + x1) * components;
row2 = (x1 < 0 || y2 > height - 1) ? empty : buffer + (int64_t(width) * y2 + x1) * components;
row3 = (x2 > width - 1 || y1 < 0) ? empty : buffer + (int64_t(width) * y1 + x2) * components;
row4 = (x2 > width - 1 || y2 > height - 1) ? empty :
buffer + (int64_t(width) * y2 + x2) * components;
}
else {
row1 = buffer + width * y1 * components + components * x1;
}
if (x1 < 0 || y2 > height - 1) {
row2 = empty;
}
else {
row2 = buffer + width * y2 * components + components * x1;
}
if (x2 > width - 1 || y1 < 0) {
row3 = empty;
}
else {
row3 = buffer + width * y1 * components + components * x2;
}
if (x2 > width - 1 || y2 > height - 1) {
row4 = empty;
}
else {
row4 = buffer + width * y2 * components + components * x2;
x1 = blender::math::clamp(x1, 0, width - 1);
x2 = blender::math::clamp(x2, 0, width - 1);
y1 = blender::math::clamp(y1, 0, height - 1);
y2 = blender::math::clamp(y2, 0, height - 1);
row1 = buffer + (int64_t(width) * y1 + x1) * components;
row2 = buffer + (int64_t(width) * y2 + x1) * components;
row3 = buffer + (int64_t(width) * y1 + x2) * components;
row4 = buffer + (int64_t(width) * y2 + x2) * components;
}
a = u - uf;
@ -355,23 +368,13 @@ BLI_INLINE void bilinear_fl_impl(const float *buffer,
}
}
namespace blender::math {
uchar4 interpolate_bilinear_byte(const uchar *buffer, int width, int height, float u, float v)
template<bool border>
BLI_INLINE uchar4 bilinear_byte_impl(const uchar *buffer, int width, int height, float u, float v)
{
BLI_assert(buffer);
uchar4 res;
#if BLI_HAVE_SSE2
/* Bilinear interpolation needs to read and blend four image pixels, while
* also handling conditions of sample coordinate being outside of the
* image, in which case black (all zeroes) should be used as the sample
* contribution.
*
* Code below does all that without any branches, by making outside the
* image sample locations still read the first pixel of the image, but
* later making sure that the result is set to zero for that sample. */
__m128 uvuv = _mm_set_ps(v, u, v, u);
__m128 uvuv_floor = floor_simd(uvuv);
@ -380,18 +383,42 @@ uchar4 interpolate_bilinear_byte(const uchar *buffer, int width, int height, flo
/* Check whether any of the coordinates are outside of the image. */
__m128i size_minus_1 = _mm_sub_epi32(_mm_set_epi32(height, width, height, width),
_mm_set1_epi32(1));
__m128i too_lo_xy12 = _mm_cmplt_epi32(xy12, _mm_setzero_si128());
__m128i too_hi_xy12 = _mm_cmplt_epi32(size_minus_1, xy12);
__m128i invalid_xy12 = _mm_or_si128(too_lo_xy12, too_hi_xy12);
/* Samples 1,2,3,4 are in this order: x1y1, x1y2, x2y1, x2y2 */
__m128i x1234 = _mm_shuffle_epi32(xy12, _MM_SHUFFLE(2, 2, 0, 0));
__m128i y1234 = _mm_shuffle_epi32(xy12, _MM_SHUFFLE(3, 1, 3, 1));
__m128i invalid_1234 = _mm_or_si128(_mm_shuffle_epi32(invalid_xy12, _MM_SHUFFLE(2, 2, 0, 0)),
_mm_shuffle_epi32(invalid_xy12, _MM_SHUFFLE(3, 1, 3, 1)));
/* Set x & y to zero for invalid samples. */
x1234 = _mm_andnot_si128(invalid_1234, x1234);
y1234 = _mm_andnot_si128(invalid_1234, y1234);
/* Samples 1,2,3,4 will be in this order: x1y1, x1y2, x2y1, x2y2. */
__m128i x1234, y1234, invalid_1234;
if constexpr (border) {
/* Blend black colors for samples right outside the image: figure out
* which of the 4 samples were outside, set their coordinates to zero
* and later on put black color into their place. */
__m128i too_lo_xy12 = _mm_cmplt_epi32(xy12, _mm_setzero_si128());
__m128i too_hi_xy12 = _mm_cmplt_epi32(size_minus_1, xy12);
__m128i invalid_xy12 = _mm_or_si128(too_lo_xy12, too_hi_xy12);
/* Samples 1,2,3,4 are in this order: x1y1, x1y2, x2y1, x2y2 */
x1234 = _mm_shuffle_epi32(xy12, _MM_SHUFFLE(2, 2, 0, 0));
y1234 = _mm_shuffle_epi32(xy12, _MM_SHUFFLE(3, 1, 3, 1));
invalid_1234 = _mm_or_si128(_mm_shuffle_epi32(invalid_xy12, _MM_SHUFFLE(2, 2, 0, 0)),
_mm_shuffle_epi32(invalid_xy12, _MM_SHUFFLE(3, 1, 3, 1)));
/* Set x & y to zero for invalid samples. */
x1234 = _mm_andnot_si128(invalid_1234, x1234);
y1234 = _mm_andnot_si128(invalid_1234, y1234);
}
else {
/* Clamp samples to image edges, unless all four of them are outside
* in which case return black. */
__m128i xy12_clamped = max_i_simd(xy12, _mm_setzero_si128());
xy12_clamped = min_i_simd(xy12_clamped, size_minus_1);
__m128i valid_xy12 = _mm_cmpeq_epi32(xy12, xy12_clamped);
__m128i valid_pairs = _mm_and_si128(valid_xy12,
_mm_shuffle_epi32(valid_xy12, _MM_SHUFFLE(0, 3, 2, 1)));
if (_mm_movemask_ps(_mm_castsi128_ps(valid_pairs)) == 0) {
return uchar4(0);
}
x1234 = _mm_shuffle_epi32(xy12_clamped, _MM_SHUFFLE(2, 2, 0, 0));
y1234 = _mm_shuffle_epi32(xy12_clamped, _MM_SHUFFLE(3, 1, 3, 1));
}
/* Read the four sample values. Do address calculations in C, since SSE
* before 4.1 makes it very cumbersome to do full integer multiplies. */
@ -404,8 +431,10 @@ uchar4 interpolate_bilinear_byte(const uchar *buffer, int width, int height, flo
int sample3 = ((const int *)buffer)[ycoord[2] * int64_t(width) + xcoord[2]];
int sample4 = ((const int *)buffer)[ycoord[3] * int64_t(width) + xcoord[3]];
__m128i samples1234 = _mm_set_epi32(sample4, sample3, sample2, sample1);
/* Set samples to black for the ones that were actually invalid. */
samples1234 = _mm_andnot_si128(invalid_1234, samples1234);
if constexpr (border) {
/* Set samples to black for the ones that were actually invalid. */
samples1234 = _mm_andnot_si128(invalid_1234, samples1234);
}
/* Expand samples from packed 8-bit RGBA to full floats:
* spread to 16 bit values. */
@ -445,9 +474,9 @@ uchar4 interpolate_bilinear_byte(const uchar *buffer, int width, int height, flo
float uf = floorf(u);
float vf = floorf(v);
int x1 = (int)uf;
int x1 = int(uf);
int x2 = x1 + 1;
int y1 = (int)vf;
int y1 = int(vf);
int y2 = y1 + 1;
/* Completely outside of the image? */
@ -455,35 +484,24 @@ uchar4 interpolate_bilinear_byte(const uchar *buffer, int width, int height, flo
return uchar4(0);
}
/* Sample including outside of edges of image. */
/* Sample locations. */
const uchar *row1, *row2, *row3, *row4;
uchar empty[4] = {0, 0, 0, 0};
if (x1 < 0 || y1 < 0) {
row1 = empty;
if constexpr (border) {
row1 = (x1 < 0 || y1 < 0) ? empty : buffer + (int64_t(width) * y1 + x1) * 4;
row2 = (x1 < 0 || y2 > height - 1) ? empty : buffer + (int64_t(width) * y2 + x1) * 4;
row3 = (x2 > width - 1 || y1 < 0) ? empty : buffer + (int64_t(width) * y1 + x2) * 4;
row4 = (x2 > width - 1 || y2 > height - 1) ? empty : buffer + (int64_t(width) * y2 + x2) * 4;
}
else {
row1 = buffer + width * y1 * 4 + 4 * x1;
}
if (x1 < 0 || y2 > height - 1) {
row2 = empty;
}
else {
row2 = buffer + width * y2 * 4 + 4 * x1;
}
if (x2 > width - 1 || y1 < 0) {
row3 = empty;
}
else {
row3 = buffer + width * y1 * 4 + 4 * x2;
}
if (x2 > width - 1 || y2 > height - 1) {
row4 = empty;
}
else {
row4 = buffer + width * y2 * 4 + 4 * x2;
x1 = blender::math::clamp(x1, 0, width - 1);
x2 = blender::math::clamp(x2, 0, width - 1);
y1 = blender::math::clamp(y1, 0, height - 1);
y2 = blender::math::clamp(y2, 0, height - 1);
row1 = buffer + (int64_t(width) * y1 + x1) * 4;
row2 = buffer + (int64_t(width) * y2 + x1) * 4;
row3 = buffer + (int64_t(width) * y1 + x2) * 4;
row4 = buffer + (int64_t(width) * y2 + x2) * 4;
}
float a = u - uf;
@ -493,26 +511,50 @@ uchar4 interpolate_bilinear_byte(const uchar *buffer, int width, int height, flo
float a_mb = a * (1.0f - b);
float ma_mb = (1.0f - a) * (1.0f - b);
res.x = (uchar)(ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0] + 0.5f);
res.y = (uchar)(ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1] + 0.5f);
res.z = (uchar)(ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2] + 0.5f);
res.w = (uchar)(ma_mb * row1[3] + a_mb * row3[3] + ma_b * row2[3] + a_b * row4[3] + 0.5f);
res.x = uchar(ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0] + 0.5f);
res.y = uchar(ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1] + 0.5f);
res.z = uchar(ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2] + 0.5f);
res.w = uchar(ma_mb * row1[3] + a_mb * row3[3] + ma_b * row2[3] + a_b * row4[3] + 0.5f);
#endif
return res;
}
uchar4 interpolate_bilinear_border_byte(
const uchar *buffer, int width, int height, float u, float v)
{
return bilinear_byte_impl<true>(buffer, width, height, u, v);
}
uchar4 interpolate_bilinear_byte(const uchar *buffer, int width, int height, float u, float v)
{
return bilinear_byte_impl<false>(buffer, width, height, u, v);
}
float4 interpolate_bilinear_border_fl(const float *buffer, int width, int height, float u, float v)
{
float4 res;
bilinear_fl_impl<true>(buffer, res, width, height, 4, u, v);
return res;
}
void interpolate_bilinear_border_fl(
const float *buffer, float *output, int width, int height, int components, float u, float v)
{
bilinear_fl_impl<true>(buffer, output, width, height, components, u, v);
}
float4 interpolate_bilinear_fl(const float *buffer, int width, int height, float u, float v)
{
float4 res;
bilinear_fl_impl(buffer, res, width, height, 4, u, v);
bilinear_fl_impl<false>(buffer, res, width, height, 4, u, v);
return res;
}
void interpolate_bilinear_fl(
const float *buffer, float *output, int width, int height, int components, float u, float v)
{
bilinear_fl_impl(buffer, output, width, height, components, u, v);
bilinear_fl_impl<false>(buffer, output, width, height, components, u, v);
}
void interpolate_bilinear_wrap_fl(const float *buffer,
@ -525,7 +567,7 @@ void interpolate_bilinear_wrap_fl(const float *buffer,
bool wrap_x,
bool wrap_y)
{
bilinear_fl_impl(buffer, output, width, height, components, u, v, wrap_x, wrap_y);
bilinear_fl_impl<false>(buffer, output, width, height, components, u, v, wrap_x, wrap_y);
}
uchar4 interpolate_bilinear_wrap_byte(const uchar *buffer, int width, int height, float u, float v)
@ -535,9 +577,9 @@ uchar4 interpolate_bilinear_wrap_byte(const uchar *buffer, int width, int height
float uf = floorf(u);
float vf = floorf(v);
int x1 = (int)uf;
int x1 = int(uf);
int x2 = x1 + 1;
int y1 = (int)vf;
int y1 = int(vf);
int y2 = y1 + 1;
/* Wrap interpolation pixels if needed. */
@ -573,7 +615,7 @@ uchar4 interpolate_bilinear_wrap_byte(const uchar *buffer, int width, int height
float4 interpolate_bilinear_wrap_fl(const float *buffer, int width, int height, float u, float v)
{
float4 res;
bilinear_fl_impl(buffer, res, width, height, 4, u, v, true, true);
bilinear_fl_impl<false>(buffer, res, width, height, 4, u, v, true, true);
return res;
}
@ -728,7 +770,7 @@ void BLI_ewa_filter(const int width,
/* Scaling `dxt` / `dyt` by full resolution can cause overflow because of huge A/B/C and esp.
* F values, scaling by aspect ratio alone does the opposite, so try something in between
* instead. */
const float ff2 = (float)width, ff = sqrtf(ff2), q = (float)height / ff;
const float ff2 = float(width), ff = sqrtf(ff2), q = float(height) / ff;
const float Ux = du[0] * ff, Vx = du[1] * q, Uy = dv[0] * ff, Vy = dv[1] * q;
float A = Vx * Vx + Vy * Vy;
float B = -2.0f * (Ux * Vx + Uy * Vy);
@ -770,8 +812,8 @@ void BLI_ewa_filter(const int width,
V0 = uv[1] * float(height);
u1 = int(floorf(U0 - ue));
u2 = int(ceilf(U0 + ue));
v1 = (int)floorf(V0 - ve);
v2 = (int)ceilf(V0 + ve);
v1 = int(floorf(V0 - ve));
v2 = int(ceilf(V0 + ve));
/* sane clamping to avoid unnecessarily huge loops */
/* NOTE: if eccentricity gets clamped (see above),
@ -786,7 +828,7 @@ void BLI_ewa_filter(const int width,
if (V0 - float(v1) > EWA_MAXIDX) {
v1 = int(V0) - EWA_MAXIDX;
}
if ((float)v2 - V0 > EWA_MAXIDX) {
if (float(v2) - V0 > EWA_MAXIDX) {
v2 = int(V0) + EWA_MAXIDX;
}
@ -807,7 +849,7 @@ void BLI_ewa_filter(const int width,
d = 0.0f;
zero_v4(result);
for (v = v1; v <= v2; v++) {
const float V = (float)v - V0;
const float V = float(v) - V0;
float DQ = ac1 + B * V;
float Q = (C * V + BU) * V + ac2;
for (u = u1; u <= u2; u++) {

View File

@ -128,7 +128,7 @@ double BLI_dir_free_space(const char *dir)
GetDiskFreeSpace(tmp, &sectorspc, &bytesps, &freec, &clusters);
return (double)(freec * bytesps * sectorspc);
return double(freec * bytesps * sectorspc);
#else
# ifdef USE_STATFS_STATVFS

View File

@ -1076,7 +1076,7 @@ int BLI_str_utf8_offset_to_column(const char *str, const size_t str_len, const i
while (offset < offset_target_clamp) {
const uint code = BLI_str_utf8_as_unicode_step_safe(str, str_len, &offset);
column += BLI_wcwidth_safe(code);
BLI_assert(offset <= (size_t)offset_target); /* See DOXY section comment. */
BLI_assert(offset <= size_t(offset_target)); /* See DOXY section comment. */
}
return column;
}
@ -1109,7 +1109,7 @@ int BLI_str_utf8_offset_to_column_with_tabs(const char *str,
const uint code = BLI_str_utf8_as_unicode_step_safe(str, str_len, &offset);
/* The following line is the only change compared with #BLI_str_utf8_offset_to_column. */
column += (code == '\t') ? (tab_width - (column % tab_width)) : BLI_wcwidth_safe(code);
BLI_assert(offset <= (size_t)offset_target); /* See DOXY section comment. */
BLI_assert(offset <= size_t(offset_target)); /* See DOXY section comment. */
}
return column;
}

View File

@ -28,10 +28,10 @@ TEST(math_interp, BilinearCharExactSamples)
{
uchar4 res;
uchar4 exp1 = {73, 108, 153, 251};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 1.0f, 2.0f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 1.0f, 2.0f);
EXPECT_EQ(exp1, res);
uchar4 exp2 = {240, 160, 90, 20};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 2.0f, 0.0f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 2.0f, 0.0f);
EXPECT_EQ(exp2, res);
}
@ -39,10 +39,10 @@ TEST(math_interp, BilinearCharHalfwayUSamples)
{
uchar4 res;
uchar4 exp1 = {31, 37, 42, 48};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0.5f, 1.0f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0.5f, 1.0f);
EXPECT_EQ(exp1, res);
uchar4 exp2 = {243, 242, 224, 223};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0.5f, 0.0f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0.5f, 0.0f);
EXPECT_EQ(exp2, res);
}
@ -50,10 +50,10 @@ TEST(math_interp, BilinearCharHalfwayVSamples)
{
uchar4 res;
uchar4 exp1 = {1, 2, 3, 4};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0.0f, 1.5f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0.0f, 1.5f);
EXPECT_EQ(exp1, res);
uchar4 exp2 = {127, 128, 129, 130};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 2.0f, 1.5f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 2.0f, 1.5f);
EXPECT_EQ(exp2, res);
}
@ -61,10 +61,11 @@ TEST(math_interp, BilinearCharSamples)
{
uchar4 res;
uchar4 exp1 = {136, 133, 132, 130};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 1.25f, 0.625f);
res = interpolate_bilinear_border_byte(
image_char[0][0], image_width, image_height, 1.25f, 0.625f);
EXPECT_EQ(exp1, res);
uchar4 exp2 = {219, 191, 167, 142};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 1.4f, 0.1f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 1.4f, 0.1f);
EXPECT_EQ(exp2, res);
}
@ -72,25 +73,39 @@ TEST(math_interp, BilinearFloatSamples)
{
float4 res;
float4 exp1 = {135.9375f, 133.28125f, 131.5625f, 129.84375f};
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 1.25f, 0.625f);
res = interpolate_bilinear_border_fl(image_fl[0][0], image_width, image_height, 1.25f, 0.625f);
EXPECT_V4_NEAR(exp1, res, float_tolerance);
float4 exp2 = {219.36f, 191.2f, 166.64f, 142.08f};
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 1.4f, 0.1f);
res = interpolate_bilinear_border_fl(image_fl[0][0], image_width, image_height, 1.4f, 0.1f);
EXPECT_V4_NEAR(exp2, res, float_tolerance);
}
TEST(math_interp, BilinearCharPartiallyOutsideImageBorder)
{
uchar4 res;
uchar4 exp1 = {1, 1, 2, 2};
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, -0.5f, 2.0f);
EXPECT_EQ(exp1, res);
uchar4 exp2 = {9, 11, 15, 22};
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 1.25f, 2.9f);
EXPECT_EQ(exp2, res);
uchar4 exp3 = {173, 115, 65, 14};
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 2.2f, -0.1f);
EXPECT_EQ(exp3, res);
}
TEST(math_interp, BilinearCharPartiallyOutsideImage)
{
uchar4 res;
uchar4 exp1 = {1, 1, 2, 2};
uint4 exp1 = {1, 2, 3, 4};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, -0.5f, 2.0f);
EXPECT_EQ(exp1, res);
uchar4 exp2 = {9, 11, 15, 22};
EXPECT_EQ(exp1, uint4(res));
uint4 exp2 = {87, 113, 147, 221};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 1.25f, 2.9f);
EXPECT_EQ(exp2, res);
uchar4 exp3 = {173, 115, 65, 14};
EXPECT_EQ(exp2, uint4(res));
uint4 exp3 = {240, 160, 90, 20};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 2.2f, -0.1f);
EXPECT_EQ(exp3, res);
EXPECT_EQ(exp3, uint4(res));
}
TEST(math_interp, BilinearCharPartiallyOutsideImageWrap)
@ -107,16 +122,30 @@ TEST(math_interp, BilinearCharPartiallyOutsideImageWrap)
EXPECT_EQ(exp3, res);
}
TEST(math_interp, BilinearFloatPartiallyOutsideImage)
TEST(math_interp, BilinearFloatPartiallyOutsideImageBorder)
{
float4 res;
float4 exp1 = {0.5f, 1, 1.5f, 2};
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, -0.5f, 2.0f);
res = interpolate_bilinear_border_fl(image_fl[0][0], image_width, image_height, -0.5f, 2.0f);
EXPECT_V4_NEAR(exp1, res, float_tolerance);
float4 exp2 = {8.675f, 11.325f, 14.725f, 22.1f};
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 1.25f, 2.9f);
res = interpolate_bilinear_border_fl(image_fl[0][0], image_width, image_height, 1.25f, 2.9f);
EXPECT_V4_NEAR(exp2, res, float_tolerance);
float4 exp3 = {172.8f, 115.2f, 64.8f, 14.4f};
res = interpolate_bilinear_border_fl(image_fl[0][0], image_width, image_height, 2.2f, -0.1f);
EXPECT_V4_NEAR(exp3, res, float_tolerance);
}
TEST(math_interp, BilinearFloatPartiallyOutsideImage)
{
float4 res;
float4 exp1 = {1.0f, 2.0f, 3.0f, 4.0f};
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, -0.5f, 2.0f);
EXPECT_V4_NEAR(exp1, res, float_tolerance);
float4 exp2 = {86.75f, 113.25f, 147.25f, 221.0f};
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 1.25f, 2.9f);
EXPECT_V4_NEAR(exp2, res, float_tolerance);
float4 exp3 = {240.0f, 160.0f, 90.0f, 20.0f};
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 2.2f, -0.1f);
EXPECT_V4_NEAR(exp3, res, float_tolerance);
}
@ -151,23 +180,23 @@ TEST(math_interp, BilinearCharFullyOutsideImage)
uchar4 res;
uchar4 exp = {0, 0, 0, 0};
/* Out of range on U */
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, -1.5f, 0);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, -1.5f, 0);
EXPECT_EQ(exp, res);
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, -1.1f, 0);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, -1.1f, 0);
EXPECT_EQ(exp, res);
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 3, 0);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 3, 0);
EXPECT_EQ(exp, res);
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 5, 0);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 5, 0);
EXPECT_EQ(exp, res);
/* Out of range on V */
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0, -3.2f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0, -3.2f);
EXPECT_EQ(exp, res);
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0, -1.5f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0, -1.5f);
EXPECT_EQ(exp, res);
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0, 3.1f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0, 3.1f);
EXPECT_EQ(exp, res);
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0, 500.0f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0, 500.0f);
EXPECT_EQ(exp, res);
}

View File

@ -249,17 +249,17 @@ class MemoryBuffer {
single_y = rel_y - last_y;
}
math::interpolate_bilinear_fl(buffer_, out, 1, 1, num_channels_, single_x, single_y);
math::interpolate_bilinear_border_fl(buffer_, out, 1, 1, num_channels_, single_x, single_y);
return;
}
math::interpolate_bilinear_fl(buffer_,
out,
get_width(),
get_height(),
num_channels_,
get_relative_x(x),
get_relative_y(y));
math::interpolate_bilinear_border_fl(buffer_,
out,
get_width(),
get_height(),
num_channels_,
get_relative_x(x),
get_relative_y(y));
}
void read_elem_sampled(float x, float y, PixelSampler sampler, float *out) const

View File

@ -104,7 +104,7 @@ static void sample_image_at_location(ImBuf *ibuf,
imbuf::interpolate_nearest_fl(ibuf, color, x, y);
break;
case PixelSampler::Bilinear:
imbuf::interpolate_bilinear_fl(ibuf, color, x, y);
imbuf::interpolate_bilinear_border_fl(ibuf, color, x, y);
break;
case PixelSampler::Bicubic:
imbuf::interpolate_cubic_bspline_fl(ibuf, color, x, y);
@ -118,7 +118,7 @@ static void sample_image_at_location(ImBuf *ibuf,
byte_color = imbuf::interpolate_nearest_byte(ibuf, x, y);
break;
case PixelSampler::Bilinear:
byte_color = imbuf::interpolate_bilinear_byte(ibuf, x, y);
byte_color = imbuf::interpolate_bilinear_border_byte(ibuf, x, y);
break;
case PixelSampler::Bicubic:
byte_color = imbuf::interpolate_cubic_bspline_byte(ibuf, x, y);

View File

@ -85,7 +85,7 @@ void MovieClipBaseOperation::execute_pixel_sampled(float output[4],
imbuf::interpolate_nearest_fl(ibuf, output, x, y);
break;
case PixelSampler::Bilinear:
imbuf::interpolate_bilinear_fl(ibuf, output, x, y);
imbuf::interpolate_bilinear_border_fl(ibuf, output, x, y);
break;
case PixelSampler::Bicubic:
imbuf::interpolate_cubic_bspline_fl(ibuf, output, x, y);

View File

@ -91,7 +91,7 @@ void MultilayerColorOperation::execute_pixel_sampled(float output[4],
imbuf::interpolate_nearest_fl(buffer_, output, x, y);
break;
case PixelSampler::Bilinear:
imbuf::interpolate_bilinear_fl(buffer_, output, x, y);
imbuf::interpolate_bilinear_border_fl(buffer_, output, x, y);
break;
case PixelSampler::Bicubic:
imbuf::interpolate_cubic_bspline_fl(buffer_, output, x, y);

View File

@ -77,7 +77,8 @@ void RenderLayersProg::do_interpolation(float output[4], float x, float y, Pixel
math::interpolate_nearest_fl(input_buffer_, output, width, height, elementsize_, x, y);
break;
case PixelSampler::Bilinear:
math::interpolate_bilinear_fl(input_buffer_, output, width, height, elementsize_, x, y);
math::interpolate_bilinear_border_fl(
input_buffer_, output, width, height, elementsize_, x, y);
break;
case PixelSampler::Bicubic:
math::interpolate_cubic_bspline_fl(input_buffer_, output, width, height, elementsize_, x, y);

View File

@ -129,8 +129,8 @@ set(LIB
set(GLSL_SRC
shaders/compositor_alpha_crop.glsl
shaders/compositor_bilateral_blur.glsl
shaders/compositor_blur.glsl
shaders/compositor_blur_variable_size.glsl
shaders/compositor_bokeh_blur.glsl
shaders/compositor_bokeh_blur_variable_size.glsl
shaders/compositor_bokeh_image.glsl
shaders/compositor_box_mask.glsl
shaders/compositor_compute_preview.glsl
@ -279,8 +279,8 @@ target_include_directories(bf_compositor_shaders PUBLIC ${CMAKE_CURRENT_BINARY_D
set(SRC_SHADER_CREATE_INFOS
shaders/infos/compositor_alpha_crop_info.hh
shaders/infos/compositor_bilateral_blur_info.hh
shaders/infos/compositor_blur_info.hh
shaders/infos/compositor_blur_variable_size_info.hh
shaders/infos/compositor_bokeh_blur_info.hh
shaders/infos/compositor_bokeh_blur_variable_size_info.hh
shaders/infos/compositor_bokeh_image_info.hh
shaders/infos/compositor_box_mask_info.hh
shaders/infos/compositor_compute_preview_info.hh

View File

@ -4,7 +4,7 @@
#include "gpu_shader_create_info.hh"
GPU_SHADER_CREATE_INFO(compositor_blur)
GPU_SHADER_CREATE_INFO(compositor_bokeh_blur)
.local_group_size(16, 16)
.push_constant(Type::INT, "radius")
.push_constant(Type::BOOL, "extend_bounds")
@ -12,5 +12,5 @@ GPU_SHADER_CREATE_INFO(compositor_blur)
.sampler(1, ImageType::FLOAT_2D, "weights_tx")
.sampler(2, ImageType::FLOAT_2D, "mask_tx")
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
.compute_source("compositor_blur.glsl")
.compute_source("compositor_bokeh_blur.glsl")
.do_static_compilation(true);

View File

@ -4,7 +4,7 @@
#include "gpu_shader_create_info.hh"
GPU_SHADER_CREATE_INFO(compositor_blur_variable_size)
GPU_SHADER_CREATE_INFO(compositor_bokeh_blur_variable_size)
.local_group_size(16, 16)
.push_constant(Type::FLOAT, "base_size")
.push_constant(Type::INT, "search_radius")
@ -13,5 +13,5 @@ GPU_SHADER_CREATE_INFO(compositor_blur_variable_size)
.sampler(2, ImageType::FLOAT_2D, "size_tx")
.sampler(3, ImageType::FLOAT_2D, "mask_tx")
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
.compute_source("compositor_blur_variable_size.glsl")
.compute_source("compositor_bokeh_blur_variable_size.glsl")
.do_static_compilation(true);

View File

@ -71,7 +71,7 @@ LookdevWorld::LookdevWorld()
/* TODO: This works around the issue that the first time the texture is accessed the image would
* overwrite the set GPU texture. A better solution would be to use image data-blocks as part of
* the studio-lights, but that requires a larger refactoring. */
BKE_image_get_gpu_texture(&image, &environment_storage->iuser, nullptr);
BKE_image_get_gpu_texture(&image, &environment_storage->iuser);
/* Create a dummy image data block to hold GPU textures generated by studio-lights. */
STRNCPY(world.id.name, "WOLookdev");

View File

@ -1267,6 +1267,28 @@ float ShadowModule::tilemap_pixel_radius()
return cubeface_diagonal / pixel_count;
}
bool ShadowModule::shadow_update_finished()
{
if (inst_.is_viewport()) {
/* For viewport, only run the shadow update once per redraw.
* This avoids the stall from the readback and freezes from long shadow update. */
return true;
}
int max_updated_view_count = tilemap_pool.tilemaps_data.size();
if (max_updated_view_count <= SHADOW_VIEW_MAX) {
/* There is enough shadow views to cover all tilemap updates.
* No readback needed as it is guaranteed that all of them will be updated. */
return true;
}
/* Read back and check if there is still tile-map to update. */
statistics_buf_.current().read();
ShadowStatistics stats = statistics_buf_.current();
/* Rendering is finished if we rendered all the remaining pages. */
return stats.page_rendered_count == stats.page_update_count;
}
void ShadowModule::set_view(View &view, GPUTexture *depth_tx)
{
if (enabled_ == false) {
@ -1313,8 +1335,7 @@ void ShadowModule::set_view(View &view, GPUTexture *depth_tx)
inst_.hiz_buffer.update();
bool tile_update_remains = true;
while (tile_update_remains) {
do {
DRW_stats_group_start("Shadow");
{
GPU_uniformbuf_clear_to_zero(shadow_multi_view_.matrices_ubo_get());
@ -1369,26 +1390,7 @@ void ShadowModule::set_view(View &view, GPUTexture *depth_tx)
GPU_memory_barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS | GPU_BARRIER_TEXTURE_FETCH);
}
DRW_stats_group_end();
if (inst_.is_viewport()) {
tile_update_remains = false;
}
else {
/* This provoke a GPU/CPU sync. Avoid it if we are sure that all tile-maps will be rendered
* in a single iteration. */
bool enough_tilemap_for_single_iteration = tilemap_pool.tilemaps_data.size() <= fb_layers;
if (enough_tilemap_for_single_iteration) {
tile_update_remains = false;
}
else {
/* Read back and check if there is still tile-map to update. */
tile_update_remains = false;
statistics_buf_.current().read();
ShadowStatistics stats = statistics_buf_.current();
tile_update_remains = stats.page_rendered_count < stats.page_update_count;
}
}
}
} while (!shadow_update_finished());
if (prev_fb) {
GPU_framebuffer_bind(prev_fb);

View File

@ -361,6 +361,7 @@ class ShadowModule {
private:
void remove_unused();
void debug_page_map_call(DRWPass *pass);
bool shadow_update_finished();
/** Compute approximate screen pixel space radius. */
float screen_pixel_radius(const View &view, const int2 &extent);

View File

@ -225,7 +225,7 @@ void VolumeModule::end_sync()
resolve_ps_.shader_set(inst_.shaders.static_shader_get(VOLUME_RESOLVE));
resolve_ps_.bind_resources(inst_.uniform_data);
resolve_ps_.bind_resources(this->result);
resolve_ps_.bind_texture("depth_tx", &inst_.render_buffers.depth_tx);
resolve_ps_.bind_resources(inst_.hiz_buffer.front);
resolve_ps_.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx);
resolve_ps_.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx);
/* Sync with the integration pass. */
@ -277,6 +277,8 @@ void VolumeModule::draw_resolve(View &view)
return;
}
inst_.hiz_buffer.update();
resolve_fb_.ensure(GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_TEXTURE(inst_.render_buffers.combined_tx));
resolve_fb_.bind();

View File

@ -11,8 +11,8 @@
void main()
{
vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depth_tx, 0));
float scene_depth = texture(depth_tx, uvs).r;
vec2 uvs = gl_FragCoord.xy * uniform_buf.volumes.viewport_size_inv;
float scene_depth = texelFetch(hiz_tx, ivec2(gl_FragCoord.xy), 0).r;
VolumeResolveSample vol = volume_resolve(
vec3(uvs, scene_depth), volume_transmittance_tx, volume_scattering_tx);

View File

@ -94,8 +94,8 @@ GPU_SHADER_CREATE_INFO(eevee_volume_resolve)
.additional_info("eevee_volume_lib")
.additional_info("draw_fullscreen")
.additional_info("eevee_render_pass_out")
.additional_info("eevee_hiz_data")
.fragment_source("eevee_volume_resolve_frag.glsl")
.sampler(0, ImageType::DEPTH_2D, "depth_tx")
.fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0)
.fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1)
/** TODO(Miguel Pozo): Volume RenderPasses. */

View File

@ -41,18 +41,11 @@ static GPENCIL_MaterialPool *gpencil_material_pool_add(GPENCIL_PrivateData *pd)
static GPUTexture *gpencil_image_texture_get(Image *image, bool *r_alpha_premult)
{
ImBuf *ibuf;
ImageUser iuser = {nullptr};
GPUTexture *gpu_tex = nullptr;
void *lock;
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
if (ibuf != nullptr && ibuf->byte_buffer.data != nullptr) {
gpu_tex = BKE_image_get_gpu_texture(image, &iuser, ibuf);
*r_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL);
}
BKE_image_release_ibuf(image, ibuf, lock);
gpu_tex = BKE_image_get_gpu_texture(image, &iuser);
*r_alpha_premult = (gpu_tex) ? (image->alpha_mode == IMA_ALPHA_PREMUL) : false;
return gpu_tex;
}

View File

@ -89,10 +89,8 @@ class MaterialModule {
/* Returns the correct flag for this texture. */
gpMaterialFlag texture_sync(::Image *image, gpMaterialFlag use_flag, gpMaterialFlag premul_flag)
{
ImBuf *ibuf;
ImageUser iuser = {nullptr};
GPUTexture *gpu_tex = nullptr;
void *lock;
bool premul = false;
if (image == nullptr) {
@ -100,13 +98,10 @@ class MaterialModule {
return GP_FLAG_NONE;
}
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
if (ibuf != nullptr) {
gpu_tex = BKE_image_get_gpu_texture(image, &iuser, ibuf);
gpu_tex = BKE_image_get_gpu_texture(image, &iuser);
if (gpu_tex) {
premul = (image->alpha_mode == IMA_ALPHA_PREMUL) != 0;
}
BKE_image_release_ibuf(image, ibuf, lock);
texture_pool_.append(gpu_tex);

View File

@ -354,24 +354,15 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata)
if (pd->edit_uv.do_stencil_overlay) {
const Brush *brush = BKE_paint_brush(&ts->imapaint.paint);
::Image *stencil_image = brush->clone.image;
ImBuf *stencil_ibuf = BKE_image_acquire_ibuf(
stencil_image, nullptr, &pd->edit_uv.stencil_lock);
GPUTexture *stencil_texture = BKE_image_get_gpu_texture(stencil_image, nullptr);
if (stencil_ibuf == nullptr) {
pd->edit_uv.stencil_ibuf = nullptr;
pd->edit_uv.stencil_image = nullptr;
}
else {
if (stencil_texture != nullptr) {
DRW_PASS_CREATE(psl->edit_uv_stencil_ps,
DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS |
DRW_STATE_BLEND_ALPHA_PREMUL);
GPUShader *sh = OVERLAY_shader_edit_uv_stencil_image();
GPUBatch *geom = DRW_cache_quad_get();
DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->edit_uv_stencil_ps);
pd->edit_uv.stencil_ibuf = stencil_ibuf;
pd->edit_uv.stencil_image = stencil_image;
GPUTexture *stencil_texture = BKE_image_get_gpu_texture(
stencil_image, nullptr, stencil_ibuf);
DRW_shgroup_uniform_texture(grp, "imgTexture", stencil_texture);
DRW_shgroup_uniform_bool_copy(grp, "imgPremultiplied", true);
DRW_shgroup_uniform_bool_copy(grp, "imgAlphaBlend", true);
@ -380,7 +371,8 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata)
float size_image[2];
BKE_image_get_size_fl(image, nullptr, size_image);
float size_stencil_image[2] = {float(stencil_ibuf->x), float(stencil_ibuf->y)};
float size_stencil_image[2] = {float(GPU_texture_original_width(stencil_texture)),
float(GPU_texture_original_height(stencil_texture))};
float obmat[4][4];
unit_m4(obmat);
@ -392,10 +384,6 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_call_obmat(grp, geom, obmat);
}
}
else {
pd->edit_uv.stencil_ibuf = nullptr;
pd->edit_uv.stencil_image = nullptr;
}
if (pd->edit_uv.do_mask_overlay) {
const bool is_combined_overlay = pd->edit_uv.mask_overlay_mode == MASK_OVERLAY_COMBINED;
@ -545,13 +533,6 @@ static void OVERLAY_edit_uv_draw_finish(OVERLAY_Data *vedata)
OVERLAY_StorageList *stl = vedata->stl;
OVERLAY_PrivateData *pd = stl->pd;
if (pd->edit_uv.stencil_ibuf) {
BKE_image_release_ibuf(
pd->edit_uv.stencil_image, pd->edit_uv.stencil_ibuf, pd->edit_uv.stencil_lock);
pd->edit_uv.stencil_image = nullptr;
pd->edit_uv.stencil_ibuf = nullptr;
}
DRW_TEXTURE_FREE_SAFE(pd->edit_uv.mask_texture);
}

View File

@ -129,7 +129,6 @@ static GPUTexture *image_camera_background_texture_get(CameraBGImage *bgpic,
bool *r_use_alpha_premult,
bool *r_use_view_transform)
{
void *lock;
Image *image = bgpic->ima;
ImageUser *iuser = &bgpic->iuser;
MovieClip *clip = nullptr;
@ -158,22 +157,16 @@ static GPUTexture *image_camera_background_texture_get(CameraBGImage *bgpic,
camera_background_images_stereo_setup(scene, draw_ctx->v3d, image, iuser);
iuser->scene = draw_ctx->scene;
ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, &lock);
if (ibuf == nullptr) {
BKE_image_release_ibuf(image, ibuf, lock);
iuser->scene = nullptr;
return nullptr;
}
width = ibuf->x;
height = ibuf->y;
tex = BKE_image_get_gpu_texture(image, iuser, ibuf);
BKE_image_release_ibuf(image, ibuf, lock);
tex = BKE_image_get_gpu_viewer_texture(image, iuser);
iuser->scene = nullptr;
if (tex == nullptr) {
return nullptr;
}
width = GPU_texture_original_width(tex);
height = GPU_texture_original_height(tex);
aspect_x = bgpic->ima->aspx;
aspect_y = bgpic->ima->aspy;
break;
@ -381,7 +374,7 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob)
if (ima != nullptr) {
ImageUser iuser = *ob->iuser;
camera_background_images_stereo_setup(draw_ctx->scene, draw_ctx->v3d, ima, &iuser);
tex = BKE_image_get_gpu_texture(ima, &iuser, nullptr);
tex = BKE_image_get_gpu_texture(ima, &iuser);
if (tex) {
size[0] = GPU_texture_original_width(tex);
size[1] = GPU_texture_original_height(tex);

View File

@ -139,7 +139,7 @@ void OVERLAY_paint_cache_init(OVERLAY_Data *vedata)
state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
GPUTexture *tex = BKE_image_get_gpu_texture(imapaint->stencil, nullptr, nullptr);
GPUTexture *tex = BKE_image_get_gpu_texture(imapaint->stencil, nullptr);
const bool mask_premult = (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL);
const bool mask_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0;

View File

@ -409,11 +409,6 @@ struct OVERLAY_PrivateData {
ListBase totals;
float total_area_ratio;
/* stencil overlay */
Image *stencil_image;
ImBuf *stencil_ibuf;
void *stencil_lock;
/* mask overlay */
Mask *mask;
eMaskOverlayMode mask_overlay_mode;

View File

@ -66,27 +66,19 @@ PassMain::Sub &MeshPass::get_subpass(
is_empty_ = false;
if (image) {
GPUTexture *texture = nullptr;
GPUTexture *tilemap = nullptr;
if (image->source == IMA_SRC_TILED) {
texture = BKE_image_get_gpu_tiles(image, iuser);
tilemap = BKE_image_get_gpu_tilemap(image, iuser);
}
else {
texture = BKE_image_get_gpu_texture(image, iuser, nullptr);
}
if (texture) {
ImageGPUTextures gputex = BKE_image_get_gpu_material_texture(image, iuser, true);
if (gputex.texture) {
auto add_cb = [&] {
PassMain::Sub *sub_pass = passes_[int(geometry_type)][int(eShaderType::TEXTURE)];
sub_pass = &sub_pass->sub(image->id.name);
if (tilemap) {
sub_pass->bind_texture(WB_TILE_ARRAY_SLOT, texture, sampler_state);
sub_pass->bind_texture(WB_TILE_DATA_SLOT, tilemap);
if (gputex.tile_mapping) {
sub_pass->bind_texture(WB_TILE_ARRAY_SLOT, gputex.texture, sampler_state);
sub_pass->bind_texture(WB_TILE_DATA_SLOT, gputex.tile_mapping);
}
else {
sub_pass->bind_texture(WB_TEXTURE_SLOT, texture, sampler_state);
sub_pass->bind_texture(WB_TEXTURE_SLOT, gputex.texture, sampler_state);
}
sub_pass->push_constant("isImageTile", tilemap != nullptr);
sub_pass->push_constant("isImageTile", gputex.tile_mapping != nullptr);
sub_pass->push_constant("imagePremult", image && image->alpha_mode == IMA_ALPHA_PREMUL);
/* TODO(@pragma37): This setting should be exposed on the user side,
* either as a global parameter (and set it here)
@ -99,8 +91,8 @@ PassMain::Sub &MeshPass::get_subpass(
return sub_pass;
};
return *texture_subpass_map_.lookup_or_add_cb(TextureSubPassKey(texture, geometry_type),
add_cb);
return *texture_subpass_map_.lookup_or_add_cb(
TextureSubPassKey(gputex.texture, geometry_type), add_cb);
}
}

View File

@ -1803,18 +1803,15 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, GPUMaterial *mater
/* Bind all textures needed by the material. */
LISTBASE_FOREACH (GPUMaterialTexture *, tex, &textures) {
if (tex->ima) {
/* Image */
GPUTexture *gputex;
const bool use_tile_mapping = tex->tiled_mapping_name[0];
ImageUser *iuser = tex->iuser_available ? &tex->iuser : nullptr;
if (tex->tiled_mapping_name[0]) {
gputex = BKE_image_get_gpu_tiles(tex->ima, iuser);
drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
gputex = BKE_image_get_gpu_tilemap(tex->ima, iuser);
drw_shgroup_material_texture(grp, gputex, tex->tiled_mapping_name, tex->sampler_state);
}
else {
gputex = BKE_image_get_gpu_texture(tex->ima, iuser, nullptr);
drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
ImageGPUTextures gputex = BKE_image_get_gpu_material_texture(
tex->ima, iuser, use_tile_mapping);
drw_shgroup_material_texture(grp, gputex.texture, tex->sampler_name, tex->sampler_state);
if (gputex.tile_mapping) {
drw_shgroup_material_texture(
grp, gputex.tile_mapping, tex->tiled_mapping_name, tex->sampler_state);
}
}
else if (tex->colorband) {

View File

@ -923,20 +923,17 @@ template<class T> inline void PassBase<T>::material_set(Manager &manager, GPUMat
for (GPUMaterialTexture *tex : ListBaseWrapper<GPUMaterialTexture>(textures)) {
if (tex->ima) {
/* Image */
const bool use_tile_mapping = tex->tiled_mapping_name[0];
ImageUser *iuser = tex->iuser_available ? &tex->iuser : nullptr;
if (tex->tiled_mapping_name[0]) {
GPUTexture *tiles = BKE_image_get_gpu_tiles(tex->ima, iuser);
manager.acquire_texture(tiles);
bind_texture(tex->sampler_name, tiles, tex->sampler_state);
ImageGPUTextures gputex = BKE_image_get_gpu_material_texture(
tex->ima, iuser, use_tile_mapping);
GPUTexture *tile_map = BKE_image_get_gpu_tilemap(tex->ima, iuser);
manager.acquire_texture(tile_map);
bind_texture(tex->tiled_mapping_name, tile_map, tex->sampler_state);
}
else {
GPUTexture *texture = BKE_image_get_gpu_texture(tex->ima, iuser, nullptr);
manager.acquire_texture(texture);
bind_texture(tex->sampler_name, texture, tex->sampler_state);
manager.acquire_texture(gputex.texture);
bind_texture(tex->sampler_name, gputex.texture, tex->sampler_state);
if (gputex.tile_mapping) {
manager.acquire_texture(gputex.tile_mapping);
bind_texture(tex->tiled_mapping_name, gputex.tile_mapping, tex->sampler_state);
}
}
else if (tex->colorband) {

View File

@ -1381,7 +1381,7 @@ static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, PropertyRNA *
char type_id[MAX_ID_NAME - 2];
RNA_property_string_get(op->ptr, prop, type_id);
if (strcmp(type_id, "__ACTIVE__") == 0) {
if (STREQ(type_id, "__ACTIVE__")) {
ks = ANIM_keyingset_get_from_enum_type(scene, scene->active_keyingset);
}
else {

View File

@ -135,6 +135,7 @@ static int bone_collection_add_exec(bContext *C, wmOperator * /*op*/)
}
ANIM_armature_bonecoll_active_set(armature, bcoll);
/* TODO: ensure the ancestors of the new bone collection are all expanded. */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
return OPERATOR_FINISHED;

View File

@ -97,6 +97,11 @@ static void undoarm_to_editarm(UndoArmature *uarm, bArmature *arm)
ED_armature_ebone_listbase_temp_clear(arm->edbo);
/* Before freeing the old bone collections, copy their 'expanded' flag. This
* flag is not supposed to be restored with any undo steps. */
bonecolls_copy_expanded_flag(blender::Span(uarm->collection_array, uarm->collection_array_num),
arm->collections_span());
/* Copy bone collections. */
ANIM_bonecoll_array_free(&arm->collection_array, &arm->collection_array_num, true);
auto bcoll_map = ANIM_bonecoll_array_copy_no_membership(&arm->collection_array,

View File

@ -514,6 +514,7 @@ set(ICON_NAMES
ipo_ease_in_out
normalize_fcurves
orientation_parent
face_corner
vertexsel
edgesel
facesel
@ -611,6 +612,7 @@ set(ICON_NAMES
outliner_ob_volume
outliner_data_volume
volume_data
pointcloud_point
current_file
home
documents
@ -694,6 +696,9 @@ set(ICON_NAMES
handle_aligned
handle_vector
handle_free
view_camera_unselected
view_unlocked
view_locked
view_perspective
view_ortho
view_camera

View File

@ -527,8 +527,8 @@ static bool gpencil_frame_snap_cframe(bGPDframe *gpf, Scene *scene)
static bool gpencil_frame_snap_nearmarker(bGPDframe *gpf, Scene *scene)
{
if (gpf->flag & GP_FRAME_SELECT) {
gpf->framenum = (int)ED_markers_find_nearest_marker_time(&scene->markers,
float(gpf->framenum));
gpf->framenum = int(
ED_markers_find_nearest_marker_time(&scene->markers, float(gpf->framenum)));
}
return false;
}

View File

@ -620,7 +620,7 @@ DEF_ICON(IPO_EASE_OUT)
DEF_ICON(IPO_EASE_IN_OUT)
DEF_ICON(NORMALIZE_FCURVES)
DEF_ICON(ORIENTATION_PARENT)
DEF_ICON_BLANK(636)
DEF_ICON(FACE_CORNER)
DEF_ICON_BLANK(637)
DEF_ICON_BLANK(638)
@ -746,7 +746,7 @@ DEF_ICON_OBJECT_DATA(POINTCLOUD_DATA)
DEF_ICON_OBJECT(OUTLINER_OB_VOLUME)
DEF_ICON_OBJECT_DATA(OUTLINER_DATA_VOLUME)
DEF_ICON_OBJECT_DATA(VOLUME_DATA)
DEF_ICON_BLANK(267)
DEF_ICON_OBJECT_DATA(POINTCLOUD_POINT)
DEF_ICON_BLANK(268)
DEF_ICON_BLANK(269)
DEF_ICON_BLANK(270)
@ -867,9 +867,9 @@ DEF_ICON(HANDLE_AUTO)
DEF_ICON(HANDLE_ALIGNED)
DEF_ICON(HANDLE_VECTOR)
DEF_ICON(HANDLE_FREE)
DEF_ICON_BLANK(882)
DEF_ICON_BLANK(883)
DEF_ICON_BLANK(884)
DEF_ICON(VIEW_CAMERA_UNSELECTED)
DEF_ICON(VIEW_UNLOCKED)
DEF_ICON(VIEW_LOCKED)
DEF_ICON(VIEW_PERSPECTIVE)
DEF_ICON(VIEW_ORTHO)
DEF_ICON(VIEW_CAMERA)

View File

@ -1144,7 +1144,7 @@ uiBut *uiDefButO_ptr(uiBlock *block,
int type,
wmOperatorType *ot,
wmOperatorCallContext opcontext,
const char *str,
blender::StringRef str,
int x,
int y,
short width,
@ -1381,7 +1381,7 @@ uiBut *uiDefIconTextButO(uiBlock *block,
const char *opname,
wmOperatorCallContext opcontext,
int icon,
const char *str,
blender::StringRef str,
int x,
int y,
short width,
@ -1392,7 +1392,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block,
wmOperatorType *ot,
wmOperatorCallContext opcontext,
int icon,
const char *str,
blender::StringRef str,
int x,
int y,
short width,

View File

@ -198,8 +198,22 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
std::optional<rctf> get_win_rect(const ARegion &region) const;
void begin_renaming();
void toggle_collapsed();
void set_collapsed(bool collapsed);
/**
* Toggle the expanded/collapsed state.
*
* \note this does not call #on_collapse_change().
* \returns true when the collapsed state was changed, false otherwise.
*/
bool toggle_collapsed();
/**
* Expand or collapse this tree view item.
*
* \note this does not call #on_collapse_change().
* \returns true when the collapsed state was changed, false otherwise.
*/
virtual bool set_collapsed(bool collapsed);
/**
* Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
* can't be sure about the item state.
@ -207,6 +221,19 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
bool is_collapsed() const;
bool is_collapsible() const;
/**
* Called when the view changes an item's state from expanded to collapsed, or vice versa. Will
* only be called if the state change is triggered through the view, not through external
* changes. E.g. a click on an item calls it, a change in the value returned by
* #should_be_collapsed() to reflect an external state change does not.
*/
virtual void on_collapse_change(bContext &C, bool is_collapsed);
/**
* If the result is not empty, it controls whether the item should be collapsed or not, usually
* depending on the data that the view represents.
*/
virtual std::optional<bool> should_be_collapsed() const;
protected:
/** See AbstractViewItem::get_rename_string(). */
/* virtual */ StringRef get_rename_string() const override;
@ -219,6 +246,13 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
*/
virtual bool supports_collapsing() const;
/**
* Toggle the collapsed/expanded state, and call on_collapse_change() if it changed.
*/
void toggle_collapsed_from_view(bContext &C);
void change_state_delayed() override;
/** See #AbstractViewItem::matches(). */
/* virtual */ bool matches(const AbstractViewItem &other) const override;

View File

@ -4779,24 +4779,13 @@ static uiBut *ui_def_but_operator_ptr(uiBlock *block,
int type,
wmOperatorType *ot,
wmOperatorCallContext opcontext,
const char *str,
const StringRef str,
int x,
int y,
short width,
short height,
const char *tip)
{
std::string operator_name;
if (!str) {
if (ot && ot->srna) {
operator_name = WM_operatortype_name(ot, nullptr);
str = operator_name.c_str();
}
else {
str = "";
}
}
if ((!tip || tip[0] == '\0') && ot && ot->srna && !ot->get_description) {
tip = RNA_struct_ui_description(ot->srna);
}
@ -4806,9 +4795,8 @@ static uiBut *ui_def_but_operator_ptr(uiBlock *block,
but->opcontext = opcontext;
but->flag &= ~UI_BUT_UNDO; /* no need for ui_but_is_rna_undo(), we never need undo here */
const bool has_label = str && str[0];
/* Enable quick tooltip label if this is a tool button without a label. */
if (!has_label && !ui_block_is_popover(block) && UI_but_is_tool(but)) {
if (str.is_empty() && !ui_block_is_popover(block) && UI_but_is_tool(but)) {
UI_but_drawflag_enable(but, UI_BUT_HAS_TOOLTIP_LABEL);
}
@ -5319,7 +5307,7 @@ uiBut *uiDefButO_ptr(uiBlock *block,
int type,
wmOperatorType *ot,
wmOperatorCallContext opcontext,
const char *str,
const StringRef str,
int x,
int y,
short width,
@ -5774,7 +5762,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block,
wmOperatorType *ot,
wmOperatorCallContext opcontext,
int icon,
const char *str,
const StringRef str,
int x,
int y,
short width,
@ -5791,7 +5779,7 @@ uiBut *uiDefIconTextButO(uiBlock *block,
const char *opname,
wmOperatorCallContext opcontext,
int icon,
const char *str,
const StringRef str,
int x,
int y,
short width,
@ -5799,7 +5787,7 @@ uiBut *uiDefIconTextButO(uiBlock *block,
const char *tip)
{
wmOperatorType *ot = WM_operatortype_find(opname, false);
if (str && str[0] == '\0') {
if (str.is_empty()) {
return uiDefIconButO_ptr(block, type, ot, opcontext, icon, x, y, width, height, tip);
}
return uiDefIconTextButO_ptr(block, type, ot, opcontext, icon, str, x, y, width, height, tip);

View File

@ -38,6 +38,8 @@ class BoneCollectionTreeView : public AbstractTreeView {
explicit BoneCollectionTreeView(bArmature &armature);
void build_tree() override;
bool listen(const wmNotifier &notifier) const override;
private:
void build_tree_node_recursive(TreeViewItemContainer &parent, const int bcoll_index);
@ -281,6 +283,37 @@ class BoneCollectionItem : public AbstractTreeViewItem {
ED_undo_push(&const_cast<bContext &>(C), "Change Armature's Active Bone Collection");
}
std::optional<bool> should_be_collapsed() const override
{
const bool is_collapsed = !bone_collection_.is_expanded();
return is_collapsed;
}
bool set_collapsed(const bool collapsed) override
{
if (!AbstractTreeViewItem::set_collapsed(collapsed)) {
return false;
}
/* Ensure that the flag in DNA is set. */
ANIM_armature_bonecoll_is_expanded_set(&bone_collection_, !collapsed);
return true;
}
void on_collapse_change(bContext &C, const bool is_collapsed) override
{
const bool is_expanded = !is_collapsed;
/* Let RNA handle the property change. This makes sure all the notifiers and DEG
* update calls are properly called. */
PointerRNA bcoll_ptr = RNA_pointer_create(
&armature_.id, &RNA_BoneCollection, &bone_collection_);
PropertyRNA *prop = RNA_struct_find_property(&bcoll_ptr, "is_expanded");
RNA_property_boolean_set(&bcoll_ptr, prop, is_expanded);
RNA_property_update(&C, &bcoll_ptr, prop);
}
bool supports_renaming() const override
{
return ANIM_armature_bonecoll_is_editable(&armature_, &bone_collection_);
@ -351,8 +384,6 @@ void BoneCollectionTreeView::build_tree_node_recursive(TreeViewItemContainer &pa
const bool has_any_selected_bones = bcolls_with_selected_bones_.contains(bcoll);
BoneCollectionItem &bcoll_tree_item = parent.add_tree_item<BoneCollectionItem>(
armature_, bcoll_index, has_any_selected_bones);
bcoll_tree_item.set_collapsed(false);
for (int child_index = bcoll->child_index; child_index < bcoll->child_index + bcoll->child_count;
child_index++)
{
@ -360,6 +391,11 @@ void BoneCollectionTreeView::build_tree_node_recursive(TreeViewItemContainer &pa
}
}
bool BoneCollectionTreeView::listen(const wmNotifier &notifier) const
{
return notifier.data == ND_BONE_COLLECTION;
}
void BoneCollectionTreeView::build_bcolls_with_selected_bones()
{
bcolls_with_selected_bones_.clear();

View File

@ -5961,17 +5961,16 @@ void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propn
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but = uiDefIconTextButO(block,
UI_BTYPE_BUT,
"UI_OT_eyedropper_color",
WM_OP_INVOKE_DEFAULT,
icon,
"",
0,
0,
UI_UNIT_X,
UI_UNIT_Y,
RNA_property_ui_description(prop));
uiBut *but = uiDefIconButO(block,
UI_BTYPE_BUT,
"UI_OT_eyedropper_color",
WM_OP_INVOKE_DEFAULT,
icon,
0,
0,
UI_UNIT_X,
UI_UNIT_Y,
RNA_property_ui_description(prop));
but->rnapoin = *ptr;
but->rnaprop = prop;
but->rnaindex = -1;

View File

@ -354,7 +354,7 @@ void AbstractTreeViewItem::collapse_chevron_click_fn(bContext *C,
AbstractTreeViewItem *hovered_item = from_item_handle<AbstractTreeViewItem>(hovered_item_handle);
BLI_assert(hovered_item != nullptr);
hovered_item->toggle_collapsed();
hovered_item->toggle_collapsed_from_view(*C);
/* When collapsing an item with an active child, make this collapsed item active instead so the
* active item stays visible. */
if (hovered_item->has_active_child()) {
@ -504,24 +504,63 @@ bool AbstractTreeViewItem::is_collapsed() const
return is_collapsible() && !is_open_;
}
void AbstractTreeViewItem::toggle_collapsed()
bool AbstractTreeViewItem::toggle_collapsed()
{
is_open_ = !is_open_;
return set_collapsed(is_open_);
}
void AbstractTreeViewItem::set_collapsed(const bool collapsed)
bool AbstractTreeViewItem::set_collapsed(const bool collapsed)
{
if (!is_collapsible()) {
return false;
}
if (collapsed == is_collapsed()) {
return false;
}
is_open_ = !collapsed;
return true;
}
bool AbstractTreeViewItem::is_collapsible() const
{
BLI_assert_msg(get_tree_view().is_reconstructed(),
"State can't be queried until reconstruction is completed");
if (children_.is_empty()) {
return false;
}
return this->supports_collapsing();
}
void AbstractTreeViewItem::on_collapse_change(bContext & /*C*/, const bool /*is_collapsed*/)
{
/* Do nothing by default. */
}
std::optional<bool> AbstractTreeViewItem::should_be_collapsed() const
{
return std::nullopt;
}
void AbstractTreeViewItem::toggle_collapsed_from_view(bContext &C)
{
if (toggle_collapsed()) {
on_collapse_change(C, is_collapsed());
}
}
void AbstractTreeViewItem::change_state_delayed()
{
AbstractViewItem::change_state_delayed();
const std::optional<bool> should_be_collapsed = this->should_be_collapsed();
if (should_be_collapsed.has_value()) {
/* This reflects an external state change and therefore shouldn't call #on_collapse_change().
*/
set_collapsed(*should_be_collapsed);
}
}
void AbstractTreeViewItem::ensure_parents_uncollapsed()
{
for (AbstractTreeViewItem *parent = parent_; parent; parent = parent->parent_) {

View File

@ -1458,17 +1458,18 @@ static void file_draw_invalid_asset_library_hint(const bContext *C,
sx + UI_UNIT_X, sy, suggestion, width - UI_UNIT_X, line_height, text_col, nullptr, &sy);
uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
uiBut *but = uiDefIconTextButO(block,
UI_BTYPE_BUT,
"SCREEN_OT_userpref_show",
WM_OP_INVOKE_DEFAULT,
ICON_PREFERENCES,
nullptr,
sx + UI_UNIT_X,
sy - line_height - UI_UNIT_Y * 1.2f,
UI_UNIT_X * 8,
UI_UNIT_Y,
nullptr);
wmOperatorType *ot = WM_operatortype_find("SCREEN_OT_userpref_show", false);
uiBut *but = uiDefIconTextButO_ptr(block,
UI_BTYPE_BUT,
ot,
WM_OP_INVOKE_DEFAULT,
ICON_PREFERENCES,
WM_operatortype_name(ot, nullptr),
sx + UI_UNIT_X,
sy - line_height - UI_UNIT_Y * 1.2f,
UI_UNIT_X * 8,
UI_UNIT_Y,
nullptr);
PointerRNA *but_opptr = UI_but_operator_ptr_ensure(but);
RNA_enum_set(but_opptr, "section", USER_SECTION_FILE_PATHS);

View File

@ -2627,7 +2627,8 @@ static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent * /*event
/* Better for user feedback. */
RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME));
return WM_operator_props_dialog_popup(C, op, 300);
return WM_operator_props_dialog_popup(
C, op, 300, IFACE_("Create a New Image"), IFACE_("New Image"));
}
static void image_new_draw(bContext * /*C*/, wmOperator *op)

View File

@ -357,7 +357,6 @@ float2 node_from_view(const bNode &node, const float2 &co)
{
const float2 node_location = co / UI_SCALE_FAC;
return bke::nodeFromView(&node, node_location);
;
}
static bool is_node_panels_supported(const bNode &node)

View File

@ -138,7 +138,7 @@ class GeometryDataSetTreeView : public ui::AbstractTreeView {
mesh.add_tree_item<GeometryDataSetTreeViewItem>(bke::GeometryComponent::Type::Mesh,
bke::AttrDomain::Corner,
IFACE_("Face Corner"),
ICON_NODE_CORNER);
ICON_FACE_CORNER);
GeometryDataSetTreeViewItem &curve = this->add_tree_item<GeometryDataSetTreeViewItem>(
bke::GeometryComponent::Type::Curve, IFACE_("Curve"), ICON_CURVE_DATA);
@ -158,7 +158,7 @@ class GeometryDataSetTreeView : public ui::AbstractTreeView {
pointcloud.add_tree_item<GeometryDataSetTreeViewItem>(bke::GeometryComponent::Type::PointCloud,
bke::AttrDomain::Point,
IFACE_("Point"),
ICON_PARTICLE_POINT);
ICON_POINTCLOUD_POINT);
this->add_tree_item<GeometryDataSetTreeViewItem>(
bke::GeometryComponent::Type::Volume, IFACE_("Volume Grids"), ICON_VOLUME_DATA);

View File

@ -2455,7 +2455,7 @@ static int text_jump_exec(bContext *C, wmOperator *op)
static int text_jump_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
{
return WM_operator_props_dialog_popup(C, op, 200);
return WM_operator_props_dialog_popup(C, op, 200, IFACE_("Jump to Line Number"));
}
void TEXT_OT_jump(wmOperatorType *ot)

View File

@ -6,8 +6,10 @@ set(INC
../include
../../blenkernel
../../blenloader
../../blentranslation
../../makesrna
../../windowmanager
../../../../extern/fmtlib/include
)

View File

@ -7,6 +7,7 @@
*/
#include <cstring>
#include <fmt/format.h>
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@ -15,6 +16,7 @@
#ifdef WIN32
# include "BLI_winstuff.h"
#endif
#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "BKE_callbacks.h"
@ -24,6 +26,8 @@
#include "BKE_report.h"
#include "BLT_translation.h"
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_types.hh"
@ -238,21 +242,42 @@ static void PREFERENCES_OT_asset_library_remove(wmOperatorType *ot)
/** \name Add Extension Repository Operator
* \{ */
enum class bUserExtensionRepoAddType {
Online = 0,
Local = 1,
};
static int preferences_extension_repo_add_exec(bContext *C, wmOperator *op)
{
char name[FILE_MAXFILE];
char directory[FILE_MAX];
const bUserExtensionRepoAddType repo_type = bUserExtensionRepoAddType(
RNA_enum_get(op->ptr, "type"));
Main *bmain = CTX_data_main(C);
BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_PRE);
RNA_string_get(op->ptr, "directory", directory);
BLI_path_slash_rstrip(directory);
char name[sizeof(bUserExtensionRepo::name)];
char custom_directory[FILE_MAX] = "";
BLI_path_split_file_part(directory, name, sizeof(name));
const bool use_custom_directory = RNA_boolean_get(op->ptr, "use_custom_directory");
RNA_string_get(op->ptr, "name", name);
const char *module = name;
bUserExtensionRepo *new_repo = BKE_preferences_extension_repo_add(&U, name, module, directory);
if (use_custom_directory) {
RNA_string_get(op->ptr, "custom_directory", custom_directory);
BLI_path_slash_rstrip(custom_directory);
}
const char *module = custom_directory[0] ? BLI_path_basename(custom_directory) : name;
bUserExtensionRepo *new_repo = BKE_preferences_extension_repo_add(
&U, name, module, custom_directory);
if (use_custom_directory) {
new_repo->flag |= USER_EXTENSION_REPO_FLAG_USE_CUSTOM_DIRECTORY;
}
if (repo_type == bUserExtensionRepoAddType::Online) {
RNA_string_get(op->ptr, "remote_path", new_repo->remote_path);
new_repo->flag |= USER_EXTENSION_REPO_FLAG_USE_REMOTE_PATH;
}
/* Activate new repository in the UI for further setup. */
U.active_extension_repo = BLI_findindex(&U.extension_repos, new_repo);
@ -266,16 +291,49 @@ static int preferences_extension_repo_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static int preferences_extension_repo_add_invoke(bContext *C,
wmOperator *op,
const wmEvent * /*event*/)
static int preferences_extension_repo_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (!RNA_struct_property_is_set(op->ptr, "directory")) {
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
const bUserExtensionRepoAddType repo_type = bUserExtensionRepoAddType(
RNA_enum_get(op->ptr, "type"));
PropertyRNA *prop_name = RNA_struct_find_property(op->ptr, "name");
if (!RNA_property_is_set(op->ptr, prop_name)) {
const char *name_default = nullptr;
if (repo_type == bUserExtensionRepoAddType::Online) {
name_default = "Online Repository";
}
else {
name_default = "User Repository";
}
RNA_property_string_set(op->ptr, prop_name, name_default);
}
return preferences_extension_repo_add_exec(C, op);
return WM_operator_props_popup_confirm(C, op, event);
}
static bool preferences_extension_repo_add_poll_property(const bContext * /*C*/,
wmOperator *op,
const PropertyRNA *prop)
{
PointerRNA *ptr = op->ptr;
const char *prop_id = RNA_property_identifier(prop);
const bUserExtensionRepoAddType repo_type = bUserExtensionRepoAddType(RNA_enum_get(ptr, "type"));
/* Only show remote_path for remote repositories. */
if (STREQ(prop_id, "remote_path")) {
if (repo_type != bUserExtensionRepoAddType::Online) {
return false;
}
}
if (STREQ(prop_id, "custom_directory")) {
if (!RNA_boolean_get(ptr, "use_custom_directory")) {
return false;
}
}
/* Else, show it! */
return true;
}
static void PREFERENCES_OT_extension_repo_add(wmOperatorType *ot)
@ -284,18 +342,52 @@ static void PREFERENCES_OT_extension_repo_add(wmOperatorType *ot)
ot->idname = "PREFERENCES_OT_extension_repo_add";
ot->description = "Add a directory to be used as a local extension repository";
ot->exec = preferences_extension_repo_add_exec;
ot->invoke = preferences_extension_repo_add_invoke;
ot->exec = preferences_extension_repo_add_exec;
ot->poll_property = preferences_extension_repo_add_poll_property;
ot->flag = OPTYPE_INTERNAL;
ot->flag = OPTYPE_INTERNAL | OPTYPE_REGISTER;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER,
FILE_SPECIAL,
FILE_OPENFILE,
WM_FILESEL_DIRECTORY,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
static const EnumPropertyItem repo_type_items[] = {
{int(bUserExtensionRepoAddType::Online),
"ONLINE",
ICON_WORLD,
"Add Online Repository",
"Add a repository referencing an remote repository "
"with support for listing and updating extensions"},
{int(bUserExtensionRepoAddType::Local),
"LOCAL",
ICON_DISK_DRIVE,
"Add Local Repository",
"Add a repository managed manually without referencing an external repository"},
{0, nullptr, 0, nullptr, nullptr},
};
PropertyRNA *prop;
prop = RNA_def_string(ot->srna, "name", nullptr, sizeof(bUserExtensionRepo::name), "Name", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_string(
ot->srna, "remote_path", nullptr, sizeof(bUserExtensionRepo::remote_path), "URL", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "use_custom_directory", false, "Custom Directory", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
/* WARNING: `RNA_def_string_dir_path` should be used but the file selector crashes from
* #WM_operator_props_popup_confirm as it closes the popup before showing the file-selector. */
prop = RNA_def_string(ot->srna,
"custom_directory",
nullptr,
sizeof(bUserExtensionRepo::remote_path),
"Directory",
"");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
ot->prop = RNA_def_enum(
ot->srna, "type", repo_type_items, 0, "Type", "The kind of repository to add");
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
/** \} */
@ -304,6 +396,11 @@ static void PREFERENCES_OT_extension_repo_add(wmOperatorType *ot)
/** \name Remove Extension Repository Operator
* \{ */
enum class bUserExtensionRepoRemoveType {
RepoOnly = 0,
RepoWithDirectory = 1,
};
static bool preferences_extension_repo_remove_poll(bContext *C)
{
if (BLI_listbase_is_empty(&U.extension_repos)) {
@ -313,9 +410,49 @@ static bool preferences_extension_repo_remove_poll(bContext *C)
return true;
}
static int preferences_extension_repo_remove_invoke(bContext *C,
wmOperator *op,
const wmEvent * /*event*/)
{
const int index = RNA_int_get(op->ptr, "index");
bUserExtensionRepoRemoveType repo_type = bUserExtensionRepoRemoveType(
RNA_enum_get(op->ptr, "type"));
bUserExtensionRepo *repo = static_cast<bUserExtensionRepo *>(
BLI_findlink(&U.extension_repos, index));
if (!repo) {
return OPERATOR_CANCELLED;
}
std::string message;
if (repo_type == bUserExtensionRepoRemoveType::RepoWithDirectory) {
char dirpath[FILE_MAX];
BKE_preferences_extension_repo_dirpath_get(repo, dirpath, sizeof(dirpath));
if (dirpath[0]) {
message = fmt::format(IFACE_("Remove all files in \"{}\"."), dirpath);
}
else {
message = IFACE_("Remove, local files not found.");
repo_type = bUserExtensionRepoRemoveType::RepoOnly;
}
}
else {
message = IFACE_("Remove, keeping local files.");
}
const char *confirm_text = (repo_type == bUserExtensionRepoRemoveType::RepoWithDirectory) ?
IFACE_("Remove Repository & Files") :
IFACE_("Remove Repository");
return WM_operator_confirm_ex(
C, op, nullptr, message.c_str(), confirm_text, ALERT_ICON_WARNING, true);
}
static int preferences_extension_repo_remove_exec(bContext *C, wmOperator *op)
{
const int index = RNA_int_get(op->ptr, "index");
const bUserExtensionRepoRemoveType repo_type = bUserExtensionRepoRemoveType(
RNA_enum_get(op->ptr, "type"));
bUserExtensionRepo *repo = static_cast<bUserExtensionRepo *>(
BLI_findlink(&U.extension_repos, index));
if (!repo) {
@ -325,6 +462,19 @@ static int preferences_extension_repo_remove_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_PRE);
if (repo_type == bUserExtensionRepoRemoveType::RepoWithDirectory) {
char dirpath[FILE_MAX];
BKE_preferences_extension_repo_dirpath_get(repo, dirpath, sizeof(dirpath));
if (dirpath[0] && BLI_is_dir(dirpath)) {
if (BLI_delete(dirpath, true, true) != 0) {
BKE_reportf(op->reports,
RPT_ERROR,
"Error removing directory: %s",
errno ? strerror(errno) : "unknown");
}
}
}
BKE_preferences_extension_repo_remove(&U, repo);
const int count_remaining = BLI_listbase_count(&U.extension_repos);
/* Update active repo index to be in range. */
@ -345,12 +495,27 @@ static void PREFERENCES_OT_extension_repo_remove(wmOperatorType *ot)
ot->idname = "PREFERENCES_OT_extension_repo_remove";
ot->description = "Remove an extension repository";
ot->invoke = preferences_extension_repo_remove_invoke;
ot->exec = preferences_extension_repo_remove_exec;
ot->poll = preferences_extension_repo_remove_poll;
ot->flag = OPTYPE_INTERNAL;
static const EnumPropertyItem repo_type_items[] = {
{int(bUserExtensionRepoRemoveType::RepoOnly), "REPO_ONLY", 0, "Remove Repository"},
{int(bUserExtensionRepoRemoveType::RepoWithDirectory),
"REPO_AND_DIRECTORY",
0,
"Remove Repository & Files",
"Delete all associated local files when removing"},
{0, nullptr, 0, nullptr, nullptr},
};
RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
ot->prop = RNA_def_enum(
ot->srna, "type", repo_type_items, 0, "Type", "Method for removing the repository");
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
/** \} */

View File

@ -1462,7 +1462,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *panel)
UI_BTYPE_BUT,
ot,
WM_OP_EXEC_DEFAULT,
"Normalize",
IFACE_("Normalize"),
0,
yco,
UI_UNIT_X * 5,
@ -1478,7 +1478,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *panel)
UI_BTYPE_BUT,
ot,
WM_OP_EXEC_DEFAULT,
"Copy",
IFACE_("Copy"),
UI_UNIT_X * 5,
yco,
UI_UNIT_X * 5,

View File

@ -53,47 +53,82 @@ enum {
/* overlaps GZ_INDEX_ORTHO (switch between) */
GZ_INDEX_PERSP = 3,
GZ_INDEX_ORTHO = 4,
GZ_INDEX_CAMERA = 5,
GZ_INDEX_TOTAL = 6,
GZ_INDEX_CAMERA_OFF = 5,
GZ_INDEX_CAMERA_ON = 6,
GZ_INDEX_CAMERA_LOCK = 7,
GZ_INDEX_CAMERA_UNLOCK = 8,
GZ_INDEX_TOTAL = 9,
};
struct NavigateGizmoInfo {
const char *opname;
const char *gizmo;
uint icon;
void (*op_prop_fn)(PointerRNA *ptr);
};
static void navigate_context_toggle_camera_lock_init(PointerRNA *ptr)
{
RNA_string_set(ptr, "data_path", "space_data.lock_camera");
}
static NavigateGizmoInfo g_navigate_params[GZ_INDEX_TOTAL] = {
{
"VIEW3D_OT_move",
"GIZMO_GT_button_2d",
ICON_VIEW_PAN,
nullptr,
},
{
"VIEW3D_OT_rotate",
"VIEW3D_GT_navigate_rotate",
ICON_NONE,
nullptr,
},
{
"VIEW3D_OT_zoom",
"GIZMO_GT_button_2d",
ICON_VIEW_ZOOM,
nullptr,
},
{
"VIEW3D_OT_view_persportho",
"GIZMO_GT_button_2d",
ICON_VIEW_PERSPECTIVE,
nullptr,
},
{
"VIEW3D_OT_view_persportho",
"GIZMO_GT_button_2d",
ICON_VIEW_ORTHO,
nullptr,
},
{
"VIEW3D_OT_view_camera",
"GIZMO_GT_button_2d",
ICON_VIEW_CAMERA_UNSELECTED,
nullptr,
},
{
"VIEW3D_OT_view_camera",
"GIZMO_GT_button_2d",
ICON_VIEW_CAMERA,
nullptr,
},
{
"WM_OT_context_toggle",
"GIZMO_GT_button_2d",
ICON_VIEW_LOCKED,
navigate_context_toggle_camera_lock_init,
},
{
"WM_OT_context_toggle",
"GIZMO_GT_button_2d",
ICON_VIEW_UNLOCKED,
navigate_context_toggle_camera_lock_init,
},
};
@ -106,6 +141,7 @@ struct NavigateWidgetGroup {
char is_persp;
bool is_camera;
char viewlock;
char cameralock;
} rv3d;
} state;
};
@ -171,17 +207,29 @@ static void WIDGETGROUP_navigate_setup(const bContext *C, wmGizmoGroup *gzgroup)
}
wmOperatorType *ot = WM_operatortype_find(info->opname, true);
WM_gizmo_operator_set(gz, 0, ot, nullptr);
PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot, NULL);
if (info->op_prop_fn != NULL) {
info->op_prop_fn(ptr);
}
}
{
wmGizmo *gz = navgroup->gz_array[GZ_INDEX_CAMERA];
wmGizmo *gz = navgroup->gz_array[GZ_INDEX_CAMERA_OFF];
WM_gizmo_operator_set(gz, 0, ot_view_camera, nullptr);
}
{
wmGizmo *gz = navgroup->gz_array[GZ_INDEX_CAMERA_ON];
WM_gizmo_operator_set(gz, 0, ot_view_camera, nullptr);
}
/* Click only buttons (not modal). */
{
int gz_ids[] = {GZ_INDEX_PERSP, GZ_INDEX_ORTHO, GZ_INDEX_CAMERA};
int gz_ids[] = {GZ_INDEX_PERSP,
GZ_INDEX_ORTHO,
GZ_INDEX_CAMERA_OFF,
GZ_INDEX_CAMERA_ON,
GZ_INDEX_CAMERA_LOCK,
GZ_INDEX_CAMERA_UNLOCK};
for (int i = 0; i < ARRAY_SIZE(gz_ids); i++) {
wmGizmo *gz = navgroup->gz_array[gz_ids[i]];
RNA_boolean_set(gz->ptr, "show_drag", false);
@ -229,6 +277,7 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
NavigateWidgetGroup *navgroup = static_cast<NavigateWidgetGroup *>(gzgroup->customdata);
ARegion *region = CTX_wm_region(C);
const RegionView3D *rv3d = static_cast<const RegionView3D *>(region->regiondata);
const View3D *v3d = CTX_wm_view3d(C);
for (int i = 0; i < 3; i++) {
copy_v3_v3(navgroup->gz_array[GZ_INDEX_ROTATE]->matrix_offset[i], rv3d->viewmat[i]);
@ -243,6 +292,7 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
(navgroup->state.rect_visible.ymax == rect_visible->ymax) &&
(navgroup->state.rv3d.is_persp == rv3d->is_persp) &&
(navgroup->state.rv3d.is_camera == (rv3d->persp == RV3D_CAMOB)) &&
(navgroup->state.rv3d.cameralock == (v3d->flag2 & V3D_LOCK_CAMERA)) &&
(navgroup->state.rv3d.viewlock == RV3D_LOCK_FLAGS(rv3d)))
{
return;
@ -252,6 +302,7 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
navgroup->state.rv3d.is_persp = rv3d->is_persp;
navgroup->state.rv3d.is_camera = (rv3d->persp == RV3D_CAMOB);
navgroup->state.rv3d.viewlock = RV3D_LOCK_FLAGS(rv3d);
navgroup->state.rv3d.cameralock = v3d->flag2 & V3D_LOCK_CAMERA;
const bool show_navigate = (U.uiflag & USER_SHOW_GIZMO_NAVIGATE) != 0;
const bool show_rotate_gizmo = (U.mini_axis_type == USER_MINI_AXIS_TYPE_GIZMO);
@ -311,7 +362,8 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
}
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
gz = navgroup->gz_array[GZ_INDEX_CAMERA];
gz = navgroup
->gz_array[(rv3d->persp == RV3D_CAMOB) ? GZ_INDEX_CAMERA_ON : GZ_INDEX_CAMERA_OFF];
gz->matrix_basis[3][0] = roundf(co[0]);
gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++));
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
@ -323,6 +375,14 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
}
if (navgroup->state.rv3d.is_camera == true) {
gz = navgroup->gz_array[(v3d->flag2 & V3D_LOCK_CAMERA) ? GZ_INDEX_CAMERA_LOCK :
GZ_INDEX_CAMERA_UNLOCK];
gz->matrix_basis[3][0] = roundf(co[0]);
gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++));
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
}
}

View File

@ -202,4 +202,4 @@ void smooth_curve_attribute(const IndexMask &curves_to_smooth,
});
}
} // namespace blender::geometry
} // namespace blender::geometry

View File

@ -83,7 +83,7 @@ void GPU_storagebuf_copy_sub_from_vertbuf(
/**
* Ensure the ssbo is ready to be used as an indirect buffer in `GPU_batch_draw_indirect`.
* NOTE: Internallly, this is only required for the OpenGL backend.
* NOTE: Internally, this is only required for the OpenGL backend.
*/
void GPU_storagebuf_sync_as_indirect_buffer(GPUStorageBuf *ssbo);

View File

@ -69,7 +69,7 @@ class GLContext : public Context {
static bool generate_mipmap_workaround;
static float derivative_signs[2];
/** VBO for missing vertex attrib binding. Avoid undefined behavior on some implementation. */
/** VBO for missing vertex attribute binding. Avoid undefined behavior on some implementation. */
GLuint default_attr_vbo_;
/** Used for debugging purpose. Bitflags of all bound slots. */

Some files were not shown because too many files have changed in this diff Show More