WIP: Field type inferencing using a constraint solver method #120420

Draft
Lukas Tönne wants to merge 52 commits from LukasTonne/blender:socket-type-inference into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
83 changed files with 1223 additions and 904 deletions
Showing only changes of commit 8f71366ba7 - Show all commits

View File

@ -473,6 +473,8 @@ endfunction()
# Ninja only: assign 'heavy pool' to some targets that are especially RAM-consuming to build.
function(setup_heavy_lib_pool)
if(WITH_NINJA_POOL_JOBS AND NINJA_MAX_NUM_PARALLEL_COMPILE_HEAVY_JOBS)
set(_HEAVY_LIBS)
set(_TARGET)
if(WITH_CYCLES)
list(APPEND _HEAVY_LIBS "cycles_device" "cycles_kernel")
endif()
@ -483,11 +485,13 @@ function(setup_heavy_lib_pool)
list(APPEND _HEAVY_LIBS "bf_intern_openvdb")
endif()
foreach(TARGET ${_HEAVY_LIBS})
if(TARGET ${TARGET})
set_property(TARGET ${TARGET} PROPERTY JOB_POOL_COMPILE compile_heavy_job_pool)
foreach(_TARGET ${_HEAVY_LIBS})
if(TARGET ${_TARGET})
set_property(TARGET ${_TARGET} PROPERTY JOB_POOL_COMPILE compile_heavy_job_pool)
endif()
endforeach()
unset(_TARGET)
unset(_HEAVY_LIBS)
endif()
endfunction()

View File

@ -44,17 +44,36 @@
inkscape:window-width="1920"
inkscape:window-height="1009"
id="namedview34335"
showgrid="false"
inkscape:zoom="1"
inkscape:cx="455.5"
inkscape:cy="342.5"
showgrid="true"
inkscape:zoom="5.6568544"
inkscape:cx="347.80814"
inkscape:cy="81.052113"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer8"
inkscape:showpageshadow="2"
inkscape:deskcolor="#808080"
showguides="true" />
showguides="true"
guidecolor="#c34e00"
guideopacity="0.6">
<inkscape:grid
id="grid1"
units="px"
originx="0"
originy="0"
spacingx="1"
spacingy="1"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
dotted="false"
gridanglex="30"
gridanglez="30"
visible="true" />
</sodipodi:namedview>
<defs
id="defs4" />
<g
@ -7348,25 +7367,6 @@
id="path10253"
inkscape:connector-curvature="0" />
</g>
<g
id="g37394"
inkscape:label="DA-19"
style="display:inline;enable-background:new">
<path
inkscape:connector-curvature="0"
id="path12791-5"
d="m 385,621 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z m 0,5 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z m 0,5 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-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:2;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" />
<rect
style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
id="rect21004-5-8-0-0"
width="18"
height="18"
x="381.99985"
y="-636"
transform="scale(1,-1)"
inkscape:label="frame" />
</g>
<g
id="g37409"
inkscape:label="DA-18"
@ -8182,20 +8182,6 @@
id="path27669-6-3"
inkscape:connector-curvature="0" />
</g>
<g
id="g13413"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
style="display:inline;fill:#ffffff;enable-background:new"
inkscape:label="BA-23">
<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.5;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 475.5,579 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z m 0,5 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z m 0,5 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z"
id="ellipse12367"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssssssssss" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
id="g18361"
@ -13152,46 +13138,6 @@
id="path28715"
inkscape:connector-curvature="0" />
</g>
<g
id="g6603"
style="display:inline;fill:#ffffff;enable-background:new"
inkscape:label="O-12">
<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:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 237.49219,305 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 1 0 1,0 V 306 h 3 v 12 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -1.5 v -12 h 3 v 1.5 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 7,6 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 V 312 h 2 v 6 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -6 h 2 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
id="path6924-7"
inkscape:connector-curvature="0" />
</g>
<g
id="g120719"
style="display:inline;enable-background:new"
inkscape:label="O-11">
<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:accumulate"
d="m 216.49219,305 a 0.50005,0.50005 0 1 0 0,1 H 218 v 6.00391 c 0,2.19985 1.79782,3.99206 4,3.99609 h 1 a 0.50005,0.50005 0 0 0 0.002,0 c 2.20199,-0.005 3.998,-1.79624 3.998,-3.99609 V 306 h 1.49219 a 0.50005,0.50005 0 1 0 0,-1 h -4 a 0.50005,0.50005 0 1 0 0,1 H 226 v 6.00391 c 0,1.65832 -1.33799,2.99265 -3.00195,2.99609 H 222 c -1.66382,-0.003 -3,-1.33777 -3,-2.99609 V 306 h 1.49219 a 0.50005,0.50005 0 1 0 0,-1 z m 1,13 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z"
id="path10901"
inkscape:connector-curvature="0" />
</g>
<g
id="g120716"
style="display:inline;enable-background:new"
inkscape:label="O-10">
<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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 201.49219,305 a 0.50005,0.50005 0 1 0 0,1 h 2.5039 l -0.002,0.14258 -4.95898,11.4082 a 0.50005,0.50005 0 0 0 -0.041,0.21289 L 199,318 h -2.50781 a 0.50005,0.50005 0 1 0 0,1 h 6 a 0.50005,0.50005 0 1 0 0,-1 H 200 a 0.50005,0.50005 0 0 0 0,-0.0137 l -0.004,-0.13867 4.95508,-11.39844 a 0.50005,0.50005 0 0 0 0.041,-0.19141 L 204.99609,306 h 2.4961 a 0.50005,0.50005 0 1 0 0,-1 z"
id="path10892"
inkscape:connector-curvature="0" />
</g>
<g
id="g120740"
style="display:inline;enable-background:new"
inkscape:label="O-9">
<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:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 177,305 a 1.0001,1.0001 0 0 0 -1,1 v 5.83203 a 1.0001,1.0001 0 0 0 0,0.32617 V 318 a 1.0001,1.0001 0 0 0 1,1 h 6 c 2.19729,0 4,-1.80271 4,-4 0,-1.76747 -1.1852,-3.22799 -2.78516,-3.75195 C 184.67235,310.59788 185,309.84948 185,309 c 0,-2.19729 -1.80271,-4 -4,-4 z m 1,2 h 3 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 h -3 z m 0,6 h 3 2 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 h -5 z"
id="path10949"
inkscape:connector-curvature="0" />
</g>
<g
id="g60277"
inkscape:label="O-8">
@ -15525,27 +15471,6 @@
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccc" />
</g>
<g
id="g158053"
style="display:inline;enable-background:new"
inkscape:label="J-2">
<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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 33.75,200 c -0.212514,-4.2e-4 -0.402079,0.13353 -0.472656,0.33398 L 31.644531,205 H 27.5 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 0.75 c 4.22e-4,0.17006 0.08724,0.32824 0.230469,0.41992 l 3.166015,2.03711 -1.367187,3.87695 c -0.01909,0.0533 -0.029,0.10942 -0.0293,0.16602 v 0.75 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 0.75 c 0.119714,-2e-5 0.235448,-0.043 0.326172,-0.12109 L 33.935547,211 h 0.128906 l 3.359375,2.87891 c 0.09174,0.079 0.209022,0.12201 0.330078,0.12109 L 38.5,213.99414 c 0.273087,-0.002 0.49394,-0.223 0.496094,-0.49609 L 39,212.75195 c -7.9e-5,-0.0572 -0.01,-0.11407 -0.0293,-0.16797 l -1.367187,-3.87695 3.166015,-2.03711 C 40.912757,206.57824 40.999577,206.42006 41,206.25 v -0.75 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 h -4.144531 l -1.632813,-4.66602 C 34.652079,200.13353 34.462514,199.99958 34.25,200 h -0.251953 z"
id="path14398"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccc" />
</g>
<g
id="g158056"
style="display:inline;enable-background:new"
inkscape:label="J-1">
<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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 12.75,200 a 0.50004997,0.50004997 0 0 0 -0.472656,0.33398 L 10.644531,205 H 6.5 A 0.50004997,0.50004997 0 0 0 6,205.5 v 0.75 a 0.50004997,0.50004997 0 0 0 0.2304688,0.41992 l 3.1660156,2.03711 -1.3671875,3.87695 A 0.50004997,0.50004997 0 0 0 8,212.75 v 0.75 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 0.75 a 0.50004997,0.50004997 0 0 0 0.3261719,-0.12109 L 12.935547,211 h 0.128906 l 3.359375,2.87891 A 0.50004997,0.50004997 0 0 0 16.753906,214 L 17.5,213.99414 a 0.50004997,0.50004997 0 0 0 0.496094,-0.49609 L 18,212.75195 a 0.50004997,0.50004997 0 0 0 -0.0293,-0.16797 l -1.367187,-3.87695 3.166015,-2.03711 A 0.50004997,0.50004997 0 0 0 20,206.25 V 205.5 A 0.50004997,0.50004997 0 0 0 19.5,205 h -4.144531 l -1.632813,-4.66602 A 0.50004997,0.50004997 0 0 0 13.25,200 h -0.251953 z m 0.25,1.30078 1.527344,4.36524 A 0.50004997,0.50004997 0 0 0 15,206 h 3.962891 l -3.232422,2.08008 a 0.50004997,0.50004997 0 0 0 -0.201172,0.58594 L 17,212.83398 l -0.002,0.16407 h -0.06445 l -3.357422,-2.87696 A 0.50004997,0.50004997 0 0 0 13.25,210 h -0.5 a 0.50004997,0.50004997 0 0 0 -0.326172,0.12109 L 9.0644531,213 H 9 v -0.16406 l 1.470703,-4.16992 a 0.50004997,0.50004997 0 0 0 -0.201172,-0.58594 L 7.0371094,206 H 11 a 0.50004997,0.50004997 0 0 0 0.472656,-0.33398 z"
id="path14401"
inkscape:connector-curvature="0" />
</g>
<g
id="g6932"
style="display:inline;fill:#ffffff;enable-background:new"
@ -17728,35 +17653,6 @@
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccc" />
</g>
<g
id="g34174"
style="display:inline;enable-background:new"
inkscape:label="D-17">
<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:new"
d="M 355.49219,73.992188 A 0.50004994,0.50004994 0 0 0 355,74.5 v 3.792969 l -2.11914,-2.117188 a 0.50004994,0.50004994 0 0 0 -0.0234,-0.02539 c -10e-4,-0.0015 -0.002,-0.0024 -0.004,-0.0039 a 0.50004994,0.50004994 0 0 0 -0.1875,-0.121093 c -1.78999,-1.727877 -3.76997,-2.331734 -5.85938,-1.875 -2.1873,0.478135 -3.98484,2.053048 -4.77539,4.175781 a 0.50004994,0.50004994 0 1 0 0.9375,0.347656 c 0.67415,-1.810183 2.19925,-3.142137 4.05078,-3.546875 1.87803,-0.410528 3.46011,0.02939 5.12305,1.722656 a 0.50004994,0.50004994 0 0 0 0.002,0.002 0.50004994,0.50004994 0 0 0 0.002,0.002 0.50004994,0.50004994 0 0 0 0.0332,0.03125 L 354.29297,79 H 350.5 a 0.50004994,0.50004994 0 1 0 0,1 h 5 a 0.50004994,0.50004994 0 0 0 0.5,-0.5 v -5 a 0.50004994,0.50004994 0 0 0 -0.50781,-0.507812 z"
id="path13235"
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: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"
d="m 342.49805,81.992188 a 0.50004994,0.50004994 0 0 0 -0.5,0.5 v 5 a 0.50004994,0.50004994 0 1 0 1,0 v -3.792969 l 2.11914,2.11914 a 0.50004994,0.50004994 0 0 0 0.0234,0.02539 l 0.004,0.002 c 7.2e-4,7.3e-4 0.001,0.0012 0.002,0.002 a 0.50004994,0.50004994 0 0 0 0.18555,0.121094 c 1.78998,1.727877 3.76997,2.331734 5.85938,1.875 2.1873,-0.478136 3.98484,-2.053048 4.77539,-4.175781 a 0.50028327,0.50028327 0 1 0 -0.9375,-0.34961 c -0.67415,1.810184 -2.19925,3.14409 -4.05078,3.548829 -1.87804,0.410528 -3.46011,-0.03135 -5.12305,-1.72461 a 0.50004994,0.50004994 0 0 0 -0.004,-0.0039 l -0.0332,-0.03125 -2.11328,-2.115234 h 3.79297 a 0.50004994,0.50004994 0 1 0 0,-1 z"
id="path13252"
inkscape:connector-curvature="0" />
</g>
<g
id="g12536"
transform="matrix(0,1,1,0,270,-183)"
style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:label="D-16">
<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 261.49023,51.996094 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707032 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 L 258.70703,57 H 268.5 c 0.83435,0 1.5,0.665651 1.5,1.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 c 0,-1.374789 -1.12521,-2.5 -2.5,-2.5 h -9.79297 l 3.14649,-3.146484 a 0.50005,0.50005 0 0 0 -0.36329,-0.857422 z"
id="path12534"
inkscape:connector-curvature="0" />
</g>
<g
id="g25642"
transform="translate(-63,-20)"
@ -17883,31 +17779,6 @@
id="path14614"
inkscape:connector-curvature="0" />
</g>
<g
id="g34180"
style="display:inline;enable-background:new"
inkscape:label="D-2">
<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 30.474609,74.994141 a 0.50004997,0.50004997 0 0 0 -0.40625,0.757812 L 33.128906,81 H 27.5 a 0.50004997,0.50004997 0 1 0 0,1 h 5.628906 l -3.060547,5.248047 a 0.50004997,0.50004997 0 1 0 0.863282,0.503906 L 34,82.492188 l 3.068359,5.259765 a 0.50004997,0.50004997 0 1 0 0.863282,-0.503906 L 34.871094,82 H 40.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -5.628906 l 3.060547,-5.248047 A 0.50004997,0.50004997 0 1 0 37.068359,75.248047 L 34,80.507812 30.931641,75.248047 a 0.50004997,0.50004997 0 0 0 -0.457032,-0.253906 z"
id="path14603"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
id="g14591"
inkscape:label="D-1">
<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:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 9.25,74 a 0.50005,0.50005 0 0 0 -0.4765625,0.351562 l -2.75,8.820313 A 0.50005,0.50005 0 0 0 6,83.320312 v 0.173829 a 0.50005,0.50005 0 1 0 1,0 v -0.09766 L 7.7460938,81 A 0.50005,0.50005 0 0 0 7.75,81 h 3.5 a 0.50005,0.50005 0 0 0 0.0039,0 L 12,83.396484 v 0.09766 a 0.50005,0.50005 0 1 0 1,0 v -0.173829 a 0.50005,0.50005 0 0 0 -0.02344,-0.148437 l -2.75,-8.820313 A 0.50005,0.50005 0 0 0 9.75,74 Z M 9.5,75.375 10.941406,80 H 8.0585938 Z"
id="path14584"
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: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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 14.5,79 a 0.50005,0.50005 0 1 0 0,1 H 19 v 0.08008 l -4.896484,6.365234 A 0.50005,0.50005 0 0 0 14,86.75 v 0.75 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5 a 0.50005,0.50005 0 1 0 0,-1 H 15 v -0.08008 l 4.896484,-6.365234 A 0.50005,0.50005 0 0 0 20,80.25 V 79.5 A 0.50005,0.50005 0 0 0 19.5,79 Z"
id="path14589"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;enable-background:new"
id="g27713"
@ -18115,46 +17986,6 @@
id="path28601-3" />
</g>
</g>
<g
id="g41646"
style="display:inline;enable-background:new"
inkscape:label="C-17">
<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 350.50195,56 a 0.50005,0.50005 0 0 0 -0.34765,0.859375 l 3.14648,3.146484 h -10.79297 a 0.50005,0.50005 0 1 0 0,1 h 10.79297 l -3.14648,3.146485 a 0.50005,0.50005 0 1 0 0.70703,0.707031 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.707031 l -4,-4 A 0.50005,0.50005 0 0 0 350.50195,56 Z"
id="path9970"
inkscape:connector-curvature="0" />
</g>
<g
id="g41643"
style="display:inline;enable-background:new"
inkscape:label="C-16">
<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 326.49023,56 a 0.50005,0.50005 0 0 0 -0.34375,0.152344 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707031 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707031 l -3.14649,-3.146485 H 334.5 a 0.50005,0.50005 0 1 0 0,-1 h -10.79297 l 3.14649,-3.146484 A 0.50005,0.50005 0 0 0 326.49023,56 Z"
id="path12420"
inkscape:connector-curvature="0" />
</g>
<g
id="g41649"
style="display:inline;enable-background:new"
inkscape:label="C-15">
<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:new"
d="m 309.49414,52.994141 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 L 312.29297,57 H 305 c -2.7555,0 -5,2.244499 -5,5 0,2.755501 2.2445,5 5,5 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 305 c -2.21506,0 -4,-1.784939 -4,-4 0,-2.215061 1.78494,-4 4,-4 h 7.29297 l -3.14649,3.146484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.707032 l -4,-4 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z"
id="path13229"
inkscape:connector-curvature="0" />
</g>
<g
id="g41652"
style="display:inline;enable-background:new"
inkscape:label="C-14">
<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:new"
d="m 283.49023,52.996094 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707032 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 L 280.70703,58 H 288 c 2.21506,0 4,1.784939 4,4 0,2.215061 -1.78494,4 -4,4 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 c 2.7555,0 5,-2.244499 5,-5 0,-2.755501 -2.2445,-5 -5,-5 h -7.29297 l 3.14649,-3.146484 a 0.50005,0.50005 0 0 0 -0.36329,-0.857422 z"
id="path13225"
inkscape:connector-curvature="0" />
</g>
<g
transform="translate(-189,-42)"
style="display:inline;fill:#ffffff;enable-background:new"
@ -18164,11 +17995,6 @@
id="g17552-8"
transform="matrix(-1,0,0,1,508,-7e-5)"
style="fill:#ffffff">
<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 201.49219,94.998047 a 0.50005,0.50005 0 0 0 -0.38867,0.195312 0.50005,0.50005 0 0 0 -0.006,0.0059 l -3.95118,3.953125 a 0.50005,0.50005 0 1 0 0.70704,0.707031 L 201,96.712891 v 8.792969 a 0.50005,0.50005 0 1 0 1,0 v -8.792969 l 3.14648,3.146484 a 0.50005,0.50005 0 1 0 0.70704,-0.707031 l -3.95508,-3.955078 a 0.50005,0.50005 0 0 0 -0.40625,-0.199219 z"
id="path14327-2"
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.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:accumulate"
d="M 195.49219,104.99219 A 0.50005,0.50005 0 0 0 195,105.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 2.5 h -11 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
@ -18179,11 +18005,6 @@
id="g17548-0"
transform="matrix(-1,0,0,1,508,-7e-5)"
style="fill:#ffffff">
<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 222.49219,95.005859 A 0.50005,0.50005 0 0 0 222,95.511719 v 8.792971 l -3.14648,-3.14649 a 0.50005,0.50005 0 1 0 -0.70704,0.70703 l 3.95704,3.95704 a 0.50005,0.50005 0 0 0 0.79296,0.002 0.50005,0.50005 0 0 0 0.004,-0.006 l 3.95313,-3.95313 a 0.50005,0.50005 0 1 0 -0.70704,-0.70703 L 223,104.30469 v -8.792971 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
id="path14329-2"
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.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:accumulate"
d="M 216.49219,104.99219 A 0.50005,0.50005 0 0 0 216,105.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 2.5 h -11 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
@ -18244,26 +18065,6 @@
inkscape:connector-curvature="0" />
</g>
</g>
<g
id="g41658"
style="display:inline;enable-background:new"
inkscape:label="C-3">
<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 34.492188,54.005859 A 0.50005,0.50005 0 0 0 34,54.511719 v 9.792969 l -3.146484,-3.146485 a 0.50005,0.50005 0 1 0 -0.707032,0.707031 l 4,4 a 0.50005,0.50005 0 0 0 0.707032,0 l 4,-4 A 0.50005,0.50005 0 1 0 38.146484,61.158203 L 35,64.304688 v -9.792969 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z"
id="path14329"
inkscape:connector-curvature="0" />
</g>
<g
id="g41655"
style="display:inline;enable-background:new"
inkscape:label="C-2">
<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 13.492188,54.005859 a 0.50005,0.50005 0 0 0 -0.345704,0.146485 l -3.9999996,4 a 0.50005,0.50005 0 1 0 0.7070312,0.707031 L 13,55.712891 v 9.792968 a 0.50005,0.50005 0 1 0 1,0 v -9.792968 l 3.146484,3.146484 a 0.50005,0.50005 0 1 0 0.707032,-0.707031 l -4,-4 a 0.50005,0.50005 0 0 0 -0.361328,-0.146485 z"
id="path14327"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;stroke-width:1.14286;enable-background:new"
id="g13938"
@ -18405,7 +18206,7 @@
</g>
</g>
<g
transform="translate(-231.007,-588)"
transform="translate(-231.507,-587.9375)"
id="g23192-6"
style="display:inline;fill:#ffffff;enable-background:new"
inkscape:export-filename="blender_icons.png"
@ -18443,34 +18244,6 @@
id="path12541-0"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
id="g6750-7"
transform="translate(-315,-567)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:label="B-15">
<rect
y="598"
x="614"
height="16"
width="16"
id="rect6732-0"
style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1;stroke-opacity:1;marker:none" />
<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:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 618.74609,599 a 0.50005,0.50005 0 0 0 -0.48437,0.37695 l -3.2461,12.75 A 0.50005,0.50005 0 0 0 615,612.25 v 0.25 a 0.50005,0.50005 0 1 0 1,0 v -0.1875 l 0.84961,-3.33398 A 0.50005,0.50005 0 0 0 617,609 h 4 a 0.50005,0.50005 0 0 0 0.14844,-0.0195 h 0.002 L 622,612.3125 V 612.5 a 0.50005,0.50005 0 1 0 1,0 v -0.25 a 0.50005,0.50005 0 0 0 -0.0156,-0.12305 l -3.25391,-12.75 A 0.50005,0.50005 0 0 0 619.24609,599 Z m 0.25,1.54492 1.90235,7.45508 h -3.80078 z"
id="path6736-8"
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: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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 310,45 v -5 h 1.5 c 0.83481,0 1.5,0.664144 1.5,1.498047 v 2.007812 c 0,0.833914 -0.66519,1.498047 -1.5,1.496094 z m 4,-1.494141 V 41.498047 C 314,40.122764 312.87431,39 311.5,39 H 310 v -6.5 c 0.004,-0.28226 -0.22555,-0.512233 -0.50781,-0.507812 C 309.21605,31.996188 308.99568,32.22386 309,32.5 v 13 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 l 2,0.002 c 1.37431,0.002 2.5,-1.120801 2.5,-2.496094 z"
transform="translate(315,567)"
id="path6744-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsccccccsccccccccc" />
</g>
<g
id="g49131"
style="display:inline;enable-background:new"
@ -19393,6 +19166,305 @@
d=""
inkscape:connector-curvature="0" />
</g>
<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;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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 12.740433,201.30788 c -0.212514,-4.1e-4 -0.402079,0.13353 -0.472656,0.33398 l -1.367188,3.35353 H 7.5060583 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 0.75 c 4.22e-4,0.17006 0.08724,0.32824 0.230469,0.41992 l 2.247932,1.72997 -0.980354,2.66847 c -0.01909,0.0533 -0.029,0.10942 -0.0293,0.16602 v 0.75 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 0.75 c 0.119713,-2e-5 0.2354477,-0.043 0.3261717,-0.12109 l 2.875,-1.73829 h 0.128906 l 2.90625,1.73829 c 0.09174,0.079 0.209022,0.12201 0.330078,0.12109 l 0.746094,-0.006 c 0.273084,-0.002 0.49394,-0.223 0.496094,-0.49609 l 0.0039,-0.7461 c -7.9e-5,-0.0572 -0.01,-0.11407 -0.0293,-0.16797 l -1.018075,-2.64906 2.263556,-1.74938 c 0.143229,-0.0917 0.230049,-0.24986 0.230472,-0.41992 v -0.75 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 h -3.416628 l -1.354244,-3.35353 c -0.07058,-0.20045 -0.260139,-0.33439 -0.472653,-0.33398 h -0.251953 z m 0.25,1.30078 1.248775,3.05275 c 0.07058,0.20045 0.260142,0.3344 0.472656,0.33398 h 3.257085 l -2.35206,1.79235 c -0.194539,0.12525 -0.277747,0.36761 -0.201172,0.58594 l 1.121591,2.94007 -0.002,0.16407 h -0.06445 l -2.904297,-1.73634 c -0.09071,-0.0781 -0.20643,-0.1445 -0.326128,-0.14453 h -0.5 c -0.119714,2e-5 -0.235448,0.0664 -0.326172,0.14453 l -2.8749997,1.73829 h -0.06445 v -0.16406 l 1.0838687,-2.96144 c 0.07658,-0.21833 -0.0066,-0.46069 -0.201172,-0.58594 l -2.3455877,-1.77294 h 3.2441377 c 0.212514,4.2e-4 0.402079,-0.13353 0.472656,-0.33398 z"
id="path14401"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccccsccccccccccccccccccccccccccccccccccc" />
<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;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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 33.744225,201.275 c -0.212514,-4.2e-4 -0.402079,0.13353 -0.472656,0.33398 l -1.345551,3.38438 h -3.437424 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 0.75 c 4.22e-4,0.17006 0.08724,0.32824 0.230469,0.41992 l 2.21584,1.74985 -0.925245,2.6837 c -0.01909,0.0533 -0.029,0.10942 -0.0293,0.16602 v 0.75 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 0.75 c 0.119714,-2e-5 0.235448,-0.043 0.326172,-0.12109 l 2.873242,-1.81824 h 0.128906 l 2.873239,1.81824 c 0.09174,0.079 0.209022,0.12201 0.330078,0.12109 l 0.746094,-0.006 c 0.273087,-0.002 0.49394,-0.223 0.496094,-0.49609 l 0.0039,-0.7461 c -7.9e-5,-0.0572 -0.01,-0.11407 -0.0293,-0.16797 l -0.925245,-2.6837 2.193743,-1.74985 c 0.143229,-0.0917 0.230049,-0.24986 0.230472,-0.41992 v -0.75 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 h -3.39323 l -1.367648,-3.38438 c -0.07058,-0.20045 -0.260142,-0.3344 -0.472656,-0.33398 h -0.251953 z"
id="path14398"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccc" />
<path
d="m 29.496975,84.009467 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z m 4.013247,-8.970457 c -0.379073,0.01666 -0.602206,0.432889 -0.40625,0.757812 l 1.998047,3.200331 h -3.61244 c -0.676158,-0.0096 -0.676158,1.00956 0,1 h 3.61244 l -2.044081,3.215115 c -0.365869,0.583132 0.535437,1.109233 0.863282,0.503906 l 2.051893,-3.226833 2.051893,3.204736 c 0.327845,0.605327 1.229151,0.07923 0.863282,-0.503906 l -2.044081,-3.193018 h 3.603287 c 0.676159,0.0096 0.676159,-1.00956 0,-1 h -3.603287 l 2.044081,-3.215115 c 0.365869,-0.583132 -0.535437,-1.109233 -0.863282,-0.503906 l -2.051893,3.226833 -2.005859,-3.212049 c -0.09244,-0.163879 -0.269052,-0.261995 -0.457032,-0.253906 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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
id="path1-0"
sodipodi:nodetypes="ssssscccccccccccccccccccc" />
<g
id="g13"
transform="translate(-2.9916664,9.0091398)">
<g
id="g2-7"
transform="translate(24.003496,-31.000599)"
style="display:inline;enable-background:new">
<g
id="g12940-5-7-5"
style="display:inline;fill:#ffffff;stroke:#ffffff;enable-background:new"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:label="BA-20"
transform="matrix(0,1.0017897,-1,0,912.95152,-309.73386)" />
<g
id="g12940-5-7-5-2"
style="display:inline;fill:#ffffff;stroke:#ffffff;enable-background:new"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:label="BA-20"
transform="matrix(0,-1.0017897,1,0,-257.95236,514.72503)">
<g
id="g11">
<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:new"
d="m 405.46978,579.95581 c -0.0786,0.005 1.01466,0.006 2.75112,0.002 -2.39046,1.17179 -3.76136,4.49271 -2.99824,7.27846 0.76312,2.78575 3.11603,4.49155 5.7784,4.71875 l -8.4e-4,-1 c -2.59859,-0.27264 -4.17102,-1.63685 -4.81356,-3.98242 -0.64254,-2.34557 0.50423,-5.20147 2.81719,-6.15552 0.009,0.80023 -0.0108,2.01265 9.3e-4,2.69464 -0.008,0.60881 1.01884,0.5718 0.99185,-0.0157 -0.002,-0.49551 0.001,-3.60295 0.007,-4.5362 -1.4729,8.2e-4 -2.81924,-4.8e-4 -4.52617,-0.008 -0.62523,0.0109 -0.61936,0.99943 -0.009,1.00441 z"
id="path12897-5-0-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsccsccccccc"
transform="rotate(180,411.493,585.45194)" />
<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:new"
d="m 405.45285,579.95581 c -0.0786,0.005 1.05365,-0.002 2.79011,-0.006 -2.39046,1.17179 -3.8662,4.53149 -2.99824,7.28627 0.8992,2.85391 3.08617,4.49155 5.74854,4.71875 l -8.4e-4,-1 c -2.49653,-0.35216 -4.00508,-1.56869 -4.7837,-3.98242 -0.74659,-2.31444 0.47303,-5.20147 2.78599,-6.15552 0.009,0.80023 -0.0108,2.01265 9.3e-4,2.69464 -0.008,0.60881 1.01884,0.5718 0.99185,-0.0157 -0.002,-0.49551 0.001,-3.60295 0.007,-4.5362 -1.4729,8.2e-4 -2.82703,-4.8e-4 -4.53396,-0.008 -0.62523,0.0109 -0.61936,0.99943 -0.009,1.00441 z"
id="path12897-5-0-3-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsccsccccccc" />
</g>
</g>
</g>
</g>
<g
id="g41652-9"
style="display:inline;enable-background:new"
inkscape:label="C-14"
transform="translate(-0.015715,-0.00588001)">
<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:new"
d="m 283.51233,53.990463 c -0.12976,0.0036 -0.25303,0.05754 -0.34375,0.15039 l -3.00563,3.005631 c -0.19518,0.195265 -0.19518,0.511767 0,0.707032 l 3.00563,2.983534 c 0.47126,0.490506 1.19754,-0.235768 0.70704,-0.707032 L 281.7235,58 h 5.28213 c 2.21506,0 4,1.784939 4,4 0,2.215061 -1.78494,4 -4,4 h -1.5 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1.5 c 2.7555,0 5,-2.244499 5,-5 0,-2.755501 -2.2445,-5 -5,-5 h -5.28213 l 2.15212,-2.152115 c 0.32527,-0.318007 0.0914,-0.869901 -0.36329,-0.857422 z"
id="path13225-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sccccccsssccsssccs" />
</g>
<g
id="g41649-6"
style="display:inline;enable-background:new"
inkscape:label="C-15"
transform="translate(-0.00915292,-0.00145419)">
<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:new"
d="m 309.47936,53.98851 c -0.44941,8.8e-5 -0.6706,0.546838 -0.34766,0.859375 L 311.26172,57 H 306 c -2.7555,0 -5,2.244499 -5,5 0,2.755501 2.2445,5 5,5 h 1.5 c 0.67616,0.0096 0.67616,-1.009563 0,-1 H 306 c -2.21506,0 -4,-1.784939 -4,-4 0,-2.215061 1.78494,-4 4,-4 h 5.26172 l -2.13002,2.130018 c -0.4905,0.471264 0.23578,1.197538 0.70704,0.707032 l 2.98353,-2.983534 c 0.19518,-0.195265 0.19518,-0.511767 0,-0.707032 l -2.98353,-3.005631 c -0.0942,-0.09737 -0.2239,-0.152345 -0.35938,-0.152343 z"
id="path13229-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccsssccsssccccccc" />
</g>
<g
id="g41643-0"
style="display:inline;enable-background:new"
inkscape:label="C-16"
transform="translate(-0.00487658,-0.02012584)">
<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 325.47376,56.994369 c -0.13003,0.0041 -0.25334,0.05878 -0.34375,0.152344 l -2.98353,3.005631 c -0.19518,0.195265 -0.19518,0.511766 0,0.707031 l 2.98353,2.983534 c 0.47126,0.49054 1.19758,-0.235768 0.70704,-0.707031 l -2.13002,-2.130019 h 9.78516 c 0.67616,0.0096 0.67616,-1.009563 0,-1 h -9.78516 l 2.13002,-2.152115 c 0.32886,-0.317809 0.0938,-0.873816 -0.36329,-0.859375 z"
id="path12420-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sccccccccccs" />
</g>
<g
id="g41646-0"
style="display:inline;enable-background:new"
inkscape:label="C-17"
transform="translate(-6.9000302e-4,-0.00541755)">
<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 351.51842,56.994369 c -0.4494,9.7e-5 -0.67058,0.546842 -0.34765,0.859375 l 2.13001,2.152115 H 343.5 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 9.80078 l -2.13001,2.130019 c -0.49088,0.471253 0.23577,1.197904 0.70703,0.707031 l 2.98353,-2.983534 c 0.19518,-0.195265 0.19518,-0.511766 0,-0.707031 l -2.98353,-3.005631 c -0.0942,-0.09737 -0.2239,-0.152345 -0.35938,-0.152344 z"
id="path9970-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccc" />
</g>
<g
id="g12536-6"
transform="matrix(0,1,1,0,269.99891,-182.99403)"
style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:label="D-16">
<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 261.44603,53.01256 c -0.12976,0.0036 -0.25303,0.05754 -0.34375,0.15039 l -2.98353,2.983534 c -0.19518,0.195265 -0.19518,0.511767 0,0.707032 l 2.98353,2.983534 c 0.47126,0.490506 1.19754,-0.235768 0.70704,-0.707032 L 259.6793,57 h 7.78214 c 0.83435,0 1.5,0.665651 1.5,1.5 v 5 c -0.01,0.676161 1.00956,0.676161 1,0 v -5 c 0,-1.374789 -1.12521,-2.5 -2.5,-2.5 h -7.78214 l 2.13002,-2.130018 c 0.32528,-0.318006 0.0914,-0.869901 -0.36329,-0.857422 z"
id="path12534-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sccccccssccssccs" />
</g>
<g
id="g41655-5"
style="display:inline;enable-background:new"
inkscape:label="C-2"
transform="translate(5.0109005e-4,6.7208698e-4)">
<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 13.492188,54.005859 c -0.129887,0.0021 -0.253871,0.05461 -0.345704,0.146485 l -2.983534,2.961437 c -0.4908328,0.471254 0.235777,1.197864 0.707032,0.707031 L 13,55.712891 v 9.792968 c -0.0096,0.676161 1.009563,0.676161 1,0 v -9.792968 l 2.130018,2.130018 c 0.471254,0.490807 1.197838,-0.235776 0.707032,-0.707031 l -2.983534,-2.983534 c -0.09566,-0.09571 -0.226027,-0.148557 -0.361328,-0.146485 z"
id="path14327-21"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccc" />
</g>
<g
id="g41658-1"
style="display:inline;enable-background:new"
inkscape:label="C-3"
transform="translate(9.1724349e-4,-0.01620461)">
<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 34.492188,54.005859 C 34.216815,54.01017 33.996766,54.236332 34,54.511719 v 9.792969 L 31.869982,62.174669 C 31.398728,61.683862 30.672144,62.410445 31.16295,62.8817 l 2.983534,2.983534 c 0.195265,0.195185 0.511767,0.195185 0.707032,0 l 2.983534,-3.005631 c 0.490806,-0.471255 -0.235778,-1.197838 -0.707032,-0.707031 L 35,64.304688 v -9.792969 c 0.0033,-0.281503 -0.226323,-0.510249 -0.507812,-0.50586 z"
id="path14329-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccc" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
id="g14591-2"
inkscape:label="D-1"
transform="translate(6.6805276e-5,-0.015625)">
<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:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 9.25,75 c -0.2186269,4.08e-4 -0.4116423,0.142796 -0.4765625,0.351562 l -2.75,7.820313 C 6.0081924,83.219891 6.0002907,83.269935 6,83.320312 v 0.173829 c -0.00956,0.676161 1.0095626,0.676161 1,0 v -0.09766 L 7.7460938,81 c 0.0013,5e-6 0.0026,5e-6 0.00391,0 h 3.5000002 c 0.0013,5e-6 0.0026,5e-6 0.0039,0 L 12,83.396484 v 0.09766 c -0.0096,0.676161 1.009563,0.676161 1,0 v -0.173829 c -2.91e-4,-0.05038 -0.0082,-0.100421 -0.02344,-0.148437 l -2.75,-7.820313 C 10.161641,75.142799 9.9686268,75.000409 9.75,75 Z M 9.5,76.375 10.941406,80 H 8.0585938 Z"
id="path14584-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccccccccc" />
<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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 14.5,79 c -0.676161,-0.0096 -0.676161,1.009563 0,1 H 19 v 0.08008 l -4.896484,5.365234 C 14.036382,85.532696 13.999992,85.639807 14,85.75 v 0.75 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 h 5 c 0.676161,0.0096 0.676161,-1.009563 0,-1 H 15 v -0.08008 l 4.896484,-5.365234 C 19.963618,80.467304 20.000008,80.360193 20,80.25 V 79.5 c -2.8e-5,-0.276131 -0.223869,-0.499972 -0.5,-0.5 z"
id="path14589-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccc" />
</g>
<path
d="m 96.499447,54.005859 c -0.27538,0.0043 -0.49542,0.230473 -0.49219,0.50586 v 7.792969 l -2.13002,-2.130019 c -0.47125,-0.490807 -1.19784,0.235776 -0.70703,0.707031 l 2.98353,2.983534 c 0.19527,0.195185 0.51177,0.195185 0.70704,0 l 2.98353,-3.005631 c 0.490803,-0.471255 -0.23578,-1.197838 -0.70703,-0.707031 l -2.13002,2.152116 v -7.792969 c 0.003,-0.281503 -0.22632,-0.510249 -0.50781,-0.50586 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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
id="path1-8" />
<path
d="m 117.50866,53.999925 c 0.12988,0.0021 0.25387,0.05461 0.3457,0.146485 l 2.98353,2.961437 c 0.49084,0.471254 -0.23577,1.197855 -0.70703,0.707031 l -2.13002,-2.107921 v 7.792965 c 0.01,0.67616 -1.00956,0.67616 -1,0 v -7.792965 l -2.13001,2.130018 c -0.47126,0.490807 -1.19784,-0.235776 -0.70704,-0.707031 l 2.98354,-2.983534 c 0.0957,-0.09571 0.22603,-0.148557 0.36133,-0.146485 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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
id="path1-2" />
<g
style="display:inline;fill:#ffffff;enable-background:new"
id="g6750-7-3"
transform="translate(-315.02125,-566.9779)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:label="B-15">
<rect
y="598"
x="614"
height="16"
width="16"
id="rect6732-0-9"
style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1;stroke-opacity:1;marker:none" />
<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:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 618.74609,600.01647 c -0.22865,1.3e-4 -0.42808,0.15534 -0.48437,0.37695 l -3.2461,10.71706 c -0.0103,0.0402 -0.0155,0.0815 -0.0156,0.12305 v 0.25 c -0.01,0.67617 1.00956,0.67617 1,0 v -0.1875 l 0.84961,-3.33398 c 0.0487,0.0148 0.0995,0.022 0.15039,0.0215 h 4 c 0.0502,9.9e-4 0.10022,-0.006 0.14844,-0.0195 h 0.002 l 0.84956,3.332 v 0.1875 c -0.01,0.67617 1.00956,0.67617 1,0 v -0.25 c -7e-5,-0.0415 -0.005,-0.0828 -0.0156,-0.12305 l -3.25391,-10.71706 c -0.0563,-0.22162 -0.25574,-0.37683 -0.4844,-0.37695 z m 0.25,1.54492 1.90235,5.42214 h -3.80078 z"
id="path6736-8-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccccc" />
<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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 310,43.983534 v -5 h 1.5 c 0.83481,0 1.5,0.664144 1.5,1.498047 v 2.007812 c 0,0.833914 -0.66519,1.498047 -1.5,1.496094 z m 4,-1.494141 v -2.007812 c 0,-1.375283 -1.12569,-2.498047 -2.5,-2.498047 H 310 v -4.467068 c 0.004,-0.28226 -0.22555,-0.512233 -0.50781,-0.507812 -0.27614,0.004 -0.49651,0.231672 -0.49219,0.507812 v 10.967068 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 l 2,0.002 c 1.37431,0.002 2.5,-1.120801 2.5,-2.496094 z"
transform="translate(315,567)"
id="path6744-7-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsccccccsccccccccc" />
</g>
<g
id="g36632-6-5"
transform="translate(665.94763,-830.99076)"
style="display:inline;enable-background:new"
inkscape:label="DA-24">
<rect
style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
id="rect37443-9-7"
width="18"
height="18"
x="-284.00723"
y="-1467"
transform="scale(1,-1)"
inkscape:label="frame" />
<g
id="g36628-4-2" />
<path
id="path9540-8"
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:butt;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 -280.46073,1453.9904 c -0.6573,0.01 -0.6573,0.9907 0,1 h 10.95009 c 0.6573,-0.01 0.6573,-0.9907 0,-1 z m 0,4.0102 c -0.6573,0.01 -0.6573,0.9907 0,1 h 10.95009 c 0.6573,-0.01 0.6573,-0.9907 0,-1 z m 0,3.979 c -0.6573,0.01 -0.6573,0.99 0,1 h 10.95009 c 0.6573,-0.01 0.6573,-0.99 0,-1 z"
sodipodi:nodetypes="ccccccccccccccc" />
</g>
<g
id="g11-1"
style="display:inline;enable-background:new"
transform="translate(-0.03250111,0.50646802)"
inkscape:transform-center-x="-0.1767767"
inkscape:transform-center-y="3.4029514">
<ellipse
style="display:inline;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;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;enable-background:new"
id="path29001-7"
cy="580.74786"
cx="475.05066"
ry="1.2872622"
rx="1.3535534" />
<ellipse
style="display:inline;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;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;enable-background:new"
id="path29001-7-1"
cy="589.22015"
cx="475.04419"
rx="1.3535534"
ry="1.2872622" />
<ellipse
style="display:inline;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;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;enable-background:new"
id="path29001-7-6"
cy="585.00568"
cx="475.02209"
rx="1.3535534"
ry="1.2872622" />
</g>
<g
id="g120740-0"
style="display:inline;enable-background:new"
inkscape:label="O-9"
transform="translate(0.98654635,0.00563)">
<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:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 177,305.99437 c -0.55226,5e-5 -0.99994,0.44774 -1,1 v 4.83766 c -0.0179,0.10799 -0.0179,0.21818 0,0.32617 v 4.82533 c 6e-5,0.55227 0.44774,0.99995 1,1 h 4.00563 c 2.19729,0 4,-1.16189 4,-3.35918 0,-1.76747 -0.45037,-2.32201 -1.78516,-3.04484 0.45751,-0.65017 0.78516,-1.31019 0.78516,-2.15967 0,-2.19729 -1.80271,-3.42547 -4,-3.42547 z m 1,2 h 2.00563 c 1.11641,0 2,0.30906 2,1.42547 0,1.11641 -0.88359,1.58016 -2,1.58016 H 178 Z M 178,313 h 2.00563 1 c 1.11641,0 2,0.50794 2,1.62435 0,1.11641 -0.88359,1.35918 -2,1.35918 H 178 Z"
id="path10949-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccsscssccsssccccssscc" />
</g>
<g
id="g120716-9"
style="display:inline;enable-background:new"
inkscape:label="O-10"
transform="translate(-0.00165001,-0.03118)">
<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;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 200.47572,306.03125 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 2.5039 l -0.002,0.14258 -2.92604,9.4082 c -0.0291,0.0671 -0.0431,0.13978 -0.041,0.21289 l 0.006,0.23633 h -2.50781 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 6 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -2.4923 c 6e-5,-0.005 6e-5,-0.009 0,-0.0137 l -0.004,-0.13867 2.92214,-9.39844 c 0.0261,-0.0605 0.0401,-0.12553 0.041,-0.19141 l 0.004,-0.25778 h 2.4961 c 0.67616,0.01 0.67616,-1.00956 0,-1 z"
id="path10892-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccc" />
</g>
<g
id="g120719-6"
style="display:inline;enable-background:new"
inkscape:label="O-11"
transform="translate(-0.07739391,-0.07242392)">
<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:accumulate"
d="m 217.55469,306.0625 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.50781 v 3.97266 c 0,2.19985 1.29782,4.00769 3.5,4.01172 h 1 0.002 c 2.20199,-0.005 3.498,-1.81187 3.498,-4.01172 v -3.97266 h 1.49219 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.50781 v 3.97266 c 0,1.65832 -0.83799,3.00828 -2.50195,3.01172 h -0.99805 c -1.66382,-0.003 -2.5,-1.3534 -2.5,-3.01172 v -3.97266 h 1.49219 c 0.67616,0.01 0.67616,-1.00956 0,-1 z m 1,11 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 8.96875 c 0.67616,0.01 0.67616,-1.00956 0,-1 z"
id="path10901-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccscccsccccccsccsccccccccc" />
</g>
<g
id="g6603-4"
style="display:inline;fill:#ffffff;enable-background:new"
inkscape:label="O-12"
transform="translate(-0.0021004,-0.010836)">
<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:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 237.49219,305.99437 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c -0.01,0.67616 1.00956,0.67616 1,0 v -1.5 h 3 v 10.03336 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 4 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1.5 v -10.03336 h 3 v 1.5 c -0.01,0.67616 1.00956,0.67616 1,0 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 7,5.00563 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c -0.01,0.67616 1.00956,0.67616 1,0 V 312 h 2 v 5.02773 h -0.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 2 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -0.5 V 312 h 2 v 0.5 c -0.01,0.67616 1.00956,0.67616 1,0 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
id="path6924-7-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccc" />
</g>
</g>
<g
inkscape:groupmode="layer"

Before

Width:  |  Height:  |  Size: 2.6 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

View File

@ -289,11 +289,11 @@ class NLA_OT_bake(Operator):
else:
objects = context.selected_editable_objects
if bake_options.do_pose and not bake_options.do_object:
pose_object = getattr(context, 'pose_object', None)
pose_object = getattr(context, "pose_object", None)
if pose_object and pose_object not in objects:
# The active object might not be selected, but it is the one in pose mode.
# It can be assumed this pose needs baking.
objects.append(context.pose_object)
objects.append(pose_object)
objects = [obj for obj in objects if obj.pose is not None]
object_action_pairs = (
@ -459,8 +459,8 @@ class ARMATURE_OT_copy_bone_color_to_selected(Operator):
bl_options = {'REGISTER', 'UNDO'}
_bone_type_enum = [
('EDIT', 'Bone', 'Copy Bone colors from the active bone to all selected bones'),
('POSE', 'Pose Bone', 'Copy Pose Bone colors from the active pose bone to all selected pose bones'),
('EDIT', "Bone", "Copy Bone colors from the active bone to all selected bones"),
('POSE', "Pose Bone", "Copy Pose Bone colors from the active pose bone to all selected pose bones"),
]
bone_type: EnumProperty(
@ -648,7 +648,7 @@ class ARMATURE_OT_collection_remove_unused(Operator):
for bcoll in reversed(list(bcolls_to_remove)):
armature.collections.remove(bcoll)
self.report({'INFO'}, 'Removed %d of %d bone collections' %
self.report({'INFO'}, "Removed %d of %d bone collections" %
(num_bcolls_to_remove, num_bcolls_before_removal))

View File

@ -115,13 +115,13 @@ class WM_OT_previews_batch_generate(Operator):
"--",
])
if not self.use_scenes:
cmd.append('--no_scenes')
cmd.append("--no_scenes")
if not self.use_collections:
cmd.append('--no_collections')
cmd.append("--no_collections")
if not self.use_objects:
cmd.append('--no_objects')
cmd.append("--no_objects")
if not self.use_intern_data:
cmd.append('--no_data_intern')
cmd.append("--no_data_intern")
if not self.use_backups:
cmd.append("--no_backups")
if subprocess.call(cmd):
@ -225,13 +225,13 @@ class WM_OT_previews_batch_clear(Operator):
"--clear",
])
if not self.use_scenes:
cmd.append('--no_scenes')
cmd.append("--no_scenes")
if not self.use_collections:
cmd.append('--no_collections')
cmd.append("--no_collections")
if not self.use_objects:
cmd.append('--no_objects')
cmd.append("--no_objects")
if not self.use_intern_data:
cmd.append('--no_data_intern')
cmd.append("--no_data_intern")
if not self.use_backups:
cmd.append("--no_backups")
if subprocess.call(cmd):

View File

@ -301,7 +301,7 @@ class QuickExplode(ObjectModeOperator, Operator):
settings.normal_factor = self.velocity
settings.render_type = 'NONE'
explode = obj.modifiers.new(name='Explode', type='EXPLODE')
explode = obj.modifiers.new(name="Explode", type='EXPLODE')
explode.use_edge_cut = True
if self.fade:

View File

@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import Panel, Menu
from bpy.types import Panel, Menu, UIList
from rna_prop_ui import PropertyPanel
@ -27,6 +27,39 @@ class LayerDataButtonsPanel:
return grease_pencil and grease_pencil.layers.active
class GREASE_PENCIL_UL_masks(UIList):
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
mask = item
if self.layout_type in {'DEFAULT', 'COMPACT'}:
row = layout.row(align=True)
row.prop(mask, "name", text="", emboss=False, icon_value=icon)
row.prop(mask, "invert", text="", emboss=False)
row.prop(mask, "hide", text="", emboss=False)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.prop(mask, "name", text="", emboss=False, icon_value=icon)
class GREASE_PENCIL_MT_layer_mask_add(Menu):
bl_label = "Add Mask"
def draw(self, context):
layout = self.layout
grease_pencil = context.grease_pencil
active_layer = grease_pencil.layers.active
found = False
for layer in grease_pencil.layers:
if layer == active_layer or layer.name in active_layer.mask_layers:
continue
found = True
layout.operator("grease_pencil.layer_mask_add", text=layer.name).name = layer.name
if not found:
layout.label(text="No layers to add")
class DATA_PT_context_grease_pencil(DataButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
@ -91,14 +124,58 @@ class DATA_PT_grease_pencil_layers(DataButtonsPanel, Panel):
col.operator("grease_pencil.layer_remove", icon='REMOVE', text="")
# Layer main properties
if layer:
layout.use_property_split = True
layout.use_property_decorate = True
col = layout.column(align=True)
if not layer:
return
row = layout.row(align=True)
row.prop(layer, "opacity", text="Opacity", slider=True)
layout.use_property_split = True
layout.use_property_decorate = True
col = layout.column(align=True)
# Layer main properties
row = layout.row(align=True)
row.prop(layer, "blend_mode", text="Blend Mode")
row = layout.row(align=True)
row.prop(layer, "opacity", text="Opacity", slider=True)
class DATA_PT_grease_pencil_layer_masks(LayerDataButtonsPanel, Panel):
bl_label = "Masks"
bl_parent_id = "DATA_PT_grease_pencil_layers"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
grease_pencil = context.grease_pencil
layer = grease_pencil.layers.active
self.layout.prop(layer, "use_masks", text="")
def draw(self, context):
layout = self.layout
grease_pencil = context.grease_pencil
layer = grease_pencil.layers.active
layout = self.layout
layout.enabled = layer.use_masks
if not layer:
return
rows = 4
row = layout.row()
col = row.column()
col.template_list("GREASE_PENCIL_UL_masks", "", layer, "mask_layers", layer.mask_layers,
"active_mask_index", rows=rows, sort_lock=True)
col = row.column(align=True)
col.menu("GREASE_PENCIL_MT_layer_mask_add", icon='ADD', text="")
col.operator("grease_pencil.layer_mask_remove", icon='REMOVE', text="")
col.separator()
sub = col.column(align=True)
sub.operator("grease_pencil.layer_mask_reorder", icon='TRIA_UP', text="").direction = 'UP'
sub.operator("grease_pencil.layer_mask_reorder", icon='TRIA_DOWN', text="").direction = 'DOWN'
class DATA_PT_grease_pencil_layer_transform(LayerDataButtonsPanel, Panel):
@ -149,6 +226,9 @@ class DATA_PT_grease_pencil_layer_relations(LayerDataButtonsPanel, Panel):
col = layout.row(align=True)
col.prop(layer, "pass_index")
col = layout.row(align=True)
col.prop_search(layer, "viewlayer_render", context.scene, "view_layers", text="View Layer")
class DATA_PT_grease_pencil_custom_props(DataButtonsPanel, PropertyPanel, Panel):
_context_path = "object.data"
@ -156,8 +236,11 @@ class DATA_PT_grease_pencil_custom_props(DataButtonsPanel, PropertyPanel, Panel)
classes = (
GREASE_PENCIL_UL_masks,
GREASE_PENCIL_MT_layer_mask_add,
DATA_PT_context_grease_pencil,
DATA_PT_grease_pencil_layers,
DATA_PT_grease_pencil_layer_masks,
DATA_PT_grease_pencil_layer_transform,
DATA_PT_grease_pencil_layer_relations,
DATA_PT_grease_pencil_custom_props,

View File

@ -180,7 +180,7 @@ class CLIP_HT_header(Header):
row = layout.row(align=True)
icon = 'LOCKED' if sc.lock_selection else 'UNLOCKED'
row.operator("clip.lock_selection_toggle", icon=icon, text="", depress=sc.lock_selection)
row.popover(panel='CLIP_PT_display')
row.popover(panel="CLIP_PT_display")
elif sc.view == 'GRAPH':
row = layout.row(align=True)
@ -243,11 +243,11 @@ class CLIP_HT_header(Header):
row = layout.row()
row.template_ID(sc, "mask", new="mask.new")
row.popover(panel='CLIP_PT_mask_display')
row.popover(panel="CLIP_PT_mask_display")
row = layout.row(align=True)
icon = 'LOCKED' if sc.lock_selection else 'UNLOCKED'
row.operator("clip.lock_selection_toggle", icon=icon, text="", depress=sc.lock_selection)
row.popover(panel='CLIP_PT_display')
row.popover(panel="CLIP_PT_display")
def draw(self, context):
layout = self.layout
@ -1054,8 +1054,7 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel):
sub.operator("clip.stabilize_2d_add", icon='ADD', text="")
sub.operator("clip.stabilize_2d_remove", icon='REMOVE', text="")
sub.menu('CLIP_MT_stabilize_2d_context_menu', text="",
icon='DOWNARROW_HLT')
sub.menu("CLIP_MT_stabilize_2d_context_menu", text="", icon='DOWNARROW_HLT')
# Usually we don't hide things from interface, but here every pixel of
# vertical space is precious.
@ -1071,8 +1070,7 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel):
sub.operator("clip.stabilize_2d_rotation_add", icon='ADD', text="")
sub.operator("clip.stabilize_2d_rotation_remove", icon='REMOVE', text="")
sub.menu('CLIP_MT_stabilize_2d_rotation_context_menu', text="",
icon='DOWNARROW_HLT')
sub.menu("CLIP_MT_stabilize_2d_rotation_context_menu", text="", icon='DOWNARROW_HLT')
col = layout.column()
col.prop(stab, "use_autoscale")

View File

@ -906,7 +906,7 @@ class IMAGE_HT_header(Header):
row.prop(sima, "show_stereo_3d", text="")
if show_maskedit:
row = layout.row()
row.popover(panel='IMAGE_PT_mask_display')
row.popover(panel="IMAGE_PT_mask_display")
# layers.
layout.template_image_layers(ima, iuser)

View File

@ -407,7 +407,7 @@ class NODE_PT_material_slots(Panel):
iface_("Slot")
)
# Duplicate part of 'EEVEE_MATERIAL_PT_context_material'.
# Duplicate part of `EEVEE_MATERIAL_PT_context_material`.
def draw(self, context):
layout = self.layout
row = layout.row()
@ -933,7 +933,7 @@ class NODE_PT_node_tree_interface(Panel):
if 'OUTPUT' in active_item.in_out:
layout.prop(active_item, "attribute_domain")
layout.prop(active_item, "default_attribute_name")
if hasattr(active_item, 'draw'):
if hasattr(active_item, "draw"):
active_item.draw(context, layout)
if active_item.item_type == 'PANEL':

View File

@ -190,7 +190,7 @@ def marker_menu_generic(layout, context):
layout.separator()
layout.menu('NLA_MT_marker_select')
layout.menu("NLA_MT_marker_select")
layout.separator()

View File

@ -460,7 +460,7 @@ class _draw_tool_settings_context_mode:
if (tool is None) or (not tool.has_datablock):
return False
# See: 'VIEW3D_PT_tools_brush', basically a duplicate
# See: `VIEW3D_PT_tools_brush`, basically a duplicate
tool_settings = context.tool_settings
settings = tool_settings.particle_edit
brush = settings.brush

View File

@ -138,7 +138,7 @@ class AssetLibrary {
* Remove an asset from the library that was added using #add_external_asset() or
* #add_local_id_asset(). Can usually be expected to be constant time complexity (worst case may
* differ).
* \note This is save to call if \a asset is freed (dangling reference), will not perform any
* \note This is safe to call if \a asset is freed (dangling reference), will not perform any
* change then.
* \return True on success, false if the asset couldn't be found inside the library (also the
* case when the reference is dangling).

View File

@ -207,14 +207,14 @@ AssetRepresentation &AssetLibrary::add_external_asset(StringRef relative_asset_p
const int id_type,
std::unique_ptr<AssetMetaData> metadata)
{
AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path);
AssetIdentifier identifier = this->asset_identifier_from_library(relative_asset_path);
return asset_storage_->add_external_asset(
std::move(identifier), name, id_type, std::move(metadata), *this);
}
AssetRepresentation &AssetLibrary::add_local_id_asset(StringRef relative_asset_path, ID &id)
{
AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path);
AssetIdentifier identifier = this->asset_identifier_from_library(relative_asset_path);
return asset_storage_->add_local_id_asset(std::move(identifier), id, *this);
}

View File

@ -43,7 +43,7 @@ bool AssetStorage::remove_asset(AssetRepresentation &asset)
return external_assets_.remove_as(&asset);
}
void AssetStorage::remap_ids_and_remove_invalid(const blender::bke::id::IDRemapper &mappings)
void AssetStorage::remap_ids_and_remove_invalid(const bke::id::IDRemapper &mappings)
{
Set<AssetRepresentation *> removed_assets;
@ -61,7 +61,7 @@ void AssetStorage::remap_ids_and_remove_invalid(const blender::bke::id::IDRemapp
}
for (AssetRepresentation *asset : removed_assets) {
remove_asset(*asset);
this->remove_asset(*asset);
}
}

View File

@ -148,6 +148,7 @@ class Layer;
bool is_selected() const; \
void set_selected(bool selected); \
bool use_onion_skinning() const; \
bool use_masks() const; \
bool is_child_of(const LayerGroup &group) const;
/* Implements the forwarding of the methods defined by #TREENODE_COMMON_METHODS. */
@ -192,6 +193,10 @@ class Layer;
{ \
return this->as_node().use_onion_skinning(); \
} \
inline bool class_name::use_masks() const \
{ \
return this->as_node().use_masks(); \
} \
inline bool class_name::is_child_of(const LayerGroup &group) const \
{ \
return this->as_node().is_child_of(group); \
@ -456,6 +461,13 @@ class Layer : public ::GreasePencilLayer {
StringRefNull parent_bone_name() const;
void set_parent_bone_name(const char *new_name);
/**
* Returns the view layer name that this layer should be rendered in or an empty
* `StringRefNull` if no such name is set.
*/
StringRefNull view_layer_name() const;
void set_view_layer_name(const char *new_name);
private:
using SortedKeysIterator = const int *;
@ -678,6 +690,11 @@ inline bool TreeNode::use_onion_skinning() const
{
return ((this->flag & GP_LAYER_TREE_NODE_USE_ONION_SKINNING) != 0);
}
inline bool TreeNode::use_masks() const
{
return ((this->flag & GP_LAYER_TREE_NODE_HIDE_MASKS) == 0) &&
(!this->parent_group() || this->parent_group()->as_node().use_masks());
}
inline bool TreeNode::is_child_of(const LayerGroup &group) const
{
if (const LayerGroup *parent = this->parent_group()) {

View File

@ -11,6 +11,7 @@
#include "BKE_action.h"
#include "BKE_anim_data.hh"
#include "BKE_animsys.h"
#include "BKE_curves.hh"
#include "BKE_customdata.hh"
#include "BKE_deform.hh"
@ -628,14 +629,12 @@ LayerMask::LayerMask()
LayerMask::LayerMask(StringRefNull name) : LayerMask()
{
this->layer_name = BLI_strdup(name.c_str());
this->layer_name = BLI_strdup_null(name.c_str());
}
LayerMask::LayerMask(const LayerMask &other) : LayerMask()
{
if (other.layer_name) {
this->layer_name = BLI_strdup(other.layer_name);
}
this->layer_name = BLI_strdup_null(other.layer_name);
this->flag = other.flag;
}
@ -672,7 +671,10 @@ Layer::Layer()
zero_v3(this->rotation);
copy_v3_fl(this->scale, 1.0f);
this->viewlayername = nullptr;
BLI_listbase_clear(&this->masks);
this->active_mask_index = 0;
this->runtime = MEM_new<LayerRuntime>(__func__);
}
@ -686,7 +688,11 @@ Layer::Layer(const Layer &other) : Layer()
{
new (&this->base) TreeNode(other.base.wrap());
/* TODO: duplicate masks. */
LISTBASE_FOREACH (GreasePencilLayerMask *, other_mask, &other.masks) {
LayerMask *new_mask = MEM_new<LayerMask>(__func__, *reinterpret_cast<LayerMask *>(other_mask));
BLI_addtail(&this->masks, reinterpret_cast<GreasePencilLayerMask *>(new_mask));
}
this->active_mask_index = other.active_mask_index;
this->blend_mode = other.blend_mode;
this->opacity = other.opacity;
@ -698,6 +704,8 @@ Layer::Layer(const Layer &other) : Layer()
copy_v3_v3(this->rotation, other.rotation);
copy_v3_v3(this->scale, other.scale);
this->set_view_layer_name(other.viewlayername);
/* Note: We do not duplicate the frame storage since it is only needed for writing to file. */
this->runtime->frames_ = other.runtime->frames_;
this->runtime->sorted_keys_cache_ = other.runtime->sorted_keys_cache_;
@ -715,11 +723,12 @@ Layer::~Layer()
MEM_SAFE_FREE(this->frames_storage.values);
LISTBASE_FOREACH_MUTABLE (GreasePencilLayerMask *, mask, &this->masks) {
MEM_SAFE_FREE(mask->layer_name);
MEM_freeN(mask);
MEM_delete(reinterpret_cast<LayerMask *>(mask));
}
BLI_listbase_clear(&this->masks);
MEM_SAFE_FREE(this->parsubstr);
MEM_SAFE_FREE(this->viewlayername);
MEM_delete(this->runtime);
this->runtime = nullptr;
@ -1015,6 +1024,19 @@ float4x4 Layer::local_transform() const
float3(this->translation), float3(this->rotation), float3(this->scale));
}
StringRefNull Layer::view_layer_name() const
{
return (this->viewlayername != nullptr) ? StringRefNull(this->viewlayername) : StringRefNull();
}
void Layer::set_view_layer_name(const char *new_name)
{
if (this->viewlayername != nullptr) {
MEM_freeN(this->viewlayername);
}
this->viewlayername = BLI_strdup_null(new_name);
}
LayerGroup::LayerGroup()
{
new (&this->base) TreeNode(GP_LAYER_TREE_GROUP);
@ -2507,8 +2529,21 @@ void GreasePencil::rename_node(blender::bke::greasepencil::TreeNode &node,
if (node.name() == new_name) {
return;
}
node.set_name(node.is_layer() ? unique_layer_name(*this, new_name) :
unique_layer_group_name(*this, new_name));
std::string old_name = node.name();
if (node.is_layer()) {
node.set_name(unique_layer_name(*this, new_name));
BKE_animdata_fix_paths_rename_all(&this->id, "layers", old_name.c_str(), node.name().c_str());
for (bke::greasepencil::Layer *layer : this->layers_for_write()) {
LISTBASE_FOREACH (GreasePencilLayerMask *, mask, &layer->masks) {
if (STREQ(mask->layer_name, old_name.c_str())) {
mask->layer_name = BLI_strdup(node.name().c_str());
}
}
}
}
else if (node.is_group()) {
node.set_name(unique_layer_group_name(*this, new_name));
}
}
static void shrink_customdata(CustomData &data, const int index_to_remove, const int size)
@ -2680,6 +2715,7 @@ static void read_layer(BlendDataReader *reader,
BLO_read_data_address(reader, &node->base.name);
node->base.parent = parent;
BLO_read_data_address(reader, &node->parsubstr);
BLO_read_data_address(reader, &node->viewlayername);
/* Read frames storage. */
BLO_read_int32_array(reader, node->frames_storage.num, &node->frames_storage.keys);
@ -2748,6 +2784,7 @@ static void write_layer(BlendWriter *writer, GreasePencilLayer *node)
BLO_write_struct(writer, GreasePencilLayer, node);
BLO_write_string(writer, node->base.name);
BLO_write_string(writer, node->parsubstr);
BLO_write_string(writer, node->viewlayername);
BLO_write_int32_array(writer, node->frames_storage.num, node->frames_storage.keys);
BLO_write_struct_array(

View File

@ -426,6 +426,8 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
SET_FLAG_FROM_TEST(new_layer.base.flag,
(gpl->onion_flag & GP_LAYER_ONIONSKIN),
GP_LAYER_TREE_NODE_USE_ONION_SKINNING);
SET_FLAG_FROM_TEST(
new_layer.base.flag, (gpl->flag & GP_LAYER_USE_MASK) == 0, GP_LAYER_TREE_NODE_HIDE_MASKS);
new_layer.blend_mode = int8_t(gpl->blend_mode);
@ -436,9 +438,11 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
copy_v3_v3(new_layer.rotation, gpl->rotation);
copy_v3_v3(new_layer.scale, gpl->scale);
new_layer.set_view_layer_name(gpl->viewlayername);
/* Convert the layer masks. */
LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
LayerMask *new_mask = MEM_new<LayerMask>(mask->name);
LayerMask *new_mask = MEM_new<LayerMask>(__func__, mask->name);
new_mask->flag = mask->flag;
BLI_addtail(&new_layer.masks, new_mask);
}

View File

@ -90,9 +90,8 @@ class IDPropertySerializer {
std::shared_ptr<DictionaryValue> create_dictionary(const IDProperty *id_property) const
{
std::shared_ptr<DictionaryValue> result = std::make_shared<DictionaryValue>();
DictionaryValue::Items &attributes = result->elements();
attributes.append_as(std::pair(IDP_KEY_NAME, new StringValue(id_property->name)));
attributes.append_as(std::pair(IDP_KEY_TYPE, new StringValue(type_name())));
result->append_str(IDP_KEY_NAME, id_property->name);
result->append_str(IDP_KEY_TYPE, this->type_name());
return result;
}
};
@ -101,7 +100,7 @@ class IDPropertySerializer {
* \brief Helper class for parsing DictionaryValues.
*/
struct DictionaryEntryParser {
const DictionaryValue::Lookup lookup;
DictionaryValue::Lookup lookup;
public:
explicit DictionaryEntryParser(const DictionaryValue &value) : lookup(value.create_lookup()) {}
@ -174,92 +173,74 @@ struct DictionaryEntryParser {
private:
std::optional<std::string> get_string(StringRef key) const
{
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
if (value_ptr == nullptr) {
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
if (value == nullptr) {
return std::nullopt;
}
const DictionaryValue::LookupValue &value = *value_ptr;
if (value->type() != eValueType::String) {
if (value->get()->type() != eValueType::String) {
return std::nullopt;
}
return value->as_string_value()->value();
return value->get()->as_string_value()->value();
}
const ArrayValue *get_array(StringRef key) const
{
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
if (value_ptr == nullptr) {
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
if (value == nullptr) {
return nullptr;
}
const DictionaryValue::LookupValue &value = *value_ptr;
if (value->type() != eValueType::Array) {
if (value->get()->type() != eValueType::Array) {
return nullptr;
}
return value->as_array_value();
return value->get()->as_array_value();
}
std::optional<bool> get_bool(StringRef key) const
{
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
if (value_ptr == nullptr) {
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
if (value == nullptr) {
return std::nullopt;
}
const DictionaryValue::LookupValue &value = *value_ptr;
if (value->type() != eValueType::Boolean) {
if (value->get()->type() != eValueType::Boolean) {
return std::nullopt;
}
return value->as_boolean_value()->value();
return value->get()->as_boolean_value()->value();
}
std::optional<int32_t> get_int(StringRef key) const
{
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
if (value_ptr == nullptr) {
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
if (value == nullptr) {
return std::nullopt;
}
const DictionaryValue::LookupValue &value = *value_ptr;
if (value->type() != eValueType::Int) {
if (value->get()->type() != eValueType::Int) {
return std::nullopt;
}
return value->as_int_value()->value();
return value->get()->as_int_value()->value();
}
std::optional<int32_t> get_enum(StringRef key) const
{
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
if (value_ptr == nullptr) {
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
if (value == nullptr) {
return std::nullopt;
}
const DictionaryValue::LookupValue &value = *value_ptr;
if (value->type() != eValueType::Int) {
if (value->get()->type() != eValueType::Int) {
return std::nullopt;
}
return value->as_int_value()->value();
return value->get()->as_int_value()->value();
}
std::optional<double> get_double(StringRef key) const
{
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
if (value_ptr == nullptr) {
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
if (value == nullptr) {
return std::nullopt;
}
const DictionaryValue::LookupValue &value = *value_ptr;
if (value->type() != eValueType::Double) {
if (value->get()->type() != eValueType::Double) {
return std::nullopt;
}
return value->as_double_value()->value();
return value->get()->as_double_value()->value();
}
std::optional<float> get_float(StringRef key) const
@ -270,19 +251,16 @@ struct DictionaryEntryParser {
template<typename PrimitiveType, typename ValueType>
std::optional<Vector<PrimitiveType>> get_array_primitive(StringRef key) const
{
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
if (value_ptr == nullptr) {
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
if (value == nullptr) {
return std::nullopt;
}
const DictionaryValue::LookupValue &value = *value_ptr;
if (value->type() != eValueType::Array) {
if (value->get()->type() != eValueType::Array) {
return std::nullopt;
}
Vector<PrimitiveType> result;
const ArrayValue::Items &elements = value->as_array_value()->elements();
for (const ArrayValue::Item &element : elements) {
for (const std::shared_ptr<Value> &element : value->get()->as_array_value()->elements()) {
const ValueType *value_type = static_cast<const ValueType *>(element.get());
PrimitiveType primitive_value = value_type->value();
result.append_as(primitive_value);
@ -321,8 +299,7 @@ class IDPStringSerializer : public IDPropertySerializer {
const IDProperty *id_property) const override
{
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
DictionaryValue::Items &attributes = result->elements();
attributes.append_as(std::pair(IDP_KEY_VALUE, new StringValue(IDP_String(id_property))));
result->append_str(IDP_KEY_VALUE, IDP_String(id_property));
return result;
}
@ -361,8 +338,7 @@ class IDPBoolSerializer : public IDPropertySerializer {
const IDProperty *id_property) const override
{
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
DictionaryValue::Items &attributes = result->elements();
attributes.append_as(std::pair(IDP_KEY_VALUE, new BooleanValue(IDP_Bool(id_property) != 0)));
result->append(IDP_KEY_VALUE, std::make_shared<BooleanValue>(IDP_Bool(id_property) != 0));
return result;
}
@ -401,8 +377,7 @@ class IDPIntSerializer : public IDPropertySerializer {
const IDProperty *id_property) const override
{
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
DictionaryValue::Items &attributes = result->elements();
attributes.append_as(std::pair(IDP_KEY_VALUE, new IntValue(IDP_Int(id_property))));
result->append_int(IDP_KEY_VALUE, IDP_Int(id_property));
return result;
}
@ -441,8 +416,7 @@ class IDPFloatSerializer : public IDPropertySerializer {
const IDProperty *id_property) const override
{
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
DictionaryValue::Items &attributes = result->elements();
attributes.append_as(std::pair(IDP_KEY_VALUE, new DoubleValue(IDP_Float(id_property))));
result->append_double(IDP_KEY_VALUE, IDP_Float(id_property));
return result;
}
@ -481,8 +455,7 @@ class IDPDoubleSerializer : public IDPropertySerializer {
const IDProperty *id_property) const override
{
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
DictionaryValue::Items &attributes = result->elements();
attributes.append_as(std::pair(IDP_KEY_VALUE, new DoubleValue(IDP_Double(id_property))));
result->append_double(IDP_KEY_VALUE, IDP_Double(id_property));
return result;
}
@ -521,45 +494,38 @@ class IDPArraySerializer : public IDPropertySerializer {
const IDProperty *id_property) const override
{
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
DictionaryValue::Items &attributes = result->elements();
const IDPropertySerializer &subtype_serializer = serializer_for(
static_cast<eIDPropertyType>(id_property->subtype));
attributes.append_as(
std::pair(IDP_KEY_SUBTYPE, new StringValue(subtype_serializer.type_name())));
result->append_str(IDP_KEY_SUBTYPE, subtype_serializer.type_name());
std::shared_ptr<ArrayValue> array = std::make_shared<ArrayValue>();
ArrayValue &array = *result->append_array(IDP_KEY_VALUE);
switch (static_cast<eIDPropertyType>(id_property->subtype)) {
case IDP_INT: {
int32_t *values = static_cast<int32_t *>(IDP_Array(id_property));
add_values<int32_t, IntValue>(array.get(), Span<int32_t>(values, id_property->len));
add_values<int32_t, IntValue>(array, Span<int32_t>(values, id_property->len));
break;
}
case IDP_FLOAT: {
float *values = static_cast<float *>(IDP_Array(id_property));
add_values<float, DoubleValue>(array.get(), Span<float>(values, id_property->len));
add_values<float, DoubleValue>(array, Span<float>(values, id_property->len));
break;
}
case IDP_DOUBLE: {
double *values = static_cast<double *>(IDP_Array(id_property));
add_values<double, DoubleValue>(array.get(), Span<double>(values, id_property->len));
add_values<double, DoubleValue>(array, Span<double>(values, id_property->len));
break;
}
case IDP_GROUP: {
IDProperty *values = static_cast<IDProperty *>(IDP_Array(id_property));
add_values(array.get(), Span<IDProperty>(values, id_property->len));
add_values(array, Span<IDProperty>(values, id_property->len));
break;
}
default: {
/* IDP_ARRAY only supports IDP_INT, IDP_FLOAT, IDP_DOUBLE and IDP_GROUP. */
BLI_assert_unreachable();
break;
}
}
attributes.append_as(std::pair(IDP_KEY_VALUE, std::move(array)));
return result;
}
@ -576,17 +542,13 @@ class IDPArraySerializer : public IDPropertySerializer {
switch (*property_subtype) {
case IDP_INT:
return idprop_array_int_from_value(entry_reader);
case IDP_FLOAT:
return idprop_array_float_from_value(entry_reader);
case IDP_DOUBLE:
return idprop_array_double_from_value(entry_reader);
default:
break;
return nullptr;
}
return nullptr;
}
private:
@ -596,25 +558,22 @@ class IDPArraySerializer : public IDPropertySerializer {
typename PrimitiveType,
/* Type of value that can store the PrimitiveType in the Array. */
typename ValueType>
void add_values(ArrayValue *array, Span<PrimitiveType> values) const
void add_values(ArrayValue &array, Span<PrimitiveType> values) const
{
ArrayValue::Items &items = array->elements();
for (PrimitiveType value : values) {
items.append_as(std::make_shared<ValueType>(value));
array.append(std::make_shared<ValueType>(value));
}
}
void add_values(ArrayValue *array, Span<IDProperty> values) const
void add_values(ArrayValue &array, Span<IDProperty> values) const
{
ArrayValue::Items &items = array->elements();
for (const IDProperty &id_property : values) {
const IDPropertySerializer &value_serializer = serializer_for(
static_cast<eIDPropertyType>(id_property.type));
if (!value_serializer.supports_serializing()) {
continue;
}
std::shared_ptr<DictionaryValue> value = value_serializer.idprop_to_dictionary(&id_property);
items.append_as(value);
array.append(value_serializer.idprop_to_dictionary(&id_property));
}
}
@ -686,18 +645,15 @@ class IDPGroupSerializer : public IDPropertySerializer {
const IDProperty *id_property) const override
{
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
DictionaryValue::Items &attributes = result->elements();
std::shared_ptr<ArrayValue> array = std::make_shared<ArrayValue>();
ArrayValue::Items &elements = array->elements();
LISTBASE_FOREACH (IDProperty *, sub_property, &id_property->data.group) {
const IDPropertySerializer &sub_property_serializer = serializer_for(
static_cast<eIDPropertyType>(sub_property->type));
elements.append_as(sub_property_serializer.idprop_to_dictionary(sub_property));
array->append(sub_property_serializer.idprop_to_dictionary(sub_property));
}
attributes.append_as(std::pair(IDP_KEY_VALUE, array));
result->append(IDP_KEY_VALUE, std::move(array));
return result;
}
@ -716,7 +672,7 @@ class IDPGroupSerializer : public IDPropertySerializer {
}
std::unique_ptr<IDProperty, IDPropertyDeleter> result = create_group(name->c_str());
for (const ArrayValue::Item &element : array->elements()) {
for (const std::shared_ptr<Value> &element : array->elements()) {
if (element->type() != eValueType::Dictionary) {
continue;
}
@ -840,13 +796,12 @@ std::unique_ptr<ArrayValue> convert_to_serialize_values(const IDProperty *proper
{
BLI_assert(properties != nullptr);
std::unique_ptr<ArrayValue> result = std::make_unique<ArrayValue>();
ArrayValue::Items &elements = result->elements();
const IDProperty *current_property = properties;
while (current_property != nullptr) {
const IDPropertySerializer &serializer = serializer_for(
static_cast<eIDPropertyType>(current_property->type));
if (serializer.supports_serializing()) {
elements.append_as(serializer.idprop_to_dictionary(current_property));
result->append(serializer.idprop_to_dictionary(current_property));
}
current_property = current_property->next;
}
@ -877,8 +832,7 @@ static IDProperty *idprop_from_value(const ArrayValue &value)
IDProperty *result = nullptr;
IDProperty *previous_added = nullptr;
const ArrayValue::Items &elements = value.elements();
for (const ArrayValue::Item &element : elements) {
for (const std::shared_ptr<Value> &element : value.elements()) {
if (element->type() != eValueType::Dictionary) {
continue;
}

View File

@ -18,11 +18,11 @@ static void check_container_value(ArrayValue *value)
{
ASSERT_NE(value, nullptr);
ASSERT_EQ(value->type(), eValueType::Array);
const ArrayValue::Items elements = value->elements();
const Span<std::shared_ptr<Value>> elements = value->elements();
EXPECT_FALSE(elements.is_empty());
EXPECT_EQ(elements.size(), 1);
const ArrayValue::Item &item = value->elements()[0];
const std::shared_ptr<Value> &item = value->elements()[0];
ASSERT_EQ(item->type(), eValueType::Dictionary);
}
@ -72,7 +72,7 @@ static void test_string_to_value(const StringRefNull prop_name, const StringRefN
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
check_container_value(value.get());
const ArrayValue::Item &item = value->elements()[0];
const std::shared_ptr<Value> &item = value->elements()[0];
const DictionaryValue *object = item->as_dictionary_value();
const DictionaryValue::Lookup lookup = object->create_lookup();
@ -93,7 +93,7 @@ static void test_int_to_value(const StringRefNull prop_name, int32_t prop_conten
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
check_container_value(value.get());
const ArrayValue::Item &item = value->elements()[0];
const std::shared_ptr<Value> &item = value->elements()[0];
const DictionaryValue *object = item->as_dictionary_value();
const DictionaryValue::Lookup lookup = object->create_lookup();
@ -114,7 +114,7 @@ static void test_float_to_value(const StringRefNull prop_name, float prop_conten
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
check_container_value(value.get());
const ArrayValue::Item &item = value->elements()[0];
const std::shared_ptr<Value> &item = value->elements()[0];
const DictionaryValue *object = item->as_dictionary_value();
const DictionaryValue::Lookup lookup = object->create_lookup();
@ -135,7 +135,7 @@ static void test_double_to_value(const StringRefNull prop_name, double prop_cont
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
check_container_value(value.get());
const ArrayValue::Item &item = value->elements()[0];
const std::shared_ptr<Value> &item = value->elements()[0];
const DictionaryValue *object = item->as_dictionary_value();
const DictionaryValue::Lookup lookup = object->create_lookup();
@ -157,7 +157,7 @@ static void test_array_to_value(const StringRefNull prop_name, Vector<PrimitiveT
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
check_container_value(value.get());
const ArrayValue::Item &item = value->elements()[0];
const std::shared_ptr<Value> &item = value->elements()[0];
const DictionaryValue *object = item->as_dictionary_value();
const DictionaryValue::Lookup lookup = object->create_lookup();
@ -168,7 +168,7 @@ static void test_array_to_value(const StringRefNull prop_name, Vector<PrimitiveT
const std::shared_ptr<Value> &element = *lookup.lookup_ptr("value");
const ArrayValue *subvalues = element->as_array_value();
ASSERT_NE(subvalues, nullptr);
const ArrayValue::Items &subitems = subvalues->elements();
const Span<std::shared_ptr<Value>> subitems = subvalues->elements();
ASSERT_EQ(subitems.size(), prop_content.size());
for (size_t i = 0; i < prop_content.size(); i++) {

View File

@ -198,7 +198,7 @@ class StringValue : public Value {
std::string string_;
public:
StringValue(const StringRef string) : Value(eValueType::String), string_(string) {}
StringValue(std::string string) : Value(eValueType::String), string_(std::move(string)) {}
const std::string &value() const
{
@ -206,44 +206,12 @@ class StringValue : public Value {
}
};
/**
* Template for arrays and objects.
*
* Both ArrayValue and DictionaryValue store their values in an array.
*/
template<
/** The container type where the elements are stored in. */
typename Container,
/** ValueType representing the value (object/array). */
eValueType V,
/** Type of the data inside the container. */
typename ContainerItem = typename Container::value_type>
class ContainerValue : public Value {
public:
using Items = Container;
using Item = ContainerItem;
private:
Container inner_value_;
class ArrayValue : public Value {
Vector<std::shared_ptr<Value>> values_;
public:
ContainerValue() : Value(V) {}
ArrayValue() : Value(eValueType::Array) {}
const Container &elements() const
{
return inner_value_;
}
Container &elements()
{
return inner_value_;
}
};
class ArrayValue : public ContainerValue<Vector<std::shared_ptr<Value>>, eValueType::Array> {
public:
void append(std::shared_ptr<Value> value);
void append_bool(bool value);
void append_int(int value);
@ -252,32 +220,38 @@ class ArrayValue : public ContainerValue<Vector<std::shared_ptr<Value>>, eValueT
void append_null();
std::shared_ptr<DictionaryValue> append_dict();
std::shared_ptr<ArrayValue> append_array();
};
/**
* Internal storage type for DictionaryValue.
*
* The elements are stored as an key value pair. The value is a shared pointer so it can be shared
* when using `DictionaryValue::create_lookup`.
*/
using DictionaryElementType = std::pair<std::string, std::shared_ptr<Value>>;
Span<std::shared_ptr<Value>> elements() const
{
return values_;
}
};
/**
* Object is a key-value container where the key must be a std::string.
* Internally it is stored in a blender::Vector to ensure the order of keys.
*/
class DictionaryValue
: public ContainerValue<Vector<DictionaryElementType>, eValueType::Dictionary> {
class DictionaryValue : public Value {
public:
using LookupValue = std::shared_ptr<Value>;
using Lookup = Map<std::string, LookupValue>;
/**
* Elements are stored as an key value pair. The value is a shared pointer so it can be
* shared when using `DictionaryValue::create_lookup`.
*/
using Item = std::pair<std::string, std::shared_ptr<Value>>;
using Lookup = Map<std::string, std::shared_ptr<Value>>;
private:
Vector<Item> values_;
public:
DictionaryValue() : Value(eValueType::Dictionary) {}
/**
* Return a lookup map to quickly lookup by key.
*
* The lookup is owned by the caller.
*/
const Lookup create_lookup() const;
Lookup create_lookup() const;
const std::shared_ptr<Value> *lookup(const StringRef key) const;
std::optional<StringRefNull> lookup_str(const StringRef key) const;
@ -285,6 +259,10 @@ class DictionaryValue
std::optional<double> lookup_double(const StringRef key) const;
const DictionaryValue *lookup_dict(const StringRef key) const;
const ArrayValue *lookup_array(const StringRef key) const;
Span<Item> elements() const
{
return values_;
}
void append(std::string key, std::shared_ptr<Value> value);
void append_int(std::string key, int64_t value);

View File

@ -68,11 +68,10 @@ const DictionaryValue *Value::as_dictionary_value() const
static void convert_to_json(nlohmann::ordered_json &j, const Value &value);
static void convert_to_json(nlohmann::ordered_json &j, const ArrayValue &value)
{
const ArrayValue::Items &items = value.elements();
/* Create a json array to store the elements. If this isn't done and items is empty it would
* return use a null value, in stead of an empty array. */
j = "[]"_json;
for (const ArrayValue::Item &item_value : items) {
for (const std::shared_ptr<Value> &item_value : value.elements()) {
nlohmann::ordered_json json_item;
convert_to_json(json_item, *item_value);
j.push_back(json_item);
@ -81,11 +80,10 @@ static void convert_to_json(nlohmann::ordered_json &j, const ArrayValue &value)
static void convert_to_json(nlohmann::ordered_json &j, const DictionaryValue &value)
{
const DictionaryValue::Items &attributes = value.elements();
/* Create a json object to store the attributes. If this isn't done and attributes is empty it
* would return use a null value, in stead of an empty object. */
j = "{}"_json;
for (const DictionaryValue::Item &attribute : attributes) {
for (const DictionaryValue::Item &attribute : value.elements()) {
nlohmann::ordered_json json_item;
convert_to_json(json_item, *attribute.second);
j[attribute.first] = json_item;
@ -143,11 +141,8 @@ static std::unique_ptr<Value> convert_from_json(const nlohmann::ordered_json &j)
static std::unique_ptr<ArrayValue> convert_from_json_to_array(const nlohmann::ordered_json &j)
{
std::unique_ptr<ArrayValue> array = std::make_unique<ArrayValue>();
ArrayValue::Items &elements = array->elements();
for (auto element : j.items()) {
nlohmann::ordered_json element_json = element.value();
std::unique_ptr<Value> value = convert_from_json(element_json);
elements.append_as(value.release());
array->append(convert_from_json(element.value()));
}
return array;
}
@ -156,12 +151,8 @@ static std::unique_ptr<DictionaryValue> convert_from_json_to_object(
const nlohmann::ordered_json &j)
{
std::unique_ptr<DictionaryValue> object = std::make_unique<DictionaryValue>();
DictionaryValue::Items &elements = object->elements();
for (auto element : j.items()) {
std::string key = element.key();
nlohmann::ordered_json element_json = element.value();
std::unique_ptr<Value> value = convert_from_json(element_json);
elements.append_as(std::pair(key, value.release()));
object->append(element.key(), convert_from_json(element.value()));
}
return object;
}
@ -216,7 +207,7 @@ static std::unique_ptr<Value> convert_from_json(const nlohmann::ordered_json &j)
void ArrayValue::append(std::shared_ptr<Value> value)
{
this->elements().append(std::move(value));
values_.append(std::move(value));
}
void ArrayValue::append_bool(const bool value)
@ -258,10 +249,10 @@ std::shared_ptr<ArrayValue> ArrayValue::append_array()
return value;
}
const DictionaryValue::Lookup DictionaryValue::create_lookup() const
DictionaryValue::Lookup DictionaryValue::create_lookup() const
{
Lookup result;
for (const Item &item : elements()) {
for (const Item &item : values_) {
result.add_as(item.first, item.second);
}
return result;
@ -269,7 +260,7 @@ const DictionaryValue::Lookup DictionaryValue::create_lookup() const
const std::shared_ptr<Value> *DictionaryValue::lookup(const StringRef key) const
{
for (const auto &item : this->elements()) {
for (const auto &item : values_) {
if (item.first == key) {
return &item.second;
}
@ -325,7 +316,7 @@ const ArrayValue *DictionaryValue::lookup_array(const StringRef key) const
void DictionaryValue::append(std::string key, std::shared_ptr<Value> value)
{
this->elements().append({std::move(key), std::move(value)});
values_.append({std::move(key), std::move(value)});
}
void DictionaryValue::append_int(std::string key, const int64_t value)
@ -338,9 +329,9 @@ void DictionaryValue::append_double(std::string key, const double value)
this->append(std::move(key), std::make_shared<DoubleValue>(value));
}
void DictionaryValue::append_str(std::string key, const std::string value)
void DictionaryValue::append_str(std::string key, std::string value)
{
this->append(std::move(key), std::make_shared<StringValue>(value));
this->append(std::move(key), std::make_shared<StringValue>(std::move(value)));
}
std::shared_ptr<DictionaryValue> DictionaryValue::append_dict(std::string key)

View File

@ -2993,8 +2993,8 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 9)) {
const float default_snap_angle_increment = DEG2RADF(15.0f);
const float default_snap_angle_increment_precision = DEG2RADF(5.0f);
const float default_snap_angle_increment = DEG2RADF(5.0f);
const float default_snap_angle_increment_precision = DEG2RADF(1.0f);
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
scene->toolsettings->snap_angle_increment_2d = default_snap_angle_increment;
scene->toolsettings->snap_angle_increment_3d = default_snap_angle_increment;

View File

@ -330,10 +330,10 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
scene->eevee.flag |= SCE_EEVEE_SHADOW_SOFT;
/* Default Rotate Increment. */
const float default_snap_angle_increment = DEG2RADF(15.0f);
const float default_snap_angle_increment = DEG2RADF(5.0f);
scene->toolsettings->snap_angle_increment_2d = default_snap_angle_increment;
scene->toolsettings->snap_angle_increment_3d = default_snap_angle_increment;
const float default_snap_angle_increment_precision = DEG2RADF(5.0f);
const float default_snap_angle_increment_precision = DEG2RADF(1.0f);
scene->toolsettings->snap_angle_increment_2d_precision = default_snap_angle_increment_precision;
scene->toolsettings->snap_angle_increment_3d_precision = default_snap_angle_increment_precision;

View File

@ -136,6 +136,13 @@ SphericalHarmonicL1 lightprobe_irradiance_sample(
#ifdef IRRADIANCE_GRID_SAMPLING
float random = interlieved_gradient_noise(UTIL_TEXEL, 0.0, 0.0);
random = fract(random + sampling_rng_1D_get(SAMPLING_LIGHTPROBE));
#endif
#ifdef GPU_METAL
/* NOTE: Performs a chunked unroll to avoid the compiler unrolling the entire loop, avoiding
* very high instruction counts and long compilation time. Full unroll results in 90k +
* instructions. Chunked unroll is 5.1k instructions with reduced register pressure, while
* retaining most of the benefits of unrolling. */
# pragma clang loop unroll_count(16)
#endif
for (; i < IRRADIANCE_GRID_MAX; i++) {
/* Last grid is tagged as invalid to stop the iteration. */

View File

@ -17,7 +17,7 @@ void main()
int frame = gl_VertexID + cacheStart;
bool use_custom_color = customColor.x >= 0.0;
finalColor = (use_custom_color) ? vec4(customColor, 1.0) : vec4(1.0);
finalColor = (use_custom_color) ? vec4(customColor, 1.0) : colorVertex;
/* Bias to reduce z fighting with the path */
gl_Position.z -= 1e-4;

View File

@ -221,27 +221,30 @@ AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
/* apart from strictly keyframe-related contexts, this shouldn't even happen */
/* XXX: nla and channel here may not be necessary... */
if (ELEM(ac->datatype,
ANIMCONT_ACTION,
ANIMCONT_SHAPEKEY,
ANIMCONT_DOPESHEET,
ANIMCONT_FCURVES,
ANIMCONT_NLA,
ANIMCONT_CHANNEL,
ANIMCONT_TIMELINE))
if (!ELEM(ac->datatype,
ANIMCONT_ACTION,
ANIMCONT_SHAPEKEY,
ANIMCONT_DOPESHEET,
ANIMCONT_FCURVES,
ANIMCONT_NLA,
ANIMCONT_CHANNEL,
ANIMCONT_TIMELINE))
{
/* handling depends on the type of animation-context we've got */
if (ale) {
/* NLA Control Curves occur on NLA strips,
* and shouldn't be subjected to this kind of mapping. */
if (ale->type != ANIMTYPE_NLACURVE) {
return ale->adt;
}
}
return nullptr;
}
/* cannot handle... */
return nullptr;
/* handling depends on the type of animation-context we've got */
if (!ale) {
return nullptr;
}
/* NLA Control Curves occur on NLA strips,
* and shouldn't be subjected to this kind of mapping. */
if (ale->type == ANIMTYPE_NLACURVE) {
return nullptr;
}
return ale->adt;
}
/* ------------------- */

View File

@ -98,12 +98,12 @@ class AbstractFile {
bool exists() const
{
return BLI_exists(get_file_path());
return BLI_exists(this->get_file_path());
}
size_t get_file_size() const
{
return BLI_file_size(get_file_path());
return BLI_file_size(this->get_file_path());
}
};
@ -125,7 +125,7 @@ class BlendFile : public AbstractFile {
std::string get_filename() const
{
char filename[FILE_MAX];
BLI_path_split_file_part(get_file_path(), filename, sizeof(filename));
BLI_path_split_file_part(this->get_file_path(), filename, sizeof(filename));
return std::string(filename);
}
@ -136,232 +136,62 @@ class BlendFile : public AbstractFile {
};
/**
* \brief Single entry inside a #AssetIndexFile for reading.
* \brief add id + name to the attributes.
*
* NOTE: id and name are encoded like #ID.name
*/
struct AssetEntryReader {
private:
/**
* \brief Lookup table containing the elements of the entry.
*/
DictionaryValue::Lookup lookup;
static void add_id_name(DictionaryValue &result, const short idcode, const StringRefNull name)
{
char idcode_prefix[2];
/* Similar to `BKE_libblock_alloc`. */
*((short *)idcode_prefix) = idcode;
std::string name_with_idcode = std::string(idcode_prefix, sizeof(idcode_prefix)) + name;
StringRef get_name_with_idcode() const
{
return lookup.lookup(ATTRIBUTE_ENTRIES_NAME)->as_string_value()->value();
}
result.append_str(ATTRIBUTE_ENTRIES_NAME, name_with_idcode);
}
public:
AssetEntryReader(const DictionaryValue &entry) : lookup(entry.create_lookup()) {}
ID_Type get_idcode() const
{
const StringRef name_with_idcode = get_name_with_idcode();
return GS(name_with_idcode.data());
}
StringRef get_name() const
{
const StringRef name_with_idcode = get_name_with_idcode();
return name_with_idcode.substr(2);
}
bool has_description() const
{
return lookup.contains(ATTRIBUTE_ENTRIES_DESCRIPTION);
}
StringRef get_description() const
{
return lookup.lookup(ATTRIBUTE_ENTRIES_DESCRIPTION)->as_string_value()->value();
}
bool has_author() const
{
return lookup.contains(ATTRIBUTE_ENTRIES_AUTHOR);
}
StringRef get_author() const
{
return lookup.lookup(ATTRIBUTE_ENTRIES_AUTHOR)->as_string_value()->value();
}
bool has_copyright() const
{
return lookup.contains(ATTRIBUTE_ENTRIES_COPYRIGHT);
}
StringRef get_copyright() const
{
return lookup.lookup(ATTRIBUTE_ENTRIES_COPYRIGHT)->as_string_value()->value();
}
bool has_license() const
{
return lookup.contains(ATTRIBUTE_ENTRIES_LICENSE);
}
StringRef get_license() const
{
return lookup.lookup(ATTRIBUTE_ENTRIES_LICENSE)->as_string_value()->value();
}
StringRefNull get_catalog_name() const
{
return lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_NAME)->as_string_value()->value();
}
CatalogID get_catalog_id() const
{
const StringRefNull catalog_id =
lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_ID)->as_string_value()->value();
CatalogID catalog_uuid(catalog_id);
return catalog_uuid;
}
void add_tags_to_meta_data(AssetMetaData *asset_data) const
{
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS);
if (value_ptr == nullptr) {
return;
}
const ArrayValue *array_value = (*value_ptr)->as_array_value();
const ArrayValue::Items &elements = array_value->elements();
for (const ArrayValue::Item &item : elements) {
const StringRefNull tag_name = item->as_string_value()->value();
BKE_asset_metadata_tag_add(asset_data, tag_name.c_str());
}
}
void add_properties_to_meta_data(AssetMetaData *asset_data) const
{
BLI_assert(asset_data->properties == nullptr);
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(
ATTRIBUTE_ENTRIES_PROPERTIES);
if (value_ptr == nullptr) {
return;
}
const Value &value = *(value_ptr->get());
IDProperty *properties = convert_from_serialize_value(value);
asset_data->properties = properties;
}
};
struct AssetEntryWriter {
private:
DictionaryValue::Items &attributes;
public:
AssetEntryWriter(DictionaryValue &entry) : attributes(entry.elements()) {}
/**
* \brief add id + name to the attributes.
*
* NOTE: id and name are encoded like #ID.name
*/
void add_id_name(const short idcode, const StringRefNull name)
{
char idcode_prefix[2];
/* Similar to `BKE_libblock_alloc`. */
*((short *)idcode_prefix) = idcode;
std::string name_with_idcode = std::string(idcode_prefix, sizeof(idcode_prefix)) + name;
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_NAME, new StringValue(name_with_idcode)));
}
void add_catalog_id(const CatalogID &catalog_id)
{
attributes.append_as(
std::pair(ATTRIBUTE_ENTRIES_CATALOG_ID, new StringValue(catalog_id.str())));
}
void add_catalog_name(const StringRefNull catalog_name)
{
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_CATALOG_NAME, new StringValue(catalog_name)));
}
void add_description(const StringRefNull description)
{
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_DESCRIPTION, new StringValue(description)));
}
void add_author(const StringRefNull author)
{
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_AUTHOR, new StringValue(author)));
}
void add_copyright(const StringRefNull copyright)
{
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_COPYRIGHT, new StringValue(copyright)));
}
void add_license(const StringRefNull license)
{
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_LICENSE, new StringValue(license)));
}
void add_tags(const ListBase /* AssetTag */ *asset_tags)
{
ArrayValue *tags = new ArrayValue();
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_TAGS, tags));
ArrayValue::Items &tag_items = tags->elements();
LISTBASE_FOREACH (AssetTag *, tag, asset_tags) {
tag_items.append_as(new StringValue(tag->name));
}
}
void add_properties(const IDProperty *properties)
{
std::unique_ptr<Value> value = convert_to_serialize_values(properties);
if (value == nullptr) {
return;
}
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_PROPERTIES, value.release()));
}
};
static void init_value_from_file_indexer_entry(AssetEntryWriter &result,
static void init_value_from_file_indexer_entry(DictionaryValue &result,
const FileIndexerEntry *indexer_entry)
{
const BLODataBlockInfo &datablock_info = indexer_entry->datablock_info;
result.add_id_name(indexer_entry->idcode, datablock_info.name);
add_id_name(result, indexer_entry->idcode, datablock_info.name);
const AssetMetaData &asset_data = *datablock_info.asset_data;
result.add_catalog_id(asset_data.catalog_id);
result.add_catalog_name(asset_data.catalog_simple_name);
result.append_str(ATTRIBUTE_ENTRIES_CATALOG_ID, CatalogID(asset_data.catalog_id).str());
result.append_str(ATTRIBUTE_ENTRIES_CATALOG_NAME, asset_data.catalog_simple_name);
if (asset_data.description != nullptr) {
result.add_description(asset_data.description);
if (const char *description = asset_data.description) {
result.append_str(ATTRIBUTE_ENTRIES_DESCRIPTION, description);
}
if (asset_data.author != nullptr) {
result.add_author(asset_data.author);
if (const char *author = asset_data.author) {
result.append_str(ATTRIBUTE_ENTRIES_AUTHOR, author);
}
if (asset_data.copyright != nullptr) {
result.add_copyright(asset_data.copyright);
if (const char *copyright = asset_data.copyright) {
result.append_str(ATTRIBUTE_ENTRIES_COPYRIGHT, copyright);
}
if (asset_data.license != nullptr) {
result.add_license(asset_data.license);
if (const char *license = asset_data.license) {
result.append_str(ATTRIBUTE_ENTRIES_LICENSE, license);
}
if (!BLI_listbase_is_empty(&asset_data.tags)) {
result.add_tags(&asset_data.tags);
ArrayValue &tags = *result.append_array(ATTRIBUTE_ENTRIES_TAGS);
LISTBASE_FOREACH (AssetTag *, tag, &asset_data.tags) {
tags.append_str(tag->name);
}
}
if (asset_data.properties != nullptr) {
result.add_properties(asset_data.properties);
if (const IDProperty *properties = asset_data.properties) {
if (std::unique_ptr<Value> value = convert_to_serialize_values(properties)) {
result.append(ATTRIBUTE_ENTRIES_PROPERTIES, std::move(value));
}
}
/* TODO: asset_data.IDProperties */
}
static void init_value_from_file_indexer_entries(DictionaryValue &result,
const FileIndexerEntries &indexer_entries)
{
ArrayValue *entries = new ArrayValue();
ArrayValue::Items &items = entries->elements();
auto entries = std::make_shared<ArrayValue>();
for (LinkNode *ln = indexer_entries.entries; ln; ln = ln->next) {
const FileIndexerEntry *indexer_entry = static_cast<const FileIndexerEntry *>(ln->link);
@ -370,80 +200,75 @@ static void init_value_from_file_indexer_entries(DictionaryValue &result,
if (indexer_entry->datablock_info.asset_data == nullptr) {
continue;
}
DictionaryValue *entry_value = new DictionaryValue();
AssetEntryWriter entry(*entry_value);
init_value_from_file_indexer_entry(entry, indexer_entry);
items.append_as(entry_value);
init_value_from_file_indexer_entry(*entries->append_dict(), indexer_entry);
}
/* When no entries to index, we should not store the entries attribute as this would make the
* size bigger than the #MIN_FILE_SIZE_WITH_ENTRIES. */
if (items.is_empty()) {
delete entries;
if (entries->elements().is_empty()) {
return;
}
DictionaryValue::Items &attributes = result.elements();
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES, entries));
result.append(ATTRIBUTE_ENTRIES, entries);
}
static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
const AssetEntryReader &entry)
const DictionaryValue &entry)
{
indexer_entry.idcode = entry.get_idcode();
const StringRef idcode_name = *entry.lookup_str(ATTRIBUTE_ENTRIES_NAME);
const std::string name = entry.get_name();
STRNCPY(indexer_entry.datablock_info.name, name.c_str());
indexer_entry.idcode = GS(idcode_name.data());
idcode_name.substr(2).copy(indexer_entry.datablock_info.name);
AssetMetaData *asset_data = BKE_asset_metadata_create();
indexer_entry.datablock_info.asset_data = asset_data;
indexer_entry.datablock_info.free_asset_data = true;
if (entry.has_description()) {
const StringRef description = entry.get_description();
asset_data->description = BLI_strdupn(description.data(), description.size());
if (const std::optional<StringRef> value = entry.lookup_str(ATTRIBUTE_ENTRIES_DESCRIPTION)) {
asset_data->description = BLI_strdupn(value->data(), value->size());
}
if (entry.has_author()) {
const StringRef author = entry.get_author();
asset_data->author = BLI_strdupn(author.data(), author.size());
if (const std::optional<StringRef> value = entry.lookup_str(ATTRIBUTE_ENTRIES_AUTHOR)) {
asset_data->author = BLI_strdupn(value->data(), value->size());
}
if (entry.has_copyright()) {
const StringRef copyright = entry.get_copyright();
asset_data->copyright = BLI_strdupn(copyright.data(), copyright.size());
if (const std::optional<StringRef> value = entry.lookup_str(ATTRIBUTE_ENTRIES_COPYRIGHT)) {
asset_data->copyright = BLI_strdupn(value->data(), value->size());
}
if (entry.has_license()) {
const StringRef license = entry.get_license();
asset_data->license = BLI_strdupn(license.data(), license.size());
if (const std::optional<StringRef> value = entry.lookup_str(ATTRIBUTE_ENTRIES_LICENSE)) {
asset_data->license = BLI_strdupn(value->data(), value->size());
}
const StringRefNull catalog_name = entry.get_catalog_name();
const StringRefNull catalog_name = *entry.lookup_str(ATTRIBUTE_ENTRIES_CATALOG_NAME);
STRNCPY_UTF8(asset_data->catalog_simple_name, catalog_name.c_str());
asset_data->catalog_id = entry.get_catalog_id();
const StringRefNull catalog_id = *entry.lookup_str(ATTRIBUTE_ENTRIES_CATALOG_ID);
asset_data->catalog_id = CatalogID(catalog_id);
entry.add_tags_to_meta_data(asset_data);
entry.add_properties_to_meta_data(asset_data);
if (const ArrayValue *array_value = entry.lookup_array(ATTRIBUTE_ENTRIES_TAGS)) {
for (const std::shared_ptr<Value> &item : array_value->elements()) {
BKE_asset_metadata_tag_add(asset_data, item->as_string_value()->value().c_str());
}
}
if (const std::shared_ptr<Value> *value = entry.lookup(ATTRIBUTE_ENTRIES_PROPERTIES)) {
asset_data->properties = convert_from_serialize_value(*value->get());
}
}
static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries,
const DictionaryValue &value)
{
const DictionaryValue::Lookup attributes = value.create_lookup();
const DictionaryValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES);
BLI_assert(entries_value != nullptr);
if (entries_value == nullptr) {
const ArrayValue *entries = value.lookup_array(ATTRIBUTE_ENTRIES);
BLI_assert(entries != nullptr);
if (entries == nullptr) {
return 0;
}
int num_entries_read = 0;
const ArrayValue::Items elements = (*entries_value)->as_array_value()->elements();
for (ArrayValue::Item element : elements) {
const AssetEntryReader asset_entry(*element->as_dictionary_value());
for (const std::shared_ptr<Value> &element : entries->elements()) {
FileIndexerEntry *entry = static_cast<FileIndexerEntry *>(
MEM_callocN(sizeof(FileIndexerEntry), __func__));
init_indexer_entry_from_value(*entry, asset_entry);
init_indexer_entry_from_value(*entry, *element->as_dictionary_value());
BLI_linklist_prepend(&indexer_entries.entries, entry);
num_entries_read += 1;
@ -483,21 +308,19 @@ struct AssetLibraryIndex {
std::string library_path;
public:
AssetLibraryIndex(const StringRef library_path) : library_path(library_path)
{
init_indices_base_path();
this->init_indices_base_path();
}
uint64_t hash() const
{
DefaultHash<StringRefNull> hasher;
return hasher(get_library_file_path());
return get_default_hash(this->library_path);
}
StringRefNull get_library_file_path() const
{
return library_path;
return this->library_path;
}
/**
@ -516,7 +339,7 @@ struct AssetLibraryIndex {
ss << std::setfill('0') << std::setw(16) << std::hex << hash() << SEP_STR;
BLI_path_append(index_path, sizeof(index_path), ss.str().c_str());
indices_base_path = std::string(index_path);
this->indices_base_path = std::string(index_path);
}
/**
@ -527,7 +350,7 @@ struct AssetLibraryIndex {
std::string index_file_path(const BlendFile &asset_file) const
{
std::stringstream ss;
ss << indices_base_path;
ss << this->indices_base_path;
ss << std::setfill('0') << std::setw(16) << std::hex << asset_file.hash() << "_"
<< asset_file.get_filename() << ".index.json";
return ss.str();
@ -539,7 +362,7 @@ struct AssetLibraryIndex {
*/
void collect_preexisting_file_indices()
{
const char *index_path = indices_base_path.c_str();
const char *index_path = this->indices_base_path.c_str();
if (!BLI_is_dir(index_path)) {
return;
}
@ -548,7 +371,7 @@ struct AssetLibraryIndex {
for (int i = 0; i < dir_entries_num; i++) {
direntry *entry = &dir_entries[i];
if (BLI_str_endswith(entry->relname, ".index.json")) {
preexisting_file_indices.add_as(std::string(entry->path));
this->preexisting_file_indices.add_as(std::string(entry->path));
}
}
@ -557,7 +380,7 @@ struct AssetLibraryIndex {
void mark_as_used(const std::string &filename)
{
PreexistingFileIndexInfo *preexisting = preexisting_file_indices.lookup_ptr(filename);
PreexistingFileIndexInfo *preexisting = this->preexisting_file_indices.lookup_ptr(filename);
if (preexisting) {
preexisting->is_used = true;
}
@ -571,7 +394,7 @@ struct AssetLibraryIndex {
bool delete_file_index(const std::string &filename)
{
if (BLI_delete(filename.c_str(), false, false) == 0) {
preexisting_file_indices.remove(filename);
this->preexisting_file_indices.remove(filename);
return true;
}
return false;
@ -590,7 +413,7 @@ struct AssetLibraryIndex {
Set<StringRef> files_to_remove;
for (auto preexisting_index : preexisting_file_indices.items()) {
for (auto preexisting_index : this->preexisting_file_indices.items()) {
if (preexisting_index.value.is_used) {
continue;
}
@ -654,7 +477,7 @@ struct AssetIndex {
root->append_int(ATTRIBUTE_VERSION, CURRENT_VERSION);
init_value_from_file_indexer_entries(*root, indexer_entries);
contents = std::move(root);
this->contents = std::move(root);
}
/**
@ -665,16 +488,12 @@ struct AssetIndex {
int get_version() const
{
const DictionaryValue *root = contents->as_dictionary_value();
const DictionaryValue *root = this->contents->as_dictionary_value();
if (root == nullptr) {
return UNKNOWN_VERSION;
}
const DictionaryValue::Lookup attributes = root->create_lookup();
const DictionaryValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION);
if (version_value == nullptr) {
return UNKNOWN_VERSION;
}
return (*version_value)->as_int_value()->value();
const std::optional<int64_t> version_value = root->lookup_int(ATTRIBUTE_VERSION);
return version_value.value_or(UNKNOWN_VERSION);
}
bool is_latest_version() const
@ -689,7 +508,7 @@ struct AssetIndex {
*/
int extract_into(FileIndexerEntries &indexer_entries) const
{
const DictionaryValue *root = contents->as_dictionary_value();
const DictionaryValue *root = this->contents->as_dictionary_value();
const int num_entries_read = init_indexer_entries_from_value(indexer_entries, *root);
return num_entries_read;
}
@ -717,7 +536,7 @@ class AssetIndexFile : public AbstractFile {
void mark_as_used()
{
library_index.mark_as_used(filename);
this->library_index.mark_as_used(this->filename);
}
const char *get_file_path() const override
@ -730,7 +549,7 @@ class AssetIndexFile : public AbstractFile {
*/
bool is_older_than(BlendFile &asset_file) const
{
return BLI_file_older(get_file_path(), asset_file.get_file_path());
return BLI_file_older(this->get_file_path(), asset_file.get_file_path());
}
/**
@ -746,7 +565,7 @@ class AssetIndexFile : public AbstractFile {
{
JsonFormatter formatter;
std::ifstream is;
is.open(filename);
is.open(this->filename);
std::unique_ptr<Value> read_data = formatter.deserialize(is);
is.close();
@ -755,19 +574,19 @@ class AssetIndexFile : public AbstractFile {
bool ensure_parent_path_exists() const
{
return BLI_file_ensure_parent_dir_exists(get_file_path());
return BLI_file_ensure_parent_dir_exists(this->get_file_path());
}
void write_contents(AssetIndex &content)
{
JsonFormatter formatter;
if (!ensure_parent_path_exists()) {
CLOG_ERROR(&LOG, "Index not created: couldn't create folder [%s].", get_file_path());
CLOG_ERROR(&LOG, "Index not created: couldn't create folder [%s].", this->get_file_path());
return;
}
std::ofstream os;
os.open(filename, std::ios::out | std::ios::trunc);
os.open(this->filename, std::ios::out | std::ios::trunc);
formatter.serialize(os, *content.contents);
os.close();
}
@ -779,39 +598,38 @@ int AssetLibraryIndex::remove_broken_index_files()
{
Set<StringRef> files_to_remove;
preexisting_file_indices.foreach_item(
[&](const std::string &index_path, const PreexistingFileIndexInfo &) {
AssetIndexFile index_file(*this, index_path);
for (const std::string &index_path : this->preexisting_file_indices.keys()) {
AssetIndexFile index_file(*this, index_path);
/* Bug was causing empty index files, so non-empty ones can be skipped. */
if (index_file.constains_entries()) {
return;
}
/* Bug was causing empty index files, so non-empty ones can be skipped. */
if (index_file.constains_entries()) {
continue;
}
/* Use the file modification time stamp to attempt to remove empty index files from a
* certain period (when the bug was in there). Starting from a day before the bug was
* introduced until a day after the fix should be enough to mitigate possible local time
* zone issues. */
/* Use the file modification time stamp to attempt to remove empty index files from a
* certain period (when the bug was in there). Starting from a day before the bug was
* introduced until a day after the fix should be enough to mitigate possible local time
* zone issues. */
std::tm tm_from{};
tm_from.tm_year = 2022 - 1900; /* 2022 */
tm_from.tm_mon = 11 - 1; /* November */
tm_from.tm_mday = 8; /* Day before bug was introduced. */
std::tm tm_to{};
tm_from.tm_year = 2022 - 1900; /* 2022 */
tm_from.tm_mon = 12 - 1; /* December */
tm_from.tm_mday = 3; /* Day after fix. */
std::time_t timestamp_from = std::mktime(&tm_from);
std::time_t timestamp_to = std::mktime(&tm_to);
BLI_stat_t stat = {};
if (BLI_stat(index_file.get_file_path(), &stat) == -1) {
return;
}
if (IN_RANGE(stat.st_mtime, timestamp_from, timestamp_to)) {
CLOG_INFO(&LOG, 2, "Remove potentially broken index file [%s].", index_path.c_str());
files_to_remove.add(index_path);
}
});
std::tm tm_from{};
tm_from.tm_year = 2022 - 1900; /* 2022 */
tm_from.tm_mon = 11 - 1; /* November */
tm_from.tm_mday = 8; /* Day before bug was introduced. */
std::tm tm_to{};
tm_from.tm_year = 2022 - 1900; /* 2022 */
tm_from.tm_mon = 12 - 1; /* December */
tm_from.tm_mday = 3; /* Day after fix. */
std::time_t timestamp_from = std::mktime(&tm_from);
std::time_t timestamp_to = std::mktime(&tm_to);
BLI_stat_t stat = {};
if (BLI_stat(index_file.get_file_path(), &stat) == -1) {
continue;
}
if (IN_RANGE(stat.st_mtime, timestamp_from, timestamp_to)) {
CLOG_INFO(&LOG, 2, "Remove potentially broken index file [%s].", index_path.c_str());
files_to_remove.add(index_path);
}
}
int num_files_deleted = 0;
for (StringRef files_to_remove : files_to_remove) {

View File

@ -524,6 +524,169 @@ static void GREASE_PENCIL_OT_layer_duplicate(wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna, "empty_keyframes", false, "Empty Keyframes", "Add Empty Keyframes");
}
static int grease_pencil_layer_mask_add_exec(bContext *C, wmOperator *op)
{
using namespace ::blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
if (!grease_pencil.has_active_layer()) {
return OPERATOR_CANCELLED;
}
Layer &active_layer = *grease_pencil.get_active_layer();
int mask_name_length;
char *mask_name = RNA_string_get_alloc(op->ptr, "name", nullptr, 0, &mask_name_length);
BLI_SCOPED_DEFER([&] { MEM_SAFE_FREE(mask_name); });
if (TreeNode *node = grease_pencil.find_node_by_name(mask_name)) {
if (grease_pencil.is_layer_active(&node->as_layer())) {
BKE_report(op->reports, RPT_ERROR, "Cannot add active layer as mask");
return OPERATOR_CANCELLED;
}
if (BLI_findstring(&active_layer.masks,
mask_name,
offsetof(GreasePencilLayerMask, layer_name)) != nullptr)
{
BKE_report(op->reports, RPT_ERROR, "Layer already added");
return OPERATOR_CANCELLED;
}
LayerMask *new_mask = MEM_new<LayerMask>(__func__, mask_name);
BLI_addtail(&active_layer.masks, reinterpret_cast<GreasePencilLayerMask *>(new_mask));
/* Make the newly added mask active. */
active_layer.active_mask_index = BLI_listbase_count(&active_layer.masks) - 1;
}
else {
BKE_report(op->reports, RPT_ERROR, "Unable to find layer to add");
return OPERATOR_CANCELLED;
}
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, &grease_pencil);
return OPERATOR_FINISHED;
}
static void GREASE_PENCIL_OT_layer_mask_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add New Mask Layer";
ot->idname = "GREASE_PENCIL_OT_layer_mask_add";
ot->description = "Add new layer as masking";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* callbacks */
ot->exec = grease_pencil_layer_mask_add_exec;
ot->poll = active_grease_pencil_layer_poll;
/* properties */
RNA_def_string(ot->srna, "name", nullptr, 0, "Layer", "Name of the layer");
}
static int grease_pencil_layer_mask_remove_exec(bContext *C, wmOperator * /*op*/)
{
using namespace ::blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
if (!grease_pencil.has_active_layer()) {
return OPERATOR_CANCELLED;
}
Layer &active_layer = *grease_pencil.get_active_layer();
if (GreasePencilLayerMask *mask = reinterpret_cast<GreasePencilLayerMask *>(
BLI_findlink(&active_layer.masks, active_layer.active_mask_index)))
{
BLI_remlink(&active_layer.masks, mask);
MEM_delete(reinterpret_cast<LayerMask *>(mask));
active_layer.active_mask_index = std::max(active_layer.active_mask_index - 1, 0);
}
else {
return OPERATOR_CANCELLED;
}
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, &grease_pencil);
return OPERATOR_FINISHED;
}
static void GREASE_PENCIL_OT_layer_mask_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Mask Layer";
ot->idname = "GREASE_PENCIL_OT_layer_mask_remove";
ot->description = "Remove Layer Mask";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* callbacks */
ot->exec = grease_pencil_layer_mask_remove_exec;
ot->poll = active_grease_pencil_layer_poll;
}
enum class LayerMaskMoveDirection : int8_t { Up = -1, Down = 1 };
static int grease_pencil_layer_mask_reorder_exec(bContext *C, wmOperator *op)
{
using namespace ::blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
if (!grease_pencil.has_active_layer()) {
return OPERATOR_CANCELLED;
}
Layer &active_layer = *grease_pencil.get_active_layer();
const int direction = RNA_enum_get(op->ptr, "direction");
bool changed = false;
if (GreasePencilLayerMask *mask = reinterpret_cast<GreasePencilLayerMask *>(
BLI_findlink(&active_layer.masks, active_layer.active_mask_index)))
{
if (BLI_listbase_link_move(&active_layer.masks, mask, direction)) {
active_layer.active_mask_index = std::max(active_layer.active_mask_index + direction, 0);
changed = true;
}
}
else {
return OPERATOR_CANCELLED;
}
if (changed) {
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, &grease_pencil);
}
return OPERATOR_FINISHED;
}
static void GREASE_PENCIL_OT_layer_mask_reorder(wmOperatorType *ot)
{
static const EnumPropertyItem enum_direction[] = {
{int(LayerMaskMoveDirection::Up), "UP", 0, "Up", ""},
{int(LayerMaskMoveDirection::Down), "DOWN", 0, "Down", ""},
{0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
ot->name = "Reorder Grease Pencil Layer Mask";
ot->idname = "GREASE_PENCIL_OT_layer_mask_reorder";
ot->description = "Reorder the active Grease Pencil mask layer up/down in the list";
/* api callbacks */
ot->exec = grease_pencil_layer_mask_reorder_exec;
ot->poll = active_grease_pencil_layer_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ot->prop = RNA_def_enum(ot->srna, "direction", enum_direction, 0, "Direction", "");
}
} // namespace blender::ed::greasepencil
void ED_operatortypes_grease_pencil_layers()
@ -540,4 +703,8 @@ void ED_operatortypes_grease_pencil_layers()
WM_operatortype_append(GREASE_PENCIL_OT_layer_duplicate);
WM_operatortype_append(GREASE_PENCIL_OT_layer_group_add);
WM_operatortype_append(GREASE_PENCIL_OT_layer_mask_add);
WM_operatortype_append(GREASE_PENCIL_OT_layer_mask_remove);
WM_operatortype_append(GREASE_PENCIL_OT_layer_mask_reorder);
}

View File

@ -255,6 +255,27 @@ class LayerViewItem : public AbstractTreeViewItem {
PointerRNA layer_ptr = RNA_pointer_create(&grease_pencil_.id, &RNA_GreasePencilLayer, &layer_);
uiBlock *block = uiLayoutGetBlock(&row);
const int icon = (layer_.base.flag & GP_LAYER_TREE_NODE_HIDE_MASKS) == 0 ? ICON_CLIPUV_DEHLT :
ICON_CLIPUV_HLT;
but = uiDefIconButR(block,
UI_BTYPE_ICON_TOGGLE,
0,
icon,
0,
0,
UI_UNIT_X,
UI_UNIT_Y,
&layer_ptr,
"use_masks",
0,
0.0f,
0.0f,
nullptr);
if (layer_.parent_group().use_masks()) {
UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
but = uiDefIconButR(block,
UI_BTYPE_ICON_TOGGLE,
0,
@ -359,6 +380,9 @@ class LayerGroupViewItem : public AbstractTreeViewItem {
PointerRNA group_ptr = RNA_pointer_create(
&grease_pencil_.id, &RNA_GreasePencilLayerGroup, &group_);
const int icon = (group_.base.flag & GP_LAYER_TREE_NODE_HIDE_MASKS) == 0 ? ICON_CLIPUV_DEHLT :
ICON_CLIPUV_HLT;
uiItemR(&row, &group_ptr, "use_masks", UI_ITEM_R_ICON_ONLY, nullptr, icon);
uiItemR(&row, &group_ptr, "hide", UI_ITEM_R_ICON_ONLY, nullptr, ICON_NONE);
uiItemR(&row, &group_ptr, "lock", UI_ITEM_R_ICON_ONLY, nullptr, ICON_NONE);
}

View File

@ -99,7 +99,7 @@ void enable_ex(Main *bmain, Depsgraph *depsgraph, Object *ob)
BM_mesh_bm_from_me(ss->bm, mesh, &convert_params);
triangulate(ss->bm);
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
BM_data_layer_ensure_named(ss->bm, &ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
/* Make sure the data for existing faces are initialized. */
if (mesh->faces_num != ss->bm->totface) {

View File

@ -1311,15 +1311,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
else if (event->prev_val == KM_PRESS) {
t->modifiers |= MOD_PRECISION;
/* If we are already in a snapping mode, we don't want to add mouse precision,
* it makes things like rotate snap really tedious. */
if (t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) {
t->mouse.precision = false;
}
else {
/* Shift is modifier for higher precision transform. */
t->mouse.precision = true;
}
t->mouse.precision = true;
t->redraw |= TREDRAW_HARD;
}

View File

@ -426,13 +426,16 @@ void MTLStorageBuf::read(void *data)
else {
/** Direct storage buffer read. */
/* If we have a synchronization event from a prior memory sync, ensure memory is fully synced.
* Otherwise, assume read is asynchronous. */
* Otherwise, assume read is synchronous and stall until in-flight work is complete. */
if (gpu_write_fence_ != nil) {
/* Ensure the GPU updates are visible to the host before reading. */
while (gpu_write_fence_.signaledValue < host_read_signal_value_) {
BLI_time_sleep_ms(1);
}
}
else {
GPU_finish();
}
/* Managed buffers need to be explicitly flushed back to host. */
if (metal_buffer_->get_resource_options() & MTLResourceStorageModeManaged) {

View File

@ -448,7 +448,7 @@ static void colormanage_cache_handle_release(void *cache_handle)
/** \name Initialization / De-initialization
* \{ */
static void colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config,
static bool colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config,
char *colorspace_name,
const char *role,
const char *backup_role)
@ -457,56 +457,56 @@ static void colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config,
ociocs = OCIO_configGetColorSpace(config, role);
if (!ociocs && backup_role) {
if (ociocs == nullptr && backup_role) {
ociocs = OCIO_configGetColorSpace(config, backup_role);
}
if (ociocs) {
const char *name = OCIO_colorSpaceGetName(ociocs);
if (ociocs == nullptr) {
/* Overall fallback role. */
ociocs = OCIO_configGetColorSpace(config, "default");
}
/* assume function was called with buffer properly allocated to MAX_COLORSPACE_NAME chars */
BLI_strncpy(colorspace_name, name, MAX_COLORSPACE_NAME);
OCIO_colorSpaceRelease(ociocs);
}
else {
printf("Color management: Error could not find role %s role.\n", role);
if (ociocs == nullptr) {
printf("Color management: Error, could not find role \"%s\"\n", role);
return false;
}
const char *name = OCIO_colorSpaceGetName(ociocs);
/* assume function was called with buffer properly allocated to MAX_COLORSPACE_NAME chars */
BLI_strncpy(colorspace_name, name, MAX_COLORSPACE_NAME);
OCIO_colorSpaceRelease(ociocs);
return true;
}
static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
static bool colormanage_load_config(OCIO_ConstConfigRcPtr *config)
{
int tot_colorspace, tot_display, tot_display_view, tot_looks;
int index, viewindex, viewindex2;
const char *name;
bool ok = true;
/* get roles */
colormanage_role_color_space_name_get(config, global_role_data, OCIO_ROLE_DATA, nullptr);
colormanage_role_color_space_name_get(
ok &= colormanage_role_color_space_name_get(config, global_role_data, OCIO_ROLE_DATA, nullptr);
ok &= colormanage_role_color_space_name_get(
config, global_role_scene_linear, OCIO_ROLE_SCENE_LINEAR, nullptr);
colormanage_role_color_space_name_get(
ok &= colormanage_role_color_space_name_get(
config, global_role_color_picking, OCIO_ROLE_COLOR_PICKING, nullptr);
colormanage_role_color_space_name_get(
ok &= colormanage_role_color_space_name_get(
config, global_role_texture_painting, OCIO_ROLE_TEXTURE_PAINT, nullptr);
colormanage_role_color_space_name_get(
ok &= colormanage_role_color_space_name_get(
config, global_role_default_sequencer, OCIO_ROLE_DEFAULT_SEQUENCER, OCIO_ROLE_SCENE_LINEAR);
colormanage_role_color_space_name_get(
ok &= colormanage_role_color_space_name_get(
config, global_role_default_byte, OCIO_ROLE_DEFAULT_BYTE, OCIO_ROLE_TEXTURE_PAINT);
colormanage_role_color_space_name_get(
ok &= colormanage_role_color_space_name_get(
config, global_role_default_float, OCIO_ROLE_DEFAULT_FLOAT, OCIO_ROLE_SCENE_LINEAR);
/* load colorspaces */
tot_colorspace = OCIO_configGetNumColorSpaces(config);
for (index = 0; index < tot_colorspace; index++) {
OCIO_ConstColorSpaceRcPtr *ocio_colorspace;
const char *description;
bool is_invertible, is_data;
const int tot_colorspace = OCIO_configGetNumColorSpaces(config);
for (int index = 0; index < tot_colorspace; index++) {
const char *name = OCIO_configGetColorSpaceNameByIndex(config, index);
name = OCIO_configGetColorSpaceNameByIndex(config, index);
ocio_colorspace = OCIO_configGetColorSpace(config, name);
description = OCIO_colorSpaceGetDescription(ocio_colorspace);
is_invertible = OCIO_colorSpaceIsInvertible(ocio_colorspace);
is_data = OCIO_colorSpaceIsData(ocio_colorspace);
OCIO_ConstColorSpaceRcPtr *ocio_colorspace = OCIO_configGetColorSpace(config, name);
const char *description = OCIO_colorSpaceGetDescription(ocio_colorspace);
const bool is_invertible = OCIO_colorSpaceIsInvertible(ocio_colorspace);
const bool is_data = OCIO_colorSpaceIsData(ocio_colorspace);
ColorSpace *colorspace = colormanage_colorspace_add(name, description, is_invertible, is_data);
@ -525,51 +525,49 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
}
/* load displays */
viewindex2 = 0;
tot_display = OCIO_configGetNumDisplays(config);
const int tot_display = OCIO_configGetNumDisplays(config);
int viewindex2 = 0;
for (index = 0; index < tot_display; index++) {
const char *displayname;
ColorManagedDisplay *display;
for (int index = 0; index < tot_display; index++) {
const char *displayname = OCIO_configGetDisplay(config, index);
displayname = OCIO_configGetDisplay(config, index);
display = colormanage_display_add(displayname);
ColorManagedDisplay *display = colormanage_display_add(displayname);
/* load views */
tot_display_view = OCIO_configGetNumViews(config, displayname);
for (viewindex = 0; viewindex < tot_display_view; viewindex++, viewindex2++) {
const char *viewname;
ColorManagedView *view;
LinkData *display_view;
viewname = OCIO_configGetView(config, displayname, viewindex);
const int tot_display_view = OCIO_configGetNumViews(config, displayname);
for (int viewindex = 0; viewindex < tot_display_view; viewindex++, viewindex2++) {
const char *viewname = OCIO_configGetView(config, displayname, viewindex);
/* first check if view transform with given name was already loaded */
view = colormanage_view_get_named(viewname);
ColorManagedView *view = colormanage_view_get_named(viewname);
if (!view) {
view = colormanage_view_add(viewname);
}
display_view = BLI_genericNodeN(view);
LinkData *display_view = BLI_genericNodeN(view);
BLI_addtail(&display->views, display_view);
}
}
global_tot_display = tot_display;
if (global_tot_display == 0) {
printf("Color management: Error, could not find any displays\n");
ok = false;
}
else if (global_tot_view == 0) {
printf("Color management: Error, could not find any views\n");
ok = false;
}
/* load looks */
tot_looks = OCIO_configGetNumLooks(config);
const int tot_looks = OCIO_configGetNumLooks(config);
colormanage_look_add("None", "", true);
for (index = 0; index < tot_looks; index++) {
OCIO_ConstLookRcPtr *ocio_look;
const char *process_space;
name = OCIO_configGetLookNameByIndex(config, index);
ocio_look = OCIO_configGetLook(config, name);
process_space = OCIO_lookGetProcessSpace(ocio_look);
for (int index = 0; index < tot_looks; index++) {
const char *name = OCIO_configGetLookNameByIndex(config, index);
OCIO_ConstLookRcPtr *ocio_look = OCIO_configGetLook(config, name);
const char *process_space = OCIO_lookGetProcessSpace(ocio_look);
OCIO_lookRelease(ocio_look);
colormanage_look_add(name, process_space, false);
@ -587,6 +585,8 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
mul_m3_m3m3(imbuf_aces_to_scene_linear, imbuf_xyz_to_scene_linear, OCIO_ACES_TO_XYZ);
invert_m3_m3(imbuf_scene_linear_to_aces, imbuf_aces_to_scene_linear);
return ok;
}
static void colormanage_free_config()
@ -645,60 +645,61 @@ static void colormanage_free_config()
/* free looks */
BLI_freelistN(&global_looks);
global_tot_looks = 0;
OCIO_exit();
}
void colormanagement_init()
{
const char *ocio_env;
char configfile[FILE_MAX];
OCIO_ConstConfigRcPtr *config = nullptr;
OCIO_init();
ocio_env = BLI_getenv("OCIO");
/* First try config from environment variable. */
const char *ocio_env = BLI_getenv("OCIO");
if (ocio_env && ocio_env[0] != '\0') {
config = OCIO_configCreateFromEnv();
if (config != nullptr) {
printf("Color management: Using %s as a configuration file\n", ocio_env);
OCIO_setCurrentConfig(config);
const bool ok = colormanage_load_config(config);
OCIO_configRelease(config);
if (!ok) {
printf("Color management: Failed to load config from environment\n");
colormanage_free_config();
config = nullptr;
}
}
}
/* Then try bunded config file. */
if (config == nullptr) {
const std::optional<std::string> configdir = BKE_appdir_folder_id(BLENDER_DATAFILES,
"colormanagement");
if (configdir.has_value()) {
char configfile[FILE_MAX];
BLI_path_join(configfile, sizeof(configfile), configdir->c_str(), BCM_CONFIG_FILE);
config = OCIO_configCreateFromFile(configfile);
if (config != nullptr) {
OCIO_setCurrentConfig(config);
const bool ok = colormanage_load_config(config);
OCIO_configRelease(config);
if (!ok) {
printf("Color management: Failed to load bundled config\n");
colormanage_free_config();
config = nullptr;
}
}
}
}
/* Then use fallback. */
if (config == nullptr) {
printf("Color management: using fallback mode for management\n");
config = OCIO_configCreateFallback();
}
if (config) {
OCIO_setCurrentConfig(config);
colormanage_load_config(config);
OCIO_configRelease(config);
}
/* If there are no valid display/views, use fallback mode. */
if (global_tot_display == 0 || global_tot_view == 0) {
printf("Color management: no displays/views in the config, using fallback mode instead\n");
/* Free old config. */
colormanage_free_config();
/* Initialize fallback config. */
printf("Color management: Using fallback mode for management\n");
config = OCIO_configCreateFallback();
colormanage_load_config(config);
}
@ -730,6 +731,7 @@ void colormanagement_exit()
memset(&global_color_picking_state, 0, sizeof(global_color_picking_state));
colormanage_free_config();
OCIO_exit();
}
/** \} */

View File

@ -240,6 +240,7 @@ typedef enum GreasePencilLayerTreeNodeFlag {
GP_LAYER_TREE_NODE_USE_LIGHTS = (1 << 4),
GP_LAYER_TREE_NODE_USE_ONION_SKINNING = (1 << 5),
GP_LAYER_TREE_NODE_EXPANDED = (1 << 6),
GP_LAYER_TREE_NODE_HIDE_MASKS = (1 << 7),
} GreasePencilLayerTreeNodeFlag;
struct GreasePencilLayerTreeGroup;
@ -292,6 +293,8 @@ typedef struct GreasePencilLayer {
* List of `GreasePencilLayerMask`.
*/
ListBase masks;
int active_mask_index;
char _pad2[4];
/**
* Layer parent object. Can be an armature in which case the `parsubstr` is the bone name.
*/
@ -302,7 +305,9 @@ typedef struct GreasePencilLayer {
* Use the functions is the `bke::greasepencil::Layer` class instead.
*/
float translation[3], rotation[3], scale[3];
char _pad2[4];
char _pad3[4];
/** Name of the view layer used to filter render output. */
char *viewlayername;
/**
* Runtime struct pointer.
*/

View File

@ -377,10 +377,10 @@
.snap_flag_anim = SCE_SNAP, \
.snap_transform_mode_flag = SCE_SNAP_TRANSFORM_MODE_TRANSLATE, \
.snap_face_nearest_steps = 1, \
.snap_angle_increment_3d = DEG2RADF(15.0f), \
.snap_angle_increment_2d = DEG2RADF(15.0f), \
.snap_angle_increment_3d_precision = DEG2RADF(5.0f), \
.snap_angle_increment_2d_precision = DEG2RADF(5.0f), \
.snap_angle_increment_3d = DEG2RADF(5.0f), \
.snap_angle_increment_2d = DEG2RADF(5.0f), \
.snap_angle_increment_3d_precision = DEG2RADF(1.0f), \
.snap_angle_increment_2d_precision = DEG2RADF(1.0f), \
\
.curve_paint_settings = _DNA_DEFAULTS_CurvePaintSettings, \
\

View File

@ -64,6 +64,60 @@ static void rna_grease_pencil_dependency_update(Main *bmain, Scene * /*scene*/,
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, rna_grease_pencil(ptr));
}
static void rna_grease_pencil_layer_mask_name_get(PointerRNA *ptr, char *dst)
{
using namespace blender;
GreasePencilLayerMask *mask = static_cast<GreasePencilLayerMask *>(ptr->data);
if (mask->layer_name != nullptr) {
strcpy(dst, mask->layer_name);
}
else {
dst[0] = '\0';
}
}
static int rna_grease_pencil_layer_mask_name_length(PointerRNA *ptr)
{
using namespace blender;
GreasePencilLayerMask *mask = static_cast<GreasePencilLayerMask *>(ptr->data);
if (mask->layer_name != nullptr) {
return strlen(mask->layer_name);
}
return 0;
}
static void rna_grease_pencil_layer_mask_name_set(PointerRNA *ptr, const char *value)
{
using namespace blender;
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
GreasePencilLayerMask *mask = static_cast<GreasePencilLayerMask *>(ptr->data);
const std::string oldname(mask->layer_name);
if (bke::greasepencil::TreeNode *node = grease_pencil->find_node_by_name(oldname)) {
grease_pencil->rename_node(*node, value);
}
}
static int rna_grease_pencil_active_mask_index_get(PointerRNA *ptr)
{
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
return layer->active_mask_index;
}
static void rna_grease_pencil_active_mask_index_set(PointerRNA *ptr, int value)
{
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
layer->active_mask_index = value;
}
static void rna_grease_pencil_active_mask_index_range(
PointerRNA *ptr, int *min, int *max, int * /*softmin*/, int * /*softmax*/)
{
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
*min = 0;
*max = max_ii(0, BLI_listbase_count(&layer->masks) - 1);
}
static void rna_iterator_grease_pencil_layers_begin(CollectionPropertyIterator *iter,
PointerRNA *ptr)
{
@ -229,6 +283,60 @@ static int rna_iterator_grease_pencil_layer_groups_length(PointerRNA *ptr)
#else
static void rna_def_grease_pencil_layers_mask_api(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
PropertyRNA *prop;
RNA_def_property_srna(cprop, "GreasePencilLayerMasks");
srna = RNA_def_struct(brna, "GreasePencilLayerMasks", nullptr);
RNA_def_struct_sdna(srna, "GreasePencilLayer");
RNA_def_struct_ui_text(
srna, "Grease Pencil Mask Layers", "Collection of grease pencil masking layers");
prop = RNA_def_property(srna, "active_mask_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_int_funcs(prop,
"rna_grease_pencil_active_mask_index_get",
"rna_grease_pencil_active_mask_index_set",
"rna_grease_pencil_active_mask_index_range");
RNA_def_property_ui_text(prop, "Active Layer Mask Index", "Active index in layer mask array");
}
static void rna_def_grease_pencil_layer_mask(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "GreasePencilLayerMask", nullptr);
RNA_def_struct_sdna(srna, "GreasePencilLayerMask");
RNA_def_struct_ui_text(srna, "Grease Pencil Masking Layers", "List of Mask Layers");
// RNA_def_struct_path_func(srna, "rna_GreasePencilLayerMask_path");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Layer", "Mask layer name");
RNA_def_property_string_sdna(prop, nullptr, "layer_name");
RNA_def_property_string_funcs(prop,
"rna_grease_pencil_layer_mask_name_get",
"rna_grease_pencil_layer_mask_name_length",
"rna_grease_pencil_layer_mask_name_set");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, nullptr);
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_LAYER_MASK_HIDE);
RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
RNA_def_property_ui_text(prop, "Hide", "Set mask Visibility");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_LAYER_MASK_INVERT);
RNA_def_property_ui_icon(prop, ICON_SELECT_INTERSECT, 1);
RNA_def_property_ui_text(prop, "Invert", "Invert mask");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
}
static void rna_def_grease_pencil_layer(BlenderRNA *brna)
{
StructRNA *srna;
@ -236,6 +344,15 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
static const float scale_defaults[3] = {1.0f, 1.0f, 1.0f};
static const EnumPropertyItem rna_enum_layer_blend_modes_items[] = {
{GP_LAYER_BLEND_NONE, "REGULAR", 0, "Regular", ""},
{GP_LAYER_BLEND_HARDLIGHT, "HARDLIGHT", 0, "Hard Light", ""},
{GP_LAYER_BLEND_ADD, "ADD", 0, "Add", ""},
{GP_LAYER_BLEND_SUBTRACT, "SUBTRACT", 0, "Subtract", ""},
{GP_LAYER_BLEND_MULTIPLY, "MULTIPLY", 0, "Multiply", ""},
{GP_LAYER_BLEND_DIVIDE, "DIVIDE", 0, "Divide", ""},
{0, nullptr, 0, nullptr, nullptr}};
srna = RNA_def_struct(brna, "GreasePencilLayer", nullptr);
RNA_def_struct_sdna(srna, "GreasePencilLayer");
RNA_def_struct_ui_text(srna, "Grease Pencil Layer", "Collection of related drawings");
@ -251,6 +368,13 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, "rna_grease_pencil_update");
/* Mask Layers */
prop = RNA_def_property(srna, "mask_layers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, nullptr, "masks", nullptr);
RNA_def_property_struct_type(prop, "GreasePencilLayerMask");
RNA_def_property_ui_text(prop, "Masks", "List of Masking Layers");
rna_def_grease_pencil_layers_mask_api(brna, prop);
/* Visibility */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
@ -282,6 +406,16 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
prop, "Onion Skinning", "Display onion skins before and after the current frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Use Masks. */
prop = RNA_def_property(srna, "use_masks", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_HIDE_MASKS);
RNA_def_property_ui_text(
prop,
"Use Masks",
"The visibility of drawings on this layer is affected by the layers in its masks list");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* pass index for compositing and modifiers */
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Layer Index\" pass");
@ -325,6 +459,19 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3);
RNA_def_property_ui_text(prop, "Scale", "Scale of the layer");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
prop = RNA_def_property(srna, "viewlayer_render", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, nullptr, "viewlayername");
RNA_def_property_ui_text(
prop,
"ViewLayer",
"Only include Layer in this View Layer render output (leave blank to include always)");
prop = RNA_def_property(srna, "blend_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "blend_mode");
RNA_def_property_enum_items(prop, rna_enum_layer_blend_modes_items);
RNA_def_property_ui_text(prop, "Blend Mode", "Blend mode");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
}
static void rna_def_grease_pencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
@ -385,6 +532,16 @@ static void rna_def_grease_pencil_layer_group(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Locked", "Protect group from further editing and/or frame changes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
/* Use Masks. */
prop = RNA_def_property(srna, "use_masks", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_HIDE_MASKS);
RNA_def_property_ui_text(prop,
"Use Masks",
"The visibility of drawings in the layers in this group is affected by "
"the layers in the masks lists");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
}
static void rna_def_grease_pencil_data(BlenderRNA *brna)
@ -461,6 +618,7 @@ void RNA_def_grease_pencil(BlenderRNA *brna)
{
rna_def_grease_pencil_data(brna);
rna_def_grease_pencil_layer(brna);
rna_def_grease_pencil_layer_mask(brna);
rna_def_grease_pencil_layer_group(brna);
}

View File

@ -827,6 +827,7 @@ static void rna_Window_workspace_update(bContext *C, PointerRNA *ptr)
if (new_workspace) {
wmWindowManager *wm = CTX_wm_manager(C);
WM_event_add_notifier_ex(wm, win, NC_SCREEN | ND_WORKSPACE_SET, new_workspace);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, nullptr);
win->workspace_hook->temp_workspace_store = nullptr;
}
}

View File

@ -77,7 +77,7 @@ class AntiAliasingOperation : public NodeOperation {
* algorithm expects it in the [0, 10] range. */
float get_local_contrast_adaptation_factor()
{
return node_storage(bnode()).threshold * 10.0f;
return node_storage(bnode()).contrast_limit * 10.0f;
}
/* Blender encodes the corner rounding factor in the float [0, 1] range, while the SMAA algorithm

View File

@ -1486,6 +1486,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NUMSELECT);
UI_fontstyle_set(&style->widget);
/* Width based on the text lengths. */
int text_width = std::max(
120 * UI_SCALE_FAC,