Brush Assets: Support adding shortcut to asset shelf items #117861

Merged
Hans Goudey merged 15 commits from HooglyBoogly/blender:brush-assets-shortcut into brush-assets-project 2024-02-07 19:02:47 +01:00
123 changed files with 1487 additions and 569 deletions
Showing only changes of commit ef64b454c0 - 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