Merge branch 'master' of https://github.com/highfidelity/hifi into amc
10
interface/resources/icons/tablet-icons/mic-clip-i.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.3383 4.13446L23.8713 5.60152C21.9374 3.46761 19.2033 2.06723 16.0691 2.06723C13.0683 2.06723 10.4009 3.40093 8.46707 5.40147L7 3.9344C9.26728 1.53375 12.5348 0 16.0691 0C19.7368 0 23.071 1.60044 25.3383 4.13446ZM21.9376 7.53584L20.4705 9.0029C19.4703 7.66921 17.8698 6.86899 16.0693 6.86899C14.4022 6.86899 12.9351 7.66921 11.8682 8.80285L10.4011 7.33578C11.8015 5.80203 13.802 4.80176 16.0693 4.80176C18.4033 4.80176 20.5372 5.86871 21.9376 7.53584ZM17.9575 30.1572C17.9575 31.1771 17.1307 32.0039 16.1108 32.0039C15.0909 32.0039 14.2642 31.1771 14.2642 30.1572C14.2642 29.1373 15.0909 28.3105 16.1108 28.3105C17.1307 28.3105 17.9575 29.1373 17.9575 30.1572ZM18.3632 11.0801H14.1597L15.0116 25.8539H17.4867L18.3632 11.0801Z" fill="#EA4C5F"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="32" height="32" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1 KiB |
3
interface/resources/icons/tablet-icons/mic-gate-i.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.1999 4.72587C17.5049 4.72587 18.5628 3.66795 18.5628 2.36294C18.5628 1.05792 17.5049 0 16.1999 0C14.8948 0 13.8369 1.05792 13.8369 2.36294C13.8369 3.66795 14.8948 4.72587 16.1999 4.72587ZM18.6667 11.8004V14.7337H13.7334V11.8004C13.7334 10.467 14.8667 9.40039 16.2 9.40039C17.6 9.40039 18.6667 10.467 18.6667 11.8004ZM13.7334 20.1332V17.2666H18.6667V20.1332C18.6667 21.4665 17.5333 22.5332 16.2 22.5332C14.8667 22.5332 13.7334 21.4665 13.7334 20.1332ZM23.6665 20.6V17.0667C23.6665 16.4 23.0665 15.9334 22.4665 15.9334C21.7998 15.9334 21.3332 16.4667 21.3332 17.1333V20.6C21.3332 23.0666 19.0665 25.0666 16.3332 25.0666C13.5999 25.0666 11.3333 23.0666 11.3333 20.6V17.0667C11.3333 16.4 10.8666 15.8667 10.2666 15.8667C9.59999 15.8 9 16.2667 9 16.9333V20.6C9 23.9999 11.6666 26.7999 15.1333 27.3332V29.5998H12.2666C11.6 29.5998 11.0666 30.1332 11.0666 30.7998C11.0666 31.4665 11.6 31.9998 12.2666 31.9998H20.4665C21.1332 31.9998 21.6665 31.4665 21.6665 30.7998C21.6665 30.1332 21.1332 29.5998 20.4665 29.5998H17.5332V27.3332C20.9998 26.7332 23.6665 23.9999 23.6665 20.6Z" fill="#00B4EF" fill-opacity="0.7"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -1,25 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1"
|
||||
id="svg2" inkscape:version="0.91 r13725" sodipodi:docname="mic-mute-a.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 50 50"
|
||||
style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#EA4C5F;}
|
||||
</style>
|
||||
<sodipodi:namedview bordercolor="#666666" borderopacity="1" gridtolerance="10" guidetolerance="10" id="namedview18" inkscape:current-layer="svg2" inkscape:cx="25" inkscape:cy="25" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-height="480" inkscape:window-maximized="0" inkscape:window-width="852" inkscape:window-x="0" inkscape:window-y="0" inkscape:zoom="4.72" objecttolerance="10" pagecolor="#ff0000" showgrid="false">
|
||||
</sodipodi:namedview>
|
||||
<g id="Layer_2">
|
||||
</g>
|
||||
<g id="Layer_1">
|
||||
<path id="path8" class="st0" d="M28.9,17.1v-0.5c0-2-1.7-3.6-3.7-3.6l0,0c-2,0-3.7,1.6-3.7,3.6v6.9L28.9,17.1z"/>
|
||||
<path id="path10" class="st0" d="M21.5,29.2v0.2c0,2,1.6,3.6,3.7,3.6l0,0c2,0,3.7-1.6,3.7-3.6v-6.6L21.5,29.2z"/>
|
||||
<path id="path12" class="st0" d="M39.1,16.8L13.6,39.1c-0.7,0.6-1.8,0.5-2.4-0.2L11,38.7c-0.6-0.7-0.5-1.8,0.2-2.4l25.4-22.4
|
||||
c0.7-0.6,1.8-0.5,2.4,0.2l0.2,0.2C39.8,15.1,39.7,16.1,39.1,16.8z"/>
|
||||
<path id="path14" class="st0" d="M23.4,40.2v3.4h-4.3c-1,0-1.8,0.8-1.8,1.8s0.8,1.8,1.8,1.8h12.3c1,0,1.8-0.8,1.8-1.8
|
||||
s-0.8-1.8-1.8-1.8H27v-3.4c5.2-0.8,9.2-5,9.2-10.1c0-0.1,0-5.1,0-5.3c0-1-0.9-1.7-1.8-1.7c-1,0-1.7,0.8-1.7,1.8c0,0.3,0,4.8,0,5.2
|
||||
c0,3.7-3.4,6.7-7.5,6.7c-3.6,0-6.7-2.3-7.3-5.4L15,34C16.4,37.2,19.6,39.7,23.4,40.2z"/>
|
||||
<path id="path16" class="st0" d="M17.7,24.9c0-1-0.7-1.8-1.6-1.8c-1-0.1-1.8,0.7-1.9,1.6c0,0.2,0,4.2,0,5.3l3.5-3.1
|
||||
C17.7,25.9,17.7,25,17.7,24.9z"/>
|
||||
</g>
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.6441 4.13328L24.1775 5.59992C22.2442 3.46662 19.5109 2.06664 16.3776 2.06664C13.3776 2.06664 10.711 3.39995 8.77768 5.39993L7.31104 3.93328C9.57767 1.53331 12.8443 0 16.3776 0C20.0442 0 23.3775 1.59998 25.6441 4.13328ZM20.7777 9.00072L22.2444 7.53408C20.8444 5.86743 18.7111 4.80078 16.3778 4.80078C14.1111 4.80078 12.1112 5.80077 10.7112 7.33408L12.1778 8.80073C13.2445 7.66741 14.7111 6.86742 16.3778 6.86742C18.1777 6.86742 19.7777 7.66741 20.7777 9.00072ZM18.8803 12.0758V11.7496C18.8803 10.4445 17.7763 9.40039 16.4775 9.40039C15.1787 9.40039 14.0747 10.4445 14.0747 11.7496V16.2521L18.8803 12.0758ZM14.543 21.5129L12.6113 23.2103C13.4959 24.2599 14.9141 24.9311 16.4774 24.9311C19.14 24.9311 21.348 22.9735 21.348 20.559V17.1658C21.348 16.5132 21.8026 15.9912 22.452 15.9912C23.0364 15.9912 23.6209 16.448 23.6209 17.1005V20.559C23.6209 23.887 21.0233 26.6277 17.6464 27.1498V29.3684H20.5038C21.1532 29.3684 21.6727 29.8905 21.6727 30.543C21.6727 31.1956 21.1532 31.7176 20.5038 31.7176H12.5161C11.8667 31.7176 11.3471 31.1956 11.3471 30.543C11.3471 29.8905 11.8667 29.3684 12.5161 29.3684H15.3085V27.1498C13.5328 26.915 11.9589 26.0045 10.8771 24.7343L8.9443 26.4327C8.48972 26.8242 7.77537 26.759 7.38573 26.3022L7.25585 26.1717C6.8662 25.7149 6.93114 24.9971 7.38573 24.6056L23.8806 9.98853C24.3352 9.597 25.0495 9.66226 25.4392 10.119L25.5691 10.2495C25.9587 10.7716 25.8938 11.4241 25.5041 11.8809L18.8803 17.7015V20.1017C18.8803 21.4068 17.7763 22.4509 16.4775 22.4509C15.6689 22.4509 14.9744 22.0838 14.543 21.5129ZM10.5679 15.9919C11.1523 15.9919 11.6069 16.5139 11.6069 17.1664V18.4715L9.33398 20.4944V17.0359C9.39892 16.4486 9.91845 15.9266 10.5679 15.9919Z" fill="#EA4C5F"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.8 KiB |
|
@ -1,25 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1"
|
||||
id="svg2" inkscape:version="0.91 r13725" sodipodi:docname="mic-mute-a.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 50 50"
|
||||
style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#EA4C5F;}
|
||||
</style>
|
||||
<sodipodi:namedview bordercolor="#666666" borderopacity="1" gridtolerance="10" guidetolerance="10" id="namedview18" inkscape:current-layer="svg2" inkscape:cx="25" inkscape:cy="25" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-height="480" inkscape:window-maximized="0" inkscape:window-width="852" inkscape:window-x="0" inkscape:window-y="0" inkscape:zoom="4.72" objecttolerance="10" pagecolor="#ff0000" showgrid="false">
|
||||
</sodipodi:namedview>
|
||||
<g id="Layer_2">
|
||||
</g>
|
||||
<g id="Layer_1">
|
||||
<path id="path8" class="st0" d="M28.9,17.1v-0.5c0-2-1.7-3.6-3.7-3.6l0,0c-2,0-3.7,1.6-3.7,3.6v6.9L28.9,17.1z"/>
|
||||
<path id="path10" class="st0" d="M21.5,29.2v0.2c0,2,1.6,3.6,3.7,3.6l0,0c2,0,3.7-1.6,3.7-3.6v-6.6L21.5,29.2z"/>
|
||||
<path id="path12" class="st0" d="M39.1,16.8L13.6,39.1c-0.7,0.6-1.8,0.5-2.4-0.2L11,38.7c-0.6-0.7-0.5-1.8,0.2-2.4l25.4-22.4
|
||||
c0.7-0.6,1.8-0.5,2.4,0.2l0.2,0.2C39.8,15.1,39.7,16.1,39.1,16.8z"/>
|
||||
<path id="path14" class="st0" d="M23.4,40.2v3.4h-4.3c-1,0-1.8,0.8-1.8,1.8s0.8,1.8,1.8,1.8h12.3c1,0,1.8-0.8,1.8-1.8
|
||||
s-0.8-1.8-1.8-1.8H27v-3.4c5.2-0.8,9.2-5,9.2-10.1c0-0.1,0-5.1,0-5.3c0-1-0.9-1.7-1.8-1.7c-1,0-1.7,0.8-1.7,1.8c0,0.3,0,4.8,0,5.2
|
||||
c0,3.7-3.4,6.7-7.5,6.7c-3.6,0-6.7-2.3-7.3-5.4L15,34C16.4,37.2,19.6,39.7,23.4,40.2z"/>
|
||||
<path id="path16" class="st0" d="M17.7,24.9c0-1-0.7-1.8-1.6-1.8c-1-0.1-1.8,0.7-1.9,1.6c0,0.2,0,4.2,0,5.3l3.5-3.1
|
||||
C17.7,25.9,17.7,25,17.7,24.9z"/>
|
||||
</g>
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.6441 4.13328L24.1775 5.59992C22.2442 3.46662 19.5109 2.06664 16.3776 2.06664C13.3776 2.06664 10.711 3.39995 8.77768 5.39993L7.31104 3.93328C9.57767 1.53331 12.8443 0 16.3776 0C20.0442 0 23.3775 1.59998 25.6441 4.13328ZM20.7777 9.00072L22.2444 7.53408C20.8444 5.86743 18.7111 4.80078 16.3778 4.80078C14.1111 4.80078 12.1112 5.80077 10.7112 7.33408L12.1778 8.80073C13.2445 7.66741 14.7111 6.86742 16.3778 6.86742C18.1777 6.86742 19.7777 7.66741 20.7777 9.00072ZM18.8803 12.0758V11.7496C18.8803 10.4445 17.7763 9.40039 16.4775 9.40039C15.1787 9.40039 14.0747 10.4445 14.0747 11.7496V16.2521L18.8803 12.0758ZM14.543 21.5129L12.6113 23.2103C13.4959 24.2599 14.9141 24.9311 16.4774 24.9311C19.14 24.9311 21.348 22.9735 21.348 20.559V17.1658C21.348 16.5132 21.8026 15.9912 22.452 15.9912C23.0364 15.9912 23.6209 16.448 23.6209 17.1005V20.559C23.6209 23.887 21.0233 26.6277 17.6464 27.1498V29.3684H20.5038C21.1532 29.3684 21.6727 29.8905 21.6727 30.543C21.6727 31.1956 21.1532 31.7176 20.5038 31.7176H12.5161C11.8667 31.7176 11.3471 31.1956 11.3471 30.543C11.3471 29.8905 11.8667 29.3684 12.5161 29.3684H15.3085V27.1498C13.5328 26.915 11.9589 26.0045 10.8771 24.7343L8.9443 26.4327C8.48972 26.8242 7.77537 26.759 7.38573 26.3022L7.25585 26.1717C6.8662 25.7149 6.93114 24.9971 7.38573 24.6056L23.8806 9.98853C24.3352 9.597 25.0495 9.66226 25.4392 10.119L25.5691 10.2495C25.9587 10.7716 25.8938 11.4241 25.5041 11.8809L18.8803 17.7015V20.1017C18.8803 21.4068 17.7763 22.4509 16.4775 22.4509C15.6689 22.4509 14.9744 22.0838 14.543 21.5129ZM10.5679 15.9919C11.1523 15.9919 11.6069 16.5139 11.6069 17.1664V18.4715L9.33398 20.4944V17.0359C9.39893 16.4486 9.91845 15.9266 10.5679 15.9919Z" fill="#EA4C5F"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.8 KiB |
|
@ -1,60 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 40 40"
|
||||
style="enable-background:new 0 0 40 40;"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="mic-mute.svg"><metadata
|
||||
id="metadata6958"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6956" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1824"
|
||||
inkscape:window-height="1057"
|
||||
id="namedview6954"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.9"
|
||||
inkscape:cx="-40.338983"
|
||||
inkscape:cy="20"
|
||||
inkscape:window-x="88"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" /><style
|
||||
type="text/css"
|
||||
id="style6942">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style><ellipse
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path8048"
|
||||
cx="20.1"
|
||||
cy="20.5"
|
||||
rx="15.967586"
|
||||
ry="15.967585" /><rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#feffff;stroke-width:0;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect8065"
|
||||
width="30.1991"
|
||||
height="2.9999897"
|
||||
x="13.432917"
|
||||
y="-1.2235159"
|
||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)" /></svg>
|
Before Width: | Height: | Size: 2.2 KiB |
|
@ -1,70 +1,3 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 50 50"
|
||||
style="enable-background:new 0 0 50 50;"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="mic-unmute-a.svg"><metadata
|
||||
id="metadata22"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs20" /><sodipodi:namedview
|
||||
pagecolor="#ff0000"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="852"
|
||||
inkscape:window-height="480"
|
||||
id="namedview18"
|
||||
showgrid="false"
|
||||
inkscape:zoom="4.72"
|
||||
inkscape:cx="25"
|
||||
inkscape:cy="25"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg2" /><style
|
||||
type="text/css"
|
||||
id="style4">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style><g
|
||||
id="Layer_2" /><g
|
||||
id="Layer_1"
|
||||
style="fill:#000000;fill-opacity:1"><path
|
||||
class="st0"
|
||||
d="M31.4,14.1l2.2-2.2c-2.1-2.5-5.3-4.1-8.8-4.1c-3.4,0-6.4,1.5-8.5,3.8c0.7,0.7,1.5,1.5,2.2,2.2 c1.6-1.7,3.8-2.9,6.3-2.9C27.5,10.9,29.9,12.1,31.4,14.1z"
|
||||
id="path8"
|
||||
style="fill:#000000;fill-opacity:1" /><path
|
||||
class="st0"
|
||||
d="M36.5,9l2.2-2.2C35.3,3,30.3,0.6,24.8,0.6c-5.3,0-10.2,2.3-13.6,5.9c0.7,0.7,1.5,1.5,2.2,2.2 c2.9-3,6.9-5,11.4-5C29.5,3.7,33.6,5.8,36.5,9z"
|
||||
id="path10"
|
||||
style="fill:#000000;fill-opacity:1" /><path
|
||||
class="st0"
|
||||
d="M28.5,22.7v-4.4c0-2-1.6-3.6-3.7-3.6h0c-2,0-3.7,1.6-3.7,3.6v4.4H28.5z"
|
||||
id="path12"
|
||||
style="fill:#000000;fill-opacity:1" /><path
|
||||
class="st0"
|
||||
d="M21.1,26.5v4.3c0,2,1.7,3.6,3.7,3.6h0c2,0,3.7-1.6,3.7-3.6v-4.3H21.1z"
|
||||
id="path14"
|
||||
style="fill:#000000;fill-opacity:1" /><path
|
||||
class="st0"
|
||||
d="M36,31.5c0-0.1,0-5.1,0-5.3c0-1-0.9-1.7-1.8-1.7c-1,0-1.7,0.8-1.7,1.8c0,0.3,0,4.8,0,5.2 c0,3.7-3.4,6.7-7.5,6.7c-4.1,0-7.5-3-7.5-6.7c0-0.4,0-4.9,0-5.3c0-1-0.7-1.8-1.6-1.8C14.9,24.3,14,25,14,26c0,0.3,0,5.4,0,5.5 c0,5.1,4,9.3,9.2,10.1l0,3.4h-4.3c-1,0-1.8,0.8-1.8,1.8c0,1,0.8,1.8,1.8,1.8h12.3c1,0,1.8-0.8,1.8-1.8c0-1-0.8-1.8-1.8-1.8h-4.4 l0-3.4C32,40.7,36,36.6,36,31.5z"
|
||||
id="path16"
|
||||
style="fill:#000000;fill-opacity:1" /></g></svg>
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.8664 5.59992L25.3331 4.13328C23.0664 1.59998 19.7332 0 16.0665 0C12.5333 0 9.26664 1.53331 7 3.93328L8.46665 5.39993C10.4 3.39995 13.0666 2.06664 16.0665 2.06664C19.1998 2.06664 21.9331 3.46662 23.8664 5.59992ZM20.4664 8.99975L21.9331 7.5331C20.5331 5.86646 18.3998 4.7998 16.0665 4.7998C13.7999 4.7998 11.7999 5.79979 10.3999 7.3331L11.8665 8.79975C12.9332 7.66643 14.3998 6.86644 16.0665 6.86644C17.8665 6.86644 19.4664 7.66643 20.4664 8.99975ZM18.5334 11.8004V14.7337H13.6001V11.8004C13.6001 10.467 14.7334 9.40039 16.0667 9.40039C17.4667 9.40039 18.5334 10.467 18.5334 11.8004ZM13.6001 17.2666V20.1332C13.6001 21.4665 14.7334 22.5332 16.0667 22.5332C17.4 22.5332 18.5334 21.4665 18.5334 20.1332V17.2666H13.6001ZM23.5332 17.0667V20.6C23.5332 23.9999 20.8665 26.7332 17.3999 27.3332V29.5998H20.3332C20.9999 29.5998 21.5332 30.1332 21.5332 30.7998C21.5332 31.4665 20.9999 31.9998 20.3332 31.9998H12.1333C11.4667 31.9998 10.9333 31.4665 10.9333 30.7998C10.9333 30.1332 11.4667 29.5998 12.1333 29.5998H14.9999V27.3332C11.5333 26.7999 8.8667 23.9999 8.8667 20.6V16.9333C8.8667 16.2667 9.46669 15.8 10.1333 15.8667C10.7333 15.8667 11.2 16.4 11.2 17.0667V20.6C11.2 23.0666 13.4666 25.0666 16.1999 25.0666C18.9332 25.0666 21.1999 23.0666 21.1999 20.6V17.1333C21.1999 16.4667 21.6665 15.9334 22.3332 15.9334C22.9332 15.9334 23.5332 16.4 23.5332 17.0667Z" fill="white"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -1,22 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g id="Layer_2">
|
||||
</g>
|
||||
<g id="Layer_1">
|
||||
<path class="st0" d="M31.4,14.1l2.2-2.2c-2.1-2.5-5.3-4.1-8.8-4.1c-3.4,0-6.4,1.5-8.5,3.8c0.7,0.7,1.5,1.5,2.2,2.2
|
||||
c1.6-1.7,3.8-2.9,6.3-2.9C27.5,10.9,29.9,12.1,31.4,14.1z"/>
|
||||
<path class="st0" d="M36.5,9l2.2-2.2C35.3,3,30.3,0.6,24.8,0.6c-5.3,0-10.2,2.3-13.6,5.9c0.7,0.7,1.5,1.5,2.2,2.2
|
||||
c2.9-3,6.9-5,11.4-5C29.5,3.7,33.6,5.8,36.5,9z"/>
|
||||
<path class="st0" d="M28.5,22.7v-4.4c0-2-1.6-3.6-3.7-3.6h0c-2,0-3.7,1.6-3.7,3.6v4.4H28.5z"/>
|
||||
<path class="st0" d="M21.1,26.5v4.3c0,2,1.7,3.6,3.7,3.6h0c2,0,3.7-1.6,3.7-3.6v-4.3H21.1z"/>
|
||||
<path class="st0" d="M36,31.5c0-0.1,0-5.1,0-5.3c0-1-0.9-1.7-1.8-1.7c-1,0-1.7,0.8-1.7,1.8c0,0.3,0,4.8,0,5.2
|
||||
c0,3.7-3.4,6.7-7.5,6.7c-4.1,0-7.5-3-7.5-6.7c0-0.4,0-4.9,0-5.3c0-1-0.7-1.8-1.6-1.8C14.9,24.3,14,25,14,26c0,0.3,0,5.4,0,5.5
|
||||
c0,5.1,4,9.3,9.2,10.1l0,3.4h-4.3c-1,0-1.8,0.8-1.8,1.8c0,1,0.8,1.8,1.8,1.8h12.3c1,0,1.8-0.8,1.8-1.8c0-1-0.8-1.8-1.8-1.8h-4.4
|
||||
l0-3.4C32,40.7,36,36.6,36,31.5z"/>
|
||||
</g>
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.8664 5.59992L25.3331 4.13328C23.0664 1.59998 19.7332 0 16.0665 0C12.5333 0 9.26664 1.53331 7 3.93328L8.46665 5.39993C10.4 3.39995 13.0666 2.06664 16.0665 2.06664C19.1998 2.06664 21.9331 3.46662 23.8664 5.59992ZM20.4664 8.99975L21.9331 7.5331C20.5331 5.86646 18.3998 4.7998 16.0665 4.7998C13.7999 4.7998 11.7999 5.79979 10.3999 7.3331L11.8665 8.79975C12.9332 7.66643 14.3998 6.86644 16.0665 6.86644C17.8665 6.86644 19.4664 7.66643 20.4664 8.99975ZM18.5334 11.8004V14.7337H13.6001V11.8004C13.6001 10.467 14.7334 9.40039 16.0667 9.40039C17.4667 9.40039 18.5334 10.467 18.5334 11.8004ZM13.6001 17.2666V20.1332C13.6001 21.4665 14.7334 22.5332 16.0667 22.5332C17.4 22.5332 18.5334 21.4665 18.5334 20.1332V17.2666H13.6001ZM23.5332 17.0667V20.6C23.5332 23.9999 20.8665 26.7332 17.3999 27.3332V29.5998H20.3332C20.9999 29.5998 21.5332 30.1332 21.5332 30.7998C21.5332 31.4665 20.9999 31.9998 20.3332 31.9998H12.1333C11.4667 31.9998 10.9333 31.4665 10.9333 30.7998C10.9333 30.1332 11.4667 29.5998 12.1333 29.5998H14.9999V27.3332C11.5333 26.7999 8.8667 23.9999 8.8667 20.6V16.9333C8.8667 16.2667 9.46669 15.8 10.1333 15.8667C10.7333 15.8667 11.2 16.4 11.2 17.0667V20.6C11.2 23.0666 13.4666 25.0666 16.1999 25.0666C18.9332 25.0666 21.1999 23.0666 21.1999 20.6V17.1333C21.1999 16.4667 21.6665 15.9334 22.3332 15.9334C22.9332 15.9334 23.5332 16.4 23.5332 17.0667Z" fill="white"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -59,4 +59,4 @@
|
|||
d="m 27.9,20.9 c 0,0 0,-3.6 0,-3.8 0,-0.7 -0.6,-1.2 -1.3,-1.2 -0.7,0 -1.2,0.6 -1.2,1.3 0,0.2 0,3.4 0,3.7 0,2.6 -2.4,4.8 -5.3,4.8 -2.9,0 -5.3,-2.1 -5.3,-4.8 0,-0.3 0,-3.5 0,-3.8 0,-0.7 -0.5,-1.3 -1.2,-1.3 -0.7,0 -1.3,0.5 -1.3,1.2 0,0.2 0,3.9 0,3.9 0,3.6 2.9,6.6 6.6,7.2 l 0,2.4 -3.1,0 c -0.7,0 -1.3,0.6 -1.3,1.3 0,0.7 0.6,1.3 1.3,1.3 l 8.8,0 c 0.7,0 1.3,-0.6 1.3,-1.3 0,-0.7 -0.6,-1.3 -1.3,-1.3 l -3.2,0 0,-2.4 c 3.6,-0.5 6.5,-3.5 6.5,-7.2 z"
|
||||
id="path6952"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" /></svg>
|
||||
style="fill:#ffffff" /></svg>
|
||||
|
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
@ -7,24 +7,57 @@
|
|||
//
|
||||
|
||||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.4
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import "./hifi/audio" as HifiAudio
|
||||
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
Item {
|
||||
id: root;
|
||||
objectName: "AvatarInputsBar"
|
||||
property int modality: Qt.NonModal
|
||||
width: audio.width;
|
||||
height: audio.height;
|
||||
x: 10; y: 5;
|
||||
|
||||
readonly property bool ignoreRadiusEnabled: AvatarInputs.ignoreRadiusEnabled;
|
||||
x: 10;
|
||||
y: 5;
|
||||
readonly property bool shouldReposition: true;
|
||||
property bool hmdActive: HMD.active;
|
||||
width: hmdActive ? audio.width : audioApplication.width;
|
||||
height: hmdActive ? audio.height : audioApplication.height;
|
||||
|
||||
Timer {
|
||||
id: hmdActiveCheckTimer;
|
||||
interval: 500;
|
||||
repeat: true;
|
||||
onTriggered: {
|
||||
root.hmdActive = HMD.active;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
HifiAudio.MicBar {
|
||||
id: audio;
|
||||
visible: AvatarInputs.showAudioTools;
|
||||
visible: AvatarInputs.showAudioTools && root.hmdActive;
|
||||
standalone: true;
|
||||
dragTarget: parent;
|
||||
dragTarget: parent;
|
||||
}
|
||||
|
||||
HifiAudio.MicBarApplication {
|
||||
id: audioApplication;
|
||||
visible: AvatarInputs.showAudioTools && !root.hmdActive;
|
||||
standalone: true;
|
||||
dragTarget: parent;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
HMD.displayModeChanged.connect(function(isHmdMode) {
|
||||
root.hmdActive = isHmdMode;
|
||||
});
|
||||
}
|
||||
|
||||
BubbleIcon {
|
||||
dragTarget: parent
|
||||
visible: !root.hmdActive;
|
||||
}
|
||||
}
|
||||
|
|
100
interface/resources/qml/BubbleIcon.qml
Normal file
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/06/19
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import "./hifi/audio" as HifiAudio
|
||||
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
Rectangle {
|
||||
id: bubbleRect
|
||||
width: bubbleIcon.width + 10
|
||||
height: bubbleIcon.height + 10
|
||||
radius: 5;
|
||||
property var dragTarget: null;
|
||||
property bool ignoreRadiusEnabled: AvatarInputs.ignoreRadiusEnabled;
|
||||
|
||||
function updateOpacity() {
|
||||
if (ignoreRadiusEnabled) {
|
||||
bubbleRect.opacity = 1.0;
|
||||
} else {
|
||||
bubbleRect.opacity = 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
updateOpacity();
|
||||
}
|
||||
|
||||
onIgnoreRadiusEnabledChanged: {
|
||||
updateOpacity();
|
||||
}
|
||||
|
||||
color: "#00000000";
|
||||
border {
|
||||
width: mouseArea.containsMouse || mouseArea.containsPress ? 2 : 0;
|
||||
color: "#80FFFFFF";
|
||||
}
|
||||
anchors {
|
||||
left: dragTarget ? dragTarget.right : undefined
|
||||
top: dragTarget ? dragTarget.top : undefined
|
||||
}
|
||||
|
||||
// borders are painted over fill, so reduce the fill to fit inside the border
|
||||
Rectangle {
|
||||
color: "#55000000";
|
||||
width: 40;
|
||||
height: 40;
|
||||
|
||||
radius: 5;
|
||||
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter;
|
||||
horizontalCenter: parent.horizontalCenter;
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea;
|
||||
anchors.fill: parent
|
||||
|
||||
hoverEnabled: true;
|
||||
scrollGestureEnabled: false;
|
||||
onClicked: {
|
||||
Tablet.playSound(TabletEnums.ButtonClick);
|
||||
Users.toggleIgnoreRadius();
|
||||
}
|
||||
drag.target: dragTarget;
|
||||
onContainsMouseChanged: {
|
||||
var rectOpacity = (ignoreRadiusEnabled && containsMouse) ? 1.0 : (containsMouse ? 1.0 : 0.7);
|
||||
if (containsMouse) {
|
||||
Tablet.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
bubbleRect.opacity = rectOpacity;
|
||||
}
|
||||
}
|
||||
Image {
|
||||
id: bubbleIcon
|
||||
source: "../icons/tablet-icons/bubble-i.svg";
|
||||
sourceSize: Qt.size(32, 32);
|
||||
smooth: true;
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: (parent.height - bubbleIcon.height) / 2
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: (parent.width - bubbleIcon.width) / 2
|
||||
}
|
||||
ColorOverlay {
|
||||
id: bubbleIconOverlay
|
||||
anchors.fill: bubbleIcon
|
||||
source: bubbleIcon
|
||||
color: "#FFFFFF";
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ CheckBox {
|
|||
leftPadding: 0
|
||||
property int colorScheme: hifi.colorSchemes.light
|
||||
property string color: hifi.colors.lightGrayText
|
||||
property int fontSize: hifi.fontSizes.inputLabel
|
||||
readonly property bool isLightColorScheme: colorScheme === hifi.colorSchemes.light
|
||||
property bool isRedCheck: false
|
||||
property bool isRound: false
|
||||
|
@ -109,7 +110,7 @@ CheckBox {
|
|||
|
||||
contentItem: Text {
|
||||
id: root
|
||||
font.pixelSize: hifi.fontSizes.inputLabel
|
||||
font.pixelSize: fontSize;
|
||||
font.family: "Raleway"
|
||||
font.weight: Font.DemiBold
|
||||
text: checkBox.text
|
||||
|
|
|
@ -21,6 +21,7 @@ Item {
|
|||
property int switchWidth: 70;
|
||||
readonly property int switchRadius: height/2;
|
||||
property string labelTextOff: "";
|
||||
property int labelTextSize: hifi.fontSizes.inputLabel;
|
||||
property string labelGlyphOffText: "";
|
||||
property int labelGlyphOffSize: 32;
|
||||
property string labelTextOn: "";
|
||||
|
@ -89,7 +90,7 @@ Item {
|
|||
RalewaySemiBold {
|
||||
id: labelOff;
|
||||
text: labelTextOff;
|
||||
size: hifi.fontSizes.inputLabel;
|
||||
size: labelTextSize;
|
||||
color: originalSwitch.checked ? hifi.colors.lightGrayText : "#FFFFFF";
|
||||
anchors.top: parent.top;
|
||||
anchors.right: parent.right;
|
||||
|
@ -130,7 +131,7 @@ Item {
|
|||
RalewaySemiBold {
|
||||
id: labelOn;
|
||||
text: labelTextOn;
|
||||
size: hifi.fontSizes.inputLabel;
|
||||
size: labelTextSize;
|
||||
color: originalSwitch.checked ? "#FFFFFF" : hifi.colors.lightGrayText;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
|
|
152
interface/resources/qml/hifi/EditAvatarInputsBar.qml
Normal file
|
@ -0,0 +1,152 @@
|
|||
//
|
||||
// EditAvatarInputsBar.qml
|
||||
// qml/hifi
|
||||
//
|
||||
// Audio setup
|
||||
//
|
||||
// Created by Wayne Chen on 3/20/2019
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import stylesUit 1.0
|
||||
import controlsUit 1.0 as HifiControlsUit
|
||||
import "../windows"
|
||||
|
||||
Rectangle {
|
||||
id: editRect
|
||||
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
color: hifi.colors.baseGray;
|
||||
|
||||
signal sendToScript(var message);
|
||||
function emitSendToScript(message) {
|
||||
sendToScript(message);
|
||||
}
|
||||
|
||||
function fromScript(message) {
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: title;
|
||||
color: hifi.colors.white;
|
||||
text: qsTr("Avatar Inputs Persistent UI Settings")
|
||||
size: 20
|
||||
font.bold: true
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
leftMargin: (parent.width - width) / 2
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Slider {
|
||||
id: xSlider
|
||||
anchors {
|
||||
top: title.bottom
|
||||
topMargin: 50
|
||||
left: parent.left
|
||||
leftMargin: 20
|
||||
}
|
||||
label: "X OFFSET: " + value.toFixed(2);
|
||||
maximumValue: 1.0
|
||||
minimumValue: -1.0
|
||||
stepSize: 0.05
|
||||
value: -0.2
|
||||
width: 300
|
||||
onValueChanged: {
|
||||
emitSendToScript({
|
||||
"method": "reposition",
|
||||
"x": value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Slider {
|
||||
id: ySlider
|
||||
anchors {
|
||||
top: xSlider.bottom
|
||||
topMargin: 50
|
||||
left: parent.left
|
||||
leftMargin: 20
|
||||
}
|
||||
label: "Y OFFSET: " + value.toFixed(2);
|
||||
maximumValue: 1.0
|
||||
minimumValue: -1.0
|
||||
stepSize: 0.05
|
||||
value: -0.125
|
||||
width: 300
|
||||
onValueChanged: {
|
||||
emitSendToScript({
|
||||
"method": "reposition",
|
||||
"y": value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Slider {
|
||||
id: zSlider
|
||||
anchors {
|
||||
top: ySlider.bottom
|
||||
topMargin: 50
|
||||
left: parent.left
|
||||
leftMargin: 20
|
||||
}
|
||||
label: "Z OFFSET: " + value.toFixed(2);
|
||||
maximumValue: 0.0
|
||||
minimumValue: -1.0
|
||||
stepSize: 0.05
|
||||
value: -0.5
|
||||
width: 300
|
||||
onValueChanged: {
|
||||
emitSendToScript({
|
||||
"method": "reposition",
|
||||
"z": value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Button {
|
||||
id: setVisibleButton;
|
||||
text: setVisible ? "SET INVISIBLE" : "SET VISIBLE";
|
||||
width: 300;
|
||||
property bool setVisible: true;
|
||||
anchors {
|
||||
top: zSlider.bottom
|
||||
topMargin: 50
|
||||
left: parent.left
|
||||
leftMargin: 20
|
||||
}
|
||||
onClicked: {
|
||||
setVisible = !setVisible;
|
||||
emitSendToScript({
|
||||
"method": "setVisible",
|
||||
"visible": setVisible
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Button {
|
||||
id: printButton;
|
||||
text: "PRINT POSITIONS";
|
||||
width: 300;
|
||||
anchors {
|
||||
top: setVisibleButton.bottom
|
||||
topMargin: 50
|
||||
left: parent.left
|
||||
leftMargin: 20
|
||||
}
|
||||
onClicked: {
|
||||
emitSendToScript({
|
||||
"method": "print",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -129,6 +129,7 @@ Item {
|
|||
height: 40
|
||||
// Anchors
|
||||
anchors.top: avatarImage.top
|
||||
anchors.topMargin: avatarImage.visible ? 18 : 0;
|
||||
anchors.left: avatarImage.right
|
||||
anchors.leftMargin: avatarImage.visible ? 5 : 0;
|
||||
anchors.rightMargin: 5;
|
||||
|
|
|
@ -31,6 +31,8 @@ Rectangle {
|
|||
property string title: "Audio Settings"
|
||||
property int switchHeight: 16
|
||||
property int switchWidth: 40
|
||||
property bool pushToTalk: (bar.currentIndex === 0) ? AudioScriptingInterface.pushToTalkDesktop : AudioScriptingInterface.pushToTalkHMD;
|
||||
property bool muted: (bar.currentIndex === 0) ? AudioScriptingInterface.mutedDesktop : AudioScriptingInterface.mutedHMD;
|
||||
readonly property real verticalScrollWidth: 10
|
||||
readonly property real verticalScrollShaft: 8
|
||||
signal sendToScript(var message);
|
||||
|
@ -44,7 +46,7 @@ Rectangle {
|
|||
|
||||
|
||||
property bool isVR: AudioScriptingInterface.context === "VR"
|
||||
property real rightMostInputLevelPos: 440
|
||||
property real rightMostInputLevelPos: root.width
|
||||
//placeholder for control sizes and paddings
|
||||
//recalculates dynamically in case of UI size is changed
|
||||
QtObject {
|
||||
|
@ -103,7 +105,9 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: enablePeakValues();
|
||||
Component.onCompleted: {
|
||||
enablePeakValues();
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: flickView;
|
||||
|
@ -178,15 +182,25 @@ Rectangle {
|
|||
height: root.switchHeight;
|
||||
switchWidth: root.switchWidth;
|
||||
labelTextOn: "Mute microphone";
|
||||
labelTextSize: 16;
|
||||
backgroundOnColor: "#E3E3E3";
|
||||
checked: AudioScriptingInterface.muted;
|
||||
checked: muted;
|
||||
onClicked: {
|
||||
if (AudioScriptingInterface.pushToTalk && !checked) {
|
||||
if (pushToTalk && !checked) {
|
||||
// disable push to talk if unmuting
|
||||
AudioScriptingInterface.pushToTalk = false;
|
||||
if (bar.currentIndex === 0) {
|
||||
AudioScriptingInterface.pushToTalkDesktop = false;
|
||||
}
|
||||
else {
|
||||
AudioScriptingInterface.pushToTalkHMD = false;
|
||||
}
|
||||
}
|
||||
if (bar.currentIndex === 0) {
|
||||
AudioScriptingInterface.mutedDesktop = checked;
|
||||
}
|
||||
else {
|
||||
AudioScriptingInterface.mutedHMD = checked;
|
||||
}
|
||||
AudioScriptingInterface.muted = checked;
|
||||
checked = Qt.binding(function() { return AudioScriptingInterface.muted; }); // restore binding
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,6 +212,7 @@ Rectangle {
|
|||
anchors.topMargin: 24
|
||||
anchors.left: parent.left
|
||||
labelTextOn: "Noise Reduction";
|
||||
labelTextSize: 16;
|
||||
backgroundOnColor: "#E3E3E3";
|
||||
checked: AudioScriptingInterface.noiseReduction;
|
||||
onCheckedChanged: {
|
||||
|
@ -213,7 +228,8 @@ Rectangle {
|
|||
anchors.top: noiseReductionSwitch.bottom
|
||||
anchors.topMargin: 24
|
||||
anchors.left: parent.left
|
||||
labelTextOn: qsTr("Push To Talk (T)");
|
||||
labelTextOn: (bar.currentIndex === 0) ? qsTr("Push To Talk (T)") : qsTr("Push To Talk");
|
||||
labelTextSize: 16;
|
||||
backgroundOnColor: "#E3E3E3";
|
||||
checked: (bar.currentIndex === 0) ? AudioScriptingInterface.pushToTalkDesktop : AudioScriptingInterface.pushToTalkHMD;
|
||||
onCheckedChanged: {
|
||||
|
@ -222,13 +238,6 @@ Rectangle {
|
|||
} else {
|
||||
AudioScriptingInterface.pushToTalkHMD = checked;
|
||||
}
|
||||
checked = Qt.binding(function() {
|
||||
if (bar.currentIndex === 0) {
|
||||
return AudioScriptingInterface.pushToTalkDesktop;
|
||||
} else {
|
||||
return AudioScriptingInterface.pushToTalkHMD;
|
||||
}
|
||||
}); // restore binding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -245,7 +254,8 @@ Rectangle {
|
|||
switchWidth: root.switchWidth;
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
labelTextOn: qsTr("Warn when muted");
|
||||
labelTextOn: qsTr("Warn when muted in HMD");
|
||||
labelTextSize: 16;
|
||||
backgroundOnColor: "#E3E3E3";
|
||||
checked: AudioScriptingInterface.warnWhenMuted;
|
||||
onClicked: {
|
||||
|
@ -263,6 +273,7 @@ Rectangle {
|
|||
anchors.topMargin: 24
|
||||
anchors.left: parent.left
|
||||
labelTextOn: qsTr("Audio Level Meter");
|
||||
labelTextSize: 16;
|
||||
backgroundOnColor: "#E3E3E3";
|
||||
checked: AvatarInputs.showAudioTools;
|
||||
onCheckedChanged: {
|
||||
|
@ -279,6 +290,7 @@ Rectangle {
|
|||
anchors.topMargin: 24
|
||||
anchors.left: parent.left
|
||||
labelTextOn: qsTr("Stereo input");
|
||||
labelTextSize: 16;
|
||||
backgroundOnColor: "#E3E3E3";
|
||||
checked: AudioScriptingInterface.isStereoInput;
|
||||
onCheckedChanged: {
|
||||
|
@ -314,7 +326,7 @@ Rectangle {
|
|||
|
||||
Separator {
|
||||
id: secondSeparator;
|
||||
anchors.top: pttTextContainer.bottom;
|
||||
anchors.top: pttTextContainer.visible ? pttTextContainer.bottom : switchesContainer.bottom;
|
||||
anchors.topMargin: 10;
|
||||
}
|
||||
|
||||
|
@ -341,7 +353,7 @@ Rectangle {
|
|||
width: margins.sizeText + margins.sizeLevel;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: margins.sizeCheckBox;
|
||||
size: 16;
|
||||
size: 22;
|
||||
color: hifi.colors.white;
|
||||
text: qsTr("Choose input device");
|
||||
}
|
||||
|
@ -349,16 +361,17 @@ Rectangle {
|
|||
|
||||
ListView {
|
||||
id: inputView;
|
||||
width: parent.width - margins.paddings*2;
|
||||
width: rightMostInputLevelPos;
|
||||
anchors.top: inputDeviceHeader.bottom;
|
||||
anchors.topMargin: 10;
|
||||
x: margins.paddings
|
||||
interactive: false;
|
||||
height: contentHeight;
|
||||
spacing: 4;
|
||||
clip: true;
|
||||
model: AudioScriptingInterface.devices.input;
|
||||
delegate: Item {
|
||||
width: rightMostInputLevelPos
|
||||
width: rightMostInputLevelPos - margins.paddings*2
|
||||
height: margins.sizeCheckBox > checkBoxInput.implicitHeight ?
|
||||
margins.sizeCheckBox : checkBoxInput.implicitHeight
|
||||
|
||||
|
@ -374,6 +387,7 @@ Rectangle {
|
|||
boxSize: margins.sizeCheckBox / 2
|
||||
isRound: true
|
||||
text: devicename
|
||||
fontSize: 16;
|
||||
onPressed: {
|
||||
if (!checked) {
|
||||
stereoInput.checked = false;
|
||||
|
@ -407,7 +421,7 @@ Rectangle {
|
|||
|
||||
Separator {
|
||||
id: thirdSeparator;
|
||||
anchors.top: loopbackAudio.bottom;
|
||||
anchors.top: loopbackAudio.visible ? loopbackAudio.bottom : inputView.bottom;
|
||||
anchors.topMargin: 10;
|
||||
}
|
||||
|
||||
|
@ -434,7 +448,7 @@ Rectangle {
|
|||
anchors.left: parent.left
|
||||
anchors.leftMargin: margins.sizeCheckBox
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
size: 16;
|
||||
size: 22;
|
||||
color: hifi.colors.white;
|
||||
text: qsTr("Choose output device");
|
||||
}
|
||||
|
@ -443,7 +457,8 @@ Rectangle {
|
|||
ListView {
|
||||
id: outputView
|
||||
width: parent.width - margins.paddings*2
|
||||
x: margins.paddings
|
||||
x: margins.paddings;
|
||||
interactive: false;
|
||||
height: contentHeight;
|
||||
anchors.top: outputDeviceHeader.bottom;
|
||||
anchors.topMargin: 10;
|
||||
|
@ -464,6 +479,7 @@ Rectangle {
|
|||
checked: bar.currentIndex === 0 ? selectedDesktop : selectedHMD;
|
||||
checkable: !checked
|
||||
text: devicename
|
||||
fontSize: 16
|
||||
onPressed: {
|
||||
if (!checked) {
|
||||
AudioScriptingInterface.setOutputDevice(info, bar.currentIndex === 1);
|
||||
|
@ -526,7 +542,7 @@ Rectangle {
|
|||
RalewayRegular {
|
||||
// The slider for my card is special, it controls the master gain
|
||||
id: avatarGainSliderText;
|
||||
text: "Avatar volume";
|
||||
text: "People volume";
|
||||
size: 16;
|
||||
anchors.left: parent.left;
|
||||
color: hifi.colors.white;
|
||||
|
|
|
@ -12,24 +12,26 @@
|
|||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
property var peak;
|
||||
|
||||
width: 70;
|
||||
height: 8;
|
||||
|
||||
color: "transparent";
|
||||
|
||||
Item {
|
||||
QtObject {
|
||||
id: colors;
|
||||
|
||||
readonly property string unmuted: "#FFF";
|
||||
readonly property string muted: "#E2334D";
|
||||
readonly property string gutter: "#575757";
|
||||
readonly property string greenStart: "#39A38F";
|
||||
readonly property string greenEnd: "#1FC6A6";
|
||||
readonly property string yellow: "#C0C000";
|
||||
readonly property string red: colors.muted;
|
||||
readonly property string fill: "#55000000";
|
||||
}
|
||||
|
||||
|
||||
Text {
|
||||
id: status;
|
||||
|
||||
|
@ -79,23 +81,19 @@ Rectangle {
|
|||
anchors { fill: mask }
|
||||
source: mask
|
||||
start: Qt.point(0, 0);
|
||||
end: Qt.point(70, 0);
|
||||
end: Qt.point(bar.width, 0);
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0;
|
||||
color: colors.greenStart;
|
||||
}
|
||||
GradientStop {
|
||||
position: 0.8;
|
||||
position: 0.5;
|
||||
color: colors.greenEnd;
|
||||
}
|
||||
GradientStop {
|
||||
position: 0.801;
|
||||
color: colors.red;
|
||||
}
|
||||
GradientStop {
|
||||
position: 1;
|
||||
color: colors.red;
|
||||
color: colors.yellow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,11 +60,11 @@ RowLayout {
|
|||
}
|
||||
}
|
||||
|
||||
// RalewayRegular {
|
||||
// Layout.leftMargin: 2;
|
||||
// size: 14;
|
||||
// color: "white";
|
||||
// font.italic: true
|
||||
// text: audioLoopedBack ? qsTr("Speak in your input") : "";
|
||||
// }
|
||||
RalewayRegular {
|
||||
Layout.leftMargin: 2;
|
||||
size: 18;
|
||||
color: "white";
|
||||
font.italic: true
|
||||
text: audioLoopedBack ? qsTr("Speak in your input") : "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,14 +16,33 @@ import stylesUit 1.0
|
|||
import TabletScriptingInterface 1.0
|
||||
|
||||
Rectangle {
|
||||
id: micBar
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
property var muted: AudioScriptingInterface.muted;
|
||||
readonly property var level: AudioScriptingInterface.inputLevel;
|
||||
readonly property var clipping: AudioScriptingInterface.clipping;
|
||||
property var pushToTalk: AudioScriptingInterface.pushToTalk;
|
||||
property var pushingToTalk: AudioScriptingInterface.pushingToTalk;
|
||||
|
||||
readonly property var userSpeakingLevel: 0.4;
|
||||
property bool gated: false;
|
||||
Component.onCompleted: {
|
||||
AudioScriptingInterface.noiseGateOpened.connect(function() { gated = false; });
|
||||
AudioScriptingInterface.noiseGateClosed.connect(function() { gated = true; });
|
||||
HMD.displayModeChanged.connect(function() {
|
||||
muted = AudioScriptingInterface.muted;
|
||||
pushToTalk = AudioScriptingInterface.pushToTalk;
|
||||
});
|
||||
AudioScriptingInterface.mutedChanged.connect(function() {
|
||||
muted = AudioScriptingInterface.muted;
|
||||
});
|
||||
AudioScriptingInterface.pushToTalkChanged.connect(function() {
|
||||
pushToTalk = AudioScriptingInterface.pushToTalk;
|
||||
});
|
||||
AudioScriptingInterface.pushingToTalkChanged.connect(function() {
|
||||
pushingToTalk = AudioScriptingInterface.pushingToTalk;
|
||||
});
|
||||
}
|
||||
|
||||
property bool standalone: false;
|
||||
|
@ -67,10 +86,10 @@ Rectangle {
|
|||
hoverEnabled: true;
|
||||
scrollGestureEnabled: false;
|
||||
onClicked: {
|
||||
if (AudioScriptingInterface.pushToTalk) {
|
||||
if (pushToTalk) {
|
||||
return;
|
||||
}
|
||||
AudioScriptingInterface.muted = !AudioScriptingInterface.muted;
|
||||
AudioScriptingInterface.muted = !muted;
|
||||
Tablet.playSound(TabletEnums.ButtonClick);
|
||||
}
|
||||
drag.target: dragTarget;
|
||||
|
@ -84,16 +103,16 @@ Rectangle {
|
|||
QtObject {
|
||||
id: colors;
|
||||
|
||||
readonly property string unmuted: "#FFF";
|
||||
readonly property string muted: "#E2334D";
|
||||
readonly property string unmutedColor: "#FFF";
|
||||
readonly property string mutedColor: "#E2334D";
|
||||
readonly property string gutter: "#575757";
|
||||
readonly property string greenStart: "#39A38F";
|
||||
readonly property string greenEnd: "#1FC6A6";
|
||||
readonly property string yellow: "#C0C000";
|
||||
readonly property string red: colors.muted;
|
||||
readonly property string red: colors.mutedColor;
|
||||
readonly property string fill: "#55000000";
|
||||
readonly property string border: standalone ? "#80FFFFFF" : "#55FFFFFF";
|
||||
readonly property string icon: AudioScriptingInterface.muted ? muted : unmuted;
|
||||
readonly property string icon: muted ? colors.mutedColor : unmutedColor;
|
||||
}
|
||||
|
||||
Item {
|
||||
|
@ -113,9 +132,12 @@ Rectangle {
|
|||
readonly property string unmutedIcon: "../../../icons/tablet-icons/mic-unmute-i.svg";
|
||||
readonly property string mutedIcon: "../../../icons/tablet-icons/mic-mute-i.svg";
|
||||
readonly property string pushToTalkIcon: "../../../icons/tablet-icons/mic-ptt-i.svg";
|
||||
readonly property string clippingIcon: "../../../icons/tablet-icons/mic-clip-i.svg";
|
||||
readonly property string gatedIcon: "../../../icons/tablet-icons/mic-gate-i.svg";
|
||||
|
||||
id: image;
|
||||
source: (AudioScriptingInterface.pushToTalk && !AudioScriptingInterface.pushingToTalk) ? pushToTalkIcon : AudioScriptingInterface.muted ? mutedIcon : unmutedIcon;
|
||||
source: (pushToTalk && !pushingToTalk) ? pushToTalkIcon : muted ? mutedIcon :
|
||||
clipping ? clippingIcon : gated ? gatedIcon : unmutedIcon;
|
||||
|
||||
width: 30;
|
||||
height: 30;
|
||||
|
@ -138,9 +160,7 @@ Rectangle {
|
|||
Item {
|
||||
id: status;
|
||||
|
||||
readonly property string color: AudioScriptingInterface.muted ? colors.muted : colors.unmuted;
|
||||
|
||||
visible: (AudioScriptingInterface.pushToTalk && !AudioScriptingInterface.pushingToTalk) || AudioScriptingInterface.muted;
|
||||
visible: (pushToTalk && !pushingToTalk) || muted;
|
||||
|
||||
anchors {
|
||||
left: parent.left;
|
||||
|
@ -157,9 +177,9 @@ Rectangle {
|
|||
verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
|
||||
color: parent.color;
|
||||
color: colors.icon;
|
||||
|
||||
text: (AudioScriptingInterface.pushToTalk && !AudioScriptingInterface.pushingToTalk) ? (HMD.active ? "MUTED PTT" : "MUTED PTT-(T)") : (AudioScriptingInterface.muted ? "MUTED" : "MUTE");
|
||||
text: (pushToTalk && !pushingToTalk) ? (HMD.active ? "MUTED PTT" : "MUTED PTT-(T)") : (muted ? "MUTED" : "MUTE");
|
||||
font.pointSize: 12;
|
||||
}
|
||||
|
||||
|
@ -169,9 +189,9 @@ Rectangle {
|
|||
verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
|
||||
width: AudioScriptingInterface.pushToTalk && !AudioScriptingInterface.pushingToTalk ? (HMD.active ? 27 : 25) : 50;
|
||||
width: pushToTalk && !pushingToTalk ? (HMD.active ? 27 : 25) : 50;
|
||||
height: 4;
|
||||
color: parent.color;
|
||||
color: colors.icon;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
@ -180,9 +200,9 @@ Rectangle {
|
|||
verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
|
||||
width: AudioScriptingInterface.pushToTalk && !AudioScriptingInterface.pushingToTalk ? (HMD.active ? 27 : 25) : 50;
|
||||
width: pushToTalk && !pushingToTalk ? (HMD.active ? 27 : 25) : 50;
|
||||
height: 4;
|
||||
color: parent.color;
|
||||
color: colors.icon;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
255
interface/resources/qml/hifi/audio/MicBarApplication.qml
Normal file
|
@ -0,0 +1,255 @@
|
|||
//
|
||||
// MicBarApplication.qml
|
||||
// qml/hifi/audio
|
||||
//
|
||||
// Created by Zach Pomerantz on 6/14/2017
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import stylesUit 1.0
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
Rectangle {
|
||||
id: micBar;
|
||||
readonly property var level: AudioScriptingInterface.inputLevel;
|
||||
readonly property var clipping: AudioScriptingInterface.clipping;
|
||||
property var muted: AudioScriptingInterface.muted;
|
||||
property var pushToTalk: AudioScriptingInterface.pushToTalk;
|
||||
property var pushingToTalk: AudioScriptingInterface.pushingToTalk;
|
||||
readonly property var userSpeakingLevel: 0.4;
|
||||
property bool gated: false;
|
||||
Component.onCompleted: {
|
||||
AudioScriptingInterface.noiseGateOpened.connect(function() { gated = false; });
|
||||
AudioScriptingInterface.noiseGateClosed.connect(function() { gated = true; });
|
||||
HMD.displayModeChanged.connect(function() {
|
||||
muted = AudioScriptingInterface.muted;
|
||||
pushToTalk = AudioScriptingInterface.pushToTalk;
|
||||
});
|
||||
AudioScriptingInterface.mutedChanged.connect(function() {
|
||||
muted = AudioScriptingInterface.muted;
|
||||
});
|
||||
AudioScriptingInterface.pushToTalkChanged.connect(function() {
|
||||
pushToTalk = AudioScriptingInterface.pushToTalk;
|
||||
});
|
||||
}
|
||||
|
||||
readonly property string unmutedIcon: "../../../icons/tablet-icons/mic-unmute-i.svg";
|
||||
readonly property string mutedIcon: "../../../icons/tablet-icons/mic-mute-i.svg";
|
||||
readonly property string pushToTalkIcon: "../../../icons/tablet-icons/mic-ptt-i.svg";
|
||||
readonly property string clippingIcon: "../../../icons/tablet-icons/mic-clip-i.svg";
|
||||
readonly property string gatedIcon: "../../../icons/tablet-icons/mic-gate-i.svg";
|
||||
property bool standalone: false;
|
||||
property var dragTarget: null;
|
||||
|
||||
width: 44;
|
||||
height: 44;
|
||||
|
||||
radius: 5;
|
||||
opacity: 0.7;
|
||||
|
||||
onLevelChanged: {
|
||||
var rectOpacity = (muted && (level >= userSpeakingLevel)) ? 1.0 : 0.7;
|
||||
if (pushToTalk && !pushingToTalk) {
|
||||
rectOpacity = (mouseArea.containsMouse) ? 1.0 : 0.7;
|
||||
} else if (mouseArea.containsMouse && rectOpacity != 1.0) {
|
||||
rectOpacity = 1.0;
|
||||
}
|
||||
micBar.opacity = rectOpacity;
|
||||
}
|
||||
|
||||
color: "#00000000";
|
||||
border {
|
||||
width: mouseArea.containsMouse || mouseArea.containsPress ? 2 : 0;
|
||||
color: colors.border;
|
||||
}
|
||||
|
||||
// borders are painted over fill, so reduce the fill to fit inside the border
|
||||
Rectangle {
|
||||
color: standalone ? colors.fill : "#00000000";
|
||||
width: 40;
|
||||
height: 40;
|
||||
|
||||
radius: 5;
|
||||
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter;
|
||||
horizontalCenter: parent.horizontalCenter;
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea;
|
||||
|
||||
anchors {
|
||||
left: icon.left;
|
||||
right: bar.right;
|
||||
top: icon.top;
|
||||
bottom: icon.bottom;
|
||||
}
|
||||
|
||||
hoverEnabled: true;
|
||||
scrollGestureEnabled: false;
|
||||
onClicked: {
|
||||
if (pushToTalk) {
|
||||
return;
|
||||
}
|
||||
AudioScriptingInterface.muted = !muted;
|
||||
Tablet.playSound(TabletEnums.ButtonClick);
|
||||
muted = Qt.binding(function() { return AudioScriptingInterface.muted; }); // restore binding
|
||||
}
|
||||
drag.target: dragTarget;
|
||||
onContainsMouseChanged: {
|
||||
if (containsMouse) {
|
||||
Tablet.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: colors;
|
||||
|
||||
readonly property string unmutedColor: "#FFF";
|
||||
readonly property string gatedColor: "#00BDFF";
|
||||
readonly property string mutedColor: "#E2334D";
|
||||
readonly property string gutter: "#575757";
|
||||
readonly property string greenStart: "#39A38F";
|
||||
readonly property string greenEnd: "#1FC6A6";
|
||||
readonly property string yellow: "#C0C000";
|
||||
readonly property string fill: "#55000000";
|
||||
readonly property string border: standalone ? "#80FFFFFF" : "#55FFFFFF";
|
||||
readonly property string icon: (muted || clipping) ? mutedColor : gated ? gatedColor : unmutedColor;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: icon;
|
||||
|
||||
anchors {
|
||||
left: parent.left;
|
||||
top: parent.top;
|
||||
}
|
||||
|
||||
width: 40;
|
||||
height: 40;
|
||||
|
||||
Item {
|
||||
Image {
|
||||
id: image;
|
||||
source: (pushToTalk) ? pushToTalkIcon : muted ? mutedIcon :
|
||||
clipping ? clippingIcon : gated ? gatedIcon : unmutedIcon;
|
||||
width: 29;
|
||||
height: 32;
|
||||
anchors {
|
||||
left: parent.left;
|
||||
top: parent.top;
|
||||
topMargin: 5;
|
||||
}
|
||||
}
|
||||
|
||||
ColorOverlay {
|
||||
id: imageOverlay
|
||||
anchors { fill: image }
|
||||
source: image;
|
||||
color: pushToTalk ? (pushingToTalk ? colors.unmutedColor : colors.mutedColor) : colors.icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: status;
|
||||
|
||||
visible: pushToTalk || (muted && (level >= userSpeakingLevel));
|
||||
|
||||
anchors {
|
||||
left: parent.left;
|
||||
top: icon.bottom;
|
||||
topMargin: 2;
|
||||
}
|
||||
|
||||
width: parent.width;
|
||||
height: statusTextMetrics.height;
|
||||
|
||||
TextMetrics {
|
||||
id: statusTextMetrics
|
||||
text: statusText.text
|
||||
font: statusText.font
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
id: statusText
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter;
|
||||
verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
|
||||
color: pushToTalk ? (pushingToTalk ? colors.unmutedColor : colors.mutedColor) : (level >= userSpeakingLevel && muted) ? colors.mutedColor : colors.unmutedColor;
|
||||
font.bold: true
|
||||
|
||||
text: pushToTalk ? (HMD.active ? "PTT" : "PTT-(T)") : (muted ? "MUTED" : "MUTE");
|
||||
size: 12;
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: bar;
|
||||
|
||||
anchors {
|
||||
right: parent.right;
|
||||
rightMargin: 7;
|
||||
top: parent.top
|
||||
topMargin: 5
|
||||
}
|
||||
|
||||
width: 8;
|
||||
height: 32;
|
||||
|
||||
Rectangle { // base
|
||||
id: baseBar
|
||||
radius: 4;
|
||||
anchors { fill: parent }
|
||||
color: colors.gutter;
|
||||
}
|
||||
|
||||
Rectangle { // mask
|
||||
id: mask;
|
||||
visible: (!(pushToTalk && !pushingToTalk))
|
||||
height: parent.height * level;
|
||||
width: parent.width;
|
||||
radius: 5;
|
||||
anchors {
|
||||
bottom: parent.bottom;
|
||||
bottomMargin: 0;
|
||||
left: parent.left;
|
||||
leftMargin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
LinearGradient {
|
||||
anchors { fill: mask }
|
||||
visible: (!(pushToTalk && !pushingToTalk))
|
||||
source: mask
|
||||
start: Qt.point(0, 0);
|
||||
end: Qt.point(0, bar.height);
|
||||
rotation: 180
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.0;
|
||||
color: colors.greenStart;
|
||||
}
|
||||
GradientStop {
|
||||
position: 0.5;
|
||||
color: colors.greenEnd;
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0;
|
||||
color: colors.yellow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -64,11 +64,11 @@ RowLayout {
|
|||
height: 32;
|
||||
}
|
||||
|
||||
// RalewayRegular {
|
||||
// Layout.leftMargin: 2;
|
||||
// size: 14;
|
||||
// color: "white";
|
||||
// font.italic: true
|
||||
// text: isPlaying ? qsTr("Listen to your output") : "";
|
||||
// }
|
||||
RalewayRegular {
|
||||
Layout.leftMargin: 2;
|
||||
size: 18;
|
||||
color: "white";
|
||||
font.italic: true
|
||||
text: isPlaying ? qsTr("Listen to your output") : "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
HifiAudio.MicBar {
|
||||
HifiAudio.MicBarApplication {
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: 30
|
||||
|
|
|
@ -338,6 +338,10 @@ Setting::Handle<int> maxOctreePacketsPerSecond{"maxOctreePPS", DEFAULT_MAX_OCTRE
|
|||
|
||||
Setting::Handle<bool> loginDialogPoppedUp{"loginDialogPoppedUp", false};
|
||||
|
||||
static const QUrl AVATAR_INPUTS_BAR_QML = PathUtils::qmlUrl("AvatarInputsBar.qml");
|
||||
static const QUrl MIC_BAR_APPLICATION_QML = PathUtils::qmlUrl("hifi/audio/MicBarApplication.qml");
|
||||
static const QUrl BUBBLE_ICON_QML = PathUtils::qmlUrl("BubbleIcon.qml");
|
||||
|
||||
static const QString STANDARD_TO_ACTION_MAPPING_NAME = "Standard to Action";
|
||||
static const QString NO_MOVEMENT_MAPPING_NAME = "Standard to Action (No Movement)";
|
||||
static const QString NO_MOVEMENT_MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/standard_nomovement.json";
|
||||
|
@ -2372,7 +2376,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
});
|
||||
});
|
||||
auto rootItemLoadedFunctor = [webSurface, url, isTablet] {
|
||||
Application::setupQmlSurface(webSurface->getSurfaceContext(), isTablet || url == LOGIN_DIALOG.toString());
|
||||
Application::setupQmlSurface(webSurface->getSurfaceContext(), isTablet || url == LOGIN_DIALOG.toString() || url == AVATAR_INPUTS_BAR_QML.toString() ||
|
||||
url == BUBBLE_ICON_QML.toString());
|
||||
};
|
||||
if (webSurface->getRootItem()) {
|
||||
rootItemLoadedFunctor();
|
||||
|
@ -2878,11 +2883,19 @@ void Application::initializeGL() {
|
|||
}
|
||||
|
||||
#if !defined(DISABLE_QML)
|
||||
QStringList chromiumFlags;
|
||||
// Bug 21993: disable microphone and camera input
|
||||
chromiumFlags << "--use-fake-device-for-media-stream";
|
||||
// Disable signed distance field font rendering on ATI/AMD GPUs, due to
|
||||
// https://highfidelity.manuscript.com/f/cases/13677/Text-showing-up-white-on-Marketplace-app
|
||||
std::string vendor{ (const char*)glGetString(GL_VENDOR) };
|
||||
if ((vendor.find("AMD") != std::string::npos) || (vendor.find("ATI") != std::string::npos)) {
|
||||
qputenv("QTWEBENGINE_CHROMIUM_FLAGS", QByteArray("--disable-distance-field-text"));
|
||||
chromiumFlags << "--disable-distance-field-text";
|
||||
}
|
||||
|
||||
// Ensure all Qt webengine processes launched from us have the appropriate command line flags
|
||||
if (!chromiumFlags.empty()) {
|
||||
qputenv("QTWEBENGINE_CHROMIUM_FLAGS", chromiumFlags.join(' ').toLocal8Bit());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3291,6 +3304,7 @@ void Application::onDesktopRootItemCreated(QQuickItem* rootItem) {
|
|||
auto qml = PathUtils::qmlUrl("AvatarInputsBar.qml");
|
||||
offscreenUi->show(qml, "AvatarInputsBar");
|
||||
#endif
|
||||
_desktopRootItemCreated = true;
|
||||
}
|
||||
|
||||
void Application::userKickConfirmation(const QUuid& nodeID) {
|
||||
|
@ -3722,14 +3736,11 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
|
||||
// If this is a first run we short-circuit the address passed in
|
||||
if (_firstRun.get()) {
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
DependencyManager::get<AddressManager>()->goToEntry();
|
||||
sentTo = SENT_TO_ENTRY;
|
||||
#endif
|
||||
_firstRun.set(false);
|
||||
|
||||
} else {
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
QString goingTo = "";
|
||||
if (addressLookupString.isEmpty()) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::HomeLocation)) {
|
||||
|
@ -3743,7 +3754,6 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(!goingTo.isEmpty() ? goingTo : addressLookupString);
|
||||
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
|
||||
sentTo = SENT_TO_PREVIOUS_LOCATION;
|
||||
#endif
|
||||
}
|
||||
|
||||
UserActivityLogger::getInstance().logAction("startup_sent_to", {
|
||||
|
@ -8972,6 +8982,38 @@ void Application::updateLoginDialogPosition() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::createAvatarInputsBar() {
|
||||
const glm::vec3 LOCAL_POSITION { 0.0, 0.0, -1.0 };
|
||||
// DEFAULT_DPI / tablet scale percentage
|
||||
const float DPI = 31.0f / (75.0f / 100.0f);
|
||||
|
||||
EntityItemProperties properties;
|
||||
properties.setType(EntityTypes::Web);
|
||||
properties.setName("AvatarInputsBarEntity");
|
||||
properties.setSourceUrl(AVATAR_INPUTS_BAR_QML.toString());
|
||||
properties.setParentID(getMyAvatar()->getSelfID());
|
||||
properties.setParentJointIndex(getMyAvatar()->getJointIndex("_CAMERA_MATRIX"));
|
||||
properties.setPosition(LOCAL_POSITION);
|
||||
properties.setLocalRotation(Quaternions::IDENTITY);
|
||||
//properties.setDimensions(LOGIN_DIMENSIONS);
|
||||
properties.setPrimitiveMode(PrimitiveMode::SOLID);
|
||||
properties.getGrab().setGrabbable(false);
|
||||
properties.setIgnorePickIntersection(false);
|
||||
properties.setAlpha(1.0f);
|
||||
properties.setDPI(DPI);
|
||||
properties.setVisible(true);
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
_avatarInputsBarID = entityScriptingInterface->addEntityInternal(properties, entity::HostType::LOCAL);
|
||||
}
|
||||
|
||||
void Application::destroyAvatarInputsBar() {
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
if (!_avatarInputsBarID.isNull()) {
|
||||
entityScriptingInterface->deleteEntity(_avatarInputsBarID);
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::hasRiftControllers() {
|
||||
return PluginUtils::isOculusTouchControllerAvailable();
|
||||
}
|
||||
|
|
|
@ -330,6 +330,9 @@ public:
|
|||
void createLoginDialog();
|
||||
void updateLoginDialogPosition();
|
||||
|
||||
void createAvatarInputsBar();
|
||||
void destroyAvatarInputsBar();
|
||||
|
||||
// Check if a headset is connected
|
||||
bool hasRiftControllers();
|
||||
bool hasViveControllers();
|
||||
|
@ -704,12 +707,14 @@ private:
|
|||
int _maxOctreePPS = DEFAULT_MAX_OCTREE_PPS;
|
||||
bool _interstitialModeEnabled{ false };
|
||||
|
||||
bool _loginDialogPoppedUp = false;
|
||||
bool _loginDialogPoppedUp{ false };
|
||||
bool _desktopRootItemCreated{ false };
|
||||
bool _developerMenuVisible{ false };
|
||||
QString _previousAvatarSkeletonModel;
|
||||
float _previousAvatarTargetScale;
|
||||
CameraMode _previousCameraMode;
|
||||
QUuid _loginDialogID;
|
||||
QUuid _avatarInputsBarID;
|
||||
LoginStateManager _loginStateManager;
|
||||
|
||||
quint64 _lastFaceTrackerUpdate;
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <UsersScriptingInterface.h>
|
||||
#include <UUID.h>
|
||||
#include <shared/ConicalViewFrustum.h>
|
||||
#include <ui/AvatarInputs.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
@ -84,7 +85,6 @@ AvatarManager::AvatarManager(QObject* parent) :
|
|||
|
||||
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
|
||||
AvatarSharedPointer avatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer);
|
||||
|
||||
const auto otherAvatar = std::static_pointer_cast<OtherAvatar>(avatar);
|
||||
if (otherAvatar && _space) {
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
|
@ -210,7 +210,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
{
|
||||
// lock the hash for read to check the size
|
||||
QReadLocker lock(&_hashLock);
|
||||
if (_avatarHash.size() < 2 && _avatarsToFadeOut.isEmpty()) {
|
||||
if (_avatarHash.size() < 2) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -375,19 +375,12 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
qApp->getMain3DScene()->enqueueTransaction(renderTransaction);
|
||||
}
|
||||
|
||||
if (!_spaceProxiesToDelete.empty() && _space) {
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
workloadTransaction.remove(_spaceProxiesToDelete);
|
||||
_spaceProxiesToDelete.clear();
|
||||
}
|
||||
_space->enqueueTransaction(workloadTransaction);
|
||||
|
||||
_numAvatarsUpdated = numAvatarsUpdated;
|
||||
_numAvatarsNotUpdated = numAvatarsNotUpdated;
|
||||
_numHeroAvatarsUpdated = numHerosUpdated;
|
||||
|
||||
simulateAvatarFades(deltaTime);
|
||||
|
||||
_avatarSimulationTime = (float)(usecTimestampNow() - startTime) / (float)USECS_PER_MSEC;
|
||||
}
|
||||
|
||||
|
@ -400,31 +393,6 @@ void AvatarManager::postUpdate(float deltaTime, const render::ScenePointer& scen
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarManager::simulateAvatarFades(float deltaTime) {
|
||||
if (_avatarsToFadeOut.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QReadLocker locker(&_hashLock);
|
||||
QVector<AvatarSharedPointer>::iterator avatarItr = _avatarsToFadeOut.begin();
|
||||
const render::ScenePointer& scene = qApp->getMain3DScene();
|
||||
render::Transaction transaction;
|
||||
while (avatarItr != _avatarsToFadeOut.end()) {
|
||||
auto avatar = std::static_pointer_cast<Avatar>(*avatarItr);
|
||||
avatar->updateFadingStatus();
|
||||
if (!avatar->isFading()) {
|
||||
// fading to zero is such a rare event we push a unique transaction for each
|
||||
if (avatar->isInScene()) {
|
||||
avatar->removeFromScene(*avatarItr, scene, transaction);
|
||||
}
|
||||
avatarItr = _avatarsToFadeOut.erase(avatarItr);
|
||||
} else {
|
||||
++avatarItr;
|
||||
}
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
AvatarSharedPointer AvatarManager::newSharedAvatar(const QUuid& sessionUUID) {
|
||||
auto otherAvatar = new OtherAvatar(qApp->thread());
|
||||
otherAvatar->setSessionUUID(sessionUUID);
|
||||
|
@ -452,7 +420,6 @@ void AvatarManager::buildPhysicsTransaction(PhysicsEngine::Transaction& transact
|
|||
transaction.objectsToRemove.push_back(mState);
|
||||
}
|
||||
avatar->resetDetailedMotionStates();
|
||||
|
||||
} else {
|
||||
if (avatar->getDetailedMotionStates().size() == 0) {
|
||||
avatar->createDetailedMotionStates(avatar);
|
||||
|
@ -520,10 +487,6 @@ void AvatarManager::removeDeadAvatarEntities(const SetOfEntities& deadEntities)
|
|||
|
||||
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
|
||||
auto avatar = std::static_pointer_cast<OtherAvatar>(removedAvatar);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
_spaceProxiesToDelete.push_back(avatar->getSpaceIndex());
|
||||
}
|
||||
AvatarHashMap::handleRemovedAvatar(avatar, removalReason);
|
||||
avatar->tearDownGrabs();
|
||||
|
||||
|
@ -534,16 +497,39 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar
|
|||
// it might not fire until after we create a new instance for the same remote avatar, which creates a race
|
||||
// on the creation of entities for that avatar instance and the deletion of entities for this instance
|
||||
avatar->removeAvatarEntitiesFromTree();
|
||||
|
||||
if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) {
|
||||
emit AvatarInputs::getInstance()->avatarEnteredIgnoreRadius(avatar->getSessionUUID());
|
||||
emit DependencyManager::get<UsersScriptingInterface>()->enteredIgnoreRadius();
|
||||
|
||||
workload::Transaction workloadTransaction;
|
||||
workloadTransaction.remove(avatar->getSpaceIndex());
|
||||
_space->enqueueTransaction(workloadTransaction);
|
||||
|
||||
const render::ScenePointer& scene = qApp->getMain3DScene();
|
||||
render::Transaction transaction;
|
||||
avatar->removeFromScene(avatar, scene, transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
} else if (removalReason == KillAvatarReason::AvatarDisconnected) {
|
||||
// remove from node sets, if present
|
||||
DependencyManager::get<NodeList>()->removeFromIgnoreMuteSets(avatar->getSessionUUID());
|
||||
DependencyManager::get<UsersScriptingInterface>()->avatarDisconnected(avatar->getSessionUUID());
|
||||
avatar->fadeOut(qApp->getMain3DScene(), removalReason);
|
||||
render::Transaction transaction;
|
||||
auto scene = qApp->getMain3DScene();
|
||||
avatar->fadeOut(transaction, removalReason);
|
||||
|
||||
workload::SpacePointer space = _space;
|
||||
transaction.transitionFinishedOperator(avatar->getRenderItemID(), [space, avatar]() {
|
||||
const render::ScenePointer& scene = qApp->getMain3DScene();
|
||||
render::Transaction transaction;
|
||||
avatar->removeFromScene(avatar, scene, transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
|
||||
workload::Transaction workloadTransaction;
|
||||
workloadTransaction.remove(avatar->getSpaceIndex());
|
||||
space->enqueueTransaction(workloadTransaction);
|
||||
});
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
_avatarsToFadeOut.push_back(removedAvatar);
|
||||
}
|
||||
|
||||
void AvatarManager::clearOtherAvatars() {
|
||||
|
|
|
@ -220,8 +220,6 @@ private:
|
|||
explicit AvatarManager(QObject* parent = 0);
|
||||
explicit AvatarManager(const AvatarManager& other);
|
||||
|
||||
void simulateAvatarFades(float deltaTime);
|
||||
|
||||
AvatarSharedPointer newSharedAvatar(const QUuid& sessionUUID) override;
|
||||
|
||||
// called only from the AvatarHashMap thread - cannot be called while this thread holds the
|
||||
|
@ -231,8 +229,6 @@ private:
|
|||
KillAvatarReason removalReason = KillAvatarReason::NoReason) override;
|
||||
void handleTransitAnimations(AvatarTransit::Status status);
|
||||
|
||||
QVector<AvatarSharedPointer> _avatarsToFadeOut;
|
||||
|
||||
using SetOfOtherAvatars = std::set<OtherAvatarPointer>;
|
||||
SetOfOtherAvatars _avatarsToChangeInPhysics;
|
||||
|
||||
|
@ -252,7 +248,6 @@ private:
|
|||
|
||||
mutable std::mutex _spaceLock;
|
||||
workload::SpacePointer _space;
|
||||
std::vector<int32_t> _spaceProxiesToDelete;
|
||||
|
||||
AvatarTransit::TransitConfig _transitConfig;
|
||||
};
|
||||
|
|
|
@ -942,8 +942,6 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
|
|||
}
|
||||
|
||||
handleChangedAvatarEntityData();
|
||||
|
||||
updateFadingStatus();
|
||||
}
|
||||
|
||||
// As far as I know no HMD system supports a play area of a kilometer in radius.
|
||||
|
|
|
@ -356,7 +356,6 @@ void OtherAvatar::simulate(float deltaTime, bool inView) {
|
|||
PROFILE_RANGE(simulation, "grabs");
|
||||
applyGrabChanges();
|
||||
}
|
||||
updateFadingStatus();
|
||||
}
|
||||
|
||||
void OtherAvatar::handleChangedAvatarEntityData() {
|
||||
|
|
|
@ -88,44 +88,44 @@ void Audio::setMuted(bool isMuted) {
|
|||
void Audio::setMutedDesktop(bool isMuted) {
|
||||
bool changed = false;
|
||||
withWriteLock([&] {
|
||||
if (_desktopMuted != isMuted) {
|
||||
if (_mutedDesktop != isMuted) {
|
||||
changed = true;
|
||||
_desktopMuted = isMuted;
|
||||
_mutedDesktop = isMuted;
|
||||
auto client = DependencyManager::get<AudioClient>().data();
|
||||
QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false));
|
||||
}
|
||||
});
|
||||
if (changed) {
|
||||
emit mutedChanged(isMuted);
|
||||
emit desktopMutedChanged(isMuted);
|
||||
emit mutedDesktopChanged(isMuted);
|
||||
}
|
||||
}
|
||||
|
||||
bool Audio::getMutedDesktop() const {
|
||||
return resultWithReadLock<bool>([&] {
|
||||
return _desktopMuted;
|
||||
return _mutedDesktop;
|
||||
});
|
||||
}
|
||||
|
||||
void Audio::setMutedHMD(bool isMuted) {
|
||||
bool changed = false;
|
||||
withWriteLock([&] {
|
||||
if (_hmdMuted != isMuted) {
|
||||
if (_mutedHMD != isMuted) {
|
||||
changed = true;
|
||||
_hmdMuted = isMuted;
|
||||
_mutedHMD = isMuted;
|
||||
auto client = DependencyManager::get<AudioClient>().data();
|
||||
QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false));
|
||||
}
|
||||
});
|
||||
if (changed) {
|
||||
emit mutedChanged(isMuted);
|
||||
emit hmdMutedChanged(isMuted);
|
||||
emit mutedHMDChanged(isMuted);
|
||||
}
|
||||
}
|
||||
|
||||
bool Audio::getMutedHMD() const {
|
||||
return resultWithReadLock<bool>([&] {
|
||||
return _hmdMuted;
|
||||
return _mutedHMD;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -217,17 +217,17 @@ void Audio::setPTTHMD(bool enabled) {
|
|||
}
|
||||
|
||||
void Audio::saveData() {
|
||||
_desktopMutedSetting.set(getMutedDesktop());
|
||||
_hmdMutedSetting.set(getMutedHMD());
|
||||
_mutedDesktopSetting.set(getMutedDesktop());
|
||||
_mutedHMDSetting.set(getMutedHMD());
|
||||
_pttDesktopSetting.set(getPTTDesktop());
|
||||
_pttHMDSetting.set(getPTTHMD());
|
||||
}
|
||||
|
||||
void Audio::loadData() {
|
||||
_desktopMuted = _desktopMutedSetting.get();
|
||||
_hmdMuted = _hmdMutedSetting.get();
|
||||
_pttDesktop = _pttDesktopSetting.get();
|
||||
_pttHMD = _pttHMDSetting.get();
|
||||
setMutedDesktop(_mutedDesktopSetting.get());
|
||||
setMutedHMD(_mutedHMDSetting.get());
|
||||
setPTTDesktop(_pttDesktopSetting.get());
|
||||
setPTTHMD(_pttHMDSetting.get());
|
||||
|
||||
auto client = DependencyManager::get<AudioClient>().data();
|
||||
QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted()), Q_ARG(bool, false));
|
||||
|
|
|
@ -41,6 +41,7 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
|||
* @hifi-assignment-client
|
||||
*
|
||||
* @property {boolean} muted - <code>true</code> if the audio input is muted, otherwise <code>false</code>.
|
||||
* @property {boolean} mutedDesktop - <code>true</code> if the audio input is muted, otherwise <code>false</code>.
|
||||
* @property {boolean} noiseReduction - <code>true</code> if noise reduction is enabled, otherwise <code>false</code>. When
|
||||
* enabled, the input audio signal is blocked (fully attenuated) when it falls below an adaptive threshold set just
|
||||
* above the noise floor.
|
||||
|
@ -68,8 +69,8 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
|||
Q_PROPERTY(bool clipping READ isClipping NOTIFY clippingChanged)
|
||||
Q_PROPERTY(QString context READ getContext NOTIFY contextChanged)
|
||||
Q_PROPERTY(AudioDevices* devices READ getDevices NOTIFY nop)
|
||||
Q_PROPERTY(bool desktopMuted READ getMutedDesktop WRITE setMutedDesktop NOTIFY desktopMutedChanged)
|
||||
Q_PROPERTY(bool hmdMuted READ getMutedHMD WRITE setMutedHMD NOTIFY hmdMutedChanged)
|
||||
Q_PROPERTY(bool mutedDesktop READ getMutedDesktop WRITE setMutedDesktop NOTIFY mutedDesktopChanged)
|
||||
Q_PROPERTY(bool mutedHMD READ getMutedHMD WRITE setMutedHMD NOTIFY mutedHMDChanged)
|
||||
Q_PROPERTY(bool pushToTalk READ getPTT WRITE setPTT NOTIFY pushToTalkChanged);
|
||||
Q_PROPERTY(bool pushToTalkDesktop READ getPTTDesktop WRITE setPTTDesktop NOTIFY pushToTalkDesktopChanged)
|
||||
Q_PROPERTY(bool pushToTalkHMD READ getPTTHMD WRITE setPTTHMD NOTIFY pushToTalkHMDChanged)
|
||||
|
@ -287,19 +288,19 @@ signals:
|
|||
|
||||
/**jsdoc
|
||||
* Triggered when desktop audio input is muted or unmuted.
|
||||
* @function Audio.desktopMutedChanged
|
||||
* @function Audio.mutedDesktopChanged
|
||||
* @param {boolean} isMuted - <code>true</code> if the audio input is muted for desktop mode, otherwise <code>false</code>.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void desktopMutedChanged(bool isMuted);
|
||||
void mutedDesktopChanged(bool isMuted);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when HMD audio input is muted or unmuted.
|
||||
* @function Audio.hmdMutedChanged
|
||||
* @function Audio.mutedHMDChanged
|
||||
* @param {boolean} isMuted - <code>true</code> if the audio input is muted for HMD mode, otherwise <code>false</code>.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void hmdMutedChanged(bool isMuted);
|
||||
void mutedHMDChanged(bool isMuted);
|
||||
|
||||
/**
|
||||
* Triggered when Push-to-Talk has been enabled or disabled.
|
||||
|
@ -418,12 +419,12 @@ private:
|
|||
bool _contextIsHMD { false };
|
||||
AudioDevices* getDevices() { return &_devices; }
|
||||
AudioDevices _devices;
|
||||
Setting::Handle<bool> _desktopMutedSetting{ QStringList { Audio::AUDIO, "desktopMuted" }, true };
|
||||
Setting::Handle<bool> _hmdMutedSetting{ QStringList { Audio::AUDIO, "hmdMuted" }, true };
|
||||
Setting::Handle<bool> _mutedDesktopSetting{ QStringList { Audio::AUDIO, "mutedDesktop" }, true };
|
||||
Setting::Handle<bool> _mutedHMDSetting{ QStringList { Audio::AUDIO, "mutedHMD" }, true };
|
||||
Setting::Handle<bool> _pttDesktopSetting{ QStringList { Audio::AUDIO, "pushToTalkDesktop" }, false };
|
||||
Setting::Handle<bool> _pttHMDSetting{ QStringList { Audio::AUDIO, "pushToTalkHMD" }, false };
|
||||
bool _desktopMuted{ true };
|
||||
bool _hmdMuted{ false };
|
||||
bool _mutedDesktop{ true };
|
||||
bool _mutedHMD{ false };
|
||||
bool _pttDesktop{ false };
|
||||
bool _pttHMD{ false };
|
||||
bool _pushingToTalk{ false };
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <AudioClient.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <trackers/FaceTracker.h>
|
||||
#include <UsersScriptingInterface.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Menu.h"
|
||||
|
@ -30,6 +31,10 @@ AvatarInputs* AvatarInputs::getInstance() {
|
|||
|
||||
AvatarInputs::AvatarInputs(QObject* parent) : QObject(parent) {
|
||||
_showAudioTools = showAudioToolsSetting.get();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto usersScriptingInterface = DependencyManager::get<UsersScriptingInterface>();
|
||||
connect(nodeList.data(), &NodeList::ignoreRadiusEnabledChanged, this, &AvatarInputs::ignoreRadiusEnabledChanged);
|
||||
connect(usersScriptingInterface.data(), &UsersScriptingInterface::enteredIgnoreRadius, this, &AvatarInputs::enteredIgnoreRadiusChanged);
|
||||
}
|
||||
|
||||
#define AI_UPDATE(name, src) \
|
||||
|
@ -83,6 +88,10 @@ void AvatarInputs::setShowAudioTools(bool showAudioTools) {
|
|||
emit showAudioToolsChanged(_showAudioTools);
|
||||
}
|
||||
|
||||
bool AvatarInputs::getIgnoreRadiusEnabled() const {
|
||||
return DependencyManager::get<NodeList>()->getIgnoreRadiusEnabled();
|
||||
}
|
||||
|
||||
void AvatarInputs::toggleCameraMute() {
|
||||
FaceTracker* faceTracker = qApp->getSelectedFaceTracker();
|
||||
if (faceTracker) {
|
||||
|
|
|
@ -42,6 +42,8 @@ class AvatarInputs : public QObject {
|
|||
AI_PROPERTY(bool, isHMD, false)
|
||||
|
||||
Q_PROPERTY(bool showAudioTools READ showAudioTools WRITE setShowAudioTools NOTIFY showAudioToolsChanged)
|
||||
Q_PROPERTY(bool ignoreRadiusEnabled READ getIgnoreRadiusEnabled NOTIFY ignoreRadiusEnabledChanged)
|
||||
//Q_PROPERTY(bool enteredIgnoreRadius READ getEnteredIgnoreRadius NOTIFY enteredIgnoreRadiusChanged)
|
||||
|
||||
public:
|
||||
static AvatarInputs* getInstance();
|
||||
|
@ -55,7 +57,9 @@ public:
|
|||
|
||||
AvatarInputs(QObject* parent = nullptr);
|
||||
void update();
|
||||
bool showAudioTools() const { return _showAudioTools; }
|
||||
bool showAudioTools() const { return _showAudioTools; }
|
||||
bool getIgnoreRadiusEnabled() const;
|
||||
//bool getEnteredIgnoreRadius() const;
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -93,6 +97,34 @@ signals:
|
|||
*/
|
||||
void showAudioToolsChanged(bool show);
|
||||
|
||||
/**jsdoc
|
||||
* @function AvatarInputs.avatarEnteredIgnoreRadius
|
||||
* @param {QUuid} avatarID
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void avatarEnteredIgnoreRadius(QUuid avatarID);
|
||||
|
||||
/**jsdoc
|
||||
* @function AvatarInputs.avatarLeftIgnoreRadius
|
||||
* @param {QUuid} avatarID
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void avatarLeftIgnoreRadius(QUuid avatarID);
|
||||
|
||||
/**jsdoc
|
||||
* @function AvatarInputs.ignoreRadiusEnabledChanged
|
||||
* @param {boolean} enabled
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void ignoreRadiusEnabledChanged(bool enabled);
|
||||
|
||||
/**jsdoc
|
||||
* @function AvatarInputs.enteredIgnoreRadiusChanged
|
||||
* @param {boolean} enabled
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void enteredIgnoreRadiusChanged();
|
||||
|
||||
protected:
|
||||
|
||||
/**jsdoc
|
||||
|
@ -106,6 +138,8 @@ protected:
|
|||
Q_INVOKABLE void toggleCameraMute();
|
||||
|
||||
private:
|
||||
void onAvatarEnteredIgnoreRadius();
|
||||
void onAvatarLeftIgnoreRadius();
|
||||
float _trailingAudioLoudness{ 0 };
|
||||
bool _showAudioTools { false };
|
||||
};
|
||||
|
|
|
@ -652,9 +652,8 @@ void Avatar::fadeIn(render::ScenePointer scene) {
|
|||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
void Avatar::fadeOut(render::ScenePointer scene, KillAvatarReason reason) {
|
||||
void Avatar::fadeOut(render::Transaction& transaction, KillAvatarReason reason) {
|
||||
render::Transition::Type transitionType = render::Transition::USER_LEAVE_DOMAIN;
|
||||
render::Transaction transaction;
|
||||
|
||||
if (reason == KillAvatarReason::YourAvatarEnteredTheirBubble) {
|
||||
transitionType = render::Transition::BUBBLE_ISECT_TRESPASSER;
|
||||
|
@ -662,7 +661,6 @@ void Avatar::fadeOut(render::ScenePointer scene, KillAvatarReason reason) {
|
|||
transitionType = render::Transition::BUBBLE_ISECT_OWNER;
|
||||
}
|
||||
fade(transaction, transitionType);
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
void Avatar::fade(render::Transaction& transaction, render::Transition::Type type) {
|
||||
|
@ -672,19 +670,6 @@ void Avatar::fade(render::Transaction& transaction, render::Transition::Type typ
|
|||
transaction.addTransitionToItem(itemId, type, _renderItemID);
|
||||
}
|
||||
}
|
||||
_isFading = true;
|
||||
}
|
||||
|
||||
void Avatar::updateFadingStatus() {
|
||||
if (_isFading) {
|
||||
render::Transaction transaction;
|
||||
transaction.queryTransitionOnItem(_renderItemID, [this](render::ItemID id, const render::Transition* transition) {
|
||||
if (!transition || transition->isFinished) {
|
||||
_isFading = false;
|
||||
}
|
||||
});
|
||||
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
void Avatar::removeFromScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||
|
|
|
@ -520,9 +520,7 @@ public:
|
|||
bool isMoving() const { return _moving; }
|
||||
|
||||
void fadeIn(render::ScenePointer scene);
|
||||
void fadeOut(render::ScenePointer scene, KillAvatarReason reason);
|
||||
bool isFading() const { return _isFading; }
|
||||
void updateFadingStatus();
|
||||
void fadeOut(render::Transaction& transaction, KillAvatarReason reason);
|
||||
|
||||
// JSDoc is in AvatarData.h.
|
||||
Q_INVOKABLE virtual float getEyeHeight() const override;
|
||||
|
@ -727,7 +725,6 @@ protected:
|
|||
bool _initialized { false };
|
||||
bool _isAnimatingScale { false };
|
||||
bool _mustFadeIn { false };
|
||||
bool _isFading { false };
|
||||
bool _reconstructSoftEntitiesJointMap { false };
|
||||
float _modelScale { 1.0f };
|
||||
|
||||
|
|
|
@ -1707,6 +1707,7 @@ protected:
|
|||
glm::vec3 _globalBoundingBoxOffset;
|
||||
|
||||
AABox _defaultBubbleBox;
|
||||
AABox _fitBoundingBox;
|
||||
|
||||
mutable ReadWriteLockable _avatarEntitiesLock;
|
||||
AvatarEntityIDs _avatarEntityRemoved; // recently removed AvatarEntity ids
|
||||
|
|
|
@ -439,7 +439,6 @@ void AvatarHashMap::removeAvatar(const QUuid& sessionUUID, KillAvatarReason remo
|
|||
}
|
||||
|
||||
auto removedAvatar = _avatarHash.take(sessionUUID);
|
||||
|
||||
if (removedAvatar) {
|
||||
removedAvatars.push_back(removedAvatar);
|
||||
}
|
||||
|
|
|
@ -26,11 +26,10 @@ QUrl getBakeableModelURL(const QUrl& url) {
|
|||
GLTF_EXTENSION
|
||||
};
|
||||
|
||||
QUrl cleanURL = url.adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment);
|
||||
QString cleanURLString = cleanURL.fileName();
|
||||
QString filename = url.fileName();
|
||||
for (auto& extension : extensionsToBake) {
|
||||
if (cleanURLString.endsWith(extension, Qt::CaseInsensitive)) {
|
||||
return cleanURL;
|
||||
if (filename.endsWith(extension, Qt::CaseInsensitive)) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -221,17 +221,15 @@ void EntityTreeRenderer::clearDomainAndNonOwnedEntities() {
|
|||
// remove all entities from the scene
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (scene) {
|
||||
render::Transaction transaction;
|
||||
for (const auto& entry : _entitiesInScene) {
|
||||
const auto& renderer = entry.second;
|
||||
const EntityItemPointer& entityItem = renderer->getEntity();
|
||||
if (!(entityItem->isLocalEntity() || (entityItem->isAvatarEntity() && entityItem->getOwningAvatarID() == getTree()->getMyAvatarSessionUUID()))) {
|
||||
renderer->removeFromScene(scene, transaction);
|
||||
fadeOutRenderable(renderer);
|
||||
} else {
|
||||
savedEntities[entry.first] = entry.second;
|
||||
}
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
_renderablesToUpdate = savedEntities;
|
||||
|
@ -258,12 +256,10 @@ void EntityTreeRenderer::clear() {
|
|||
// remove all entities from the scene
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (scene) {
|
||||
render::Transaction transaction;
|
||||
for (const auto& entry : _entitiesInScene) {
|
||||
const auto& renderer = entry.second;
|
||||
renderer->removeFromScene(scene, transaction);
|
||||
fadeOutRenderable(renderer);
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
} else {
|
||||
qCWarning(entitiesrenderer) << "EntitityTreeRenderer::clear(), Unexpected null scene, possibly during application shutdown";
|
||||
}
|
||||
|
@ -1016,10 +1012,7 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
|||
|
||||
forceRecheckEntities(); // reset our state to force checking our inside/outsideness of entities
|
||||
|
||||
// here's where we remove the entity payload from the scene
|
||||
render::Transaction transaction;
|
||||
renderable->removeFromScene(scene, transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
fadeOutRenderable(renderable);
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
|
||||
|
@ -1057,13 +1050,26 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, bool
|
|||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::fadeOutRenderable(const EntityRendererPointer& renderable) {
|
||||
render::Transaction transaction;
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
|
||||
transaction.transitionFinishedOperator(renderable->getRenderItemID(), [scene, renderable]() {
|
||||
render::Transaction transaction;
|
||||
renderable->removeFromScene(scene, transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
});
|
||||
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::playEntityCollisionSound(const EntityItemPointer& entity, const Collision& collision) {
|
||||
assert((bool)entity);
|
||||
auto renderable = renderableForEntity(entity);
|
||||
if (!renderable) {
|
||||
return;
|
||||
if (!renderable) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SharedSoundPointer collisionSound = renderable->getCollisionSound();
|
||||
if (!collisionSound) {
|
||||
return;
|
||||
|
|
|
@ -93,6 +93,8 @@ public:
|
|||
/// reloads the entity scripts, calling unload and preload
|
||||
void reloadEntityScripts();
|
||||
|
||||
void fadeOutRenderable(const EntityRendererPointer& renderable);
|
||||
|
||||
// event handles which may generate entity related events
|
||||
QUuid mousePressEvent(QMouseEvent* event);
|
||||
void mouseReleaseEvent(QMouseEvent* event);
|
||||
|
@ -255,6 +257,7 @@ private:
|
|||
std::unordered_map<EntityItemID, EntityRendererPointer> _renderablesToUpdate;
|
||||
std::unordered_map<EntityItemID, EntityRendererPointer> _entitiesInScene;
|
||||
std::unordered_map<EntityItemID, EntityItemWeakPointer> _entitiesToAdd;
|
||||
|
||||
// For Scene.shouldRenderEntities
|
||||
QList<EntityItemID> _entityIDsLastInScene;
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _created(entit
|
|||
});
|
||||
}
|
||||
|
||||
EntityRenderer::~EntityRenderer() { }
|
||||
EntityRenderer::~EntityRenderer() {}
|
||||
|
||||
//
|
||||
// Smart payload proxy members, implementing the payload interface
|
||||
|
@ -421,6 +421,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
|
|||
if (fading) {
|
||||
_isFading = Interpolate::calculateFadeRatio(_fadeStartTime) < 1.0f;
|
||||
}
|
||||
|
||||
_prevIsTransparent = transparent;
|
||||
|
||||
updateModelTransformAndBound();
|
||||
|
@ -493,4 +494,4 @@ glm::vec4 EntityRenderer::calculatePulseColor(const glm::vec4& color, const Puls
|
|||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1101,13 +1101,13 @@ void EntityScriptingInterface::handleEntityScriptCallMethodPacket(QSharedPointer
|
|||
|
||||
void EntityScriptingInterface::onAddingEntity(EntityItem* entity) {
|
||||
if (entity->isWearable()) {
|
||||
QMetaObject::invokeMethod(this, "addingWearable", Q_ARG(QUuid, entity->getEntityItemID()));
|
||||
QMetaObject::invokeMethod(this, "addingWearable", Q_ARG(EntityItemID, entity->getEntityItemID()));
|
||||
}
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::onDeletingEntity(EntityItem* entity) {
|
||||
if (entity->isWearable()) {
|
||||
QMetaObject::invokeMethod(this, "deletingWearable", Q_ARG(QUuid, entity->getEntityItemID()));
|
||||
QMetaObject::invokeMethod(this, "deletingWearable", Q_ARG(EntityItemID, entity->getEntityItemID()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,12 +71,12 @@ void UserActivityLoggerScriptingInterface::makeUserConnection(QString otherID, b
|
|||
doLogAction("makeUserConnection", payload);
|
||||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::bubbleToggled(bool newValue) {
|
||||
doLogAction(newValue ? "bubbleOn" : "bubbleOff");
|
||||
void UserActivityLoggerScriptingInterface::privacyShieldToggled(bool newValue) {
|
||||
doLogAction(newValue ? "privacyShieldOn" : "privacyShieldOff");
|
||||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::bubbleActivated() {
|
||||
doLogAction("bubbleActivated");
|
||||
void UserActivityLoggerScriptingInterface::privacyShieldActivated() {
|
||||
doLogAction("privacyShieldActivated");
|
||||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::logAction(QString action, QVariantMap details) {
|
||||
|
|
|
@ -30,8 +30,8 @@ public:
|
|||
Q_INVOKABLE void palAction(QString action, QString target);
|
||||
Q_INVOKABLE void palOpened(float secondsOpen);
|
||||
Q_INVOKABLE void makeUserConnection(QString otherUser, bool success, QString details = "");
|
||||
Q_INVOKABLE void bubbleToggled(bool newValue);
|
||||
Q_INVOKABLE void bubbleActivated();
|
||||
Q_INVOKABLE void privacyShieldToggled(bool newValue);
|
||||
Q_INVOKABLE void privacyShieldActivated();
|
||||
Q_INVOKABLE void logAction(QString action, QVariantMap details = QVariantMap{});
|
||||
Q_INVOKABLE void commercePurchaseSuccess(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem);
|
||||
Q_INVOKABLE void commercePurchaseFailure(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem, QString errorDetails);
|
||||
|
|
|
@ -38,10 +38,10 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums);
|
||||
case PacketType::AvatarIdentity:
|
||||
case PacketType::AvatarData:
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::SendMaxTranslationDimension);
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::FBXJointOrderChange);
|
||||
case PacketType::BulkAvatarData:
|
||||
case PacketType::KillAvatar:
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::SendMaxTranslationDimension);
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::FBXJointOrderChange);
|
||||
case PacketType::MessagesData:
|
||||
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
|
||||
// ICE packets
|
||||
|
|
|
@ -266,6 +266,7 @@ enum class EntityVersion : PacketVersion {
|
|||
ModelScale,
|
||||
ReOrderParentIDProperties,
|
||||
CertificateTypeProperty,
|
||||
DisableWebMedia,
|
||||
|
||||
// Add new versions above here
|
||||
NUM_PACKET_TYPE,
|
||||
|
@ -327,7 +328,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
|||
CollisionFlag,
|
||||
AvatarTraitsAck,
|
||||
FasterAvatarEntities,
|
||||
SendMaxTranslationDimension
|
||||
SendMaxTranslationDimension,
|
||||
FBXJointOrderChange
|
||||
};
|
||||
|
||||
enum class DomainConnectRequestVersion : PacketVersion {
|
||||
|
|
|
@ -47,6 +47,10 @@ void Transaction::queryTransitionOnItem(ItemID id, TransitionQueryFunc func) {
|
|||
_queriedTransitions.emplace_back(id, func);
|
||||
}
|
||||
|
||||
void Transaction::transitionFinishedOperator(ItemID id, TransitionFinishedFunc func) {
|
||||
_transitionFinishedOperators.emplace_back(id, func);
|
||||
}
|
||||
|
||||
void Transaction::updateItem(ItemID id, const UpdateFunctorPointer& functor) {
|
||||
_updatedItems.emplace_back(id, functor);
|
||||
}
|
||||
|
@ -75,6 +79,7 @@ void Transaction::reserve(const std::vector<Transaction>& transactionContainer)
|
|||
size_t addedTransitionsCount = 0;
|
||||
size_t queriedTransitionsCount = 0;
|
||||
size_t reAppliedTransitionsCount = 0;
|
||||
size_t transitionFinishedOperatorsCount = 0;
|
||||
size_t highlightResetsCount = 0;
|
||||
size_t highlightRemovesCount = 0;
|
||||
size_t highlightQueriesCount = 0;
|
||||
|
@ -85,6 +90,7 @@ void Transaction::reserve(const std::vector<Transaction>& transactionContainer)
|
|||
updatedItemsCount += transaction._updatedItems.size();
|
||||
resetSelectionsCount += transaction._resetSelections.size();
|
||||
addedTransitionsCount += transaction._addedTransitions.size();
|
||||
transitionFinishedOperatorsCount += transaction._transitionFinishedOperators.size();
|
||||
queriedTransitionsCount += transaction._queriedTransitions.size();
|
||||
reAppliedTransitionsCount += transaction._reAppliedTransitions.size();
|
||||
highlightResetsCount += transaction._highlightResets.size();
|
||||
|
@ -99,6 +105,7 @@ void Transaction::reserve(const std::vector<Transaction>& transactionContainer)
|
|||
_addedTransitions.reserve(addedTransitionsCount);
|
||||
_queriedTransitions.reserve(queriedTransitionsCount);
|
||||
_reAppliedTransitions.reserve(reAppliedTransitionsCount);
|
||||
_transitionFinishedOperators.reserve(transitionFinishedOperatorsCount);
|
||||
_highlightResets.reserve(highlightResetsCount);
|
||||
_highlightRemoves.reserve(highlightRemovesCount);
|
||||
_highlightQueries.reserve(highlightQueriesCount);
|
||||
|
@ -142,6 +149,7 @@ void Transaction::merge(Transaction&& transaction) {
|
|||
moveElements(_resetSelections, transaction._resetSelections);
|
||||
moveElements(_addedTransitions, transaction._addedTransitions);
|
||||
moveElements(_queriedTransitions, transaction._queriedTransitions);
|
||||
moveElements(_transitionFinishedOperators, transaction._transitionFinishedOperators);
|
||||
moveElements(_reAppliedTransitions, transaction._reAppliedTransitions);
|
||||
moveElements(_highlightResets, transaction._highlightResets);
|
||||
moveElements(_highlightRemoves, transaction._highlightRemoves);
|
||||
|
@ -156,6 +164,7 @@ void Transaction::merge(const Transaction& transaction) {
|
|||
copyElements(_addedTransitions, transaction._addedTransitions);
|
||||
copyElements(_queriedTransitions, transaction._queriedTransitions);
|
||||
copyElements(_reAppliedTransitions, transaction._reAppliedTransitions);
|
||||
copyElements(_transitionFinishedOperators, transaction._transitionFinishedOperators);
|
||||
copyElements(_highlightResets, transaction._highlightResets);
|
||||
copyElements(_highlightRemoves, transaction._highlightRemoves);
|
||||
copyElements(_highlightQueries, transaction._highlightQueries);
|
||||
|
@ -168,6 +177,7 @@ void Transaction::clear() {
|
|||
_resetSelections.clear();
|
||||
_addedTransitions.clear();
|
||||
_queriedTransitions.clear();
|
||||
_transitionFinishedOperators.clear();
|
||||
_reAppliedTransitions.clear();
|
||||
_highlightResets.clear();
|
||||
_highlightRemoves.clear();
|
||||
|
@ -271,6 +281,7 @@ void Scene::processTransactionFrame(const Transaction& transaction) {
|
|||
transitionItems(transaction._addedTransitions);
|
||||
reApplyTransitions(transaction._reAppliedTransitions);
|
||||
queryTransitionItems(transaction._queriedTransitions);
|
||||
resetTransitionFinishedOperator(transaction._transitionFinishedOperators);
|
||||
|
||||
// Update the numItemsAtomic counter AFTER the pending changes went through
|
||||
_numAllocatedItems.exchange(maxID);
|
||||
|
@ -394,7 +405,7 @@ void Scene::transitionItems(const Transaction::TransitionAdds& transactions) {
|
|||
// Only remove if:
|
||||
// transitioning to something other than none or we're transitioning to none from ELEMENT_LEAVE_DOMAIN or USER_LEAVE_DOMAIN
|
||||
const auto& oldTransitionType = transitionStage->getTransition(transitionId).eventType;
|
||||
if (transitionType != Transition::NONE || !(oldTransitionType == Transition::ELEMENT_LEAVE_DOMAIN || oldTransitionType == Transition::USER_LEAVE_DOMAIN)) {
|
||||
if (transitionType != oldTransitionType) {
|
||||
resetItemTransition(itemId);
|
||||
}
|
||||
}
|
||||
|
@ -440,6 +451,23 @@ void Scene::queryTransitionItems(const Transaction::TransitionQueries& transacti
|
|||
}
|
||||
}
|
||||
|
||||
void Scene::resetTransitionFinishedOperator(const Transaction::TransitionFinishedOperators& operators) {
|
||||
for (auto& finishedOperator : operators) {
|
||||
auto itemId = std::get<0>(finishedOperator);
|
||||
const auto& item = _items[itemId];
|
||||
auto func = std::get<1>(finishedOperator);
|
||||
|
||||
if (item.exist() && func != nullptr) {
|
||||
TransitionStage::Index transitionId = item.getTransitionId();
|
||||
if (!TransitionStage::isIndexInvalid(transitionId)) {
|
||||
_transitionFinishedOperatorMap[transitionId].emplace_back(func);
|
||||
} else if (func) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::resetHighlights(const Transaction::HighlightResets& transactions) {
|
||||
auto outlineStage = getStage<HighlightStage>(HighlightStage::getName());
|
||||
if (outlineStage) {
|
||||
|
@ -526,9 +554,18 @@ void Scene::setItemTransition(ItemID itemId, Index transitionId) {
|
|||
|
||||
void Scene::resetItemTransition(ItemID itemId) {
|
||||
auto& item = _items[itemId];
|
||||
if (!render::TransitionStage::isIndexInvalid(item.getTransitionId())) {
|
||||
TransitionStage::Index transitionId = item.getTransitionId();
|
||||
if (!render::TransitionStage::isIndexInvalid(transitionId)) {
|
||||
auto transitionStage = getStage<TransitionStage>(TransitionStage::getName());
|
||||
transitionStage->removeTransition(item.getTransitionId());
|
||||
|
||||
auto finishedOperators = _transitionFinishedOperatorMap[transitionId];
|
||||
for (auto finishedOperator : finishedOperators) {
|
||||
if (finishedOperator) {
|
||||
finishedOperator();
|
||||
}
|
||||
}
|
||||
_transitionFinishedOperatorMap.erase(transitionId);
|
||||
transitionStage->removeTransition(transitionId);
|
||||
setItemTransition(itemId, render::TransitionStage::INVALID_INDEX);
|
||||
}
|
||||
}
|
||||
|
@ -587,4 +624,4 @@ void Scene::resetStage(const Stage::Name& name, const StagePointer& stage) {
|
|||
} else {
|
||||
(*found).second = stage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,12 +32,15 @@ class Scene;
|
|||
// These changes must be expressed through the corresponding command from the Transaction
|
||||
// THe Transaction is then queued on the Scene so all the pending transactions can be consolidated and processed at the time
|
||||
// of updating the scene before it s rendered.
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
class Transaction {
|
||||
friend class Scene;
|
||||
public:
|
||||
|
||||
typedef std::function<void(ItemID, const Transition*)> TransitionQueryFunc;
|
||||
typedef std::function<void()> TransitionFinishedFunc;
|
||||
typedef std::function<void(HighlightStyle const*)> SelectionHighlightQueryFunc;
|
||||
|
||||
Transaction() {}
|
||||
|
@ -52,6 +55,7 @@ public:
|
|||
void removeTransitionFromItem(ItemID id);
|
||||
void reApplyTransitionToItem(ItemID id);
|
||||
void queryTransitionOnItem(ItemID id, TransitionQueryFunc func);
|
||||
void transitionFinishedOperator(ItemID id, TransitionFinishedFunc func);
|
||||
|
||||
template <class T> void updateItem(ItemID id, std::function<void(T&)> func) {
|
||||
updateItem(id, std::make_shared<UpdateFunctor<T>>(func));
|
||||
|
@ -84,6 +88,7 @@ protected:
|
|||
using Update = std::tuple<ItemID, UpdateFunctorPointer>;
|
||||
using TransitionAdd = std::tuple<ItemID, Transition::Type, ItemID>;
|
||||
using TransitionQuery = std::tuple<ItemID, TransitionQueryFunc>;
|
||||
using TransitionFinishedOperator = std::tuple<ItemID, TransitionFinishedFunc>;
|
||||
using TransitionReApply = ItemID;
|
||||
using SelectionReset = Selection;
|
||||
using HighlightReset = std::tuple<std::string, HighlightStyle>;
|
||||
|
@ -95,6 +100,7 @@ protected:
|
|||
using Updates = std::vector<Update>;
|
||||
using TransitionAdds = std::vector<TransitionAdd>;
|
||||
using TransitionQueries = std::vector<TransitionQuery>;
|
||||
using TransitionFinishedOperators = std::vector<TransitionFinishedOperator>;
|
||||
using TransitionReApplies = std::vector<TransitionReApply>;
|
||||
using SelectionResets = std::vector<SelectionReset>;
|
||||
using HighlightResets = std::vector<HighlightReset>;
|
||||
|
@ -107,6 +113,7 @@ protected:
|
|||
TransitionAdds _addedTransitions;
|
||||
TransitionQueries _queriedTransitions;
|
||||
TransitionReApplies _reAppliedTransitions;
|
||||
TransitionFinishedOperators _transitionFinishedOperators;
|
||||
SelectionResets _resetSelections;
|
||||
HighlightResets _highlightResets;
|
||||
HighlightRemoves _highlightRemoves;
|
||||
|
@ -208,6 +215,7 @@ protected:
|
|||
ItemIDSet _masterNonspatialSet;
|
||||
|
||||
void resetItems(const Transaction::Resets& transactions);
|
||||
void resetTransitionFinishedOperator(const Transaction::TransitionFinishedOperators& transactions);
|
||||
void removeItems(const Transaction::Removes& transactions);
|
||||
void updateItems(const Transaction::Updates& transactions);
|
||||
void transitionItems(const Transaction::TransitionAdds& transactions);
|
||||
|
@ -223,6 +231,8 @@ protected:
|
|||
mutable std::mutex _selectionsMutex; // mutable so it can be used in the thread safe getSelection const method
|
||||
SelectionMap _selections;
|
||||
|
||||
std::unordered_map<int32_t, std::vector<Transaction::TransitionFinishedFunc>> _transitionFinishedOperatorMap;
|
||||
|
||||
void resetSelections(const Transaction::SelectionResets& transactions);
|
||||
// More actions coming to selections soon:
|
||||
// void removeFromSelection(const Selection& selection);
|
||||
|
|
|
@ -50,4 +50,4 @@ namespace render {
|
|||
typedef std::vector<Transition::Type> TransitionTypes;
|
||||
}
|
||||
|
||||
#endif // hifi_render_Transition_h
|
||||
#endif // hifi_render_Transition_h
|
||||
|
|
138
scripts/developer/createAvatarInputsBarEntity.js
Normal file
|
@ -0,0 +1,138 @@
|
|||
"use strict";
|
||||
|
||||
(function(){
|
||||
var AppUi = Script.require("appUi");
|
||||
|
||||
var ui;
|
||||
|
||||
var onCreateAvatarInputsBarEntity = false;
|
||||
var micBarEntity = null;
|
||||
var bubbleIconEntity = null;
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
var AVATAR_INPUTS_EDIT_QML_SOURCE = "hifi/EditAvatarInputsBar.qml";
|
||||
|
||||
// DPI
|
||||
var ENTITY_DPI = 60.0;
|
||||
// QML NATURAL DIMENSIONS
|
||||
var MIC_BAR_DIMENSIONS = Vec3.multiply(30.0 / ENTITY_DPI, {x: 0.036, y: 0.048, z: 0.3});
|
||||
var BUBBLE_ICON_DIMENSIONS = Vec3.multiply(30.0 / ENTITY_DPI, {x: 0.036, y: 0.036, z: 0.3});
|
||||
// ENTITY NAMES
|
||||
var MIC_BAR_NAME = "AvatarInputsMicBarEntity";
|
||||
var BUBBLE_ICON_NAME = "AvatarInputsBubbleIconEntity";
|
||||
// CONSTANTS
|
||||
var LOCAL_POSITION_X_OFFSET = -0.2;
|
||||
var LOCAL_POSITION_Y_OFFSET = -0.125;
|
||||
var LOCAL_POSITION_Z_OFFSET = -0.5;
|
||||
|
||||
function fromQml(message) {
|
||||
if (message.method === "reposition") {
|
||||
var micBarLocalPosition = Entities.getEntityProperties(micBarEntity).localPosition;
|
||||
var bubbleIconLocalPosition = Entities.getEntityProperties(bubbleIconEntity).localPosition;
|
||||
var newMicBarLocalPosition, newBubbleIconLocalPosition;
|
||||
if (message.x !== undefined) {
|
||||
newMicBarLocalPosition = { x: -((MIC_BAR_DIMENSIONS.x) / 2) + message.x, y: micBarLocalPosition.y, z: micBarLocalPosition.z };
|
||||
newBubbleIconLocalPosition = { x: ((MIC_BAR_DIMENSIONS.x) * 1.2 / 2) + message.x, y: bubbleIconLocalPosition.y, z: bubbleIconLocalPosition.z };
|
||||
} else if (message.y !== undefined) {
|
||||
newMicBarLocalPosition = { x: micBarLocalPosition.x, y: message.y, z: micBarLocalPosition.z };
|
||||
newBubbleIconLocalPosition = { x: bubbleIconLocalPosition.x, y: ((MIC_BAR_DIMENSIONS.y - BUBBLE_ICON_DIMENSIONS.y) / 2 + message.y), z: bubbleIconLocalPosition.z };
|
||||
} else if (message.z !== undefined) {
|
||||
newMicBarLocalPosition = { x: micBarLocalPosition.x, y: micBarLocalPosition.y, z: message.z };
|
||||
newBubbleIconLocalPosition = { x: bubbleIconLocalPosition.x, y: bubbleIconLocalPosition.y, z: message.z };
|
||||
}
|
||||
var micBarProps = {
|
||||
localPosition: newMicBarLocalPosition
|
||||
};
|
||||
var bubbleIconProps = {
|
||||
localPosition: newBubbleIconLocalPosition
|
||||
};
|
||||
|
||||
Entities.editEntity(micBarEntity, micBarProps);
|
||||
Entities.editEntity(bubbleIconEntity, bubbleIconProps);
|
||||
} else if (message.method === "setVisible") {
|
||||
if (message.visible !== undefined) {
|
||||
var props = {
|
||||
visible: message.visible
|
||||
};
|
||||
Entities.editEntity(micBarEntity, props);
|
||||
Entities.editEntity(bubbleIconEntity, props);
|
||||
}
|
||||
} else if (message.method === "print") {
|
||||
// prints the local position into the hifi log.
|
||||
var micBarLocalPosition = Entities.getEntityProperties(micBarEntity).localPosition;
|
||||
var bubbleIconLocalPosition = Entities.getEntityProperties(bubbleIconEntity).localPosition;
|
||||
console.log("mic bar local position is at " + JSON.stringify(micBarLocalPosition));
|
||||
console.log("bubble icon local position is at " + JSON.stringify(bubbleIconLocalPosition));
|
||||
}
|
||||
};
|
||||
|
||||
function createEntities() {
|
||||
if (micBarEntity != null && bubbleIconEntity != null) {
|
||||
return;
|
||||
}
|
||||
// POSITIONS
|
||||
var micBarLocalPosition = {x: (-(MIC_BAR_DIMENSIONS.x / 2)) + LOCAL_POSITION_X_OFFSET, y: LOCAL_POSITION_Y_OFFSET, z: LOCAL_POSITION_Z_OFFSET};
|
||||
var bubbleIconLocalPosition = {x: (MIC_BAR_DIMENSIONS.x * 1.2 / 2) + LOCAL_POSITION_X_OFFSET, y: ((MIC_BAR_DIMENSIONS.y - BUBBLE_ICON_DIMENSIONS.y) / 2 + LOCAL_POSITION_Y_OFFSET), z: LOCAL_POSITION_Z_OFFSET};
|
||||
var props = {
|
||||
type: "Web",
|
||||
name: MIC_BAR_NAME,
|
||||
parentID: MyAvatar.SELF_ID,
|
||||
parentJointIndex: MyAvatar.getJointIndex("_CAMERA_MATRIX"),
|
||||
localPosition: micBarLocalPosition,
|
||||
localRotation: Quat.cancelOutRollAndPitch(Quat.lookAtSimple(Camera.orientation, micBarLocalPosition)),
|
||||
sourceUrl: Script.resourcesPath() + "qml/hifi/audio/MicBarApplication.qml",
|
||||
// cutoff alpha for detecting transparency
|
||||
alpha: 0.98,
|
||||
dimensions: MIC_BAR_DIMENSIONS,
|
||||
dpi: ENTITY_DPI,
|
||||
drawInFront: true,
|
||||
userData: {
|
||||
grabbable: false
|
||||
},
|
||||
};
|
||||
micBarEntity = Entities.addEntity(props, "local");
|
||||
var props = {
|
||||
type: "Web",
|
||||
name: BUBBLE_ICON_NAME,
|
||||
parentID: MyAvatar.SELF_ID,
|
||||
parentJointIndex: MyAvatar.getJointIndex("_CAMERA_MATRIX"),
|
||||
localPosition: bubbleIconLocalPosition,
|
||||
localRotation: Quat.cancelOutRollAndPitch(Quat.lookAtSimple(Camera.orientation, bubbleIconLocalPosition)),
|
||||
sourceUrl: Script.resourcesPath() + "qml/BubbleIcon.qml",
|
||||
// cutoff alpha for detecting transparency
|
||||
alpha: 0.98,
|
||||
dimensions: BUBBLE_ICON_DIMENSIONS,
|
||||
dpi: ENTITY_DPI,
|
||||
drawInFront: true,
|
||||
userData: {
|
||||
grabbable: false
|
||||
},
|
||||
};
|
||||
bubbleIconEntity = Entities.addEntity(props, "local");
|
||||
tablet.loadQMLSource(AVATAR_INPUTS_EDIT_QML_SOURCE);
|
||||
};
|
||||
function cleanup() {
|
||||
if (micBarEntity) {
|
||||
Entities.deleteEntity(micBarEntity);
|
||||
}
|
||||
if (bubbleIconEntity) {
|
||||
Entities.deleteEntity(bubbleIconEntity);
|
||||
}
|
||||
};
|
||||
|
||||
function setup() {
|
||||
ui = new AppUi({
|
||||
buttonName: "AVBAR",
|
||||
home: Script.resourcesPath() + "qml/hifi/EditAvatarInputsBar.qml",
|
||||
onMessage: fromQml,
|
||||
onOpened: createEntities,
|
||||
// onClosed: cleanup,
|
||||
normalButton: "icons/tablet-icons/edit-i.svg",
|
||||
activeButton: "icons/tablet-icons/edit-a.svg",
|
||||
});
|
||||
};
|
||||
|
||||
setup();
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
||||
}());
|
|
@ -75,6 +75,7 @@ button.clicked.connect(onClicked);
|
|||
tablet.screenChanged.connect(onScreenChanged);
|
||||
Audio.mutedChanged.connect(onMuteToggled);
|
||||
Audio.pushToTalkChanged.connect(onMuteToggled);
|
||||
HMD.displayModeChanged.connect(onMuteToggled);
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
if (onAudioScreen) {
|
||||
|
@ -84,6 +85,7 @@ Script.scriptEnding.connect(function () {
|
|||
tablet.screenChanged.disconnect(onScreenChanged);
|
||||
Audio.mutedChanged.disconnect(onMuteToggled);
|
||||
Audio.pushToTalkChanged.disconnect(onMuteToggled);
|
||||
HMD.displayModeChanged.disconnect(onMuteToggled);
|
||||
tablet.removeButton(button);
|
||||
});
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
if (HMD.active) {
|
||||
warningOverlayID = Overlays.addOverlay("text3d", {
|
||||
name: "Muted-Warning",
|
||||
localPosition: { x: 0.0, y: -0.5, z: -1.0 },
|
||||
localPosition: { x: 0.0, y: -0.45, z: -1.0 },
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0.0, y: 0.0, z: 0.0, w: 1.0 }),
|
||||
text: warningText,
|
||||
textAlpha: 1,
|
||||
|
@ -58,20 +58,6 @@
|
|||
parentID: MyAvatar.SELF_ID,
|
||||
parentJointIndex: MyAvatar.getJointIndex("_CAMERA_MATRIX")
|
||||
});
|
||||
} else {
|
||||
var textDimensions = { x: 100, y: 50 };
|
||||
warningOverlayID = Overlays.addOverlay("text", {
|
||||
name: "Muted-Warning",
|
||||
font: { size: 36 },
|
||||
text: warningText,
|
||||
x: (Window.innerWidth - textDimensions.x) / 2,
|
||||
y: (Window.innerHeight - textDimensions.y),
|
||||
width: textDimensions.x,
|
||||
height: textDimensions.y,
|
||||
textColor: { red: 226, green: 51, blue: 77 },
|
||||
backgroundAlpha: 0,
|
||||
visible: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,4 +127,4 @@
|
|||
Audio.mutedChanged.connect(startOrStopPoll);
|
||||
Audio.warnWhenMutedChanged.connect(startOrStopPoll);
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
|
|
@ -171,7 +171,7 @@ function goAway(fromStartup) {
|
|||
if (!previousBubbleState) {
|
||||
Users.toggleIgnoreRadius();
|
||||
}
|
||||
UserActivityLogger.bubbleToggled(Users.getIgnoreRadiusEnabled());
|
||||
UserActivityLogger.privacyShieldToggled(Users.getIgnoreRadiusEnabled());
|
||||
UserActivityLogger.toggledAway(true);
|
||||
MyAvatar.isAway = true;
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ function goActive() {
|
|||
|
||||
if (Users.getIgnoreRadiusEnabled() !== previousBubbleState) {
|
||||
Users.toggleIgnoreRadius();
|
||||
UserActivityLogger.bubbleToggled(Users.getIgnoreRadiusEnabled());
|
||||
UserActivityLogger.privacyShieldToggled(Users.getIgnoreRadiusEnabled());
|
||||
}
|
||||
|
||||
if (!Window.hasFocus()) {
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
// Called from the C++ scripting interface to show the bubble overlay
|
||||
function enteredIgnoreRadius() {
|
||||
createOverlays();
|
||||
UserActivityLogger.bubbleActivated();
|
||||
UserActivityLogger.privacyShieldActivated();
|
||||
}
|
||||
|
||||
// Used to set the state of the bubble HUD button
|
||||
|
@ -160,7 +160,7 @@
|
|||
function onBubbleToggled(enabled, doNotLog) {
|
||||
writeButtonProperties(enabled);
|
||||
if (doNotLog !== true) {
|
||||
UserActivityLogger.bubbleToggled(enabled);
|
||||
UserActivityLogger.privacyShieldToggled(enabled);
|
||||
}
|
||||
if (enabled) {
|
||||
createOverlays();
|
||||
|
@ -174,7 +174,7 @@
|
|||
}
|
||||
|
||||
// Setup the bubble button
|
||||
var buttonName = "BUBBLE";
|
||||
var buttonName = "SHIELD";
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
button = tablet.addButton({
|
||||
icon: "icons/tablet-icons/bubble-i.svg",
|
||||
|
|
|
@ -282,6 +282,28 @@ function checkEditPermissionsAndUpdate() {
|
|||
}
|
||||
}
|
||||
|
||||
// Copies the properties in `b` into `a`. `a` will be modified.
|
||||
function copyProperties(a, b) {
|
||||
for (var key in b) {
|
||||
a[key] = b[key];
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
const DEFAULT_DYNAMIC_PROPERTIES = {
|
||||
dynamic: true,
|
||||
damping: 0.39347,
|
||||
angularDamping: 0.39347,
|
||||
gravity: { x: 0, y: -9.8, z: 0 },
|
||||
};
|
||||
|
||||
const DEFAULT_NON_DYNAMIC_PROPERTIES = {
|
||||
dynamic: false,
|
||||
damping: 0,
|
||||
angularDamping: 0,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
};
|
||||
|
||||
const DEFAULT_ENTITY_PROPERTIES = {
|
||||
All: {
|
||||
description: "",
|
||||
|
@ -299,26 +321,14 @@ const DEFAULT_ENTITY_PROPERTIES = {
|
|||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
damping: 0,
|
||||
angularVelocity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
angularDamping: 0,
|
||||
restitution: 0.5,
|
||||
friction: 0.5,
|
||||
density: 1000,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
acceleration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
dynamic: false,
|
||||
},
|
||||
Shape: {
|
||||
|
@ -484,11 +494,6 @@ var toolBar = (function () {
|
|||
dialogWindow = null,
|
||||
tablet = null;
|
||||
|
||||
function applyProperties(originalProperties, newProperties) {
|
||||
for (var key in newProperties) {
|
||||
originalProperties[key] = newProperties[key];
|
||||
}
|
||||
}
|
||||
function createNewEntity(requestedProperties) {
|
||||
var dimensions = requestedProperties.dimensions ? requestedProperties.dimensions : DEFAULT_DIMENSIONS;
|
||||
var position = getPositionToCreateEntity();
|
||||
|
@ -496,17 +501,23 @@ var toolBar = (function () {
|
|||
|
||||
var properties = {};
|
||||
|
||||
applyProperties(properties, DEFAULT_ENTITY_PROPERTIES.All);
|
||||
copyProperties(properties, DEFAULT_ENTITY_PROPERTIES.All);
|
||||
|
||||
var type = requestedProperties.type;
|
||||
if (type === "Box" || type === "Sphere") {
|
||||
applyProperties(properties, DEFAULT_ENTITY_PROPERTIES.Shape);
|
||||
copyProperties(properties, DEFAULT_ENTITY_PROPERTIES.Shape);
|
||||
} else {
|
||||
applyProperties(properties, DEFAULT_ENTITY_PROPERTIES[type]);
|
||||
copyProperties(properties, DEFAULT_ENTITY_PROPERTIES[type]);
|
||||
}
|
||||
|
||||
// We apply the requested properties first so that they take priority over any default properties.
|
||||
applyProperties(properties, requestedProperties);
|
||||
copyProperties(properties, requestedProperties);
|
||||
|
||||
if (properties.dynamic) {
|
||||
copyProperties(properties, DEFAULT_DYNAMIC_PROPERTIES);
|
||||
} else {
|
||||
copyProperties(properties, DEFAULT_NON_DYNAMIC_PROPERTIES);
|
||||
}
|
||||
|
||||
|
||||
if (position !== null && position !== undefined) {
|
||||
|
@ -675,7 +686,6 @@ var toolBar = (function () {
|
|||
grabbable: result.grabbable
|
||||
},
|
||||
dynamic: dynamic,
|
||||
gravity: dynamic ? { x: 0, y: -10, z: 0 } : { x: 0, y: 0, z: 0 }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,10 @@ using System.Text.RegularExpressions;
|
|||
|
||||
class AvatarExporter : MonoBehaviour {
|
||||
// update version number for every PR that changes this file, also set updated version in README file
|
||||
static readonly string AVATAR_EXPORTER_VERSION = "0.4.0";
|
||||
static readonly string AVATAR_EXPORTER_VERSION = "0.4.1";
|
||||
|
||||
static readonly float HIPS_GROUND_MIN_Y = 0.01f;
|
||||
static readonly float HIPS_MIN_Y_PERCENT_OF_HEIGHT = 0.03f;
|
||||
static readonly float BELOW_GROUND_THRESHOLD_PERCENT_OF_HEIGHT = -0.15f;
|
||||
static readonly float HIPS_SPINE_CHEST_MIN_SEPARATION = 0.001f;
|
||||
static readonly int MAXIMUM_USER_BONE_COUNT = 256;
|
||||
static readonly string EMPTY_WARNING_TEXT = "None";
|
||||
|
@ -231,7 +232,8 @@ class AvatarExporter : MonoBehaviour {
|
|||
HeadMapped,
|
||||
HeadDescendantOfChest,
|
||||
EyesMapped,
|
||||
HipsNotOnGround,
|
||||
HipsNotAtBottom,
|
||||
ExtentsNotBelowGround,
|
||||
HipsSpineChestNotCoincident,
|
||||
TotalBoneCountUnderLimit,
|
||||
AvatarRuleEnd,
|
||||
|
@ -247,18 +249,26 @@ class AvatarExporter : MonoBehaviour {
|
|||
class UserBoneInformation {
|
||||
public string humanName; // bone name in Humanoid if it is mapped, otherwise ""
|
||||
public string parentName; // parent user bone name
|
||||
public BoneTreeNode boneTreeNode; // node within the user bone tree
|
||||
public int mappingCount; // number of times this bone is mapped in Humanoid
|
||||
public Vector3 position; // absolute position
|
||||
public Quaternion rotation; // absolute rotation
|
||||
public BoneTreeNode boneTreeNode;
|
||||
|
||||
public UserBoneInformation() {
|
||||
humanName = "";
|
||||
parentName = "";
|
||||
boneTreeNode = new BoneTreeNode();
|
||||
mappingCount = 0;
|
||||
position = new Vector3();
|
||||
rotation = new Quaternion();
|
||||
boneTreeNode = new BoneTreeNode();
|
||||
}
|
||||
public UserBoneInformation(string parent, BoneTreeNode treeNode, Vector3 pos) {
|
||||
humanName = "";
|
||||
parentName = parent;
|
||||
boneTreeNode = treeNode;
|
||||
mappingCount = 0;
|
||||
position = pos;
|
||||
rotation = new Quaternion();
|
||||
}
|
||||
|
||||
public bool HasHumanMapping() { return !string.IsNullOrEmpty(humanName); }
|
||||
|
@ -266,11 +276,13 @@ class AvatarExporter : MonoBehaviour {
|
|||
|
||||
class BoneTreeNode {
|
||||
public string boneName;
|
||||
public string parentName;
|
||||
public List<BoneTreeNode> children = new List<BoneTreeNode>();
|
||||
|
||||
public BoneTreeNode() {}
|
||||
public BoneTreeNode(string name) {
|
||||
public BoneTreeNode(string name, string parent) {
|
||||
boneName = name;
|
||||
parentName = parent;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -732,9 +744,11 @@ class AvatarExporter : MonoBehaviour {
|
|||
|
||||
// instantiate a game object of the user avatar to traverse the bone tree to gather
|
||||
// bone parents and positions as well as build a bone tree, then destroy it
|
||||
GameObject assetGameObject = (GameObject)Instantiate(avatarResource);
|
||||
TraverseUserBoneTree(assetGameObject.transform);
|
||||
DestroyImmediate(assetGameObject);
|
||||
GameObject avatarGameObject = (GameObject)Instantiate(avatarResource, Vector3.zero, Quaternion.identity);
|
||||
TraverseUserBoneTree(avatarGameObject.transform, userBoneTree);
|
||||
Bounds bounds = AvatarUtilities.GetAvatarBounds(avatarGameObject);
|
||||
float height = AvatarUtilities.GetAvatarHeight(avatarGameObject);
|
||||
DestroyImmediate(avatarGameObject);
|
||||
|
||||
// iterate over Humanoid bones and update user bone info to increase human mapping counts for each bone
|
||||
// as well as set their Humanoid name and build a Humanoid to user bone mapping
|
||||
|
@ -753,10 +767,10 @@ class AvatarExporter : MonoBehaviour {
|
|||
}
|
||||
|
||||
// generate the list of avatar rule failure strings for any avatar rules that are not satisfied by this avatar
|
||||
SetFailedAvatarRules();
|
||||
SetFailedAvatarRules(bounds, height);
|
||||
}
|
||||
|
||||
static void TraverseUserBoneTree(Transform modelBone) {
|
||||
static void TraverseUserBoneTree(Transform modelBone, BoneTreeNode boneTreeNode) {
|
||||
GameObject gameObject = modelBone.gameObject;
|
||||
|
||||
// check if this transform is a node containing mesh, light, or camera instead of a bone
|
||||
|
@ -770,33 +784,52 @@ class AvatarExporter : MonoBehaviour {
|
|||
if (mesh) {
|
||||
Material[] materials = skinnedMeshRenderer != null ? skinnedMeshRenderer.sharedMaterials : meshRenderer.sharedMaterials;
|
||||
StoreMaterialData(materials);
|
||||
|
||||
// ensure branches within the transform hierarchy that contain meshes are removed from the user bone tree
|
||||
Transform ancestorBone = modelBone;
|
||||
string previousBoneName = "";
|
||||
// find the name of the root child bone that this mesh is underneath
|
||||
while (ancestorBone != null) {
|
||||
if (ancestorBone.parent == null) {
|
||||
break;
|
||||
}
|
||||
previousBoneName = ancestorBone.name;
|
||||
ancestorBone = ancestorBone.parent;
|
||||
}
|
||||
// remove the bone tree node from root's children for the root child bone that has mesh children
|
||||
if (!string.IsNullOrEmpty(previousBoneName)) {
|
||||
foreach (BoneTreeNode rootChild in userBoneTree.children) {
|
||||
if (rootChild.boneName == previousBoneName) {
|
||||
userBoneTree.children.Remove(rootChild);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!light && !camera) {
|
||||
// if it is in fact a bone, add it to the bone tree as well as user bone infos list with position and parent name
|
||||
UserBoneInformation userBoneInfo = new UserBoneInformation();
|
||||
userBoneInfo.position = modelBone.position; // bone's absolute position
|
||||
|
||||
string boneName = modelBone.name;
|
||||
if (modelBone.parent == null) {
|
||||
// if no parent then this is actual root bone node of the user avatar, so consider it's parent as "root"
|
||||
boneName = GetRootBoneName(); // ensure we use the root bone name from the skeleton list for consistency
|
||||
userBoneTree = new BoneTreeNode(boneName); // initialize root of tree
|
||||
userBoneInfo.parentName = "root";
|
||||
userBoneInfo.boneTreeNode = userBoneTree;
|
||||
boneTreeNode.boneName = boneName;
|
||||
boneTreeNode.parentName = "root";
|
||||
} else {
|
||||
// otherwise add this bone node as a child to it's parent's children list
|
||||
// if its a child of the root bone, use the root bone name from the skeleton list as the parent for consistency
|
||||
string parentName = modelBone.parent.parent == null ? GetRootBoneName() : modelBone.parent.name;
|
||||
BoneTreeNode boneTreeNode = new BoneTreeNode(boneName);
|
||||
userBoneInfos[parentName].boneTreeNode.children.Add(boneTreeNode);
|
||||
userBoneInfo.parentName = parentName;
|
||||
BoneTreeNode node = new BoneTreeNode(boneName, parentName);
|
||||
boneTreeNode.children.Add(node);
|
||||
boneTreeNode = node;
|
||||
}
|
||||
|
||||
Vector3 bonePosition = modelBone.position; // bone's absolute position in avatar space
|
||||
UserBoneInformation userBoneInfo = new UserBoneInformation(boneTreeNode.parentName, boneTreeNode, bonePosition);
|
||||
userBoneInfos.Add(boneName, userBoneInfo);
|
||||
}
|
||||
|
||||
// recurse over transform node's children
|
||||
for (int i = 0; i < modelBone.childCount; ++i) {
|
||||
TraverseUserBoneTree(modelBone.GetChild(i));
|
||||
TraverseUserBoneTree(modelBone.GetChild(i), boneTreeNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -840,7 +873,7 @@ class AvatarExporter : MonoBehaviour {
|
|||
return "";
|
||||
}
|
||||
|
||||
static void SetFailedAvatarRules() {
|
||||
static void SetFailedAvatarRules(Bounds avatarBounds, float avatarHeight) {
|
||||
failedAvatarRules.Clear();
|
||||
|
||||
string hipsUserBone = "";
|
||||
|
@ -905,18 +938,29 @@ class AvatarExporter : MonoBehaviour {
|
|||
break;
|
||||
case AvatarRule.ChestMapped:
|
||||
if (!humanoidToUserBoneMappings.TryGetValue("Chest", out chestUserBone)) {
|
||||
// check to see if there is a child of Spine that we can suggest to be mapped to Chest
|
||||
string spineChild = "";
|
||||
// check to see if there is an unmapped child of Spine that we can suggest to be mapped to Chest
|
||||
string chestMappingCandidate = "";
|
||||
if (!string.IsNullOrEmpty(spineUserBone)) {
|
||||
BoneTreeNode spineTreeNode = userBoneInfos[spineUserBone].boneTreeNode;
|
||||
if (spineTreeNode.children.Count == 1) {
|
||||
spineChild = spineTreeNode.children[0].boneName;
|
||||
foreach (BoneTreeNode spineChildTreeNode in spineTreeNode.children) {
|
||||
string spineChildBone = spineChildTreeNode.boneName;
|
||||
if (userBoneInfos[spineChildBone].HasHumanMapping()) {
|
||||
continue;
|
||||
}
|
||||
// a suitable candidate for Chest should have Neck/Head or Shoulder mappings in its descendants
|
||||
if (IsHumanBoneInHierarchy(spineChildTreeNode, "Neck") ||
|
||||
IsHumanBoneInHierarchy(spineChildTreeNode, "Head") ||
|
||||
IsHumanBoneInHierarchy(spineChildTreeNode, "LeftShoulder") ||
|
||||
IsHumanBoneInHierarchy(spineChildTreeNode, "RightShoulder")) {
|
||||
chestMappingCandidate = spineChildBone;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
failedAvatarRules.Add(avatarRule, "There is no Chest bone mapped in Humanoid for the selected avatar.");
|
||||
// if the only found child of Spine is not yet mapped then add it as a suggestion for Chest mapping
|
||||
if (!string.IsNullOrEmpty(spineChild) && !userBoneInfos[spineChild].HasHumanMapping()) {
|
||||
failedAvatarRules[avatarRule] += " It is suggested that you map bone " + spineChild +
|
||||
if (!string.IsNullOrEmpty(chestMappingCandidate)) {
|
||||
failedAvatarRules[avatarRule] += " It is suggested that you map bone " + chestMappingCandidate +
|
||||
" to Chest in Humanoid.";
|
||||
}
|
||||
}
|
||||
|
@ -949,15 +993,34 @@ class AvatarExporter : MonoBehaviour {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case AvatarRule.HipsNotOnGround:
|
||||
// ensure the absolute Y position for the bone mapped to Hips (if its mapped) is at least HIPS_GROUND_MIN_Y
|
||||
case AvatarRule.HipsNotAtBottom:
|
||||
// ensure that Hips is not below a proportional percentage of the avatar's height in avatar space
|
||||
if (!string.IsNullOrEmpty(hipsUserBone)) {
|
||||
UserBoneInformation hipsBoneInfo = userBoneInfos[hipsUserBone];
|
||||
hipsPosition = hipsBoneInfo.position;
|
||||
if (hipsPosition.y < HIPS_GROUND_MIN_Y) {
|
||||
failedAvatarRules.Add(avatarRule, "The bone mapped to Hips in Humanoid (" + hipsUserBone +
|
||||
") should not be at ground level.");
|
||||
|
||||
// find the lowest y position of the bones
|
||||
float minBoneYPosition = float.MaxValue;
|
||||
foreach (var userBoneInfo in userBoneInfos) {
|
||||
Vector3 position = userBoneInfo.Value.position;
|
||||
if (position.y < minBoneYPosition) {
|
||||
minBoneYPosition = position.y;
|
||||
}
|
||||
}
|
||||
|
||||
// check that Hips is within a percentage of avatar's height from the lowest Y point of the avatar
|
||||
float bottomYRange = HIPS_MIN_Y_PERCENT_OF_HEIGHT * avatarHeight;
|
||||
if (Mathf.Abs(hipsPosition.y - minBoneYPosition) < bottomYRange) {
|
||||
failedAvatarRules.Add(avatarRule, "The bone mapped to Hips in Humanoid (" + hipsUserBone +
|
||||
") should not be at the bottom of the selected avatar.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AvatarRule.ExtentsNotBelowGround:
|
||||
// ensure the minimum Y extent of the model's bounds is not below a proportional threshold of avatar's height
|
||||
float belowGroundThreshold = BELOW_GROUND_THRESHOLD_PERCENT_OF_HEIGHT * avatarHeight;
|
||||
if (avatarBounds.min.y < belowGroundThreshold) {
|
||||
failedAvatarRules.Add(avatarRule, "The bottom extents of the selected avatar go below ground level.");
|
||||
}
|
||||
break;
|
||||
case AvatarRule.HipsSpineChestNotCoincident:
|
||||
|
@ -989,6 +1052,23 @@ class AvatarExporter : MonoBehaviour {
|
|||
}
|
||||
}
|
||||
|
||||
static bool IsHumanBoneInHierarchy(BoneTreeNode boneTreeNode, string humanBoneName) {
|
||||
UserBoneInformation userBoneInfo;
|
||||
if (userBoneInfos.TryGetValue(boneTreeNode.boneName, out userBoneInfo) && userBoneInfo.humanName == humanBoneName) {
|
||||
// this bone matches the human bone name being searched for
|
||||
return true;
|
||||
}
|
||||
|
||||
// recursively check downward through children bones for target human bone
|
||||
foreach (BoneTreeNode childNode in boneTreeNode.children) {
|
||||
if (IsHumanBoneInHierarchy(childNode, humanBoneName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static string CheckHumanBoneMappingRule(AvatarRule avatarRule, string humanBoneName) {
|
||||
string userBoneName = "";
|
||||
// avatar rule fails if bone is not mapped in Humanoid
|
||||
|
@ -999,8 +1079,8 @@ class AvatarExporter : MonoBehaviour {
|
|||
return userBoneName;
|
||||
}
|
||||
|
||||
static void CheckUserBoneDescendantOfHumanRule(AvatarRule avatarRule, string userBoneName, string descendantOfHumanName) {
|
||||
if (string.IsNullOrEmpty(userBoneName)) {
|
||||
static void CheckUserBoneDescendantOfHumanRule(AvatarRule avatarRule, string descendantUserBoneName, string descendantOfHumanName) {
|
||||
if (string.IsNullOrEmpty(descendantUserBoneName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1009,27 +1089,26 @@ class AvatarExporter : MonoBehaviour {
|
|||
return;
|
||||
}
|
||||
|
||||
string userBone = userBoneName;
|
||||
string ancestorUserBone = "";
|
||||
UserBoneInformation userBoneInfo = new UserBoneInformation();
|
||||
string userBoneName = descendantUserBoneName;
|
||||
UserBoneInformation userBoneInfo = userBoneInfos[userBoneName];
|
||||
string descendantHumanName = userBoneInfo.humanName;
|
||||
// iterate upward from user bone through user bone info parent names until root
|
||||
// is reached or the ancestor bone name matches the target descendant of name
|
||||
while (ancestorUserBone != "root") {
|
||||
if (userBoneInfos.TryGetValue(userBone, out userBoneInfo)) {
|
||||
ancestorUserBone = userBoneInfo.parentName;
|
||||
if (ancestorUserBone == descendantOfUserBoneName) {
|
||||
return;
|
||||
}
|
||||
userBone = ancestorUserBone;
|
||||
while (userBoneName != "root") {
|
||||
if (userBoneName == descendantOfUserBoneName) {
|
||||
return;
|
||||
}
|
||||
if (userBoneInfos.TryGetValue(userBoneName, out userBoneInfo)) {
|
||||
userBoneName = userBoneInfo.parentName;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// avatar rule fails if no ancestor of given user bone matched the descendant of name (no early return)
|
||||
failedAvatarRules.Add(avatarRule, "The bone mapped to " + userBoneInfo.humanName + " in Humanoid (" + userBoneName +
|
||||
") is not a child of the bone mapped to " + descendantOfHumanName + " in Humanoid (" +
|
||||
descendantOfUserBoneName + ").");
|
||||
failedAvatarRules.Add(avatarRule, "The bone mapped to " + descendantHumanName + " in Humanoid (" +
|
||||
descendantUserBoneName + ") is not a descendant of the bone mapped to " +
|
||||
descendantOfHumanName + " in Humanoid (" + descendantOfUserBoneName + ").");
|
||||
}
|
||||
|
||||
static void CheckAsymmetricalMappingRule(AvatarRule avatarRule, string[] mappingSuffixes, string appendage) {
|
||||
|
@ -1296,9 +1375,8 @@ class ExportProjectWindow : EditorWindow {
|
|||
const float MAX_SCALE_SLIDER = 2.0f;
|
||||
const int SLIDER_SCALE_EXPONENT = 10;
|
||||
const float ACTUAL_SCALE_OFFSET = 1.0f;
|
||||
const float DEFAULT_AVATAR_HEIGHT = 1.755f;
|
||||
const float MAXIMUM_RECOMMENDED_HEIGHT = DEFAULT_AVATAR_HEIGHT * 1.5f;
|
||||
const float MINIMUM_RECOMMENDED_HEIGHT = DEFAULT_AVATAR_HEIGHT * 0.25f;
|
||||
const float MAXIMUM_RECOMMENDED_HEIGHT = AvatarUtilities.DEFAULT_AVATAR_HEIGHT * 1.5f;
|
||||
const float MINIMUM_RECOMMENDED_HEIGHT = AvatarUtilities.DEFAULT_AVATAR_HEIGHT * 0.25f;
|
||||
const float SLIDER_DIFFERENCE_REMOVE_TEXT = 0.01f;
|
||||
readonly Color COLOR_YELLOW = Color.yellow; //new Color(0.9176f, 0.8274f, 0.0f);
|
||||
readonly Color COLOR_BACKGROUND = new Color(0.5f, 0.5f, 0.5f);
|
||||
|
@ -1339,9 +1417,9 @@ class ExportProjectWindow : EditorWindow {
|
|||
ShowUtility();
|
||||
|
||||
// if the avatar's starting height is outside of the recommended ranges, auto-adjust the scale to default height
|
||||
float height = GetAvatarHeight();
|
||||
float height = AvatarUtilities.GetAvatarHeight(avatarPreviewObject);
|
||||
if (height < MINIMUM_RECOMMENDED_HEIGHT || height > MAXIMUM_RECOMMENDED_HEIGHT) {
|
||||
float newScale = DEFAULT_AVATAR_HEIGHT / height;
|
||||
float newScale = AvatarUtilities.DEFAULT_AVATAR_HEIGHT / height;
|
||||
SetAvatarScale(newScale);
|
||||
scaleWarningText = "Avatar's scale automatically adjusted to be within the recommended range.";
|
||||
}
|
||||
|
@ -1524,7 +1602,7 @@ class ExportProjectWindow : EditorWindow {
|
|||
|
||||
void UpdateScaleWarning() {
|
||||
// called on any scale changes
|
||||
float height = GetAvatarHeight();
|
||||
float height = AvatarUtilities.GetAvatarHeight(avatarPreviewObject);
|
||||
if (height < MINIMUM_RECOMMENDED_HEIGHT) {
|
||||
scaleWarningText = "The height of the avatar is below the recommended minimum.";
|
||||
} else if (height > MAXIMUM_RECOMMENDED_HEIGHT) {
|
||||
|
@ -1535,23 +1613,6 @@ class ExportProjectWindow : EditorWindow {
|
|||
}
|
||||
}
|
||||
|
||||
float GetAvatarHeight() {
|
||||
// height of an avatar model can be determined to be the max Y extents of the combined bounds for all its mesh renderers
|
||||
if (avatarPreviewObject != null) {
|
||||
Bounds bounds = new Bounds();
|
||||
var meshRenderers = avatarPreviewObject.GetComponentsInChildren<MeshRenderer>();
|
||||
var skinnedMeshRenderers = avatarPreviewObject.GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||
foreach (var renderer in meshRenderers) {
|
||||
bounds.Encapsulate(renderer.bounds);
|
||||
}
|
||||
foreach (var renderer in skinnedMeshRenderers) {
|
||||
bounds.Encapsulate(renderer.bounds);
|
||||
}
|
||||
return bounds.max.y;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void SetAvatarScale(float actualScale) {
|
||||
// set the new scale uniformly on the preview avatar's transform to show the resulting avatar size
|
||||
avatarPreviewObject.transform.localScale = new Vector3(actualScale, actualScale, actualScale);
|
||||
|
@ -1571,3 +1632,28 @@ class ExportProjectWindow : EditorWindow {
|
|||
onCloseCallback();
|
||||
}
|
||||
}
|
||||
|
||||
class AvatarUtilities {
|
||||
public const float DEFAULT_AVATAR_HEIGHT = 1.755f;
|
||||
|
||||
public static Bounds GetAvatarBounds(GameObject avatarObject) {
|
||||
Bounds bounds = new Bounds();
|
||||
if (avatarObject != null) {
|
||||
var meshRenderers = avatarObject.GetComponentsInChildren<MeshRenderer>();
|
||||
var skinnedMeshRenderers = avatarObject.GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||
foreach (var renderer in meshRenderers) {
|
||||
bounds.Encapsulate(renderer.bounds);
|
||||
}
|
||||
foreach (var renderer in skinnedMeshRenderers) {
|
||||
bounds.Encapsulate(renderer.bounds);
|
||||
}
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public static float GetAvatarHeight(GameObject avatarObject) {
|
||||
// height of an avatar model can be determined to be the max Y extents of the combined bounds for all its mesh renderers
|
||||
Bounds avatarBounds = GetAvatarBounds(avatarObject);
|
||||
return avatarBounds.max.y - avatarBounds.min.y;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
High Fidelity, Inc.
|
||||
Avatar Exporter
|
||||
Version 0.4.0
|
||||
Version 0.4.1
|
||||
|
||||
Note: It is recommended to use Unity versions between 2017.4.15f1 and 2018.2.12f1 for this Avatar Exporter.
|
||||
|
||||
|
|