mirror of
https://github.com/overte-org/overte.git
synced 2025-04-16 05:48:39 +02:00
merge from upstream
This commit is contained in:
commit
ca128a3251
102 changed files with 2845 additions and 2096 deletions
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -17,6 +17,15 @@ Makefile
|
|||
local.properties
|
||||
android/libraries
|
||||
|
||||
# VSCode
|
||||
# List taken from Github Global Ignores master@435c4d92
|
||||
# https://github.com/github/gitignore/commits/master/Global/VisualStudioCode.gitignore
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# Xcode
|
||||
*.xcodeproj
|
||||
*.xcworkspace
|
||||
|
|
609
interface/resources/html/commerce/backup_instructions.html
Normal file
609
interface/resources/html/commerce/backup_instructions.html
Normal file
|
@ -0,0 +1,609 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
|
||||
body
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #333;
|
||||
background-color: #eee;
|
||||
font: 300 16px/22px "Lato", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
background: rgba(74,219,255,1);
|
||||
background: -moz-linear-gradient(-45deg, rgba(74,219,255,1) 0%, rgba(61,171,255,1) 41%, rgba(54,124,209,1) 100%);
|
||||
background: -webkit-gradient(left top, right bottom, color-stop(0%, rgba(74,219,255,1)), color-stop(41%, rgba(61,171,255,1)), color-stop(100%, rgba(54,124,209,1)));
|
||||
background: -webkit-linear-gradient(-45deg, rgba(74,219,255,1) 0%, rgba(61,171,255,1) 41%, rgba(54,124,209,1) 100%);
|
||||
background: -o-linear-gradient(-45deg, rgba(74,219,255,1) 0%, rgba(61,171,255,1) 41%, rgba(54,124,209,1) 100%);
|
||||
background: -ms-linear-gradient(-45deg, rgba(74,219,255,1) 0%, rgba(61,171,255,1) 41%, rgba(54,124,209,1) 100%);
|
||||
background: linear-gradient(135deg, rgba(74,219,255,1) 0%, rgba(61,171,255,1) 41%, rgba(54,124,209,1) 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#4adbff', endColorstr='#367cd1', GradientType=1 );
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6
|
||||
{
|
||||
margin: 0 0 .5em;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
h1 { font-size: 2.25em; } /* 36px */
|
||||
h2 { font-size: 1.75em; } /* 28px */
|
||||
h3 { font-size: 1.375em; } /* 22px */
|
||||
h4 { font-size: 1.125em; } /* 18px */
|
||||
h5 { font-size: 1em; } /* 16px */
|
||||
h6 { font-size: .875em; } /* 14px */
|
||||
|
||||
p
|
||||
{
|
||||
margin: 0 0 1.5em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
blockquote
|
||||
{
|
||||
padding: 1em 2em;
|
||||
margin: 0 0 2em;
|
||||
border-left: 5px solid #eee;
|
||||
}
|
||||
|
||||
hr
|
||||
{
|
||||
height: 0;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 2em;
|
||||
border: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
background-color: transparent;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th, td
|
||||
{
|
||||
padding: .5em 1em;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
a:link { color: #0093C5; }
|
||||
a:visited { color: #0093C5; }
|
||||
a:focus { color: black; }
|
||||
a:hover { color: #00B4EF; }
|
||||
a:active { color: #00B4EF; }
|
||||
|
||||
/* -----------------------
|
||||
Layout styles
|
||||
------------------------*/
|
||||
|
||||
.container
|
||||
{
|
||||
max-width: 50em;
|
||||
margin: 0 auto;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.header
|
||||
{
|
||||
color: #fff;
|
||||
background: #333;
|
||||
padding: 1em 1.25em;
|
||||
}
|
||||
|
||||
.header-heading { margin: 0; }
|
||||
|
||||
.nav-bar
|
||||
{
|
||||
background: #000;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.content { padding: 1em 1.25em; }
|
||||
|
||||
.footer
|
||||
{
|
||||
color: #fff;
|
||||
background: #000;
|
||||
|
||||
}
|
||||
|
||||
.alert
|
||||
{
|
||||
padding: 1em 1.25em;
|
||||
border-radius: 2px;
|
||||
border-width: thin;
|
||||
border-color: #ccc;
|
||||
background: #eee;
|
||||
}
|
||||
/* -----------------------
|
||||
Nav
|
||||
------------------------*/
|
||||
|
||||
.nav
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav li
|
||||
{
|
||||
display: inline;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nav a
|
||||
{
|
||||
display: block;
|
||||
padding: .7em 1.25em;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid gray;
|
||||
}
|
||||
|
||||
.nav a:link { color: white; }
|
||||
.nav a:visited { color: white; }
|
||||
|
||||
.nav a:focus
|
||||
{
|
||||
color: black;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.nav a:hover
|
||||
{
|
||||
color: white;
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.nav a:active
|
||||
{
|
||||
color: white;
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
/* -----------------------
|
||||
Single styles
|
||||
------------------------*/
|
||||
|
||||
.img-responsive { max-width: 100%; }
|
||||
|
||||
.btn
|
||||
{
|
||||
color: #fff !important;
|
||||
background-color: royalblue;
|
||||
border-color: #222;
|
||||
display: inline-block;
|
||||
padding: .5em 1em;
|
||||
margin-bottom: 0;
|
||||
font-weight: 400;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
border-radius: .2em;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn:hover
|
||||
{
|
||||
color: #fff !important;
|
||||
background-color: #0093C5;
|
||||
}
|
||||
|
||||
.btn:focus
|
||||
{
|
||||
color: #fff !important;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.btn:active
|
||||
{
|
||||
color: #fff !important;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.table
|
||||
{
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.list-unstyled
|
||||
{
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.list-inline
|
||||
{
|
||||
padding-left: 0;
|
||||
margin-left: -5px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.list-inline > li
|
||||
{
|
||||
display: inline-block;
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -----------------------
|
||||
Wide styles
|
||||
------------------------*/
|
||||
|
||||
@media (min-width: 42em)
|
||||
{
|
||||
.header { padding: 1.5em 3em; }
|
||||
.nav-bar { padding: 1em 3em; }
|
||||
.content { padding: 2em 3em; }
|
||||
.footer { padding: 2em 3em; }
|
||||
|
||||
.nav li
|
||||
{
|
||||
display: inline;
|
||||
margin: 0 1em 0 0;
|
||||
}
|
||||
|
||||
.nav a
|
||||
{
|
||||
display: inline;
|
||||
padding: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<title>Backing Up Your Private Keys | High Fidelity</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 1200 95" style="enable-background:new 0 0 1200 95;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st15{fill:#10bcff;}
|
||||
.st16{fill:#939598;}
|
||||
</style>
|
||||
<g id="Layer_1_1_">
|
||||
<path class="st15" d="M144,35.8v29.2h-6.3V52.3h-10.3v12.8h-6.3V35.8h6.3v11.3h10.3V35.8H144z"/>
|
||||
<path class="st15" d="M155.1,65.1h-6.3V35.8h6.3V65.1z"/>
|
||||
<path class="st15" d="M173.2,40.5c-1.5,0-2.7,0.1-3.8,0.4c-1,0.3-1.8,0.8-2.5,1.4c-0.6,0.6-1.1,1.6-1.4,2.7s-0.4,2.5-0.4,4.2v2.7
|
||||
c0,1.8,0.1,3.2,0.4,4.3c0.2,1.1,0.6,2,1.2,2.6c0.5,0.6,1.3,1.1,2.2,1.3c0.9,0.2,2,0.4,3.3,0.4c0.4,0,0.8,0,1.2-0.1
|
||||
c0.4,0,0.8-0.1,1.3-0.1v-7.9h-3.7l0.6-4.8h9v16.7c-1.1,0.4-2.5,0.7-4.3,0.9c-1.7,0.2-3.4,0.4-5.2,0.4c-2.2,0-4.1-0.3-5.7-0.8
|
||||
c-1.6-0.5-2.8-1.4-3.8-2.5c-1-1.1-1.7-2.5-2.2-4.2c-0.5-1.7-0.6-3.7-0.6-5.9v-3c0-2.1,0.2-3.9,0.6-5.6c0.5-1.7,1.2-3.1,2.3-4.3
|
||||
c1.1-1.2,2.5-2.1,4.2-2.8c1.7-0.6,3.9-1,6.5-1c1.4,0,2.8,0.1,4.2,0.4c1.4,0.2,2.5,0.5,3.4,0.8l-1,4.7c-0.8-0.2-1.7-0.4-2.6-0.6
|
||||
C175.5,40.5,174.5,40.5,173.2,40.5z"/>
|
||||
<path class="st15" d="M208.8,35.8v29.2h-6.3V52.3h-10.3v12.8H186V35.8h6.3v11.3h10.3V35.8H208.8z"/>
|
||||
<path class="st15" d="M242.2,35.8l-0.7,5.1h-10.9V47h10.1l-0.7,5.1h-9.4v13h-6.3V35.8H242.2z"/>
|
||||
<path class="st15" d="M252.3,65.1h-6.3V35.8h6.3V65.1z"/>
|
||||
<path class="st15" d="M257.4,35.8h9.6c2.5,0,4.5,0.4,6.2,1s3,1.6,4,2.7c1,1.2,1.7,2.5,2.1,4.2c0.4,1.7,0.6,3.4,0.6,5.3v2.8
|
||||
c0,1.9-0.2,3.7-0.6,5.4c-0.4,1.7-1.1,3-2.1,4.2c-1,1.2-2.3,2.1-4,2.7c-1.7,0.6-3.7,1-6.2,1h-9.5L257.4,35.8L257.4,35.8z M263.6,60
|
||||
h2.7c1.2,0,2.2-0.1,3.1-0.4c0.9-0.3,1.7-0.8,2.2-1.4s1-1.5,1.3-2.6c0.3-1.1,0.4-2.4,0.4-4.1v-2.2c0-1.7-0.1-3-0.4-4.1
|
||||
c-0.3-1.1-0.7-1.9-1.3-2.6s-1.3-1.1-2.2-1.4c-0.9-0.2-1.9-0.4-3.1-0.4h-2.7V60z"/>
|
||||
<path class="st15" d="M302,35.8l-0.6,4.9h-11.3v6.4h10.6l-0.6,4.9h-10v8.2h11.9l-0.6,4.9h-17.6V35.8H302z"/>
|
||||
<path class="st15" d="M312.4,35.8V60h11.9l-0.7,5.1h-17.4V35.8H312.4z"/>
|
||||
<path class="st15" d="M334.6,65.1h-6.3V35.8h6.3V65.1z"/>
|
||||
<path class="st15" d="M361.6,35.8l-0.7,5.1H353v24.2h-6.3V40.9h-8.6l0.7-5.1C338.8,35.8,361.6,35.8,361.6,35.8z"/>
|
||||
<path class="st15" d="M376.5,47.2l6.1-11.4h6.4l-9.6,16.5v12.8h-6.3V52.3l-9.5-16.5h6.9L376.5,47.2z"/>
|
||||
<g>
|
||||
<path class="st15" d="M58.8,92c-5.9,0-11.7-1.2-17.1-3.4c-5.3-2.2-9.9-5.4-13.9-9.4c-4-4-7.2-8.7-9.4-13.9C16,59.7,14.8,54,14.8,48
|
||||
c0-5.9,1.2-11.7,3.4-17.1c2.2-5.3,5.4-9.9,9.4-13.9s8.7-7.2,13.9-9.4C47,5.3,52.7,4.2,58.7,4.2s11.7,1.2,17.1,3.4
|
||||
C81,9.8,85.7,13,89.7,17s7.2,8.7,9.4,13.9c2.3,5.4,3.4,11.2,3.4,17.1s-1.2,11.7-3.4,17.1c-2.2,5.3-5.4,9.9-9.4,13.9
|
||||
c-4,4-8.7,7.2-13.9,9.4C70.5,90.8,64.7,92,58.8,92z M58.8,8.7C37.1,8.7,19.4,26.4,19.4,48s17.7,39.4,39.4,39.4S98.1,69.7,98.1,48
|
||||
S80.5,8.7,58.8,8.7z"/>
|
||||
<path class="st15" d="M72.2,66.7V35.9c1.9-0.6,3.3-2.5,3.3-4.6c0-2.7-2.2-4.8-4.8-4.8c-2.7,0-4.8,2.2-4.8,4.8
|
||||
c0,2.1,1.2,3.8,3.1,4.5v14.4l-20.1-9.3V29.5c1.9-0.6,3.3-2.5,3.3-4.6c0-2.7-2.2-4.8-4.8-4.8c-2.7,0-4.8,2.2-4.8,4.8
|
||||
c0,2.1,1.2,3.8,3.1,4.5v31c-1.8,0.7-3.1,2.5-3.1,4.5c0,2.7,2.2,4.8,4.8,4.8c2.7,0,4.8-2.2,4.8-4.8c0-2.1-1.4-4-3.3-4.6V44.7
|
||||
l20.1,9.3v12.7c-1.8,0.7-3.1,2.5-3.1,4.5c0,2.7,2.2,4.8,4.8,4.8c2.7,0,4.8-2.2,4.8-4.8C75.5,69.1,74.1,67.4,72.2,66.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st16" d="M418.8,34h2.6v38.6h-2.6V34z"/>
|
||||
<path class="st16" d="M471.1,35.3v29.9h-2.7V50.8h-15.6v14.4h-2.7V35.3h2.7v13h15.6v-13H471.1z"/>
|
||||
<path class="st16" d="M480.1,55.4c0,1.5,0.2,2.7,0.4,3.8c0.3,1,0.7,1.9,1.3,2.5c0.6,0.7,1.5,1.1,2.5,1.4s2.4,0.4,4,0.4
|
||||
c0.9,0,1.8-0.1,2.8-0.2c1-0.1,1.8-0.3,2.5-0.4l-0.3,2.1c-0.6,0.2-1.5,0.4-2.5,0.5c-1,0.1-2,0.2-3,0.2c-1.9,0-3.5-0.2-4.8-0.7
|
||||
c-1.3-0.4-2.4-1.1-3.2-1.9c-0.8-0.9-1.4-1.9-1.7-3.2c-0.4-1.3-0.5-2.8-0.5-4.5v-1.6c0-1.6,0.2-3,0.5-4.3c0.3-1.3,0.9-2.4,1.6-3.3
|
||||
c0.7-0.9,1.7-1.6,2.8-2.1c1.1-0.5,2.5-0.7,4.2-0.7c1.4,0,2.7,0.2,3.7,0.7c1,0.4,1.9,1,2.6,1.8c0.7,0.8,1.2,1.7,1.5,2.7
|
||||
c0.3,1,0.5,2.2,0.5,3.5v1.2c0,0.8-0.1,1.4-0.4,1.8c-0.2,0.3-0.8,0.5-1.6,0.5H480.1z M486.5,45.4c-1.1,0-2,0.1-2.8,0.4
|
||||
c-0.8,0.3-1.5,0.7-2,1.4s-0.9,1.4-1.2,2.5c-0.3,1-0.4,2.3-0.4,3.7h12.3v-1.5c0-2.2-0.5-3.8-1.4-4.9C490.1,46,488.6,45.4,486.5,45.4z
|
||||
"/>
|
||||
<path class="st16" d="M500.8,34h2.6v31.2h-2.6V34z"/>
|
||||
<path class="st16" d="M528.3,55.5c0,1.8-0.2,3.3-0.7,4.6c-0.4,1.3-1.1,2.3-1.9,3.2c-0.8,0.8-1.8,1.4-2.9,1.8
|
||||
c-1.1,0.4-2.4,0.6-3.7,0.6c-0.7,0-1.3,0-1.8-0.1c-0.5-0.1-1.1-0.1-1.6-0.3c-0.5-0.1-1-0.3-1.5-0.5c-0.5-0.2-1-0.4-1.6-0.7V75h-2.6
|
||||
V43.7h2.2l0.3,2.9c1.5-2.3,4-3.4,7.4-3.4c1.2,0,2.4,0.2,3.4,0.5c1,0.4,1.9,1,2.6,1.8c0.7,0.8,1.3,1.9,1.7,3.2
|
||||
c0.4,1.3,0.6,2.9,0.6,4.8V55.5z M525.7,54.1c0-1.3-0.1-2.5-0.3-3.6c-0.2-1.1-0.5-2-1-2.7c-0.5-0.7-1.1-1.3-2-1.7
|
||||
c-0.8-0.4-1.8-0.6-3.1-0.6c-1.3,0-2.3,0.2-3.2,0.5c-0.9,0.3-1.5,0.8-2.1,1.4c-0.5,0.6-0.9,1.4-1.1,2.3c-0.2,0.9-0.3,2-0.3,3.2v9
|
||||
c1,0.5,1.9,0.9,2.8,1.2c0.9,0.2,2,0.4,3.2,0.4c1.3,0,2.4-0.2,3.3-0.5c0.9-0.3,1.6-0.9,2.1-1.6c0.5-0.7,0.9-1.6,1.2-2.6
|
||||
c0.2-1.1,0.4-2.3,0.4-3.6V54.1z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="main">
|
||||
|
||||
<h1>Backing Up Your Private Keys</h1>
|
||||
<hr>
|
||||
|
||||
<!-- Paragraphs -->
|
||||
<h3>What are private keys?</h3>
|
||||
<p>A private key is a secret piece of text that is used to prove ownership, unlock confidential information and sign transactions.</p>
|
||||
<p>In High Fidelity, your private keys are used to securely access the contents of your Wallet and Purchases.</p>
|
||||
|
||||
<hr>
|
||||
<h3>Where are my private keys stored?"</h3>
|
||||
<p>By default, your private keys are only stored on your hard drive in High Fidelity Interface's <code>AppData</code> directory.</p>
|
||||
<p>Here is the file path of your hifikey - you can browse to it using your file explorer.</p>
|
||||
<div class="alert"> <code>HIFIKEY_PATH_REPLACEME</code> </div>
|
||||
|
||||
<hr>
|
||||
<h3>How should I make a backup of my private keys?</h3>
|
||||
<p>You should backup your <code>.hifikey</code> file above by copying it to a USB flash drive, or to a service like Dropbox or Google Drive. Restore your backup by replacing the file in Interface's AppData directory with your backed-up copy.</p>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 497.3 186.1" style="enable-background:new 0 0 497.3 186.1;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#CECECE;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
.st2{fill:#FEFEFE;}
|
||||
.st3{fill:#0DA860;}
|
||||
.st4{fill:#F9C942;}
|
||||
.st5{fill:#367CF3;}
|
||||
.st6{fill:#2D6FDC;}
|
||||
.st7{fill:#E4B83D;}
|
||||
.st8{fill:#08137C;}
|
||||
.st9{fill:#EF3B4E;}
|
||||
.st10{fill:#B8355B;}
|
||||
.st11{fill:#A7C5D1;}
|
||||
.st12{fill:#7C909B;}
|
||||
.st13{fill:#CBF2FD;}
|
||||
.st14{fill:#000222;}
|
||||
</style>
|
||||
<circle class="st0" cx="255" cy="69.5" r="61.1"/>
|
||||
<circle class="st0" cx="88" cy="69.5" r="61.1"/>
|
||||
<circle class="st1" cx="88" cy="65.5" r="61.1"/>
|
||||
<path class="st2" d="M133.4,78c0-0.1-0.1-0.2-0.1-0.3c-5-8.7-10-17.4-15-26c-4.7-8.2-9.4-16.3-14.1-24.5c-0.2-0.3-0.4-0.4-0.7-0.4
|
||||
c-10.2,0-20.4,0-30.6,0c-0.2,0-0.3,0-0.5,0c-0.1,0.1-0.2,0.2-0.2,0.3c-9.7,16.8-19.4,33.6-29.1,50.5c-0.2,0.3-0.2,0.5,0,0.8
|
||||
c4.2,7.2,8.4,14.5,12.6,21.7c1,1.7,2,3.5,3,5.2c0.1,0.1,0.3,0.1,0.5,0.1c19.4,0,38.8,0,58.2,0c0.4,0,0.6-0.1,0.8-0.4
|
||||
c4.3-7.4,8.6-14.9,12.9-22.3C131.6,81.1,132.5,79.6,133.4,78z"/>
|
||||
<path class="st3" d="M58.5,105.3c-1-1.7-2-3.4-3-5.2c-4.2-7.2-8.4-14.5-12.6-21.7c-0.2-0.3-0.2-0.5,0-0.8
|
||||
C52.6,60.8,62.3,43.9,72,27.1c0.1-0.1,0.1-0.2,0.2-0.3c0.1,0.1,0.2,0.2,0.2,0.4c5.1,8.9,10.3,17.8,15.4,26.6
|
||||
c0.1,0.1,0.2,0.2,0.2,0.4c-0.1,0.1-0.2,0.2-0.2,0.3c-3.2,5.5-6.4,11-9.6,16.5c-1.3,2.3-2.6,4.6-4,6.9c-0.1,0.1-0.2,0.2-0.2,0.3
|
||||
c-1.9,3.3-3.8,6.6-5.7,9.9c-2.7,4.7-5.5,9.4-8.2,14.2c-0.5,0.9-1.1,1.8-1.5,2.7c0,0,0,0,0,0c0,0.1-0.1,0.1-0.1,0.2
|
||||
C58.6,105.2,58.5,105.3,58.5,105.3z"/>
|
||||
<path class="st4" d="M88.1,54.2c0-0.2-0.1-0.3-0.2-0.4C82.8,44.9,77.6,36,72.5,27.2c-0.1-0.1-0.2-0.2-0.2-0.4c0.2-0.1,0.3,0,0.5,0
|
||||
c10.2,0,20.4,0,30.6,0c0.3,0,0.5,0.1,0.7,0.4c4.7,8.2,9.4,16.3,14.1,24.5c5,8.7,10,17.4,15,26c0.1,0.1,0.1,0.2,0.1,0.3
|
||||
c-0.1,0-0.1,0-0.2,0c0-0.1-0.1-0.1-0.2-0.1c-3.6-1.1-7.2-2.2-10.7-3.3c-2.5-0.8-4.9-1.5-7.4-2.3c-4.2-1.3-8.4-2.6-12.6-3.9
|
||||
c-2.3-0.7-4.6-1.4-6.8-2.1c-0.1,0-0.3-0.1-0.4,0c0,0-0.1-0.1-0.1-0.1c-1.6-2.7-3.1-5.4-4.7-8.1C89.6,56.8,88.8,55.5,88.1,54.2z"/>
|
||||
<path class="st5" d="M133.2,78c0.1,0,0.1,0,0.2,0c-0.9,1.5-1.8,3.1-2.6,4.6c-4.3,7.4-8.6,14.8-12.9,22.3c-0.2,0.3-0.4,0.4-0.8,0.4
|
||||
c-19.4,0-38.8,0-58.2,0c-0.2,0-0.3,0.1-0.5-0.1c0,0,0.1-0.1,0.1-0.1c0.1,0,0.1-0.1,0.1-0.2c0,0,0,0,0,0c0.3-0.1,0.5-0.3,0.8-0.5
|
||||
c1.1-1,2.3-2.1,3.4-3.2c1.6-1.5,3.2-3,4.8-4.5c1.1-1.1,2.3-2.1,3.4-3.2c1.6-1.5,3.3-3,4.9-4.5c1.2-1.1,2.3-2.1,3.5-3.2
|
||||
c1.8-1.7,3.6-3.4,5.4-5c0.8-0.8,1.7-1.5,2.5-2.4c0.2-0.2,0.5-0.2,0.5-0.5c1.5,0,3,0,4.5,0c3.1,0,6.2,0,9.3,0
|
||||
c0.2,0.1,0.3,0.1,0.5,0.1c10.1,0,20.3,0,30.4,0C132.9,78,133.1,78,133.2,78z"/>
|
||||
<path class="st2" d="M101.8,78c-3.1,0-6.2,0-9.3,0c-1.5,0-3,0-4.5,0c-0.2,0-0.4,0-0.5,0c-3.9,0-7.8,0-11.7,0c-0.5,0-0.9,0-1.4,0
|
||||
c1.3-2.3,2.6-4.6,4-6.9c3.2-5.5,6.4-11,9.6-16.5c0.1-0.1,0.1-0.2,0.2-0.3c0.8,1.3,1.5,2.6,2.3,3.9c1.6,2.7,3.1,5.4,4.7,8.1
|
||||
c0,0,0.1,0.1,0.1,0.1c1.2,2,2.3,4,3.5,6C99.6,74.2,100.7,76.1,101.8,78z"/>
|
||||
<path class="st6" d="M74.3,78c0.5,0,0.9,0,1.4,0c3.9,0,7.8,0,11.7,0c0.2,0,0.4,0,0.5,0c-0.1,0.3-0.3,0.4-0.5,0.5
|
||||
c-0.8,0.8-1.7,1.6-2.5,2.4c-1.8,1.7-3.6,3.4-5.4,5c-1.2,1.1-2.3,2.1-3.5,3.2c-1.6,1.5-3.2,3-4.9,4.5c-1.2,1.1-2.3,2.1-3.4,3.2
|
||||
c-1.6,1.5-3.2,3-4.8,4.5c-1.1,1.1-2.3,2.1-3.4,3.2c-0.2,0.2-0.4,0.4-0.8,0.5c0.4-0.9,1-1.8,1.5-2.7c2.7-4.7,5.4-9.4,8.2-14.2
|
||||
c1.9-3.3,3.8-6.6,5.7-9.9C74.2,78.1,74.2,78.1,74.3,78z"/>
|
||||
<path class="st6" d="M58.7,105c0,0.1,0,0.2-0.1,0.2C58.6,105.1,58.7,105.1,58.7,105z"/>
|
||||
<path class="st7" d="M101.8,78c-1.1-1.9-2.2-3.8-3.3-5.7c-1.1-2-2.3-4-3.5-6c0.1-0.2,0.3-0.1,0.4,0c2.3,0.7,4.6,1.4,6.8,2.1
|
||||
c4.2,1.3,8.4,2.6,12.6,3.9c2.5,0.8,4.9,1.5,7.4,2.3c3.6,1.1,7.2,2.2,10.7,3.3c0.1,0,0.2,0,0.2,0.1c-0.2,0-0.3,0-0.5,0
|
||||
c-10.1,0-20.3,0-30.4,0C102.1,78,101.9,78.1,101.8,78z"/>
|
||||
<g>
|
||||
<path class="st1" d="M315.5,65.6c0.1-33.6-27.3-60.9-61-61c-33.6-0.1-61,27.2-61,60.9c-0.1,33.6,27.2,61,61,61.1
|
||||
C288.1,126.6,315.5,99.3,315.5,65.6z"/>
|
||||
<path class="st1" d="M315.5,65.6c-0.1,33.7-27.4,61.1-61,61c-33.7-0.1-61-27.4-61-61.1c0.1-33.7,27.4-61,61-60.9
|
||||
C288.3,4.6,315.6,31.9,315.5,65.6z M297.6,45.8c-0.1-0.1-0.2-0.1-0.3-0.2c-7-4.4-14-8.9-20.9-13.4c-0.3-0.2-0.4-0.1-0.7,0
|
||||
c-6.9,4.4-13.9,8.8-20.8,13.3c-0.4,0.3-0.4,0.3,0,0.5c6.9,4.4,13.8,8.8,20.7,13.2c0.1,0.1,0.3,0.2,0.4,0.3
|
||||
c-7.2,4.6-14.3,9.1-21.5,13.7c0.2,0.1,0.3,0.2,0.5,0.3c6.9,4.4,13.8,8.8,20.7,13.2c0.3,0.2,0.5,0.2,0.8,0c6.7-4.3,13.3-8.5,20-12.7
|
||||
c0.4-0.2,0.8-0.5,1.2-0.8c-7.2-4.6-14.4-9.1-21.6-13.7C283.2,55,290.4,50.4,297.6,45.8z M254.5,73.3c-7.2-4.6-14.4-9.2-21.6-13.7
|
||||
c0.2-0.1,0.4-0.2,0.5-0.3c6.9-4.4,13.7-8.7,20.6-13.1c0.4-0.3,0.4-0.3,0-0.6c-6.9-4.4-13.8-8.8-20.7-13.2c-0.3-0.2-0.5-0.2-0.8,0
|
||||
c-6.9,4.4-13.8,8.8-20.7,13.2c-0.4,0.3-0.4,0.3,0,0.6c5.3,3.4,10.6,6.8,15.9,10.1c1.7,1.1,3.4,2.2,5.2,3.3
|
||||
c-7.2,4.6-14.4,9.1-21.6,13.7c0.2,0.1,0.3,0.2,0.5,0.3c6.9,4.4,13.8,8.8,20.7,13.2c0.3,0.2,0.5,0.2,0.8,0
|
||||
c5.1-3.3,10.2-6.5,15.4-9.8C250.6,75.8,252.5,74.5,254.5,73.3z M275.9,91.6c-0.1-0.1-0.2-0.2-0.3-0.2c-6.9-4.4-13.9-8.8-20.8-13.3
|
||||
c-0.2-0.2-0.4-0.2-0.7,0c-6.9,4.4-13.9,8.9-20.8,13.3c-0.1,0.1-0.2,0.2-0.4,0.3c0.2,0.1,0.3,0.2,0.4,0.3
|
||||
c6.9,4.4,13.9,8.8,20.8,13.3c0.3,0.2,0.5,0.1,0.7,0c6.9-4.4,13.8-8.8,20.7-13.2C275.7,91.8,275.8,91.7,275.9,91.6z"/>
|
||||
<path class="st8" d="M297.6,45.8c-7.2,4.6-14.4,9.1-21.6,13.7c7.2,4.6,14.4,9.1,21.6,13.7c-0.4,0.3-0.8,0.5-1.2,0.8
|
||||
c-6.7,4.2-13.3,8.5-20,12.7c-0.3,0.2-0.5,0.2-0.8,0c-6.9-4.4-13.8-8.8-20.7-13.2c-0.1-0.1-0.3-0.2-0.5-0.3
|
||||
c7.2-4.6,14.3-9.1,21.5-13.7c-0.2-0.1-0.3-0.2-0.4-0.3c-6.9-4.4-13.8-8.8-20.7-13.2c-0.4-0.3-0.4-0.3,0-0.5
|
||||
c6.9-4.4,13.9-8.8,20.8-13.3c0.2-0.2,0.4-0.2,0.7,0c7,4.5,14,8.9,20.9,13.4C297.4,45.7,297.4,45.7,297.6,45.8z"/>
|
||||
<path class="st8" d="M254.5,73.3c-2,1.3-3.9,2.5-5.8,3.7c-5.1,3.3-10.3,6.5-15.4,9.8c-0.3,0.2-0.5,0.2-0.8,0
|
||||
c-6.9-4.4-13.8-8.8-20.7-13.2c-0.1-0.1-0.3-0.2-0.5-0.3c7.2-4.6,14.3-9.1,21.6-13.7c-1.8-1.1-3.5-2.2-5.2-3.3
|
||||
c-5.3-3.4-10.6-6.8-15.9-10.1c-0.4-0.3-0.4-0.3,0-0.6c6.9-4.4,13.8-8.8,20.7-13.2c0.3-0.2,0.5-0.2,0.8,0
|
||||
c6.9,4.4,13.8,8.8,20.7,13.2c0.4,0.3,0.4,0.3,0,0.6c-6.9,4.4-13.7,8.7-20.6,13.1c-0.2,0.1-0.3,0.2-0.5,0.3
|
||||
C240.1,64.1,247.2,68.7,254.5,73.3z"/>
|
||||
<path class="st8" d="M275.9,91.6c-0.1,0.2-0.3,0.2-0.4,0.3c-6.9,4.4-13.8,8.8-20.7,13.2c-0.2,0.2-0.4,0.2-0.7,0
|
||||
c-6.9-4.4-13.9-8.9-20.8-13.3c-0.1-0.1-0.2-0.1-0.4-0.3c0.1-0.1,0.3-0.2,0.4-0.3c6.9-4.4,13.9-8.8,20.8-13.3c0.3-0.2,0.4-0.1,0.7,0
|
||||
c6.9,4.4,13.9,8.9,20.8,13.3C275.7,91.4,275.8,91.5,275.9,91.6z"/>
|
||||
</g>
|
||||
<path class="st9" d="M389.9,117c-6.8-6.8-13.7-13.6-20.5-20.5c-1.9-2-1.8-5.6,0.1-7.7c0.2-0.3,0.5-0.5,0.8-0.8
|
||||
c15.9-15.9,31.8-31.7,47.6-47.6c2.6-2.6,5.9-1.9,7.8-0.1c0.3,0.3,0.6,0.6,0.9,0.9c6.2,6.2,12.5,12.5,18.7,18.7
|
||||
c0.3,0.3,0.6,0.6,0.9,1c0.1,0.3,0.3,0.6,0.4,0.8c0.8,1.7,0.4,4-0.9,5.2c-16.4,16.3-32.7,32.7-49.1,49c-0.2,0.2-0.4,0.4-0.7,0.6
|
||||
C394,117.8,392,117.9,389.9,117z M423.3,62.2c-2,0.5-3.9,1-5.8,1.6c-1.6,0.4-1.6,0.4-0.4,1.6c0.4,0.4,0.5,0.7,0,1.1
|
||||
c-5,5-9.9,9.9-14.9,14.9c-0.1,0.1-0.3,0.4-0.5,0.2c-0.1-0.1-0.1-0.3-0.1-0.5c0-1.5-0.1-2.9-0.1-4.4c0-0.6,0.2-1.1,0.7-1.6
|
||||
c1.2-1.2,2.4-2.4,3.6-3.6c0.3-0.3,0.6-0.5,1.2-0.4c1.7,0.2,3.2-1.2,3.2-2.9c0-1.9-1.4-3.2-3.2-3.1c-1.8,0.1-3.1,1.6-2.8,3.4
|
||||
c0.1,0.4-0.1,0.7-0.4,1c-1.2,1.1-2.3,2.3-3.5,3.4c-1.2,1.1-1.7,2.4-1.6,4c0.1,2.2,0.1,4.5,0.1,6.7c0,1.3-1,2-1.7,2.7
|
||||
c-0.5,0.5-1,0-1.5-0.1c-2.2-0.5-4.4,0.7-5.3,2.7c-0.9,2.2-0.1,4.5,1.8,5.7c1.8,1.1,3.8,0.9,5.6-0.5c1.2-1,1.8-3.1,1.2-4.9
|
||||
c-0.2-0.6-0.1-1,0.3-1.4c1.7-1.6,3.3-3.3,4.9-4.9c0.5-0.5,1-0.7,1.6-0.7c2.1,0,4.2,0,6.3,0.2c1.7,0.1,3.3-0.3,4.5-1.6
|
||||
c0.4-0.5,0.9-0.9,1.4-1.4c0.5-0.6,0.9-0.6,1.3,0c0.3,0.4,0.6,0.5,1,0c1.1-1.1,2.2-2.2,3.3-3.3c0.4-0.4,0.4-0.6,0-1
|
||||
c-1.1-1.1-2.2-2.2-3.3-3.3c-0.4-0.4-0.7-0.3-1,0.1c-1,1-2,2.1-3.1,3.1c-0.5,0.5-0.7,0.8,0,1.3c0.3,0.2,0.6,0.5,0.2,0.9
|
||||
c-0.6,0.6-1.3,1.3-1.9,1.9c-0.4,0.3-0.9,0.6-1.5,0.5c-1.5-0.2-2.9-0.1-4.4-0.1c-0.2,0-0.5,0.1-0.6-0.1c0-0.1,0-0.1,0-0.2
|
||||
c3.7-3.7,7.4-7.4,11.1-11.1c0.4-0.4,0.6-0.2,0.9,0.1c1.3,1.2,1.3,1.1,1.7-0.5C422.3,66,422.8,64.1,423.3,62.2z"/>
|
||||
<path class="st10" d="M389.9,117c2.1,0.9,4.1,0.9,6-0.4c0.3-0.2,0.5-0.4,0.7-0.6c16.4-16.3,32.7-32.7,49.1-49
|
||||
c1.3-1.3,1.7-3.5,0.9-5.2c-0.1-0.3-0.2-0.6-0.4-0.8c1.4,1.4,2.7,2.7,4.1,4.1c0.6,0.6,1.3,1.2,1.8,1.9c1.7,2.2,1.5,4.8-0.5,6.8
|
||||
c-7.8,7.8-15.7,15.7-23.5,23.5c-8.3,8.3-16.5,16.5-24.8,24.8c-1,1-2.1,1.6-3.4,1.9c-1.8,0.3-3.4-0.1-4.7-1.4
|
||||
C393.5,120.5,391.7,118.8,389.9,117z"/>
|
||||
<path class="st11" d="M445.3,59.9c-6.2-6.2-12.5-12.5-18.7-18.7c5-5,10.1-10,15.1-15.1c0.6-0.6,0.8-0.6,1.4,0c6,6,12,12,18,18
|
||||
C455.9,49.4,450.6,54.7,445.3,59.9z M439.3,37.5c-0.5-0.5-0.9-1-1.4-1.4c-0.5-0.5-1.1-0.5-1.6,0c-0.4,0.4-0.8,0.8-1.2,1.2
|
||||
c-0.5,0.6-0.5,1.1,0,1.7c0.5,0.6,1.1,1.1,1.7,1.7c2,2.2,2,1.7,3.9-0.1c0,0,0,0,0.1-0.1c0.5-0.5,0.5-1.1,0-1.6
|
||||
C440.3,38.4,439.8,38,439.3,37.5z M449,47.2c-0.5-0.5-1-1-1.5-1.5c-0.7-0.6-1.1-0.5-2.5,1c-0.8,0.8-0.9,1.3-0.3,1.9
|
||||
c0.9,1,1.9,1.9,2.9,2.9c0.7,0.6,1.1,0.5,2.5-1c0.8-0.8,0.9-1.3,0.3-1.9C449.9,48.1,449.5,47.6,449,47.2z"/>
|
||||
<path class="st12" d="M445.3,59.9c5.3-5.3,10.5-10.5,15.8-15.8c1.5,1.5,3,3,4.5,4.4c0.5,0.5,0.4,0.7,0,1.1
|
||||
c-4.9,4.8-9.7,9.7-14.6,14.5c-0.2,0.2-0.5,0.5-0.7,0.7c-1.4-1.4-2.7-2.7-4.1-4.1C445.9,60.6,445.6,60.2,445.3,59.9z"/>
|
||||
<path class="st1" d="M423.3,62.2c-0.5,2-1,3.8-1.5,5.6c-0.5,1.7-0.5,1.7-1.7,0.5c-0.3-0.3-0.6-0.4-0.9-0.1
|
||||
c-3.7,3.7-7.4,7.4-11.1,11.1c0,0,0,0.1,0,0.2c0.2,0.2,0.4,0.1,0.6,0.1c1.5,0.1,2.9-0.1,4.4,0.1c0.6,0.1,1.1-0.2,1.5-0.5
|
||||
c0.7-0.6,1.3-1.2,1.9-1.9c0.4-0.4,0.1-0.7-0.2-0.9c-0.6-0.5-0.5-0.8,0-1.3c1.1-1,2.1-2,3.1-3.1c0.4-0.4,0.6-0.5,1-0.1
|
||||
c1.1,1.1,2.2,2.2,3.3,3.3c0.4,0.4,0.4,0.6,0,1c-1.1,1.1-2.2,2.2-3.3,3.3c-0.4,0.4-0.7,0.4-1,0c-0.5-0.6-0.9-0.6-1.3,0
|
||||
c-0.4,0.5-0.9,0.9-1.4,1.4c-1.2,1.4-2.7,1.7-4.5,1.6c-2.1-0.1-4.2-0.1-6.3-0.2c-0.6,0-1.2,0.3-1.6,0.7c-1.6,1.7-3.3,3.3-4.9,4.9
|
||||
c-0.4,0.4-0.6,0.8-0.3,1.4c0.6,1.7,0,3.9-1.2,4.9c-1.8,1.4-3.8,1.6-5.6,0.5c-2-1.2-2.7-3.6-1.8-5.7c0.8-2.1,3.1-3.2,5.3-2.7
|
||||
c0.5,0.1,1,0.6,1.5,0.1c0.8-0.8,1.8-1.4,1.7-2.7c-0.1-2.2-0.1-4.5-0.1-6.7c0-1.6,0.5-2.9,1.6-4c1.2-1.1,2.3-2.3,3.5-3.4
|
||||
c0.3-0.3,0.4-0.6,0.4-1c-0.2-1.8,1.1-3.3,2.8-3.4c1.8-0.1,3.2,1.3,3.2,3.1c0,1.7-1.5,3.1-3.2,2.9c-0.5-0.1-0.8,0.1-1.2,0.4
|
||||
c-1.2,1.2-2.4,2.4-3.6,3.6c-0.5,0.4-0.7,0.9-0.7,1.6c0,1.5,0.1,2.9,0.1,4.4c0,0.2,0,0.4,0.1,0.5c0.2,0.1,0.3-0.1,0.5-0.2
|
||||
c5-5,9.9-9.9,14.9-14.9c0.4-0.4,0.4-0.7,0-1.1c-1.1-1.2-1.1-1.2,0.4-1.6C419.4,63.2,421.3,62.7,423.3,62.2z"/>
|
||||
<path class="st13" d="M439.3,37.5c0.5,0.5,0.9,0.9,1.4,1.4c0.5,0.5,0.5,1,0,1.6c0,0,0,0-0.1,0.1c-1.9,1.9-1.9,2.3-3.9,0.1
|
||||
c-0.5-0.6-1.1-1.1-1.7-1.7c-0.6-0.6-0.6-1.1,0-1.7c0.4-0.4,0.8-0.8,1.2-1.2c0.5-0.5,1.1-0.5,1.6,0C438.4,36.6,438.9,37.1,439.3,37.5
|
||||
z"/>
|
||||
<path class="st13" d="M449,47.2c0.5,0.5,0.9,0.9,1.4,1.4c0.6,0.6,0.5,1.1-0.3,1.9c-1.4,1.5-1.8,1.6-2.5,1c-1-0.9-1.9-1.9-2.9-2.9
|
||||
c-0.6-0.6-0.5-1.1,0.3-1.9c1.4-1.5,1.8-1.6,2.5-1C448,46.2,448.5,46.7,449,47.2z"/>
|
||||
<g>
|
||||
<path class="st14" d="M32.1,158.8l0.2-1.2h4.2v7.7c-0.2,0.1-0.5,0.2-0.8,0.3c-0.3,0.1-0.7,0.2-1,0.2c-0.4,0.1-0.7,0.1-1.1,0.1
|
||||
s-0.7,0-1,0c-1.4,0-2.6-0.2-3.5-0.5c-0.9-0.4-1.5-0.8-2-1.5c-0.5-0.6-0.8-1.4-0.9-2.3c-0.1-0.9-0.2-1.9-0.2-2.9v-1.6
|
||||
c0-1.2,0.1-2.2,0.3-3.1c0.2-0.9,0.6-1.7,1.1-2.3s1.2-1.1,2.1-1.4c0.9-0.3,2-0.5,3.3-0.5c0.6,0,1.2,0.1,1.8,0.2
|
||||
c0.6,0.1,1.1,0.2,1.6,0.4l-0.3,1.1c-0.4-0.1-0.9-0.2-1.4-0.3c-0.5-0.1-1.1-0.1-1.7-0.1c-1,0-1.8,0.1-2.4,0.3s-1.2,0.5-1.6,1
|
||||
c-0.4,0.5-0.7,1.1-0.9,1.9s-0.3,1.8-0.3,3v1.5c0,1.2,0.1,2.1,0.3,2.9c0.2,0.8,0.5,1.4,0.9,1.8c0.4,0.5,0.9,0.8,1.6,1
|
||||
c0.7,0.2,1.5,0.3,2.4,0.3c0.5,0,0.9,0,1.4-0.1c0.4,0,0.8-0.1,1.2-0.2v-5.6H32.1z"/>
|
||||
<path class="st14" d="M44.5,154.2c1,0,1.7,0.1,2.4,0.4c0.6,0.2,1.1,0.6,1.5,1.1c0.4,0.5,0.6,1,0.8,1.7c0.2,0.7,0.2,1.4,0.2,2.2v1.2
|
||||
c0,0.8-0.1,1.5-0.3,2.2c-0.2,0.7-0.5,1.2-0.8,1.7c-0.4,0.5-0.9,0.8-1.5,1.1c-0.6,0.2-1.4,0.4-2.3,0.4c-1,0-1.7-0.1-2.4-0.4
|
||||
c-0.6-0.2-1.1-0.6-1.5-1.1s-0.6-1-0.8-1.7c-0.2-0.7-0.2-1.4-0.2-2.2v-1.2c0-0.8,0.1-1.5,0.3-2.2c0.2-0.7,0.5-1.2,0.9-1.7
|
||||
s0.9-0.8,1.5-1.1C42.8,154.3,43.6,154.2,44.5,154.2z M44.5,164.8c0.7,0,1.2-0.1,1.7-0.2s0.8-0.4,1.1-0.7c0.3-0.3,0.5-0.8,0.6-1.3
|
||||
c0.1-0.5,0.2-1.2,0.2-1.9v-1c0-0.8-0.1-1.4-0.2-2s-0.3-1-0.6-1.3c-0.3-0.3-0.6-0.6-1.1-0.7s-1-0.2-1.6-0.2c-0.7,0-1.2,0.1-1.7,0.2
|
||||
c-0.5,0.2-0.8,0.4-1.1,0.7c-0.3,0.3-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,1.9v1c0,0.8,0.1,1.4,0.2,1.9c0.1,0.5,0.3,1,0.6,1.3
|
||||
c0.3,0.3,0.6,0.6,1.1,0.7C43.2,164.7,43.8,164.8,44.5,164.8z"/>
|
||||
<path class="st14" d="M57.1,154.2c1,0,1.7,0.1,2.4,0.4c0.6,0.2,1.1,0.6,1.5,1.1c0.4,0.5,0.6,1,0.8,1.7c0.2,0.7,0.2,1.4,0.2,2.2v1.2
|
||||
c0,0.8-0.1,1.5-0.3,2.2c-0.2,0.7-0.5,1.2-0.8,1.7c-0.4,0.5-0.9,0.8-1.5,1.1c-0.6,0.2-1.4,0.4-2.3,0.4c-1,0-1.7-0.1-2.4-0.4
|
||||
c-0.6-0.2-1.1-0.6-1.5-1.1s-0.6-1-0.8-1.7c-0.2-0.7-0.2-1.4-0.2-2.2v-1.2c0-0.8,0.1-1.5,0.3-2.2c0.2-0.7,0.5-1.2,0.9-1.7
|
||||
s0.9-0.8,1.5-1.1C55.4,154.3,56.2,154.2,57.1,154.2z M57.1,164.8c0.7,0,1.2-0.1,1.7-0.2s0.8-0.4,1.1-0.7c0.3-0.3,0.5-0.8,0.6-1.3
|
||||
c0.1-0.5,0.2-1.2,0.2-1.9v-1c0-0.8-0.1-1.4-0.2-2s-0.3-1-0.6-1.3c-0.3-0.3-0.6-0.6-1.1-0.7s-1-0.2-1.6-0.2c-0.7,0-1.2,0.1-1.7,0.2
|
||||
c-0.5,0.2-0.8,0.4-1.1,0.7c-0.3,0.3-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,1.9v1c0,0.8,0.1,1.4,0.2,1.9c0.1,0.5,0.3,1,0.6,1.3
|
||||
c0.3,0.3,0.6,0.6,1.1,0.7C55.9,164.7,56.4,164.8,57.1,164.8z"/>
|
||||
<path class="st14" d="M74.3,165.5c0,0.8-0.1,1.6-0.3,2.3c-0.2,0.7-0.5,1.2-0.9,1.7c-0.4,0.5-0.9,0.8-1.6,1.1
|
||||
c-0.6,0.2-1.4,0.4-2.3,0.4c-1.3,0-2.7-0.2-4-0.6l0.3-1.1c0.6,0.2,1.2,0.3,1.8,0.4c0.6,0.1,1.2,0.1,1.9,0.1s1.3-0.1,1.8-0.3
|
||||
c0.5-0.2,0.8-0.5,1.1-0.9c0.3-0.4,0.5-0.9,0.6-1.4c0.1-0.6,0.2-1.2,0.2-1.9v-1.3c-0.1,0.2-0.3,0.5-0.5,0.7
|
||||
c-0.2,0.2-0.5,0.4-0.8,0.6c-0.3,0.2-0.7,0.3-1.1,0.4c-0.4,0.1-0.9,0.1-1.5,0.1c-0.6,0-1.2-0.1-1.8-0.3c-0.5-0.2-1-0.5-1.4-0.9
|
||||
c-0.4-0.4-0.7-1-0.9-1.6c-0.2-0.7-0.3-1.5-0.3-2.5v-0.7c0-0.9,0.1-1.7,0.4-2.4s0.6-1.2,1.1-1.7c0.5-0.5,1-0.8,1.6-1
|
||||
c0.6-0.2,1.3-0.3,2.1-0.3c0.8,0,1.6,0.1,2.3,0.3c0.7,0.2,1.4,0.4,2,0.8V165.5z M66.1,160.1c0,0.7,0.1,1.3,0.2,1.9s0.3,1,0.5,1.4
|
||||
c0.3,0.4,0.6,0.7,1,0.8s0.9,0.3,1.6,0.3c1.2,0,2.1-0.3,2.7-0.9c0.6-0.6,0.9-1.6,0.9-3V156c-0.4-0.2-0.8-0.4-1.3-0.5
|
||||
c-0.4-0.1-1-0.2-1.6-0.2c-1.3,0-2.3,0.3-3,1s-1,1.8-1,3.4V160.1z"/>
|
||||
<path class="st14" d="M77.8,149.3h1.3v16.3h-1.3V149.3z"/>
|
||||
<path class="st14" d="M83.6,160.5c0,0.8,0.1,1.4,0.2,2c0.1,0.5,0.4,1,0.7,1.3c0.3,0.3,0.8,0.6,1.3,0.7c0.5,0.2,1.2,0.2,2.1,0.2
|
||||
c0.5,0,0.9,0,1.5-0.1c0.5-0.1,1-0.1,1.3-0.2l-0.2,1.1c-0.3,0.1-0.8,0.2-1.3,0.3c-0.5,0.1-1.1,0.1-1.6,0.1c-1,0-1.8-0.1-2.5-0.3
|
||||
c-0.7-0.2-1.2-0.6-1.7-1s-0.7-1-0.9-1.7c-0.2-0.7-0.3-1.5-0.3-2.4v-0.9c0-0.8,0.1-1.6,0.3-2.3c0.2-0.7,0.5-1.3,0.8-1.7
|
||||
c0.4-0.5,0.9-0.9,1.5-1.1c0.6-0.3,1.3-0.4,2.2-0.4c0.7,0,1.4,0.1,1.9,0.3c0.5,0.2,1,0.5,1.3,0.9s0.6,0.9,0.8,1.4
|
||||
c0.2,0.5,0.2,1.2,0.2,1.8v0.6c0,0.4-0.1,0.7-0.2,0.9c-0.1,0.2-0.4,0.3-0.8,0.3H83.6z M86.9,155.3c-0.6,0-1,0.1-1.5,0.2
|
||||
s-0.8,0.4-1,0.7c-0.3,0.3-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,2h6.5v-0.8c0-1.1-0.2-2-0.7-2.6S88,155.3,86.9,155.3z"/>
|
||||
<path class="st14" d="M100.2,150h4.9c1.3,0,2.3,0.2,3.1,0.5c0.8,0.3,1.5,0.8,2,1.4c0.5,0.6,0.8,1.3,1,2.2c0.2,0.8,0.3,1.7,0.3,2.7
|
||||
v2c0,1-0.1,1.9-0.3,2.8c-0.2,0.8-0.6,1.6-1.1,2.2c-0.5,0.6-1.1,1.1-2,1.4s-1.8,0.5-3.1,0.5h-4.8V150z M101.6,164.5h3.3
|
||||
c0.8,0,1.5-0.1,2.2-0.3c0.6-0.2,1.2-0.5,1.6-0.9c0.4-0.4,0.8-1,1-1.8c0.2-0.7,0.3-1.6,0.3-2.8V157c0-1.1-0.1-2-0.3-2.7
|
||||
c-0.2-0.7-0.5-1.3-0.9-1.8c-0.4-0.4-0.9-0.8-1.6-1c-0.6-0.2-1.4-0.3-2.2-0.3h-3.4V164.5z"/>
|
||||
<path class="st14" d="M120.7,155.6c-0.2,0-0.4-0.1-0.7-0.1c-0.2,0-0.4,0-0.6,0c-1.1,0-1.9,0.3-2.4,1c-0.5,0.7-0.8,1.7-0.8,3.2v6.1
|
||||
h-1.4v-11.2h1.1l0.2,1.8c0.7-1.3,1.9-1.9,3.5-1.9c0.2,0,0.5,0,0.7,0.1c0.2,0,0.4,0.1,0.6,0.1L120.7,155.6z"/>
|
||||
<path class="st14" d="M123.8,150.1c0.7,0,1,0.3,1,1c0,0.6-0.3,1-1,1c-0.6,0-1-0.3-1-1C122.9,150.4,123.2,150.1,123.8,150.1z
|
||||
M123.2,154.4h1.4v11.2h-1.4V154.4z"/>
|
||||
<path class="st14" d="M127.1,154.4h1.5l3.8,9.9l3.8-9.9h1.5l-4.5,11.2h-1.5L127.1,154.4z"/>
|
||||
<path class="st14" d="M140.6,160.5c0,0.8,0.1,1.4,0.2,2c0.1,0.5,0.4,1,0.7,1.3c0.3,0.3,0.8,0.6,1.3,0.7c0.5,0.2,1.2,0.2,2.1,0.2
|
||||
c0.5,0,0.9,0,1.5-0.1c0.5-0.1,1-0.1,1.3-0.2l-0.2,1.1c-0.3,0.1-0.8,0.2-1.3,0.3c-0.5,0.1-1.1,0.1-1.6,0.1c-1,0-1.8-0.1-2.5-0.3
|
||||
c-0.7-0.2-1.2-0.6-1.7-1s-0.7-1-0.9-1.7c-0.2-0.7-0.3-1.5-0.3-2.4v-0.9c0-0.8,0.1-1.6,0.3-2.3c0.2-0.7,0.5-1.3,0.8-1.7
|
||||
c0.4-0.5,0.9-0.9,1.5-1.1c0.6-0.3,1.3-0.4,2.2-0.4c0.7,0,1.4,0.1,1.9,0.3c0.5,0.2,1,0.5,1.3,0.9s0.6,0.9,0.8,1.4
|
||||
c0.2,0.5,0.2,1.2,0.2,1.8v0.6c0,0.4-0.1,0.7-0.2,0.9c-0.1,0.2-0.4,0.3-0.8,0.3H140.6z M143.9,155.3c-0.6,0-1,0.1-1.5,0.2
|
||||
s-0.8,0.4-1,0.7c-0.3,0.3-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,2h6.5v-0.8c0-1.1-0.2-2-0.7-2.6S145,155.3,143.9,155.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st14" d="M217.3,150h4.9c1.3,0,2.3,0.2,3.1,0.5c0.8,0.3,1.5,0.8,2,1.4c0.5,0.6,0.8,1.3,1,2.2c0.2,0.8,0.3,1.7,0.3,2.7
|
||||
v2c0,1-0.1,1.9-0.3,2.8c-0.2,0.8-0.6,1.6-1.1,2.2c-0.5,0.6-1.1,1.1-2,1.4s-1.8,0.5-3.1,0.5h-4.8V150z M218.8,164.5h3.3
|
||||
c0.8,0,1.5-0.1,2.2-0.3c0.6-0.2,1.2-0.5,1.6-0.9c0.4-0.4,0.8-1,1-1.8c0.2-0.7,0.3-1.6,0.3-2.8V157c0-1.1-0.1-2-0.3-2.7
|
||||
c-0.2-0.7-0.5-1.3-0.9-1.8c-0.4-0.4-0.9-0.8-1.6-1c-0.6-0.2-1.4-0.3-2.2-0.3h-3.4V164.5z"/>
|
||||
<path class="st14" d="M237.9,155.6c-0.2,0-0.4-0.1-0.7-0.1c-0.2,0-0.4,0-0.6,0c-1.1,0-1.9,0.3-2.4,1c-0.5,0.7-0.8,1.7-0.8,3.2v6.1
|
||||
H232v-11.2h1.1l0.2,1.8c0.7-1.3,1.9-1.9,3.5-1.9c0.2,0,0.5,0,0.7,0.1c0.2,0,0.4,0.1,0.6,0.1L237.9,155.6z"/>
|
||||
<path class="st14" d="M244.3,154.2c1,0,1.7,0.1,2.4,0.4c0.6,0.2,1.1,0.6,1.5,1.1c0.4,0.5,0.6,1,0.8,1.7c0.2,0.7,0.2,1.4,0.2,2.2
|
||||
v1.2c0,0.8-0.1,1.5-0.3,2.2c-0.2,0.7-0.5,1.2-0.8,1.7c-0.4,0.5-0.9,0.8-1.5,1.1c-0.6,0.2-1.4,0.4-2.3,0.4c-1,0-1.7-0.1-2.4-0.4
|
||||
c-0.6-0.2-1.1-0.6-1.5-1.1s-0.6-1-0.8-1.7c-0.2-0.7-0.2-1.4-0.2-2.2v-1.2c0-0.8,0.1-1.5,0.3-2.2c0.2-0.7,0.5-1.2,0.9-1.7
|
||||
s0.9-0.8,1.5-1.1C242.7,154.3,243.4,154.2,244.3,154.2z M244.3,164.8c0.7,0,1.2-0.1,1.7-0.2s0.8-0.4,1.1-0.7
|
||||
c0.3-0.3,0.5-0.8,0.6-1.3c0.1-0.5,0.2-1.2,0.2-1.9v-1c0-0.8-0.1-1.4-0.2-2s-0.3-1-0.6-1.3c-0.3-0.3-0.6-0.6-1.1-0.7s-1-0.2-1.6-0.2
|
||||
c-0.7,0-1.2,0.1-1.7,0.2c-0.5,0.2-0.8,0.4-1.1,0.7c-0.3,0.3-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,1.9v1c0,0.8,0.1,1.4,0.2,1.9
|
||||
c0.1,0.5,0.3,1,0.6,1.3c0.3,0.3,0.6,0.6,1.1,0.7C243.1,164.7,243.7,164.8,244.3,164.8z"/>
|
||||
<path class="st14" d="M261.9,160.6c0,0.9-0.1,1.7-0.4,2.4c-0.2,0.7-0.6,1.2-1,1.7s-0.9,0.8-1.5,1s-1.2,0.3-1.9,0.3
|
||||
c-0.4,0-0.7,0-1,0c-0.3,0-0.6-0.1-0.8-0.1c-0.3-0.1-0.5-0.2-0.8-0.3c-0.3-0.1-0.5-0.2-0.8-0.4v5.7h-1.3v-16.3h1.1l0.2,1.5
|
||||
c0.8-1.2,2.1-1.8,3.9-1.8c0.6,0,1.2,0.1,1.8,0.3c0.5,0.2,1,0.5,1.4,0.9c0.4,0.4,0.7,1,0.9,1.7c0.2,0.7,0.3,1.5,0.3,2.5V160.6z
|
||||
M260.5,159.9c0-0.7,0-1.3-0.1-1.9s-0.3-1-0.5-1.4c-0.3-0.4-0.6-0.7-1-0.9c-0.4-0.2-1-0.3-1.6-0.3c-0.7,0-1.2,0.1-1.7,0.3
|
||||
c-0.4,0.2-0.8,0.4-1.1,0.7s-0.5,0.7-0.6,1.2c-0.1,0.5-0.2,1-0.2,1.7v4.7c0.5,0.3,1,0.5,1.5,0.6c0.5,0.1,1,0.2,1.7,0.2
|
||||
c0.7,0,1.3-0.1,1.7-0.3s0.8-0.5,1.1-0.8c0.3-0.4,0.5-0.8,0.6-1.4s0.2-1.2,0.2-1.9V159.9z"/>
|
||||
<path class="st14" d="M269.4,165.9c-0.7,0-1.5-0.1-2.2-0.3c-0.7-0.2-1.4-0.5-2.1-0.8v-15.5h1.3v6.6c0.4-0.6,0.9-1.1,1.5-1.3
|
||||
c0.6-0.3,1.3-0.4,2.2-0.4c0.7,0,1.3,0.1,1.8,0.3c0.6,0.2,1,0.5,1.4,0.9s0.7,1,0.9,1.6c0.2,0.7,0.3,1.5,0.3,2.5v1
|
||||
c0,1.8-0.4,3.2-1.3,4.1C272.4,165.5,271.1,165.9,269.4,165.9z M269.3,164.8c0.7,0,1.3-0.1,1.8-0.3c0.5-0.2,0.9-0.4,1.2-0.8
|
||||
c0.3-0.4,0.5-0.8,0.7-1.4c0.1-0.6,0.2-1.2,0.2-2v-0.5c0-0.7-0.1-1.3-0.2-1.9c-0.1-0.6-0.3-1-0.5-1.4s-0.6-0.7-1-0.9
|
||||
c-0.4-0.2-1-0.3-1.6-0.3c-0.5,0-1,0.1-1.4,0.2s-0.8,0.4-1.1,0.7c-0.3,0.3-0.5,0.7-0.7,1.2c-0.2,0.5-0.3,1.1-0.3,1.8v4.9
|
||||
c0.4,0.2,0.9,0.4,1.3,0.5C268.2,164.7,268.7,164.8,269.3,164.8z"/>
|
||||
<path class="st14" d="M282.3,154.2c1,0,1.7,0.1,2.4,0.4c0.6,0.2,1.1,0.6,1.5,1.1c0.4,0.5,0.6,1,0.8,1.7c0.2,0.7,0.2,1.4,0.2,2.2
|
||||
v1.2c0,0.8-0.1,1.5-0.3,2.2c-0.2,0.7-0.5,1.2-0.8,1.7c-0.4,0.5-0.9,0.8-1.5,1.1c-0.6,0.2-1.4,0.4-2.3,0.4c-1,0-1.7-0.1-2.4-0.4
|
||||
c-0.6-0.2-1.1-0.6-1.5-1.1s-0.6-1-0.8-1.7c-0.2-0.7-0.2-1.4-0.2-2.2v-1.2c0-0.8,0.1-1.5,0.3-2.2c0.2-0.7,0.5-1.2,0.9-1.7
|
||||
s0.9-0.8,1.5-1.1C280.6,154.3,281.4,154.2,282.3,154.2z M282.3,164.8c0.7,0,1.2-0.1,1.7-0.2s0.8-0.4,1.1-0.7
|
||||
c0.3-0.3,0.5-0.8,0.6-1.3c0.1-0.5,0.2-1.2,0.2-1.9v-1c0-0.8-0.1-1.4-0.2-2s-0.3-1-0.6-1.3c-0.3-0.3-0.6-0.6-1.1-0.7s-1-0.2-1.6-0.2
|
||||
c-0.7,0-1.2,0.1-1.7,0.2c-0.5,0.2-0.8,0.4-1.1,0.7c-0.3,0.3-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,1.9v1c0,0.8,0.1,1.4,0.2,1.9
|
||||
c0.1,0.5,0.3,1,0.6,1.3c0.3,0.3,0.6,0.6,1.1,0.7C281.1,164.7,281.6,164.8,282.3,164.8z"/>
|
||||
<path class="st14" d="M288.8,154.4h1.5l3.1,4.4l3.1-4.4h1.5l-3.9,5.4l4.2,5.8h-1.6l-3.4-4.9l-3.4,4.9h-1.5l4.2-5.9L288.8,154.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st14" d="M379.5,166c-1.1,0-2-0.1-2.8-0.4s-1.3-0.7-1.7-1.2c-0.4-0.6-0.7-1.2-0.9-2c-0.2-0.8-0.2-1.8-0.2-2.8V150h1.4
|
||||
v9.5c0,1,0.1,1.9,0.2,2.5c0.2,0.7,0.4,1.2,0.7,1.6c0.3,0.4,0.8,0.7,1.3,0.9c0.5,0.2,1.2,0.3,2,0.3c0.8,0,1.5-0.1,2-0.3
|
||||
c0.5-0.2,1-0.5,1.3-0.9c0.3-0.4,0.6-1,0.7-1.6s0.2-1.5,0.2-2.5V150h1.4v9.5c0,1.1-0.1,2-0.3,2.8s-0.5,1.5-0.9,2
|
||||
c-0.4,0.5-1,0.9-1.7,1.2S380.6,166,379.5,166z"/>
|
||||
<path class="st14" d="M394.4,157.1c0.7,0.1,1.3,0.3,1.8,0.5c0.5,0.2,0.9,0.5,1.2,0.9s0.5,0.8,0.6,1.2c0.1,0.5,0.2,0.9,0.2,1.5v0.3
|
||||
c0,0.6-0.1,1.2-0.3,1.8c-0.2,0.5-0.6,1-1,1.4c-0.5,0.4-1,0.7-1.8,0.9c-0.7,0.2-1.5,0.3-2.5,0.3c-0.8,0-1.6-0.1-2.4-0.2
|
||||
c-0.8-0.1-1.4-0.3-2-0.5l0.3-1.2c0.6,0.2,1.2,0.3,1.9,0.4c0.7,0.1,1.4,0.2,2.2,0.2c1.5,0,2.6-0.3,3.2-0.8c0.6-0.5,1-1.4,1-2.5
|
||||
c0-0.4,0-0.7-0.1-1c-0.1-0.3-0.2-0.6-0.4-0.9c-0.2-0.3-0.5-0.5-0.9-0.6c-0.4-0.2-0.9-0.3-1.4-0.4l-2-0.3c-1.3-0.2-2.3-0.6-2.8-1.3
|
||||
c-0.6-0.7-0.8-1.6-0.8-2.7V154c0-0.7,0.1-1.3,0.4-1.8c0.3-0.5,0.6-1,1.1-1.3c0.5-0.4,1.1-0.6,1.8-0.8c0.7-0.2,1.5-0.3,2.3-0.3
|
||||
c0.7,0,1.5,0.1,2.1,0.2c0.7,0.1,1.2,0.3,1.7,0.5l-0.3,1.1c-0.5-0.2-1.1-0.3-1.7-0.4s-1.3-0.2-2-0.2c-1.5,0-2.5,0.3-3.2,0.8
|
||||
c-0.6,0.5-1,1.3-1,2.3c0,0.8,0.2,1.4,0.6,1.8c0.4,0.4,1.1,0.7,2.2,0.8L394.4,157.1z"/>
|
||||
<path class="st14" d="M401.4,165.7V150h5.5c0.8,0,1.5,0.1,2,0.3c0.5,0.2,1,0.5,1.3,0.8c0.3,0.3,0.6,0.7,0.7,1.2
|
||||
c0.1,0.4,0.2,0.9,0.2,1.4v0.5c0,0.8-0.2,1.5-0.6,2c-0.4,0.5-0.9,0.9-1.6,1.2c0.5,0.1,0.8,0.3,1.2,0.5c0.3,0.2,0.6,0.5,0.8,0.9
|
||||
c0.2,0.3,0.4,0.7,0.5,1.1c0.1,0.4,0.2,0.8,0.2,1.3v0.5c0,0.6-0.1,1.1-0.3,1.6c-0.2,0.5-0.5,0.9-0.9,1.3c-0.4,0.4-0.9,0.6-1.5,0.8
|
||||
s-1.3,0.3-2.1,0.3H401.4z M402.8,156.9h4.2c0.9,0,1.7-0.2,2.2-0.7c0.5-0.4,0.7-1.1,0.7-1.8v-0.5c0-1.8-1-2.8-3.1-2.8h-3.9V156.9z
|
||||
M402.8,164.5h4.2c1.1,0,1.9-0.2,2.4-0.7c0.5-0.4,0.8-1.2,0.8-2.2v-0.5c0-2-1.1-3.1-3.3-3.1h-4.2V164.5z"/>
|
||||
<path class="st14" d="M421.6,150v7.1l7-7.1h1.6l-7.5,7.5l8,8.1h-1.8l-7.3-7.5v7.5h-1.3V150H421.6z"/>
|
||||
<path class="st14" d="M433.1,160.5c0,0.8,0.1,1.4,0.2,2c0.1,0.5,0.4,1,0.7,1.3c0.3,0.3,0.8,0.6,1.3,0.7c0.5,0.2,1.2,0.2,2.1,0.2
|
||||
c0.5,0,0.9,0,1.5-0.1c0.5-0.1,1-0.1,1.3-0.2l-0.2,1.1c-0.3,0.1-0.8,0.2-1.3,0.3c-0.5,0.1-1.1,0.1-1.6,0.1c-1,0-1.8-0.1-2.5-0.3
|
||||
c-0.7-0.2-1.2-0.6-1.7-1s-0.7-1-0.9-1.7c-0.2-0.7-0.3-1.5-0.3-2.4v-0.9c0-0.8,0.1-1.6,0.3-2.3c0.2-0.7,0.5-1.3,0.8-1.7
|
||||
c0.4-0.5,0.9-0.9,1.5-1.1c0.6-0.3,1.3-0.4,2.2-0.4c0.7,0,1.4,0.1,1.9,0.3c0.5,0.2,1,0.5,1.3,0.9s0.6,0.9,0.8,1.4
|
||||
c0.2,0.5,0.2,1.2,0.2,1.8v0.6c0,0.4-0.1,0.7-0.2,0.9c-0.1,0.2-0.4,0.3-0.8,0.3H433.1z M436.4,155.3c-0.6,0-1,0.1-1.5,0.2
|
||||
s-0.8,0.4-1,0.7s-0.5,0.8-0.6,1.3c-0.1,0.5-0.2,1.2-0.2,2h6.5v-0.8c0-1.1-0.2-2-0.7-2.6S437.5,155.3,436.4,155.3z"/>
|
||||
<path class="st14" d="M451.7,154.4h1.5l-4.9,12.6c-0.3,0.8-0.6,1.4-0.9,1.9c-0.3,0.5-0.6,0.9-0.9,1.2c-0.3,0.3-0.6,0.5-1,0.6
|
||||
c-0.4,0.1-0.7,0.2-1.2,0.2c-0.3,0-0.6,0-0.9-0.1c-0.3-0.1-0.5-0.1-0.8-0.2l0.2-1c0.2,0,0.4,0.1,0.6,0.1c0.2,0,0.5,0,0.7,0
|
||||
c0.3,0,0.6,0,0.9-0.1c0.3-0.1,0.5-0.2,0.7-0.4c0.2-0.2,0.4-0.5,0.6-0.8c0.2-0.4,0.4-0.9,0.6-1.5l0.4-1.2l-4.8-11.4h1.5l3.9,9.7
|
||||
L451.7,154.4z"/>
|
||||
</g>
|
||||
</svg>
|
||||
<hr>
|
||||
|
||||
<h3>What happens if I lose my passphrase?</h3>
|
||||
<p>Your passphrase is used to encrypt your private keys. If you lose your passphrase, you will no longer be able to decrypt your private key file nor have access to the contents of your Wallet or My Purchases.</p>
|
||||
<p>In order to guarantee your privacy, nobody can help you recover your passphrase, including High Fidelity.
|
||||
|
||||
<p><b>Please write it down and store it securely.</b></p>
|
||||
<p> </p>
|
||||
<hr>
|
||||
|
||||
<h2>Want to learn more?</h2>
|
||||
<p>You can find out much more about the blockchain and about commerce in High Fidelity by visiting our Docs site:</p>
|
||||
<p><a href="http://docs.highfidelity.com" class="btn">Visit High Fidelity's Docs</a></p>
|
||||
<hr>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
High Fidelity | <a href="http://highfidelity.com" target="_blank">highfidelity.com</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -88,7 +88,7 @@ FocusScope {
|
|||
return;
|
||||
}
|
||||
var oldRecommendedRect = recommendedRect;
|
||||
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedOverlayRect();
|
||||
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect();
|
||||
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
|
||||
newRecommendedRectJS.width,
|
||||
newRecommendedRectJS.height);
|
||||
|
@ -271,7 +271,7 @@ FocusScope {
|
|||
|
||||
var oldRecommendedRect = recommendedRect;
|
||||
var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height };
|
||||
var newRecommendedRect = Controller.getRecommendedOverlayRect();
|
||||
var newRecommendedRect = Controller.getRecommendedHUDRect();
|
||||
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
|
||||
var windows = d.getTopLevelWindows();
|
||||
for (var i = 0; i < windows.length; ++i) {
|
||||
|
@ -410,7 +410,7 @@ FocusScope {
|
|||
return;
|
||||
}
|
||||
|
||||
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedOverlayRect();
|
||||
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect();
|
||||
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
|
||||
newRecommendedRectJS.width,
|
||||
newRecommendedRectJS.height);
|
||||
|
@ -442,7 +442,7 @@ FocusScope {
|
|||
|
||||
var oldRecommendedRect = recommendedRect;
|
||||
var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height };
|
||||
var newRecommendedRect = Controller.getRecommendedOverlayRect();
|
||||
var newRecommendedRect = Controller.getRecommendedHUDRect();
|
||||
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
|
||||
repositionWindow(targetWindow, false, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
|
||||
}
|
||||
|
@ -459,7 +459,7 @@ FocusScope {
|
|||
return;
|
||||
}
|
||||
|
||||
var recommended = Controller.getRecommendedOverlayRect();
|
||||
var recommended = Controller.getRecommendedHUDRect();
|
||||
var maxX = recommended.x + recommended.width;
|
||||
var maxY = recommended.y + recommended.height;
|
||||
var newPosition = Qt.vector2d(targetWindow.x, targetWindow.y);
|
||||
|
|
|
@ -79,6 +79,7 @@ Rectangle {
|
|||
failureErrorText.text = result.message;
|
||||
root.activeView = "checkoutFailure";
|
||||
} else {
|
||||
root.itemHref = result.data.download_url;
|
||||
root.activeView = "checkoutSuccess";
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +115,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
onItemHrefChanged: {
|
||||
itemIsJson = root.itemHref.indexOf('.json') !== -1;
|
||||
itemIsJson = root.itemHref.endsWith('.json');
|
||||
}
|
||||
|
||||
onItemPriceChanged: {
|
||||
|
@ -125,7 +126,7 @@ Rectangle {
|
|||
id: notSetUpTimer;
|
||||
interval: 200;
|
||||
onTriggered: {
|
||||
sendToScript({method: 'checkout_walletNotSetUp'});
|
||||
sendToScript({method: 'checkout_walletNotSetUp', itemId: itemId});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -574,8 +575,8 @@ Rectangle {
|
|||
anchors.right: parent.right;
|
||||
text: "Rez It"
|
||||
onClicked: {
|
||||
if (urlHandler.canHandleUrl(itemHref)) {
|
||||
urlHandler.handleUrl(itemHref);
|
||||
if (urlHandler.canHandleUrl(root.itemHref)) {
|
||||
urlHandler.handleUrl(root.itemHref);
|
||||
}
|
||||
rezzedNotifContainer.visible = true;
|
||||
rezzedNotifContainerTimer.start();
|
||||
|
|
|
@ -78,6 +78,10 @@ Rectangle {
|
|||
onInventoryResult: {
|
||||
purchasesReceived = true;
|
||||
|
||||
if (root.pendingInventoryReply) {
|
||||
inventoryTimer.start();
|
||||
}
|
||||
|
||||
if (result.status !== 'success') {
|
||||
console.log("Failed to get purchases", result.message);
|
||||
} else {
|
||||
|
@ -98,10 +102,6 @@ Rectangle {
|
|||
previousPurchasesModel.append(inventoryResult);
|
||||
|
||||
buildFilteredPurchasesModel();
|
||||
|
||||
if (root.pendingInventoryReply) {
|
||||
inventoryTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
root.pendingInventoryReply = false;
|
||||
|
@ -112,7 +112,7 @@ Rectangle {
|
|||
id: notSetUpTimer;
|
||||
interval: 200;
|
||||
onTriggered: {
|
||||
sendToScript({method: 'checkout_walletNotSetUp'});
|
||||
sendToScript({method: 'purchases_walletNotSetUp'});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -426,7 +426,7 @@ Rectangle {
|
|||
itemName: title;
|
||||
itemId: id;
|
||||
itemPreviewImageUrl: preview;
|
||||
itemHref: root_file_url;
|
||||
itemHref: download_url;
|
||||
purchaseStatus: status;
|
||||
purchaseStatusChanged: statusChanged;
|
||||
itemEdition: model.edition_number;
|
||||
|
|
|
@ -30,12 +30,14 @@ Item {
|
|||
id: commerce;
|
||||
|
||||
onKeyFilePathIfExistsResult: {
|
||||
keyFilePath = path;
|
||||
root.keyFilePath = path;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
commerce.getKeyFilePathIfExists();
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
commerce.getKeyFilePathIfExists();
|
||||
}
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
|
@ -103,7 +105,7 @@ Item {
|
|||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "What is a 'Security Pic'?"
|
||||
answer: qsTr("Your Security Pic is an encrypted image that you selected during Wallet Setup. <b>It acts as an extra layer of Wallet security.</b><br><br>When you see your Security Pic, you know that your actions and data are securely making use of your private keys.<br><br><b>If you don't see your Security Pic on a page that is asking you for your Wallet passphrase, someone untrustworthy may be trying to gain access to your Wallet.</b><br><br>The Pic is stored on your hard drive inside the same file as your private keys.");
|
||||
answer: qsTr("Your Security Pic is an encrypted image that you selected during Wallet Setup. <b>It acts as an extra layer of Wallet security.</b><br><br>When you see your Security Pic, you know that your actions and data are securely making use of your private keys.<br><br><b>If you don't see your Security Pic on a page that is asking you for your Wallet passphrase, someone untrustworthy may be trying to gain access to your Wallet.</b><br><br>The encrypted Pic is stored on your hard drive inside the same file as your private keys.");
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
|
|
|
@ -25,13 +25,13 @@ Item {
|
|||
HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
property string keyFilePath: "";
|
||||
property string keyFilePath;
|
||||
|
||||
Hifi.QmlCommerce {
|
||||
id: commerce;
|
||||
|
||||
onKeyFilePathIfExistsResult: {
|
||||
keyFilePath = path;
|
||||
root.keyFilePath = path;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,6 +232,12 @@ Item {
|
|||
anchors.rightMargin: 55;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
commerce.getKeyFilePathIfExists();
|
||||
}
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
id: yourPrivateKeysImage;
|
||||
text: hifi.glyphs.walletKey;
|
||||
|
@ -320,8 +326,9 @@ Item {
|
|||
height: 40;
|
||||
|
||||
onClicked: {
|
||||
Qt.openUrlExternally("https://www.highfidelity.com/");
|
||||
Qt.openUrlExternally("file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/')));
|
||||
var keyPath = "file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/'));
|
||||
Qt.openUrlExternally(keyPath + "/backup_instructions.html");
|
||||
Qt.openUrlExternally(keyPath);
|
||||
removeHmdContainer.visible = true;
|
||||
removeHmdContainerTimer.start();
|
||||
}
|
||||
|
|
|
@ -176,6 +176,8 @@ Rectangle {
|
|||
commerce.getWalletStatus();
|
||||
} else if (msg.referrer === 'purchases') {
|
||||
sendToScript({method: 'goToPurchases'});
|
||||
} else {
|
||||
sendToScript({method: 'goToMarketplaceItemPage', itemId: msg.referrer});
|
||||
}
|
||||
} else if (msg.method === 'walletSetup_raiseKeyboard') {
|
||||
root.keyboardRaised = true;
|
||||
|
@ -283,7 +285,7 @@ Rectangle {
|
|||
Connections {
|
||||
onSendSignalToParent: {
|
||||
if (msg.method === "authSuccess") {
|
||||
root.activeView = "walletHome";
|
||||
commerce.getWalletStatus();
|
||||
} else {
|
||||
sendToScript(msg);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ Item {
|
|||
property string lastPage;
|
||||
property bool hasShownSecurityImageTip: false;
|
||||
property string referrer;
|
||||
property string keyFilePath;
|
||||
|
||||
Image {
|
||||
anchors.fill: parent;
|
||||
|
@ -58,7 +59,7 @@ Item {
|
|||
}
|
||||
|
||||
onKeyFilePathIfExistsResult: {
|
||||
keyFilePath.text = path;
|
||||
root.keyFilePath = path;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,7 +609,7 @@ Item {
|
|||
anchors.fill: parent;
|
||||
|
||||
RalewaySemiBold {
|
||||
id: keyFilePathText;
|
||||
id: keyFilePathHelperText;
|
||||
text: "Private Key File Location:";
|
||||
size: 18;
|
||||
anchors.top: parent.top;
|
||||
|
@ -627,7 +628,7 @@ Item {
|
|||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 30;
|
||||
anchors.top: keyFilePathText.bottom;
|
||||
anchors.top: keyFilePathHelperText.bottom;
|
||||
anchors.topMargin: 8;
|
||||
height: 24;
|
||||
width: height;
|
||||
|
@ -643,11 +644,12 @@ Item {
|
|||
}
|
||||
|
||||
onClicked: {
|
||||
Qt.openUrlExternally("file:///" + keyFilePath.text.substring(0, keyFilePath.text.lastIndexOf('/')));
|
||||
Qt.openUrlExternally("file:///" + keyFilePath.substring(0, keyFilePath.lastIndexOf('/')));
|
||||
}
|
||||
}
|
||||
RalewayRegular {
|
||||
id: keyFilePath;
|
||||
id: keyFilePathText;
|
||||
text: root.keyFilePath;
|
||||
size: 18;
|
||||
anchors.top: clipboardButton.top;
|
||||
anchors.left: clipboardButton.right;
|
||||
|
@ -670,7 +672,7 @@ Item {
|
|||
id: openInstructionsButton;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.top: keyFilePath.bottom;
|
||||
anchors.top: keyFilePathText.bottom;
|
||||
anchors.topMargin: 30;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 30;
|
||||
|
@ -682,8 +684,9 @@ Item {
|
|||
instructions01Container.visible = false;
|
||||
instructions02Container.visible = true;
|
||||
keysReadyPageFinishButton.visible = true;
|
||||
Qt.openUrlExternally("https://www.highfidelity.com/");
|
||||
Qt.openUrlExternally("file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/')));
|
||||
var keyPath = "file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/'));
|
||||
Qt.openUrlExternally(keyPath + "/backup_instructions.html");
|
||||
Qt.openUrlExternally(keyPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ Item {
|
|||
|
||||
PropertyChanges {
|
||||
target: text
|
||||
color: "#ffffff"
|
||||
color: captionColorOverride !== "" ? captionColorOverride: "#ffffff"
|
||||
text: tabletButton.hoverText
|
||||
}
|
||||
|
||||
|
@ -194,7 +194,7 @@ Item {
|
|||
|
||||
PropertyChanges {
|
||||
target: text
|
||||
color: "#333333"
|
||||
color: captionColorOverride !== "" ? captionColorOverride: "#333333"
|
||||
text: tabletButton.activeText
|
||||
}
|
||||
|
||||
|
@ -225,7 +225,7 @@ Item {
|
|||
|
||||
PropertyChanges {
|
||||
target: text
|
||||
color: "#333333"
|
||||
color: captionColorOverride !== "" ? captionColorOverride: "#333333"
|
||||
text: tabletButton.activeHoverText
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import "."
|
|||
Rectangle {
|
||||
id: modalWindow
|
||||
layer.enabled: true
|
||||
property var title: "Modal"
|
||||
property var title: "Open"
|
||||
width: tabletRoot.width
|
||||
height: tabletRoot.height
|
||||
color: "#80000000"
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/07/11
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
|
||||
uniform sampler2D sampler;
|
||||
|
||||
struct OverlayData {
|
||||
mat4 mvp;
|
||||
float alpha;
|
||||
};
|
||||
|
||||
layout(std140) uniform overlayBuffer {
|
||||
OverlayData overlay;
|
||||
};
|
||||
|
||||
in vec2 vTexCoord;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main() {
|
||||
FragColor = texture(sampler, vTexCoord);
|
||||
FragColor.a *= overlay.alpha;
|
||||
if (FragColor.a <= 0.0) {
|
||||
discard;
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/07/11
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
|
||||
struct OverlayData {
|
||||
mat4 mvp;
|
||||
float alpha;
|
||||
};
|
||||
|
||||
layout(std140) uniform overlayBuffer {
|
||||
OverlayData overlay;
|
||||
};
|
||||
|
||||
mat4 mvp = overlay.mvp;
|
||||
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 3) in vec2 TexCoord;
|
||||
|
||||
out vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = mvp * vec4(Position, 1);
|
||||
vTexCoord = TexCoord;
|
||||
}
|
|
@ -1638,12 +1638,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
properties["throttled"] = _displayPlugin ? _displayPlugin->isThrottled() : false;
|
||||
|
||||
QJsonObject bytesDownloaded;
|
||||
bytesDownloaded["atp"] = statTracker->getStat(STAT_ATP_RESOURCE_TOTAL_BYTES).toInt();
|
||||
bytesDownloaded["http"] = statTracker->getStat(STAT_HTTP_RESOURCE_TOTAL_BYTES).toInt();
|
||||
bytesDownloaded["file"] = statTracker->getStat(STAT_FILE_RESOURCE_TOTAL_BYTES).toInt();
|
||||
bytesDownloaded["total"] = bytesDownloaded["atp"].toInt() + bytesDownloaded["http"].toInt()
|
||||
+ bytesDownloaded["file"].toInt();
|
||||
properties["bytesDownloaded"] = bytesDownloaded;
|
||||
auto atpBytes = statTracker->getStat(STAT_ATP_RESOURCE_TOTAL_BYTES).toLongLong();
|
||||
auto httpBytes = statTracker->getStat(STAT_HTTP_RESOURCE_TOTAL_BYTES).toLongLong();
|
||||
auto fileBytes = statTracker->getStat(STAT_FILE_RESOURCE_TOTAL_BYTES).toLongLong();
|
||||
bytesDownloaded["atp"] = atpBytes;
|
||||
bytesDownloaded["http"] = httpBytes;
|
||||
bytesDownloaded["file"] = fileBytes;
|
||||
bytesDownloaded["total"] = atpBytes + httpBytes + fileBytes;
|
||||
properties["bytes_downloaded"] = bytesDownloaded;
|
||||
|
||||
auto myAvatar = getMyAvatar();
|
||||
glm::vec3 avatarPosition = myAvatar->getPosition();
|
||||
|
@ -2689,15 +2691,10 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
|
||||
bool Application::importJSONFromURL(const QString& urlString) {
|
||||
// we only load files that terminate in just .json (not .svo.json and not .ava.json)
|
||||
// if they come from the High Fidelity Marketplace Assets CDN
|
||||
QUrl jsonURL { urlString };
|
||||
|
||||
if (jsonURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) {
|
||||
emit svoImportRequested(urlString);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
emit svoImportRequested(urlString);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::importSVOFromURL(const QString& urlString) {
|
||||
|
@ -5054,6 +5051,7 @@ void Application::update(float deltaTime) {
|
|||
|
||||
float sensorToWorldScale = getMyAvatar()->getSensorToWorldScale();
|
||||
appRenderArgs._sensorToWorldScale = sensorToWorldScale;
|
||||
appRenderArgs._sensorToWorld = getMyAvatar()->getSensorToWorldMatrix();
|
||||
{
|
||||
PROFILE_RANGE(render, "/buildFrustrumAndArgs");
|
||||
{
|
||||
|
@ -5095,6 +5093,7 @@ void Application::update(float deltaTime) {
|
|||
ipdScale *= sensorToWorldScale;
|
||||
|
||||
auto baseProjection = appRenderArgs._renderArgs.getViewFrustum().getProjection();
|
||||
|
||||
if (getActiveDisplayPlugin()->isStereo()) {
|
||||
// Stereo modes will typically have a larger projection matrix overall,
|
||||
// so we ask for the 'mono' projection matrix, which for stereo and HMD
|
||||
|
@ -5639,14 +5638,37 @@ bool Application::nearbyEntitiesAreReadyForPhysics() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// We don't want to use EntityTree::findEntities(AABox, ...) method because that scan will snarf parented entities
|
||||
// whose bounding boxes cannot be computed (it is too loose for our purposes here). Instead we manufacture
|
||||
// custom filters and use the general-purpose EntityTree::findEntities(filter, ...)
|
||||
QVector<EntityItemPointer> entities;
|
||||
AABox avatarBox(getMyAvatar()->getPosition() - glm::vec3(PHYSICS_READY_RANGE), glm::vec3(2 * PHYSICS_READY_RANGE));
|
||||
// create two functions that use avatarBox (entityScan and elementScan), the second calls the first
|
||||
std::function<bool (EntityItemPointer&)> entityScan = [=](EntityItemPointer& entity) {
|
||||
if (entity->shouldBePhysical()) {
|
||||
bool success = false;
|
||||
AABox entityBox = entity->getAABox(success);
|
||||
// important: bail for entities that cannot supply a valid AABox
|
||||
return success && avatarBox.touches(entityBox);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
std::function<bool(const OctreeElementPointer&, void*)> elementScan = [&](const OctreeElementPointer& element, void* unused) {
|
||||
if (element->getAACube().touches(avatarBox)) {
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
entityTreeElement->getEntities(entityScan, entities);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
entityTree->withReadLock([&] {
|
||||
AABox box(getMyAvatar()->getPosition() - glm::vec3(PHYSICS_READY_RANGE), glm::vec3(2 * PHYSICS_READY_RANGE));
|
||||
entityTree->findEntities(box, entities);
|
||||
// Pass the second function to the general-purpose EntityTree::findEntities()
|
||||
// which will traverse the tree, apply the two filter functions (to element, then to entities)
|
||||
// as it traverses. The end result will be a list of entities that match.
|
||||
entityTree->findEntities(elementScan, entities);
|
||||
});
|
||||
|
||||
// For reasons I haven't found, we don't necessarily have the full scene when we receive a stats packet. Apply
|
||||
// a heuristic to try to decide when we actually know about all of the nearby entities.
|
||||
uint32_t nearbyCount = entities.size();
|
||||
if (nearbyCount == _nearbyEntitiesCountAtLastPhysicsCheck) {
|
||||
_nearbyEntitiesStabilityCount++;
|
||||
|
@ -7002,11 +7024,11 @@ glm::uvec2 Application::getUiSize() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
QRect Application::getRecommendedOverlayRect() const {
|
||||
QRect Application::getRecommendedHUDRect() const {
|
||||
auto uiSize = getUiSize();
|
||||
QRect result(0, 0, uiSize.x, uiSize.y);
|
||||
if (_displayPlugin) {
|
||||
result = getActiveDisplayPlugin()->getRecommendedOverlayRect();
|
||||
result = getActiveDisplayPlugin()->getRecommendedHUDRect();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ public:
|
|||
QRect getRenderingGeometry() const;
|
||||
|
||||
glm::uvec2 getUiSize() const;
|
||||
QRect getRecommendedOverlayRect() const;
|
||||
QRect getRecommendedHUDRect() const;
|
||||
QSize getDeviceSize() const;
|
||||
bool hasFocus() const;
|
||||
|
||||
|
|
|
@ -126,28 +126,18 @@ void Application::paintGL() {
|
|||
renderArgs._context->setStereoViews(stereoEyeOffsets);
|
||||
}
|
||||
|
||||
renderArgs._hudOperator = displayPlugin->getHUDOperator();
|
||||
renderArgs._hudTexture = _applicationOverlay.getOverlayTexture();
|
||||
renderArgs._blitFramebuffer = finalFramebuffer;
|
||||
runRenderFrame(&renderArgs);
|
||||
}
|
||||
|
||||
gpu::Batch postCompositeBatch;
|
||||
{
|
||||
PROFILE_RANGE(render, "/postComposite");
|
||||
PerformanceTimer perfTimer("postComposite");
|
||||
renderArgs._batch = &postCompositeBatch;
|
||||
renderArgs._batch->setViewportTransform(ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height()));
|
||||
renderArgs._batch->setViewTransform(renderArgs.getViewFrustum().getView());
|
||||
_overlays.render3DHUDOverlays(&renderArgs);
|
||||
}
|
||||
|
||||
auto frame = _gpuContext->endFrame();
|
||||
frame->frameIndex = _renderFrameCount;
|
||||
frame->framebuffer = finalFramebuffer;
|
||||
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) {
|
||||
DependencyManager::get<FramebufferCache>()->releaseFramebuffer(framebuffer);
|
||||
};
|
||||
frame->overlay = _applicationOverlay.getOverlayTexture();
|
||||
frame->postCompositeBatch = postCompositeBatch;
|
||||
// deliver final scene rendering commands to the display plugin
|
||||
{
|
||||
PROFILE_RANGE(render, "/pluginOutput");
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "Ledger.h"
|
||||
#include "Wallet.h"
|
||||
#include <AccountManager.h>
|
||||
#include "scripting/WalletScriptingInterface.h"
|
||||
|
||||
HIFI_QML_DEF(QmlCommerce)
|
||||
|
||||
|
@ -29,37 +28,12 @@ QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) {
|
|||
connect(ledger.data(), &Ledger::historyResult, this, &QmlCommerce::historyResult);
|
||||
connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult);
|
||||
connect(ledger.data(), &Ledger::accountResult, this, &QmlCommerce::accountResult);
|
||||
connect(ledger.data(), &Ledger::accountResult, this, [&]() {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
auto walletScriptingInterface = DependencyManager::get<WalletScriptingInterface>();
|
||||
uint status;
|
||||
|
||||
if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) {
|
||||
status = (uint)WalletStatus::WALLET_STATUS_NOT_SET_UP;
|
||||
} else if (!wallet->walletIsAuthenticatedWithPassphrase()) {
|
||||
status = (uint)WalletStatus::WALLET_STATUS_NOT_AUTHENTICATED;
|
||||
} else {
|
||||
status = (uint)WalletStatus::WALLET_STATUS_READY;
|
||||
}
|
||||
|
||||
walletScriptingInterface->setWalletStatus(status);
|
||||
emit walletStatusResult(status);
|
||||
});
|
||||
connect(wallet.data(), &Wallet::walletStatusResult, this, &QmlCommerce::walletStatusResult);
|
||||
}
|
||||
|
||||
void QmlCommerce::getWalletStatus() {
|
||||
auto walletScriptingInterface = DependencyManager::get<WalletScriptingInterface>();
|
||||
uint status;
|
||||
|
||||
if (DependencyManager::get<AccountManager>()->isLoggedIn()) {
|
||||
// This will set account info for the wallet, allowing us to decrypt and display the security image.
|
||||
account();
|
||||
} else {
|
||||
status = (uint)WalletStatus::WALLET_STATUS_NOT_LOGGED_IN;
|
||||
emit walletStatusResult(status);
|
||||
walletScriptingInterface->setWalletStatus(status);
|
||||
return;
|
||||
}
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
wallet->getWalletStatus();
|
||||
}
|
||||
|
||||
void QmlCommerce::getLoginStatus() {
|
||||
|
|
|
@ -27,13 +27,6 @@ class QmlCommerce : public OffscreenQmlDialog {
|
|||
public:
|
||||
QmlCommerce(QQuickItem* parent = nullptr);
|
||||
|
||||
enum WalletStatus {
|
||||
WALLET_STATUS_NOT_LOGGED_IN = 0,
|
||||
WALLET_STATUS_NOT_SET_UP,
|
||||
WALLET_STATUS_NOT_AUTHENTICATED,
|
||||
WALLET_STATUS_READY
|
||||
};
|
||||
|
||||
signals:
|
||||
void walletStatusResult(uint walletStatus);
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#endif
|
||||
|
||||
static const char* KEY_FILE = "hifikey";
|
||||
static const char* INSTRUCTIONS_FILE = "backup_instructions.html";
|
||||
static const char* IMAGE_HEADER = "-----BEGIN SECURITY IMAGE-----\n";
|
||||
static const char* IMAGE_FOOTER = "-----END SECURITY IMAGE-----\n";
|
||||
|
||||
|
@ -104,6 +105,38 @@ RSA* readKeys(const char* filename) {
|
|||
return key;
|
||||
}
|
||||
|
||||
bool writeBackupInstructions() {
|
||||
QString inputFilename(PathUtils::resourcesPath() + "html/commerce/backup_instructions.html");
|
||||
QString filename = PathUtils::getAppDataFilePath(INSTRUCTIONS_FILE);
|
||||
QFile outputFile(filename);
|
||||
bool retval = false;
|
||||
|
||||
if (QFile::exists(filename))
|
||||
{
|
||||
QFile::remove(filename);
|
||||
}
|
||||
QFile::copy(inputFilename, filename);
|
||||
|
||||
if (QFile::exists(filename) && outputFile.open(QIODevice::ReadWrite)) {
|
||||
|
||||
QByteArray fileData = outputFile.readAll();
|
||||
QString text(fileData);
|
||||
|
||||
text.replace(QString("HIFIKEY_PATH_REPLACEME"), keyFilePath());
|
||||
|
||||
outputFile.seek(0); // go to the beginning of the file
|
||||
outputFile.write(text.toUtf8()); // write the new text back to the file
|
||||
|
||||
outputFile.close(); // close the file handle.
|
||||
|
||||
retval = true;
|
||||
qCDebug(commerce) << "wrote html file successfully";
|
||||
} else {
|
||||
qCDebug(commerce) << "failed to open output html file" << filename;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool writeKeys(const char* filename, RSA* keys) {
|
||||
FILE* fp;
|
||||
bool retval = false;
|
||||
|
@ -121,6 +154,8 @@ bool writeKeys(const char* filename, RSA* keys) {
|
|||
QFile(QString(filename)).remove();
|
||||
return retval;
|
||||
}
|
||||
|
||||
writeBackupInstructions();
|
||||
|
||||
retval = true;
|
||||
qCDebug(commerce) << "wrote keys successfully";
|
||||
|
@ -282,9 +317,32 @@ void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArra
|
|||
|
||||
Wallet::Wallet() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||
|
||||
packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "handleChallengeOwnershipPacket");
|
||||
|
||||
connect(ledger.data(), &Ledger::accountResult, this, [&]() {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
auto walletScriptingInterface = DependencyManager::get<WalletScriptingInterface>();
|
||||
uint status;
|
||||
|
||||
if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) {
|
||||
status = (uint)WalletStatus::WALLET_STATUS_NOT_SET_UP;
|
||||
} else if (!wallet->walletIsAuthenticatedWithPassphrase()) {
|
||||
status = (uint)WalletStatus::WALLET_STATUS_NOT_AUTHENTICATED;
|
||||
} else {
|
||||
status = (uint)WalletStatus::WALLET_STATUS_READY;
|
||||
}
|
||||
|
||||
walletScriptingInterface->setWalletStatus(status);
|
||||
emit walletStatusResult(status);
|
||||
});
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() {
|
||||
getWalletStatus();
|
||||
});
|
||||
}
|
||||
|
||||
Wallet::~Wallet() {
|
||||
|
@ -470,7 +528,6 @@ bool Wallet::generateKeyPair() {
|
|||
|
||||
// TODO: redo this soon -- need error checking and so on
|
||||
writeSecurityImage(_securityImage, keyFilePath());
|
||||
emit keyFilePathIfExistsResult(getKeyFilePath());
|
||||
QString oldKey = _publicKeys.count() == 0 ? "" : _publicKeys.last();
|
||||
QString key = keyPair.first->toBase64();
|
||||
_publicKeys.push_back(key);
|
||||
|
@ -628,6 +685,7 @@ bool Wallet::writeWallet(const QString& newPassphrase) {
|
|||
QFile(QString(keyFilePath())).remove();
|
||||
QFile(tempFileName).rename(QString(keyFilePath()));
|
||||
qCDebug(commerce) << "wallet written successfully";
|
||||
emit keyFilePathIfExistsResult(getKeyFilePath());
|
||||
return true;
|
||||
} else {
|
||||
qCDebug(commerce) << "couldn't write security image to temp wallet";
|
||||
|
@ -682,3 +740,23 @@ bool Wallet::verifyOwnerChallenge(const QByteArray& encryptedText, const QString
|
|||
decryptedText = QString("hello");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Wallet::account() {
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
ledger->account();
|
||||
}
|
||||
|
||||
void Wallet::getWalletStatus() {
|
||||
auto walletScriptingInterface = DependencyManager::get<WalletScriptingInterface>();
|
||||
uint status;
|
||||
|
||||
if (DependencyManager::get<AccountManager>()->isLoggedIn()) {
|
||||
// This will set account info for the wallet, allowing us to decrypt and display the security image.
|
||||
account();
|
||||
} else {
|
||||
status = (uint)WalletStatus::WALLET_STATUS_NOT_LOGGED_IN;
|
||||
emit walletStatusResult(status);
|
||||
walletScriptingInterface->setWalletStatus(status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <DependencyManager.h>
|
||||
#include <Node.h>
|
||||
#include <ReceivedMessage.h>
|
||||
#include "scripting/WalletScriptingInterface.h"
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
|
@ -50,10 +51,20 @@ public:
|
|||
|
||||
void reset();
|
||||
|
||||
void getWalletStatus();
|
||||
enum WalletStatus {
|
||||
WALLET_STATUS_NOT_LOGGED_IN = 0,
|
||||
WALLET_STATUS_NOT_SET_UP,
|
||||
WALLET_STATUS_NOT_AUTHENTICATED,
|
||||
WALLET_STATUS_READY
|
||||
};
|
||||
|
||||
signals:
|
||||
void securityImageResult(bool exists);
|
||||
void keyFilePathIfExistsResult(const QString& path);
|
||||
|
||||
void walletStatusResult(uint walletStatus);
|
||||
|
||||
private slots:
|
||||
void handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
|
||||
|
||||
|
@ -71,6 +82,8 @@ private:
|
|||
bool readSecurityImage(const QString& inputFilePath, unsigned char** outputBufferPtr, int* outputBufferLen);
|
||||
|
||||
bool verifyOwnerChallenge(const QByteArray& encryptedText, const QString& publicKey, QString& decryptedText);
|
||||
|
||||
void account();
|
||||
};
|
||||
|
||||
#endif // hifi_Wallet_h
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <NetworkLogging.h>
|
||||
#include <NodeList.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <UserActivityLogger.h>
|
||||
|
||||
static const int AUTO_REFRESH_INTERVAL = 1000;
|
||||
|
||||
|
@ -104,6 +105,21 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping,
|
|||
|
||||
startedCallback.call();
|
||||
|
||||
QFileInfo fileInfo { path };
|
||||
int64_t size { fileInfo.size() };
|
||||
|
||||
QString extension = "";
|
||||
auto idx = path.lastIndexOf(".");
|
||||
if (idx >= 0) {
|
||||
extension = path.mid(idx + 1);
|
||||
}
|
||||
|
||||
UserActivityLogger::getInstance().logAction("uploading_asset", {
|
||||
{ "size", (qint64)size },
|
||||
{ "mapping", mapping },
|
||||
{ "extension", extension}
|
||||
});
|
||||
|
||||
auto upload = DependencyManager::get<AssetClient>()->createUpload(path);
|
||||
QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable {
|
||||
if (upload->getError() != AssetUpload::NoError) {
|
||||
|
|
|
@ -91,8 +91,8 @@ glm::vec2 ControllerScriptingInterface::getViewportDimensions() const {
|
|||
return qApp->getUiSize();
|
||||
}
|
||||
|
||||
QVariant ControllerScriptingInterface::getRecommendedOverlayRect() const {
|
||||
auto rect = qApp->getRecommendedOverlayRect();
|
||||
QVariant ControllerScriptingInterface::getRecommendedHUDRect() const {
|
||||
auto rect = qApp->getRecommendedHUDRect();
|
||||
return qRectToVariant(rect);
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ public slots:
|
|||
virtual void releaseEntityClickEvents();
|
||||
|
||||
virtual glm::vec2 getViewportDimensions() const;
|
||||
virtual QVariant getRecommendedOverlayRect() const;
|
||||
virtual QVariant getRecommendedHUDRect() const;
|
||||
|
||||
signals:
|
||||
void keyPressEvent(const KeyEvent& event);
|
||||
|
|
|
@ -29,7 +29,7 @@ int DesktopScriptingInterface::getHeight() {
|
|||
return size.height();
|
||||
}
|
||||
|
||||
void DesktopScriptingInterface::setOverlayAlpha(float alpha) {
|
||||
void DesktopScriptingInterface::setHUDAlpha(float alpha) {
|
||||
qApp->getApplicationCompositor().setAlpha(alpha);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class DesktopScriptingInterface : public QObject, public Dependency {
|
|||
Q_PROPERTY(int height READ getHeight) // Physical height of screen(s) including task bars and system menus
|
||||
|
||||
public:
|
||||
Q_INVOKABLE void setOverlayAlpha(float alpha);
|
||||
Q_INVOKABLE void setHUDAlpha(float alpha);
|
||||
Q_INVOKABLE void show(const QString& path, const QString& title);
|
||||
|
||||
int getWidth();
|
||||
|
|
|
@ -18,6 +18,12 @@ CheckoutProxy::CheckoutProxy(QObject* qmlObject, QObject* parent) : QmlWrapper(q
|
|||
WalletScriptingInterface::WalletScriptingInterface() {
|
||||
}
|
||||
|
||||
void WalletScriptingInterface::refreshWalletStatus() {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
wallet->getWalletStatus();
|
||||
}
|
||||
|
||||
static const QString CHECKOUT_QML_PATH = qApp->applicationDirPath() + "../../../qml/hifi/commerce/checkout/Checkout.qml";
|
||||
void WalletScriptingInterface::buy(const QString& name, const QString& id, const int& price, const QString& href) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "buy", Q_ARG(const QString&, name), Q_ARG(const QString&, id), Q_ARG(const int&, price), Q_ARG(const QString&, href));
|
||||
|
@ -27,7 +33,6 @@ void WalletScriptingInterface::buy(const QString& name, const QString& id, const
|
|||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
||||
|
||||
const QString CHECKOUT_QML_PATH = qApp->applicationDirPath() + "../../../qml/hifi/commerce/checkout/Checkout.qml";
|
||||
tablet->loadQMLSource(CHECKOUT_QML_PATH);
|
||||
DependencyManager::get<HMDScriptingInterface>()->openTablet();
|
||||
|
||||
|
@ -44,4 +49,4 @@ void WalletScriptingInterface::buy(const QString& name, const QString& id, const
|
|||
checkout->writeProperty("itemId", id);
|
||||
checkout->writeProperty("itemPrice", price);
|
||||
checkout->writeProperty("itemHref", href);
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
#include <ui/QmlWrapper.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include "Application.h"
|
||||
#include "commerce/Wallet.h"
|
||||
|
||||
class CheckoutProxy : public QmlWrapper {
|
||||
Q_OBJECT
|
||||
|
@ -36,6 +37,7 @@ class WalletScriptingInterface : public QObject, public Dependency {
|
|||
public:
|
||||
WalletScriptingInterface();
|
||||
|
||||
Q_INVOKABLE void refreshWalletStatus();
|
||||
Q_INVOKABLE uint getWalletStatus() { return _walletStatus; }
|
||||
void setWalletStatus(const uint& status) { _walletStatus = status; }
|
||||
|
||||
|
@ -43,6 +45,7 @@ public:
|
|||
|
||||
signals:
|
||||
void walletStatusChanged();
|
||||
void walletNotSetup();
|
||||
|
||||
private:
|
||||
uint _walletStatus;
|
||||
|
|
|
@ -26,7 +26,8 @@ Base3DOverlay::Base3DOverlay() :
|
|||
_isSolid(DEFAULT_IS_SOLID),
|
||||
_isDashedLine(DEFAULT_IS_DASHED_LINE),
|
||||
_ignoreRayIntersection(false),
|
||||
_drawInFront(false)
|
||||
_drawInFront(false),
|
||||
_drawHUDLayer(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -38,6 +39,7 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
|
|||
_isDashedLine(base3DOverlay->_isDashedLine),
|
||||
_ignoreRayIntersection(base3DOverlay->_ignoreRayIntersection),
|
||||
_drawInFront(base3DOverlay->_drawInFront),
|
||||
_drawHUDLayer(base3DOverlay->_drawHUDLayer),
|
||||
_isGrabbable(base3DOverlay->_isGrabbable)
|
||||
{
|
||||
setTransform(base3DOverlay->getTransform());
|
||||
|
@ -125,13 +127,19 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) {
|
|||
bool needRenderItemUpdate = false;
|
||||
|
||||
auto drawInFront = properties["drawInFront"];
|
||||
|
||||
if (drawInFront.isValid()) {
|
||||
bool value = drawInFront.toBool();
|
||||
setDrawInFront(value);
|
||||
needRenderItemUpdate = true;
|
||||
}
|
||||
|
||||
auto drawHUDLayer = properties["drawHUDLayer"];
|
||||
if (drawHUDLayer.isValid()) {
|
||||
bool value = drawHUDLayer.toBool();
|
||||
setDrawHUDLayer(value);
|
||||
needRenderItemUpdate = true;
|
||||
}
|
||||
|
||||
auto isGrabbable = properties["grabbable"];
|
||||
if (isGrabbable.isValid()) {
|
||||
setIsGrabbable(isGrabbable.toBool());
|
||||
|
@ -269,10 +277,10 @@ void Base3DOverlay::update(float duration) {
|
|||
// then the correct transform used for rendering is computed in the update transaction and assigned.
|
||||
if (_renderTransformDirty) {
|
||||
auto itemID = getRenderItemID();
|
||||
// Capture the render transform value in game loop before
|
||||
auto latestTransform = evalRenderTransform();
|
||||
_renderTransformDirty = false;
|
||||
if (render::Item::isValidID(itemID)) {
|
||||
// Capture the render transform value in game loop before
|
||||
auto latestTransform = evalRenderTransform();
|
||||
_renderTransformDirty = false;
|
||||
render::ScenePointer scene = qApp->getMain3DScene();
|
||||
render::Transaction transaction;
|
||||
transaction.updateItem<Overlay>(itemID, [latestTransform](Overlay& data) {
|
||||
|
@ -282,8 +290,6 @@ void Base3DOverlay::update(float duration) {
|
|||
}
|
||||
});
|
||||
scene->enqueueTransaction(transaction);
|
||||
} else {
|
||||
setRenderTransform(latestTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
bool getIsSolidLine() const { return !_isDashedLine; }
|
||||
bool getIgnoreRayIntersection() const { return _ignoreRayIntersection; }
|
||||
bool getDrawInFront() const { return _drawInFront; }
|
||||
bool getDrawHUDLayer() const { return _drawHUDLayer; }
|
||||
bool getIsGrabbable() const { return _isGrabbable; }
|
||||
|
||||
void setLineWidth(float lineWidth) { _lineWidth = lineWidth; }
|
||||
|
@ -48,6 +49,7 @@ public:
|
|||
void setIsDashedLine(bool isDashedLine) { _isDashedLine = isDashedLine; }
|
||||
void setIgnoreRayIntersection(bool value) { _ignoreRayIntersection = value; }
|
||||
virtual void setDrawInFront(bool value) { _drawInFront = value; }
|
||||
virtual void setDrawHUDLayer(bool value) { _drawHUDLayer = value; }
|
||||
void setIsGrabbable(bool value) { _isGrabbable = value; }
|
||||
|
||||
virtual AABox getBounds() const override = 0;
|
||||
|
@ -81,6 +83,7 @@ protected:
|
|||
bool _isDashedLine;
|
||||
bool _ignoreRayIntersection;
|
||||
bool _drawInFront;
|
||||
bool _drawHUDLayer;
|
||||
bool _isGrabbable { false };
|
||||
mutable bool _renderTransformDirty{ true };
|
||||
|
||||
|
|
|
@ -263,7 +263,7 @@ const render::ShapeKey Circle3DOverlay::getShapeKey() {
|
|||
if (isTransparent()) {
|
||||
builder.withTranslucent();
|
||||
}
|
||||
if (!getIsSolid() || shouldDrawHUDLayer()) {
|
||||
if (!getIsSolid()) {
|
||||
builder.withUnlit().withDepthBias();
|
||||
}
|
||||
return builder.build();
|
||||
|
|
|
@ -41,6 +41,7 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
|||
_entityPropertyFlags += PROP_MARKETPLACE_ID;
|
||||
_entityPropertyFlags += PROP_DIMENSIONS;
|
||||
_entityPropertyFlags += PROP_REGISTRATION_POINT;
|
||||
_entityPropertyFlags += PROP_CERTIFICATE_ID;
|
||||
|
||||
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>().data();
|
||||
connect(entityTreeRenderer, SIGNAL(mousePressOnEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(createOrDestroyContextOverlay(const EntityItemID&, const PointerEvent&)));
|
||||
|
@ -176,7 +177,12 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID&
|
|||
|
||||
bool ContextOverlayInterface::contextOverlayFilterPassed(const EntityItemID& entityItemID) {
|
||||
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(entityItemID, _entityPropertyFlags);
|
||||
return (entityProperties.getMarketplaceID().length() != 0);
|
||||
Setting::Handle<bool> _settingSwitch{ "commerce", false };
|
||||
if (_settingSwitch.get()) {
|
||||
return (entityProperties.getCertificateID().length() != 0);
|
||||
} else {
|
||||
return (entityProperties.getMarketplaceID().length() != 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) {
|
||||
|
|
|
@ -113,7 +113,7 @@ const render::ShapeKey Cube3DOverlay::getShapeKey() {
|
|||
if (isTransparent()) {
|
||||
builder.withTranslucent();
|
||||
}
|
||||
if (!getIsSolid() || shouldDrawHUDLayer()) {
|
||||
if (!getIsSolid()) {
|
||||
builder.withUnlit().withDepthBias();
|
||||
}
|
||||
return builder.build();
|
||||
|
|
|
@ -132,7 +132,7 @@ void Image3DOverlay::render(RenderArgs* args) {
|
|||
|
||||
const render::ShapeKey Image3DOverlay::getShapeKey() {
|
||||
auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias();
|
||||
if (_emissive || shouldDrawHUDLayer()) {
|
||||
if (_emissive) {
|
||||
builder.withUnlit();
|
||||
}
|
||||
if (isTransparent()) {
|
||||
|
|
|
@ -87,6 +87,10 @@ void ModelOverlay::update(float deltatime) {
|
|||
_drawInFrontDirty = false;
|
||||
_model->setLayeredInFront(getDrawInFront(), scene);
|
||||
}
|
||||
if (_drawInHUDDirty) {
|
||||
_drawInHUDDirty = false;
|
||||
_model->setLayeredInHUD(getDrawHUDLayer(), scene);
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
|
@ -111,6 +115,11 @@ void ModelOverlay::setDrawInFront(bool drawInFront) {
|
|||
_drawInFrontDirty = true;
|
||||
}
|
||||
|
||||
void ModelOverlay::setDrawHUDLayer(bool drawHUDLayer) {
|
||||
Base3DOverlay::setDrawHUDLayer(drawHUDLayer);
|
||||
_drawInHUDDirty = true;
|
||||
}
|
||||
|
||||
void ModelOverlay::setProperties(const QVariantMap& properties) {
|
||||
auto origPosition = getPosition();
|
||||
auto origRotation = getRotation();
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
|
||||
void setVisible(bool visible) override;
|
||||
void setDrawInFront(bool drawInFront) override;
|
||||
void setDrawHUDLayer(bool drawHUDLayer) override;
|
||||
|
||||
protected:
|
||||
Transform evalRenderTransform() override;
|
||||
|
@ -78,8 +79,6 @@ private:
|
|||
bool _scaleToFit = { false };
|
||||
float _loadPriority { 0.0f };
|
||||
|
||||
bool _visibleDirty { false };
|
||||
bool _drawInFrontDirty { false };
|
||||
AnimationPointer _animation;
|
||||
|
||||
QUrl _animationURL;
|
||||
|
@ -97,6 +96,11 @@ private:
|
|||
QUrl _jointMappingURL;
|
||||
bool _jointMappingCompleted { false };
|
||||
QVector<int> _jointMapping; // domain is index into model-joints, range is index into animation-joints
|
||||
|
||||
bool _visibleDirty { false };
|
||||
bool _drawInFrontDirty { false };
|
||||
bool _drawInHUDDirty { false };
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_ModelOverlay_h
|
||||
|
|
|
@ -32,7 +32,6 @@ Overlay::Overlay() :
|
|||
_colorPulse(0.0f),
|
||||
_color(DEFAULT_OVERLAY_COLOR),
|
||||
_visible(true),
|
||||
_drawHUDLayer(false),
|
||||
_anchor(NO_ANCHOR)
|
||||
{
|
||||
}
|
||||
|
@ -51,7 +50,6 @@ Overlay::Overlay(const Overlay* overlay) :
|
|||
_colorPulse(overlay->_colorPulse),
|
||||
_color(overlay->_color),
|
||||
_visible(overlay->_visible),
|
||||
_drawHUDLayer(overlay->_drawHUDLayer),
|
||||
_anchor(overlay->_anchor)
|
||||
{
|
||||
}
|
||||
|
@ -90,11 +88,6 @@ void Overlay::setProperties(const QVariantMap& properties) {
|
|||
setColorPulse(properties["colorPulse"].toFloat());
|
||||
}
|
||||
|
||||
if (properties["drawHUDLayer"].isValid()) {
|
||||
bool drawHUDLayer = properties["drawHUDLayer"].toBool();
|
||||
setDrawHUDLayer(drawHUDLayer);
|
||||
}
|
||||
|
||||
if (properties["visible"].isValid()) {
|
||||
bool visible = properties["visible"].toBool();
|
||||
setVisible(visible);
|
||||
|
@ -170,13 +163,6 @@ float Overlay::getAlpha() {
|
|||
return (_alphaPulse >= 0.0f) ? _alpha * pulseLevel : _alpha * (1.0f - pulseLevel);
|
||||
}
|
||||
|
||||
void Overlay::setDrawHUDLayer(bool drawHUDLayer) {
|
||||
if (drawHUDLayer != _drawHUDLayer) {
|
||||
qApp->getOverlays().setOverlayDrawHUDLayer(getOverlayID(), drawHUDLayer);
|
||||
_drawHUDLayer = drawHUDLayer;
|
||||
}
|
||||
}
|
||||
|
||||
// pulse travels from min to max, then max to min in one period.
|
||||
float Overlay::updatePulse() {
|
||||
if (_pulsePeriod <= 0.0f) {
|
||||
|
|
|
@ -58,7 +58,6 @@ public:
|
|||
virtual bool is3D() const = 0;
|
||||
bool isLoaded() { return _isLoaded; }
|
||||
bool getVisible() const { return _visible; }
|
||||
bool shouldDrawHUDLayer() const { return _drawHUDLayer; }
|
||||
virtual bool isTransparent() { return getAlphaPulse() != 0.0f || getAlpha() != 1.0f; };
|
||||
xColor getColor();
|
||||
float getAlpha();
|
||||
|
@ -117,7 +116,6 @@ protected:
|
|||
|
||||
xColor _color;
|
||||
bool _visible; // should the overlay be drawn at all
|
||||
bool _drawHUDLayer; // should the overlay be drawn on the HUD layer
|
||||
Anchor _anchor;
|
||||
|
||||
unsigned int _stackOrder { 0 };
|
||||
|
|
|
@ -37,29 +37,22 @@
|
|||
#include "Web3DOverlay.h"
|
||||
#include <QtQuick/QQuickWindow>
|
||||
|
||||
#include "render/ShapePipeline.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays")
|
||||
|
||||
extern void initOverlay3DPipelines(render::ShapePlumber& plumber, bool depthTest = false);
|
||||
|
||||
void Overlays::cleanupAllOverlays() {
|
||||
QMap<OverlayID, Overlay::Pointer> overlaysHUD;
|
||||
QMap<OverlayID, Overlay::Pointer> overlays3DHUD;
|
||||
QMap<OverlayID, Overlay::Pointer> overlaysWorld;
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
overlaysHUD.swap(_overlaysHUD);
|
||||
overlays3DHUD.swap(_overlays3DHUD);
|
||||
overlaysWorld.swap(_overlaysWorld);
|
||||
}
|
||||
|
||||
foreach(Overlay::Pointer overlay, overlaysHUD) {
|
||||
_overlaysToDelete.push_back(overlay);
|
||||
}
|
||||
foreach(Overlay::Pointer overlay, overlays3DHUD) {
|
||||
_overlaysToDelete.push_back(overlay);
|
||||
}
|
||||
foreach(Overlay::Pointer overlay, overlaysWorld) {
|
||||
_overlaysToDelete.push_back(overlay);
|
||||
}
|
||||
|
@ -73,8 +66,6 @@ void Overlays::init() {
|
|||
#if OVERLAY_PANELS
|
||||
_scriptEngine = new QScriptEngine();
|
||||
#endif
|
||||
_shapePlumber = std::make_shared<render::ShapePlumber>();
|
||||
initOverlay3DPipelines(*_shapePlumber, true);
|
||||
}
|
||||
|
||||
void Overlays::update(float deltatime) {
|
||||
|
@ -83,9 +74,6 @@ void Overlays::update(float deltatime) {
|
|||
foreach(const auto& thisOverlay, _overlaysHUD) {
|
||||
thisOverlay->update(deltatime);
|
||||
}
|
||||
foreach(const auto& thisOverlay, _overlays3DHUD) {
|
||||
thisOverlay->update(deltatime);
|
||||
}
|
||||
foreach(const auto& thisOverlay, _overlaysWorld) {
|
||||
thisOverlay->update(deltatime);
|
||||
}
|
||||
|
@ -142,23 +130,6 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
|
|||
}
|
||||
}
|
||||
|
||||
void Overlays::render3DHUDOverlays(RenderArgs* renderArgs) {
|
||||
PROFILE_RANGE(render_overlays, __FUNCTION__);
|
||||
gpu::Batch& batch = *renderArgs->_batch;
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
QMutexLocker lock(&_mutex);
|
||||
foreach(Overlay::Pointer thisOverlay, _overlays3DHUD) {
|
||||
// Reset necessary batch pipeline settings between overlays
|
||||
batch.setResourceTexture(0, textureCache->getWhiteTexture()); // FIXME - do we really need to do this??
|
||||
batch.setModelTransform(Transform());
|
||||
|
||||
renderArgs->_shapePipeline = _shapePlumber->pickPipeline(renderArgs, thisOverlay->getShapeKey());
|
||||
thisOverlay->render(renderArgs);
|
||||
}
|
||||
}
|
||||
|
||||
void Overlays::disable() {
|
||||
_enabled = false;
|
||||
}
|
||||
|
@ -173,8 +144,6 @@ Overlay::Pointer Overlays::getOverlay(OverlayID id) const {
|
|||
QMutexLocker locker(&_mutex);
|
||||
if (_overlaysHUD.contains(id)) {
|
||||
return _overlaysHUD[id];
|
||||
} else if (_overlays3DHUD.contains(id)) {
|
||||
return _overlays3DHUD[id];
|
||||
} else if (_overlaysWorld.contains(id)) {
|
||||
return _overlaysWorld[id];
|
||||
}
|
||||
|
@ -232,7 +201,7 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) {
|
|||
OverlayID thisID = OverlayID(QUuid::createUuid());
|
||||
overlay->setOverlayID(thisID);
|
||||
overlay->setStackOrder(_stackOrder++);
|
||||
if (overlay->is3D() && !overlay->shouldDrawHUDLayer()) {
|
||||
if (overlay->is3D()) {
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
_overlaysWorld[thisID] = overlay;
|
||||
|
@ -242,9 +211,6 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) {
|
|||
render::Transaction transaction;
|
||||
overlay->addToScene(overlay, scene, transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
} else if (overlay->is3D() && overlay->shouldDrawHUDLayer()) {
|
||||
QMutexLocker locker(&_mutex);
|
||||
_overlays3DHUD[thisID] = overlay;
|
||||
} else {
|
||||
QMutexLocker locker(&_mutex);
|
||||
_overlaysHUD[thisID] = overlay;
|
||||
|
@ -253,28 +219,6 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) {
|
|||
return thisID;
|
||||
}
|
||||
|
||||
void Overlays::setOverlayDrawHUDLayer(const OverlayID& id, const bool drawHUDLayer) {
|
||||
QMutexLocker locker(&_mutex);
|
||||
if (drawHUDLayer && _overlaysWorld.contains(id)) {
|
||||
std::shared_ptr<Overlay> overlay = _overlaysWorld.take(id);
|
||||
render::ScenePointer scene = qApp->getMain3DScene();
|
||||
render::Transaction transaction;
|
||||
auto itemID = overlay->getRenderItemID();
|
||||
if (render::Item::isValidID(itemID)) {
|
||||
overlay->removeFromScene(overlay, scene, transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
_overlays3DHUD[id] = overlay;
|
||||
} else if (!drawHUDLayer && _overlays3DHUD.contains(id)) {
|
||||
std::shared_ptr<Overlay> overlay = _overlays3DHUD.take(id);
|
||||
render::ScenePointer scene = qApp->getMain3DScene();
|
||||
render::Transaction transaction;
|
||||
overlay->addToScene(overlay, scene, transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
_overlaysWorld[id] = overlay;
|
||||
}
|
||||
}
|
||||
|
||||
OverlayID Overlays::cloneOverlay(OverlayID id) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
OverlayID result;
|
||||
|
@ -361,8 +305,6 @@ void Overlays::deleteOverlay(OverlayID id) {
|
|||
QMutexLocker locker(&_mutex);
|
||||
if (_overlaysHUD.contains(id)) {
|
||||
overlayToDelete = _overlaysHUD.take(id);
|
||||
} else if (_overlays3DHUD.contains(id)) {
|
||||
overlayToDelete = _overlays3DHUD.take(id);
|
||||
} else if (_overlaysWorld.contains(id)) {
|
||||
overlayToDelete = _overlaysWorld.take(id);
|
||||
} else {
|
||||
|
@ -771,7 +713,7 @@ bool Overlays::isAddedOverlay(OverlayID id) {
|
|||
}
|
||||
|
||||
QMutexLocker locker(&_mutex);
|
||||
return _overlaysHUD.contains(id) || _overlays3DHUD.contains(id) || _overlaysWorld.contains(id);
|
||||
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
|
||||
}
|
||||
|
||||
void Overlays::sendMousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||
|
|
|
@ -90,7 +90,6 @@ public:
|
|||
void init();
|
||||
void update(float deltatime);
|
||||
void renderHUD(RenderArgs* renderArgs);
|
||||
void render3DHUDOverlays(RenderArgs* renderArgs);
|
||||
void disable();
|
||||
void enable();
|
||||
|
||||
|
@ -103,8 +102,6 @@ public:
|
|||
OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); }
|
||||
OverlayID addOverlay(const Overlay::Pointer& overlay);
|
||||
|
||||
void setOverlayDrawHUDLayer(const OverlayID& id, const bool drawHUDLayer);
|
||||
|
||||
bool mousePressEvent(QMouseEvent* event);
|
||||
bool mouseDoublePressEvent(QMouseEvent* event);
|
||||
bool mouseReleaseEvent(QMouseEvent* event);
|
||||
|
@ -334,11 +331,8 @@ private:
|
|||
|
||||
mutable QMutex _mutex { QMutex::Recursive };
|
||||
QMap<OverlayID, Overlay::Pointer> _overlaysHUD;
|
||||
QMap<OverlayID, Overlay::Pointer> _overlays3DHUD;
|
||||
QMap<OverlayID, Overlay::Pointer> _overlaysWorld;
|
||||
|
||||
render::ShapePlumberPointer _shapePlumber;
|
||||
|
||||
#if OVERLAY_PANELS
|
||||
QMap<OverlayID, OverlayPanel::Pointer> _panels;
|
||||
#endif
|
||||
|
|
|
@ -34,7 +34,8 @@ namespace render {
|
|||
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay) {
|
||||
auto builder = ItemKey::Builder().withTypeShape();
|
||||
if (overlay->is3D()) {
|
||||
if (std::static_pointer_cast<Base3DOverlay>(overlay)->getDrawInFront()) {
|
||||
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay);
|
||||
if (overlay3D->getDrawInFront() || overlay3D->getDrawHUDLayer()) {
|
||||
builder.withLayered();
|
||||
}
|
||||
if (overlay->isTransparent()) {
|
||||
|
@ -49,20 +50,17 @@ namespace render {
|
|||
return overlay->getBounds();
|
||||
}
|
||||
template <> int payloadGetLayer(const Overlay::Pointer& overlay) {
|
||||
// Magic number while we are defining the layering mechanism:
|
||||
const int LAYER_2D = 2;
|
||||
const int LAYER_3D_FRONT = 1;
|
||||
const int LAYER_3D = 0;
|
||||
|
||||
if (overlay->is3D()) {
|
||||
auto overlay3D = std::dynamic_pointer_cast<Base3DOverlay>(overlay);
|
||||
if (overlay3D->getDrawInFront()) {
|
||||
return LAYER_3D_FRONT;
|
||||
return Item::LAYER_3D_FRONT;
|
||||
} else if (overlay3D->getDrawHUDLayer()) {
|
||||
return Item::LAYER_3D_HUD;
|
||||
} else {
|
||||
return LAYER_3D;
|
||||
return Item::LAYER_3D;
|
||||
}
|
||||
} else {
|
||||
return LAYER_2D;
|
||||
return Item::LAYER_2D;
|
||||
}
|
||||
}
|
||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
|
||||
|
|
|
@ -55,7 +55,7 @@ const render::ShapeKey Shape3DOverlay::getShapeKey() {
|
|||
if (isTransparent()) {
|
||||
builder.withTranslucent();
|
||||
}
|
||||
if (!getIsSolid() || shouldDrawHUDLayer()) {
|
||||
if (!getIsSolid()) {
|
||||
builder.withUnlit().withDepthBias();
|
||||
}
|
||||
return builder.build();
|
||||
|
|
|
@ -60,7 +60,7 @@ const render::ShapeKey Sphere3DOverlay::getShapeKey() {
|
|||
if (isTransparent()) {
|
||||
builder.withTranslucent();
|
||||
}
|
||||
if (!getIsSolid() || shouldDrawHUDLayer()) {
|
||||
if (!getIsSolid()) {
|
||||
builder.withUnlit().withDepthBias();
|
||||
}
|
||||
return builder.build();
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
|
||||
void setModelTransform(const Transform& transform) { _modelTransform = transform; }
|
||||
const Transform& getModelTransform() const { return _modelTransform; }
|
||||
glm::mat4 getUiTransform() const;
|
||||
|
||||
float getAlpha() const { return _alpha; }
|
||||
void setAlpha(float alpha) { if (alpha != _alpha) { emit alphaChanged(); _alpha = alpha; } }
|
||||
|
@ -122,7 +123,6 @@ protected slots:
|
|||
void sendFakeMouseEvent();
|
||||
|
||||
private:
|
||||
glm::mat4 getUiTransform() const;
|
||||
void updateTooltips();
|
||||
|
||||
DisplayPluginPointer _currentDisplayPlugin;
|
||||
|
|
|
@ -307,7 +307,7 @@ bool OpenGLDisplayPlugin::activate() {
|
|||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
connect(compositorHelper.data(), &CompositorHelper::alphaChanged, [this] {
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
auto animation = new QPropertyAnimation(this, "overlayAlpha");
|
||||
auto animation = new QPropertyAnimation(this, "hudAlpha");
|
||||
animation->setDuration(200);
|
||||
animation->setEndValue(compositorHelper->getAlpha());
|
||||
animation->start();
|
||||
|
@ -415,7 +415,7 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
_overlayPipeline = gpu::Pipeline::create(program, state);
|
||||
_hudPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -437,7 +437,7 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
void OpenGLDisplayPlugin::uncustomizeContext() {
|
||||
_presentPipeline.reset();
|
||||
_cursorPipeline.reset();
|
||||
_overlayPipeline.reset();
|
||||
_hudPipeline.reset();
|
||||
_compositeFramebuffer.reset();
|
||||
withPresentThreadLock([&] {
|
||||
_currentFrame.reset();
|
||||
|
@ -562,22 +562,23 @@ void OpenGLDisplayPlugin::updateFrameData() {
|
|||
});
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::compositeOverlay() {
|
||||
render([&](gpu::Batch& batch){
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
batch.setPipeline(_overlayPipeline);
|
||||
batch.setResourceTexture(0, _currentFrame->overlay);
|
||||
if (isStereo()) {
|
||||
for_each_eye([&](Eye eye) {
|
||||
batch.setViewportTransform(eyeViewport(eye));
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> OpenGLDisplayPlugin::getHUDOperator() {
|
||||
return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture) {
|
||||
if (_hudPipeline) {
|
||||
batch.enableStereo(false);
|
||||
batch.setPipeline(_hudPipeline);
|
||||
batch.setResourceTexture(0, hudTexture);
|
||||
if (isStereo()) {
|
||||
for_each_eye([&](Eye eye) {
|
||||
batch.setViewportTransform(eyeViewport(eye));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
} else {
|
||||
batch.setViewportTransform(ivec4(uvec2(0), _compositeFramebuffer->getSize()));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
} else {
|
||||
batch.setViewportTransform(ivec4(uvec2(0), _compositeFramebuffer->getSize()));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::compositePointer() {
|
||||
|
@ -626,29 +627,15 @@ void OpenGLDisplayPlugin::compositeLayers() {
|
|||
compositeScene();
|
||||
}
|
||||
|
||||
// Clear the depth framebuffer after drawing the scene so that the HUD elements can depth test against each other
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
batch.clearDepthFramebuffer((float) UINT32_MAX);
|
||||
});
|
||||
|
||||
#ifdef HIFI_ENABLE_NSIGHT_DEBUG
|
||||
if (false) // do not compositeoverlay if running nsight debug
|
||||
if (false) // do not draw the HUD if running nsight debug
|
||||
#endif
|
||||
{
|
||||
PROFILE_RANGE_EX(render_detail, "compositeOverlay", 0xff0077ff, (uint64_t)presentCount())
|
||||
compositeOverlay();
|
||||
}
|
||||
|
||||
// Only render HUD layer 3D overlays in HMD mode
|
||||
if (isHmd()) {
|
||||
PROFILE_RANGE_EX(render_detail, "compositeHUDOverlays", 0xff0077ff, (uint64_t)presentCount())
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
PROFILE_RANGE_EX(render_detail, "handleHUDBatch", 0xff0077ff, (uint64_t)presentCount())
|
||||
auto hudOperator = getHUDOperator();
|
||||
withPresentThreadLock([&] {
|
||||
_hudOperator = hudOperator;
|
||||
});
|
||||
_gpuContext->executeBatch(_currentFrame->postCompositeBatch);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -656,13 +643,7 @@ void OpenGLDisplayPlugin::compositeLayers() {
|
|||
compositeExtra();
|
||||
}
|
||||
|
||||
// Clear the depth buffer again and draw the pointer last so it's on top of everything
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
batch.clearDepthFramebuffer((float) UINT32_MAX);
|
||||
});
|
||||
|
||||
// Draw the pointer last so it's on top of everything
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
if (compositorHelper->getReticleVisible()) {
|
||||
PROFILE_RANGE_EX(render_detail, "compositePointer", 0xff0077ff, (uint64_t)presentCount())
|
||||
|
@ -844,7 +825,7 @@ void OpenGLDisplayPlugin::assertIsPresentThread() const {
|
|||
|
||||
bool OpenGLDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
|
||||
withNonPresentThreadLock([&] {
|
||||
_compositeOverlayAlpha = _overlayAlpha;
|
||||
_compositeHUDAlpha = _hudAlpha;
|
||||
});
|
||||
return Parent::beginFrameRender(frameIndex);
|
||||
}
|
||||
|
@ -887,8 +868,7 @@ OpenGLDisplayPlugin::~OpenGLDisplayPlugin() {
|
|||
void OpenGLDisplayPlugin::updateCompositeFramebuffer() {
|
||||
auto renderSize = getRecommendedRenderSize();
|
||||
if (!_compositeFramebuffer || _compositeFramebuffer->getSize() != renderSize) {
|
||||
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL);
|
||||
_compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", gpu::Element::COLOR_RGBA_32, depthFormat, renderSize.x, renderSize.y));
|
||||
_compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", gpu::Element::COLOR_RGBA_32, renderSize.x, renderSize.y));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <SimpleMovingAverage.h>
|
||||
#include <shared/RateCounter.h>
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
namespace gpu {
|
||||
namespace gl {
|
||||
class GLBackend;
|
||||
|
@ -30,7 +32,7 @@ namespace gpu {
|
|||
|
||||
class OpenGLDisplayPlugin : public DisplayPlugin {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float overlayAlpha MEMBER _overlayAlpha)
|
||||
Q_PROPERTY(float hudAlpha MEMBER _hudAlpha)
|
||||
using Parent = DisplayPlugin;
|
||||
protected:
|
||||
using Mutex = std::mutex;
|
||||
|
@ -93,7 +95,7 @@ protected:
|
|||
virtual QThread::Priority getPresentPriority() { return QThread::HighPriority; }
|
||||
virtual void compositeLayers();
|
||||
virtual void compositeScene();
|
||||
virtual void compositeOverlay();
|
||||
virtual std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator();
|
||||
virtual void compositePointer();
|
||||
virtual void compositeExtra() {};
|
||||
|
||||
|
@ -137,12 +139,12 @@ protected:
|
|||
gpu::FramePointer _currentFrame;
|
||||
gpu::Frame* _lastFrame { nullptr };
|
||||
gpu::FramebufferPointer _compositeFramebuffer;
|
||||
gpu::PipelinePointer _overlayPipeline;
|
||||
gpu::PipelinePointer _hudPipeline;
|
||||
gpu::PipelinePointer _simplePipeline;
|
||||
gpu::PipelinePointer _presentPipeline;
|
||||
gpu::PipelinePointer _cursorPipeline;
|
||||
gpu::TexturePointer _displayTexture{};
|
||||
float _compositeOverlayAlpha { 1.0f };
|
||||
float _compositeHUDAlpha { 1.0f };
|
||||
|
||||
struct CursorData {
|
||||
QImage image;
|
||||
|
@ -176,6 +178,6 @@ protected:
|
|||
// Any resource shared by the main thread and the presentation thread must
|
||||
// be serialized through this mutex
|
||||
mutable Mutex _presentMutex;
|
||||
float _overlayAlpha{ 1.0f };
|
||||
float _hudAlpha{ 1.0f };
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
#include "../Logging.h"
|
||||
#include "../CompositorHelper.h"
|
||||
|
||||
#include "render-utils/hmd_ui_vert.h"
|
||||
#include "render-utils/hmd_ui_frag.h"
|
||||
|
||||
static const QString MONO_PREVIEW = "Mono Preview";
|
||||
static const QString DISABLE_PREVIEW = "Disable Preview";
|
||||
static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate";
|
||||
|
@ -46,19 +49,11 @@ static const glm::mat4 IDENTITY_MATRIX;
|
|||
//#define LIVE_SHADER_RELOAD 1
|
||||
extern glm::vec3 getPoint(float yaw, float pitch);
|
||||
|
||||
static QString readFile(const QString& filename) {
|
||||
QFile file(filename);
|
||||
file.open(QFile::Text | QFile::ReadOnly);
|
||||
QString result;
|
||||
result.append(QTextStream(&file).readAll());
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::uvec2 HmdDisplayPlugin::getRecommendedUiSize() const {
|
||||
return CompositorHelper::VIRTUAL_SCREEN_SIZE;
|
||||
}
|
||||
|
||||
QRect HmdDisplayPlugin::getRecommendedOverlayRect() const {
|
||||
QRect HmdDisplayPlugin::getRecommendedHUDRect() const {
|
||||
return CompositorHelper::VIRTUAL_SCREEN_RECOMMENDED_OVERLAY_RECT;
|
||||
}
|
||||
|
||||
|
@ -108,7 +103,7 @@ void HmdDisplayPlugin::internalDeactivate() {
|
|||
|
||||
void HmdDisplayPlugin::customizeContext() {
|
||||
Parent::customizeContext();
|
||||
_overlayRenderer.build();
|
||||
_hudRenderer.build();
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::uncustomizeContext() {
|
||||
|
@ -121,7 +116,7 @@ void HmdDisplayPlugin::uncustomizeContext() {
|
|||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(0));
|
||||
});
|
||||
_overlayRenderer = OverlayRenderer();
|
||||
_hudRenderer = HUDRenderer();
|
||||
_previewTexture.reset();
|
||||
Parent::uncustomizeContext();
|
||||
}
|
||||
|
@ -171,7 +166,7 @@ float HmdDisplayPlugin::getLeftCenterPixel() const {
|
|||
void HmdDisplayPlugin::internalPresent() {
|
||||
PROFILE_RANGE_EX(render, __FUNCTION__, 0xff00ff00, (uint64_t)presentCount())
|
||||
|
||||
// Composite together the scene, overlay and mouse cursor
|
||||
// Composite together the scene, hud and mouse cursor
|
||||
hmdPresent();
|
||||
|
||||
if (_displayTexture) {
|
||||
|
@ -344,17 +339,9 @@ void HmdDisplayPlugin::updateFrameData() {
|
|||
auto correction = glm::inverse(batchPose) * currentPose;
|
||||
getGLBackend()->setCameraCorrection(correction);
|
||||
}
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
glm::mat4 modelMat = compositorHelper->getModelTransform().getMatrix();
|
||||
|
||||
for_each_eye([&](Eye eye) {
|
||||
auto modelView = glm::inverse(_currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye)) * modelMat;
|
||||
_overlayRenderer.mvps[eye] = _eyeProjections[eye] * modelView;
|
||||
});
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::OverlayRenderer::build() {
|
||||
void HmdDisplayPlugin::HUDRenderer::build() {
|
||||
vertices = std::make_shared<gpu::Buffer>();
|
||||
indices = std::make_shared<gpu::Buffer>();
|
||||
|
||||
|
@ -410,38 +397,20 @@ void HmdDisplayPlugin::OverlayRenderer::build() {
|
|||
format = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
||||
format->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||
format->setAttribute(gpu::Stream::TEXCOORD, gpu::Stream::TEXCOORD, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
|
||||
uniformBuffers[0] = std::make_shared<gpu::Buffer>(sizeof(Uniforms), nullptr);
|
||||
uniformBuffers[1] = std::make_shared<gpu::Buffer>(sizeof(Uniforms), nullptr);
|
||||
uniformsBuffer = std::make_shared<gpu::Buffer>(sizeof(Uniforms), nullptr);
|
||||
updatePipeline();
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::OverlayRenderer::updatePipeline() {
|
||||
static const QString vsFile = PathUtils::resourcesPath() + "/shaders/hmd_ui.vert";
|
||||
static const QString fsFile = PathUtils::resourcesPath() + "/shaders/hmd_ui.frag";
|
||||
|
||||
#if LIVE_SHADER_RELOAD
|
||||
static qint64 vsBuiltAge = 0;
|
||||
static qint64 fsBuiltAge = 0;
|
||||
QFileInfo vsInfo(vsFile);
|
||||
QFileInfo fsInfo(fsFile);
|
||||
auto vsAge = vsInfo.lastModified().toMSecsSinceEpoch();
|
||||
auto fsAge = fsInfo.lastModified().toMSecsSinceEpoch();
|
||||
if (!pipeline || vsAge > vsBuiltAge || fsAge > fsBuiltAge) {
|
||||
vsBuiltAge = vsAge;
|
||||
fsBuiltAge = fsAge;
|
||||
#else
|
||||
void HmdDisplayPlugin::HUDRenderer::updatePipeline() {
|
||||
if (!pipeline) {
|
||||
#endif
|
||||
QString vsSource = readFile(vsFile);
|
||||
QString fsSource = readFile(fsFile);
|
||||
auto vs = gpu::Shader::createVertex(vsSource.toLocal8Bit().toStdString());
|
||||
auto ps = gpu::Shader::createPixel(fsSource.toLocal8Bit().toStdString());
|
||||
auto vs = gpu::Shader::createVertex(std::string(hmd_ui_vert));
|
||||
auto ps = gpu::Shader::createPixel(std::string(hmd_ui_frag));
|
||||
auto program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::gl::GLBackend::makeProgram(*program, gpu::Shader::BindingSet());
|
||||
this->uniformsLocation = program->getUniformBuffers().findLocation("overlayBuffer");
|
||||
uniformsLocation = program->getUniformBuffers().findLocation("hudBuffer");
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false, false, gpu::LESS_EQUAL));
|
||||
state->setDepthTest(gpu::State::DepthTest(true, true, gpu::LESS_EQUAL));
|
||||
state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
|
@ -450,30 +419,29 @@ void HmdDisplayPlugin::OverlayRenderer::updatePipeline() {
|
|||
}
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::OverlayRenderer::render(HmdDisplayPlugin& plugin) {
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> HmdDisplayPlugin::HUDRenderer::render(HmdDisplayPlugin& plugin) {
|
||||
updatePipeline();
|
||||
for_each_eye([&](Eye eye){
|
||||
uniforms.mvp = mvps[eye];
|
||||
uniformBuffers[eye]->setSubData(0, uniforms);
|
||||
});
|
||||
plugin.render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(plugin._compositeFramebuffer);
|
||||
batch.setPipeline(pipeline);
|
||||
batch.setInputFormat(format);
|
||||
gpu::BufferView posView(vertices, VERTEX_OFFSET, vertices->getSize(), VERTEX_STRIDE, format->getAttributes().at(gpu::Stream::POSITION)._element);
|
||||
gpu::BufferView uvView(vertices, TEXTURE_OFFSET, vertices->getSize(), VERTEX_STRIDE, format->getAttributes().at(gpu::Stream::TEXCOORD)._element);
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, posView);
|
||||
batch.setInputBuffer(gpu::Stream::TEXCOORD, uvView);
|
||||
batch.setIndexBuffer(gpu::UINT16, indices, 0);
|
||||
batch.setResourceTexture(0, plugin._currentFrame->overlay);
|
||||
// FIXME use stereo information input to set both MVPs in the uniforms
|
||||
for_each_eye([&](Eye eye) {
|
||||
batch.setUniformBuffer(uniformsLocation, uniformBuffers[eye]);
|
||||
batch.setViewportTransform(plugin.eyeViewport(eye));
|
||||
return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture) {
|
||||
if (pipeline) {
|
||||
batch.setPipeline(pipeline);
|
||||
|
||||
batch.setInputFormat(format);
|
||||
gpu::BufferView posView(vertices, VERTEX_OFFSET, vertices->getSize(), VERTEX_STRIDE, format->getAttributes().at(gpu::Stream::POSITION)._element);
|
||||
gpu::BufferView uvView(vertices, TEXTURE_OFFSET, vertices->getSize(), VERTEX_STRIDE, format->getAttributes().at(gpu::Stream::TEXCOORD)._element);
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, posView);
|
||||
batch.setInputBuffer(gpu::Stream::TEXCOORD, uvView);
|
||||
batch.setIndexBuffer(gpu::UINT16, indices, 0);
|
||||
|
||||
uniformsBuffer->setSubData(0, uniforms);
|
||||
batch.setUniformBuffer(uniformsLocation, uniformsBuffer);
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
batch.setModelTransform(compositorHelper->getUiTransform());
|
||||
batch.setResourceTexture(0, hudTexture);
|
||||
|
||||
batch.drawIndexed(gpu::TRIANGLES, indexCount);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::compositePointer() {
|
||||
|
@ -500,12 +468,8 @@ void HmdDisplayPlugin::compositePointer() {
|
|||
});
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::compositeOverlay() {
|
||||
if (!_currentFrame || !_currentFrame->overlay) {
|
||||
return;
|
||||
}
|
||||
|
||||
_overlayRenderer.render(*this);
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> HmdDisplayPlugin::getHUDOperator() {
|
||||
return _hudRenderer.render(*this);
|
||||
}
|
||||
|
||||
HmdDisplayPlugin::~HmdDisplayPlugin() {
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
glm::uvec2 getRecommendedRenderSize() const override final { return _renderTargetSize; }
|
||||
bool isDisplayVisible() const override { return isHmdMounted(); }
|
||||
|
||||
QRect getRecommendedOverlayRect() const override final;
|
||||
QRect getRecommendedHUDRect() const override final;
|
||||
|
||||
virtual glm::mat4 getHeadPose() const override;
|
||||
|
||||
|
@ -53,7 +53,7 @@ protected:
|
|||
|
||||
bool internalActivate() override;
|
||||
void internalDeactivate() override;
|
||||
void compositeOverlay() override;
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator() override;
|
||||
void compositePointer() override;
|
||||
void internalPresent() override;
|
||||
void customizeContext() override;
|
||||
|
@ -91,7 +91,7 @@ private:
|
|||
gpu::TexturePointer _previewTexture;
|
||||
glm::vec2 _lastWindowSize;
|
||||
|
||||
struct OverlayRenderer {
|
||||
struct HUDRenderer {
|
||||
gpu::Stream::FormatPointer format;
|
||||
gpu::BufferPointer vertices;
|
||||
gpu::BufferPointer indices;
|
||||
|
@ -99,12 +99,9 @@ private:
|
|||
gpu::PipelinePointer pipeline;
|
||||
int32_t uniformsLocation { -1 };
|
||||
|
||||
// FIXME this is stupid, use the built in transformation pipeline
|
||||
std::array<gpu::BufferPointer, 2> uniformBuffers;
|
||||
std::array<mat4, 2> mvps;
|
||||
gpu::BufferPointer uniformsBuffer;
|
||||
|
||||
struct Uniforms {
|
||||
mat4 mvp;
|
||||
float alpha { 1.0f };
|
||||
} uniforms;
|
||||
|
||||
|
@ -119,6 +116,6 @@ private:
|
|||
|
||||
void build();
|
||||
void updatePipeline();
|
||||
void render(HmdDisplayPlugin& plugin);
|
||||
} _overlayRenderer;
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> render(HmdDisplayPlugin& plugin);
|
||||
} _hudRenderer;
|
||||
};
|
||||
|
|
|
@ -78,6 +78,7 @@ protected:
|
|||
// Will be called by the lambda posted to the scene in updateInScene.
|
||||
// This function will execute on the rendering thread, so you cannot use network caches to fetch
|
||||
// data in this method if using multi-threaded rendering
|
||||
|
||||
virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity) { }
|
||||
|
||||
// Called by the `render` method after `needsRenderUpdate`
|
||||
|
|
|
@ -1240,6 +1240,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
mapJoints(entity, model->getJointNames());
|
||||
}
|
||||
animate(entity);
|
||||
emit requestRenderUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -864,6 +864,12 @@ void EntityTree::findEntities(const ViewFrustum& frustum, QVector<EntityItemPoin
|
|||
foundEntities.swap(args.entities);
|
||||
}
|
||||
|
||||
// NOTE: assumes caller has handled locking
|
||||
void EntityTree::findEntities(RecurseOctreeOperation& elementFilter,
|
||||
QVector<EntityItemPointer>& foundEntities) {
|
||||
recurseTreeWithOperation(elementFilter, nullptr);
|
||||
}
|
||||
|
||||
EntityItemPointer EntityTree::findEntityByID(const QUuid& id) {
|
||||
EntityItemID entityID(id);
|
||||
return findEntityByEntityItemID(entityID);
|
||||
|
|
|
@ -165,6 +165,11 @@ public:
|
|||
/// \param foundEntities[out] vector of EntityItemPointer
|
||||
void findEntities(const ViewFrustum& frustum, QVector<EntityItemPointer>& foundEntities);
|
||||
|
||||
/// finds all entities that match scanOperator
|
||||
/// \parameter scanOperator function that scans entities that match criteria
|
||||
/// \parameter foundEntities[out] vector of EntityItemPointer
|
||||
void findEntities(RecurseOctreeOperation& scanOperator, QVector<EntityItemPointer>& foundEntities);
|
||||
|
||||
void addNewlyCreatedHook(NewlyCreatedEntityHook* hook);
|
||||
void removeNewlyCreatedHook(NewlyCreatedEntityHook* hook);
|
||||
|
||||
|
|
|
@ -869,6 +869,14 @@ void EntityTreeElement::getEntities(const ViewFrustum& frustum, QVector<EntityIt
|
|||
});
|
||||
}
|
||||
|
||||
void EntityTreeElement::getEntities(EntityItemFilter& filter, QVector<EntityItemPointer>& foundEntities) {
|
||||
forEachEntity([&](EntityItemPointer entity) {
|
||||
if (filter(entity)) {
|
||||
foundEntities.push_back(entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id) const {
|
||||
EntityItemPointer foundEntity = NULL;
|
||||
withReadLock([&] {
|
||||
|
|
|
@ -27,6 +27,7 @@ class EntityTreeElement;
|
|||
using EntityItems = QVector<EntityItemPointer>;
|
||||
using EntityTreeElementWeakPointer = std::weak_ptr<EntityTreeElement>;
|
||||
using EntityTreeElementPointer = std::shared_ptr<EntityTreeElement>;
|
||||
using EntityItemFilter = std::function<bool(EntityItemPointer&)>;
|
||||
|
||||
class EntityTreeUpdateArgs {
|
||||
public:
|
||||
|
@ -199,6 +200,11 @@ public:
|
|||
/// \param entities[out] vector of non-const EntityItemPointer
|
||||
void getEntities(const ViewFrustum& frustum, QVector<EntityItemPointer>& foundEntities);
|
||||
|
||||
/// finds all entities that match filter
|
||||
/// \param filter function that adds matching entities to foundEntities
|
||||
/// \param entities[out] vector of non-const EntityItemPointer
|
||||
void getEntities(EntityItemFilter& filter, QVector<EntityItemPointer>& foundEntities);
|
||||
|
||||
EntityItemPointer getEntityWithID(uint32_t id) const;
|
||||
EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id) const;
|
||||
void getEntitiesInside(const AACube& box, QVector<EntityItemPointer>& foundEntities);
|
||||
|
|
|
@ -19,6 +19,7 @@ bool GLTexelFormat::isCompressed() const {
|
|||
case GL_COMPRESSED_RED_RGTC1:
|
||||
case GL_COMPRESSED_RG_RGTC2:
|
||||
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -94,6 +95,11 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
|
|||
result = GL_R11F_G11F_B10F;
|
||||
break;
|
||||
|
||||
case gpu::RGB9E5:
|
||||
// the type should be float
|
||||
result = GL_RGB9_E5;
|
||||
break;
|
||||
|
||||
case gpu::DEPTH:
|
||||
result = GL_DEPTH_COMPONENT32;
|
||||
switch (dstFormat.getType()) {
|
||||
|
@ -244,6 +250,9 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
|
|||
case gpu::COMPRESSED_BC5_XY:
|
||||
result = GL_COMPRESSED_RG_RGTC2;
|
||||
break;
|
||||
case gpu::COMPRESSED_BC6_RGB:
|
||||
result = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
|
||||
break;
|
||||
case gpu::COMPRESSED_BC7_SRGBA:
|
||||
result = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
||||
break;
|
||||
|
@ -396,6 +405,9 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
|||
case gpu::COMPRESSED_BC5_XY:
|
||||
texel.internalFormat = GL_COMPRESSED_RG_RGTC2;
|
||||
break;
|
||||
case gpu::COMPRESSED_BC6_RGB:
|
||||
texel.internalFormat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
|
||||
break;
|
||||
case gpu::COMPRESSED_BC7_SRGBA:
|
||||
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
||||
break;
|
||||
|
@ -495,10 +507,16 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
|||
|
||||
case gpu::R11G11B10:
|
||||
texel.format = GL_RGB;
|
||||
// the type should be float
|
||||
texel.type = GL_UNSIGNED_INT_10F_11F_11F_REV;
|
||||
texel.internalFormat = GL_R11F_G11F_B10F;
|
||||
break;
|
||||
|
||||
case gpu::RGB9E5:
|
||||
texel.format = GL_RGB;
|
||||
texel.type = GL_UNSIGNED_INT_5_9_9_9_REV;
|
||||
texel.internalFormat = GL_RGB9_E5;
|
||||
break;
|
||||
|
||||
case gpu::DEPTH:
|
||||
texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
||||
|
@ -694,6 +712,9 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
|||
case gpu::COMPRESSED_BC5_XY:
|
||||
texel.internalFormat = GL_COMPRESSED_RG_RGTC2;
|
||||
break;
|
||||
case gpu::COMPRESSED_BC6_RGB:
|
||||
texel.internalFormat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
|
||||
break;
|
||||
case gpu::COMPRESSED_BC7_SRGBA:
|
||||
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
||||
break;
|
||||
|
|
|
@ -114,6 +114,7 @@ Size GL41Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const
|
|||
case GL_COMPRESSED_RED_RGTC1:
|
||||
case GL_COMPRESSED_RG_RGTC2:
|
||||
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||
glCompressedTexSubImage2D(_target, mip, 0, yOffset, size.x, size.y, internalFormat,
|
||||
static_cast<GLsizei>(sourceSize), sourcePointer);
|
||||
break;
|
||||
|
@ -131,6 +132,7 @@ Size GL41Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const
|
|||
case GL_COMPRESSED_RED_RGTC1:
|
||||
case GL_COMPRESSED_RG_RGTC2:
|
||||
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||
glCompressedTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, internalFormat,
|
||||
static_cast<GLsizei>(sourceSize), sourcePointer);
|
||||
break;
|
||||
|
|
|
@ -143,6 +143,7 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const
|
|||
case GL_COMPRESSED_RED_RGTC1:
|
||||
case GL_COMPRESSED_RG_RGTC2:
|
||||
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||
glCompressedTextureSubImage2D(_id, mip, 0, yOffset, size.x, size.y, internalFormat,
|
||||
static_cast<GLsizei>(sourceSize), sourcePointer);
|
||||
break;
|
||||
|
@ -158,6 +159,7 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const
|
|||
case GL_COMPRESSED_RED_RGTC1:
|
||||
case GL_COMPRESSED_RG_RGTC2:
|
||||
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||
if (glCompressedTextureSubImage2DEXT) {
|
||||
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
|
||||
glCompressedTextureSubImage2DEXT(_id, target, mip, 0, yOffset, size.x, size.y, internalFormat,
|
||||
|
|
|
@ -92,7 +92,7 @@ public:
|
|||
void captureNamedDrawCallInfo(std::string name);
|
||||
|
||||
Batch();
|
||||
explicit Batch(const Batch& batch);
|
||||
Batch(const Batch& batch);
|
||||
~Batch();
|
||||
|
||||
void clear();
|
||||
|
|
|
@ -24,11 +24,13 @@ const Element Element::COLOR_COMPRESSED_SRGB { TILE4x4, COMPRESSED, COMPRESSED_B
|
|||
const Element Element::COLOR_COMPRESSED_SRGBA_MASK { TILE4x4, COMPRESSED, COMPRESSED_BC1_SRGBA };
|
||||
const Element Element::COLOR_COMPRESSED_SRGBA { TILE4x4, COMPRESSED, COMPRESSED_BC3_SRGBA };
|
||||
const Element Element::COLOR_COMPRESSED_XY { TILE4x4, COMPRESSED, COMPRESSED_BC5_XY };
|
||||
const Element Element::COLOR_COMPRESSED_SRGBA_HIGH { TILE4x4, COMPRESSED, COMPRESSED_BC7_SRGBA };
|
||||
const Element Element::COLOR_COMPRESSED_SRGBA_HIGH{ TILE4x4, COMPRESSED, COMPRESSED_BC7_SRGBA };
|
||||
const Element Element::COLOR_COMPRESSED_HDR_RGB{ TILE4x4, COMPRESSED, COMPRESSED_BC6_RGB };
|
||||
|
||||
const Element Element::VEC2NU8_XY{ VEC2, NUINT8, XY };
|
||||
|
||||
const Element Element::COLOR_R11G11B10{ SCALAR, FLOAT, R11G11B10 };
|
||||
const Element Element::COLOR_RGB9E5{ SCALAR, FLOAT, RGB9E5 };
|
||||
const Element Element::VEC4F_COLOR_RGBA{ VEC4, FLOAT, RGBA };
|
||||
const Element Element::VEC2F_UV{ VEC2, FLOAT, UV };
|
||||
const Element Element::VEC2F_XY{ VEC2, FLOAT, XY };
|
||||
|
|
|
@ -187,11 +187,13 @@ enum Semantic : uint8_t {
|
|||
COMPRESSED_BC3_SRGBA,
|
||||
COMPRESSED_BC4_RED,
|
||||
COMPRESSED_BC5_XY,
|
||||
COMPRESSED_BC6_RGB,
|
||||
COMPRESSED_BC7_SRGBA,
|
||||
|
||||
_LAST_COMPRESSED,
|
||||
|
||||
R11G11B10,
|
||||
RGB9E5,
|
||||
|
||||
UNIFORM,
|
||||
UNIFORM_BUFFER,
|
||||
|
@ -240,11 +242,13 @@ static const int SEMANTIC_SIZE_FACTOR[NUM_SEMANTICS] = {
|
|||
16, //COMPRESSED_BC3_SRGBA, 1 byte/pixel * 4x4 pixels = 16 bytes
|
||||
8, //COMPRESSED_BC4_RED, 1/2 byte/pixel * 4x4 pixels = 8 bytes
|
||||
16, //COMPRESSED_BC5_XY, 1 byte/pixel * 4x4 pixels = 16 bytes
|
||||
16, //COMPRESSED_BC6_RGB, 1 byte/pixel * 4x4 pixels = 16 bytes
|
||||
16, //COMPRESSED_BC7_SRGBA, 1 byte/pixel * 4x4 pixels = 16 bytes
|
||||
|
||||
1, //_LAST_COMPRESSED,
|
||||
|
||||
1, //R11G11B10,
|
||||
1, //RGB9E5
|
||||
|
||||
1, //UNIFORM,
|
||||
1, //UNIFORM_BUFFER,
|
||||
|
@ -306,12 +310,14 @@ public:
|
|||
static const Element COLOR_BGRA_32;
|
||||
static const Element COLOR_SBGRA_32;
|
||||
static const Element COLOR_R11G11B10;
|
||||
static const Element COLOR_RGB9E5;
|
||||
static const Element COLOR_COMPRESSED_RED;
|
||||
static const Element COLOR_COMPRESSED_SRGB;
|
||||
static const Element COLOR_COMPRESSED_SRGBA_MASK;
|
||||
static const Element COLOR_COMPRESSED_SRGBA;
|
||||
static const Element COLOR_COMPRESSED_XY;
|
||||
static const Element COLOR_COMPRESSED_SRGBA_HIGH;
|
||||
static const Element COLOR_COMPRESSED_HDR_RGB;
|
||||
static const Element VEC2NU8_XY;
|
||||
static const Element VEC4F_COLOR_RGBA;
|
||||
static const Element VEC2F_UV;
|
||||
|
|
|
@ -32,14 +32,10 @@ namespace gpu {
|
|||
Mat4 pose;
|
||||
/// The collection of batches which make up the frame
|
||||
Batches batches;
|
||||
/// Single batch containing overlays to be drawn in the composite framebuffer
|
||||
Batch postCompositeBatch;
|
||||
/// The main thread updates to buffers that are applicable for this frame.
|
||||
BufferUpdates bufferUpdates;
|
||||
/// The destination framebuffer in which the results will be placed
|
||||
FramebufferPointer framebuffer;
|
||||
/// The destination texture containing the 2D overlay
|
||||
TexturePointer overlay;
|
||||
/// How to process the framebuffer when the frame dies. MUST BE THREAD SAFE
|
||||
FramebufferRecycler framebufferRecycler;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <glm/gtc/constants.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
#include <glm/gtc/packing.hpp>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QThread>
|
||||
|
@ -683,6 +684,21 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
|
||||
PROFILE_RANGE(render_gpu, "sphericalHarmonicsFromTexture");
|
||||
|
||||
auto mipFormat = cubeTexture.getStoredMipFormat();
|
||||
std::function<glm::vec3(uint32)> unpackFunc;
|
||||
|
||||
switch (mipFormat.getSemantic()) {
|
||||
case gpu::R11G11B10:
|
||||
unpackFunc = glm::unpackF2x11_1x10;
|
||||
break;
|
||||
case gpu::RGB9E5:
|
||||
unpackFunc = glm::unpackF3x9_E1x5;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
const uint sqOrder = order*order;
|
||||
|
||||
// allocate memory for calculations
|
||||
|
@ -716,17 +732,7 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) {
|
||||
PROFILE_RANGE(render_gpu, "ProcessFace");
|
||||
|
||||
auto mipFormat = cubeTexture.getStoredMipFormat();
|
||||
auto numComponents = mipFormat.getScalarCount();
|
||||
int roffset { 0 };
|
||||
int goffset { 1 };
|
||||
int boffset { 2 };
|
||||
if ((mipFormat.getSemantic() == gpu::BGRA) || (mipFormat.getSemantic() == gpu::SBGRA)) {
|
||||
roffset = 2;
|
||||
boffset = 0;
|
||||
}
|
||||
|
||||
auto data = cubeTexture.accessStoredMipFace(0, face)->readData();
|
||||
auto data = reinterpret_cast<const uint32*>( cubeTexture.accessStoredMipFace(0, face)->readData() );
|
||||
if (data == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
@ -806,29 +812,24 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
|
||||
// index of texel in texture
|
||||
|
||||
// get color from texture and map to range [0, 1]
|
||||
float red { 0.0f };
|
||||
float green { 0.0f };
|
||||
float blue { 0.0f };
|
||||
// get color from texture
|
||||
glm::vec3 color{ 0.0f, 0.0f, 0.0f };
|
||||
for (int i = 0; i < stride; ++i) {
|
||||
for (int j = 0; j < stride; ++j) {
|
||||
int k = (int)(x + i - halfStride + (y + j - halfStride) * width) * numComponents;
|
||||
red += ColorUtils::sRGB8ToLinearFloat(data[k + roffset]);
|
||||
green += ColorUtils::sRGB8ToLinearFloat(data[k + goffset]);
|
||||
blue += ColorUtils::sRGB8ToLinearFloat(data[k + boffset]);
|
||||
int k = (int)(x + i - halfStride + (y + j - halfStride) * width);
|
||||
color += unpackFunc(data[k]);
|
||||
}
|
||||
}
|
||||
glm::vec3 clr(red, green, blue);
|
||||
|
||||
// scale color and add to previously accumulated coefficients
|
||||
// red
|
||||
sphericalHarmonicsScale(shBuffB.data(), order, shBuff.data(), clr.r * fDiffSolid);
|
||||
sphericalHarmonicsScale(shBuffB.data(), order, shBuff.data(), color.r * fDiffSolid);
|
||||
sphericalHarmonicsAdd(resultR.data(), order, resultR.data(), shBuffB.data());
|
||||
// green
|
||||
sphericalHarmonicsScale(shBuffB.data(), order, shBuff.data(), clr.g * fDiffSolid);
|
||||
sphericalHarmonicsScale(shBuffB.data(), order, shBuff.data(), color.g * fDiffSolid);
|
||||
sphericalHarmonicsAdd(resultG.data(), order, resultG.data(), shBuffB.data());
|
||||
// blue
|
||||
sphericalHarmonicsScale(shBuffB.data(), order, shBuff.data(), clr.b * fDiffSolid);
|
||||
sphericalHarmonicsScale(shBuffB.data(), order, shBuff.data(), color.b * fDiffSolid);
|
||||
sphericalHarmonicsAdd(resultB.data(), order, resultB.data(), shBuffB.data());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -515,8 +515,6 @@ TexturePointer Texture::build(const ktx::KTXDescriptor& descriptor) {
|
|||
return texture;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TexturePointer Texture::unserialize(const cache::FilePointer& cacheEntry) {
|
||||
std::unique_ptr<ktx::KTX> ktxPointer = ktx::KTX::create(std::make_shared<storage::FileStorage>(cacheEntry->getFilepath().c_str()));
|
||||
if (!ktxPointer) {
|
||||
|
@ -536,7 +534,7 @@ TexturePointer Texture::unserialize(const std::string& ktxfile) {
|
|||
if (!ktxPointer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
auto texture = build(ktxPointer->toDescriptor());
|
||||
if (texture) {
|
||||
texture->setKtxBacking(ktxfile);
|
||||
|
@ -570,6 +568,12 @@ bool Texture::evalKTXFormat(const Element& mipFormat, const Element& texelFormat
|
|||
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RG_RGTC2, ktx::GLBaseInternalFormat::RG);
|
||||
} else if (texelFormat == Format::COLOR_COMPRESSED_SRGBA_HIGH && mipFormat == Format::COLOR_COMPRESSED_SRGBA_HIGH) {
|
||||
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM, ktx::GLBaseInternalFormat::RGBA);
|
||||
} else if (texelFormat == Format::COLOR_COMPRESSED_HDR_RGB && mipFormat == Format::COLOR_COMPRESSED_HDR_RGB) {
|
||||
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, ktx::GLBaseInternalFormat::RGB);
|
||||
} else if (texelFormat == Format::COLOR_RGB9E5 && mipFormat == Format::COLOR_RGB9E5) {
|
||||
header.setUncompressed(ktx::GLType::UNSIGNED_INT_5_9_9_9_REV, 1, ktx::GLFormat::RGB, ktx::GLInternalFormat::RGB9_E5, ktx::GLBaseInternalFormat::RGB);
|
||||
} else if (texelFormat == Format::COLOR_R11G11B10 && mipFormat == Format::COLOR_R11G11B10) {
|
||||
header.setUncompressed(ktx::GLType::UNSIGNED_INT_10F_11F_11F_REV, 1, ktx::GLFormat::RGB, ktx::GLInternalFormat::R11F_G11F_B10F, ktx::GLBaseInternalFormat::RGB);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -612,6 +616,12 @@ bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, E
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (header.getGLFormat() == ktx::GLFormat::RGB && header.getGLType() == ktx::GLType::UNSIGNED_INT_10F_11F_11F_REV) {
|
||||
mipFormat = Format::COLOR_R11G11B10;
|
||||
texelFormat = Format::COLOR_R11G11B10;
|
||||
} else if (header.getGLFormat() == ktx::GLFormat::RGB && header.getGLType() == ktx::GLType::UNSIGNED_INT_5_9_9_9_REV) {
|
||||
mipFormat = Format::COLOR_RGB9E5;
|
||||
texelFormat = Format::COLOR_RGB9E5;
|
||||
} else if (header.isCompressed()) {
|
||||
if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
|
||||
mipFormat = Format::COLOR_COMPRESSED_SRGB;
|
||||
|
@ -631,6 +641,9 @@ bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, E
|
|||
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM) {
|
||||
mipFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
|
||||
texelFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
|
||||
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) {
|
||||
mipFormat = Format::COLOR_COMPRESSED_HDR_RGB;
|
||||
texelFormat = Format::COLOR_COMPRESSED_HDR_RGB;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -11,9 +11,10 @@
|
|||
|
||||
#include "Image.h"
|
||||
|
||||
#include <nvtt/nvtt.h>
|
||||
#include <glm/gtc/packing.hpp>
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QBuffer>
|
||||
|
@ -42,6 +43,8 @@ bool DEV_DECIMATE_TEXTURES = false;
|
|||
std::atomic<size_t> DECIMATED_TEXTURE_COUNT{ 0 };
|
||||
std::atomic<size_t> RECTIFIED_TEXTURE_COUNT{ 0 };
|
||||
|
||||
static const auto HDR_FORMAT = gpu::Element::COLOR_R11G11B10;
|
||||
|
||||
static std::atomic<bool> compressColorTextures { false };
|
||||
static std::atomic<bool> compressNormalTextures { false };
|
||||
static std::atomic<bool> compressGrayscaleTextures { false };
|
||||
|
@ -71,6 +74,8 @@ glm::uvec2 rectifyToSparseSize(const glm::uvec2& size) {
|
|||
|
||||
namespace image {
|
||||
|
||||
QImage::Format QIMAGE_HDR_FORMAT = QImage::Format_RGB30;
|
||||
|
||||
TextureUsage::TextureLoader TextureUsage::getTextureLoaderForType(Type type, const QVariantMap& options) {
|
||||
switch (type) {
|
||||
case ALBEDO_TEXTURE:
|
||||
|
@ -213,6 +218,25 @@ void setCubeTexturesCompressionEnabled(bool enabled) {
|
|||
compressCubeTextures.store(enabled);
|
||||
}
|
||||
|
||||
static float denormalize(float value, const float minValue) {
|
||||
return value < minValue ? 0.0f : value;
|
||||
}
|
||||
|
||||
uint32 packR11G11B10F(const glm::vec3& color) {
|
||||
// Denormalize else unpacking gives high and incorrect values
|
||||
// See https://www.khronos.org/opengl/wiki/Small_Float_Formats for this min value
|
||||
static const auto minValue = 6.10e-5f;
|
||||
static const auto maxValue = 6.50e4f;
|
||||
glm::vec3 ucolor;
|
||||
ucolor.r = denormalize(color.r, minValue);
|
||||
ucolor.g = denormalize(color.g, minValue);
|
||||
ucolor.b = denormalize(color.b, minValue);
|
||||
ucolor.r = std::min(ucolor.r, maxValue);
|
||||
ucolor.g = std::min(ucolor.g, maxValue);
|
||||
ucolor.b = std::min(ucolor.b, maxValue);
|
||||
return glm::packF2x11_1x10(ucolor);
|
||||
}
|
||||
|
||||
gpu::TexturePointer processImage(const QByteArray& content, const std::string& filename,
|
||||
int maxNumPixels, TextureUsage::Type textureType,
|
||||
const std::atomic<bool>& abortProcessing) {
|
||||
|
@ -270,8 +294,6 @@ gpu::TexturePointer processImage(const QByteArray& content, const std::string& f
|
|||
return texture;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QImage processSourceImage(const QImage& srcImage, bool cubemap) {
|
||||
PROFILE_RANGE(resource_parse, "processSourceImage");
|
||||
const glm::uvec2 srcImageSize = toGlm(srcImage.size());
|
||||
|
@ -303,8 +325,8 @@ QImage processSourceImage(const QImage& srcImage, bool cubemap) {
|
|||
}
|
||||
|
||||
#if defined(NVTT_API)
|
||||
struct MyOutputHandler : public nvtt::OutputHandler {
|
||||
MyOutputHandler(gpu::Texture* texture, int face) : _texture(texture), _face(face) {}
|
||||
struct OutputHandler : public nvtt::OutputHandler {
|
||||
OutputHandler(gpu::Texture* texture, int face) : _texture(texture), _face(face) {}
|
||||
|
||||
virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel) override {
|
||||
_size = size;
|
||||
|
@ -313,12 +335,14 @@ struct MyOutputHandler : public nvtt::OutputHandler {
|
|||
_data = static_cast<gpu::Byte*>(malloc(size));
|
||||
_current = _data;
|
||||
}
|
||||
|
||||
virtual bool writeData(const void* data, int size) override {
|
||||
assert(_current + size <= _data + _size);
|
||||
memcpy(_current, data, size);
|
||||
_current += size;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void endImage() override {
|
||||
if (_face >= 0) {
|
||||
_texture->assignStoredMipFace(_miplevel, _face, _size, static_cast<const gpu::Byte*>(_data));
|
||||
|
@ -336,6 +360,51 @@ struct MyOutputHandler : public nvtt::OutputHandler {
|
|||
int _size = 0;
|
||||
int _face = -1;
|
||||
};
|
||||
|
||||
struct PackedFloatOutputHandler : public OutputHandler {
|
||||
PackedFloatOutputHandler(gpu::Texture* texture, int face, gpu::Element format) : OutputHandler(texture, face) {
|
||||
if (format == gpu::Element::COLOR_RGB9E5) {
|
||||
_packFunc = glm::packF3x9_E1x5;
|
||||
} else if (format == gpu::Element::COLOR_R11G11B10) {
|
||||
_packFunc = packR11G11B10F;
|
||||
} else {
|
||||
qCWarning(imagelogging) << "Unknown handler format";
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel) override {
|
||||
// Divide by 3 because we will compress from 3*floats to 1 uint32
|
||||
OutputHandler::beginImage(size / 3, width, height, depth, face, miplevel);
|
||||
}
|
||||
virtual bool writeData(const void* data, int size) override {
|
||||
// Expecting to write multiple of floats
|
||||
if (_packFunc) {
|
||||
assert((size % sizeof(float)) == 0);
|
||||
auto floatCount = size / sizeof(float);
|
||||
const float* floatBegin = (const float*)data;
|
||||
const float* floatEnd = floatBegin + floatCount;
|
||||
|
||||
while (floatBegin < floatEnd) {
|
||||
_pixel[_coordIndex] = *floatBegin;
|
||||
floatBegin++;
|
||||
_coordIndex++;
|
||||
if (_coordIndex == 3) {
|
||||
uint32 packedRGB = _packFunc(_pixel);
|
||||
_coordIndex = 0;
|
||||
OutputHandler::writeData(&packedRGB, sizeof(packedRGB));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::function<uint32(const glm::vec3&)> _packFunc;
|
||||
glm::vec3 _pixel;
|
||||
int _coordIndex{ 0 };
|
||||
};
|
||||
|
||||
struct MyErrorHandler : public nvtt::ErrorHandler {
|
||||
virtual void error(nvtt::Error e) override {
|
||||
qCWarning(imagelogging) << "Texture compression error:" << nvtt::errorString(e);
|
||||
|
@ -343,10 +412,113 @@ struct MyErrorHandler : public nvtt::ErrorHandler {
|
|||
};
|
||||
#endif
|
||||
|
||||
void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>& abortProcessing = false, int face = -1) {
|
||||
#if CPU_MIPMAPS
|
||||
PROFILE_RANGE(resource_parse, "generateMips");
|
||||
class SequentialTaskDispatcher : public nvtt::TaskDispatcher {
|
||||
public:
|
||||
SequentialTaskDispatcher(const std::atomic<bool>& abortProcessing) : _abortProcessing(abortProcessing) {};
|
||||
|
||||
const std::atomic<bool>& _abortProcessing;
|
||||
|
||||
virtual void dispatch(nvtt::Task* task, void* context, int count) override {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (!_abortProcessing.load()) {
|
||||
task(context, i);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void generateHDRMips(gpu::Texture* texture, const QImage& image, const std::atomic<bool>& abortProcessing, int face) {
|
||||
assert(image.format() == QIMAGE_HDR_FORMAT);
|
||||
|
||||
const int width = image.width(), height = image.height();
|
||||
std::vector<glm::vec4> data;
|
||||
std::vector<glm::vec4>::iterator dataIt;
|
||||
auto mipFormat = texture->getStoredMipFormat();
|
||||
std::function<glm::vec3(uint32)> unpackFunc;
|
||||
|
||||
nvtt::InputFormat inputFormat = nvtt::InputFormat_RGBA_32F;
|
||||
nvtt::WrapMode wrapMode = nvtt::WrapMode_Mirror;
|
||||
nvtt::AlphaMode alphaMode = nvtt::AlphaMode_None;
|
||||
|
||||
nvtt::CompressionOptions compressionOptions;
|
||||
compressionOptions.setQuality(nvtt::Quality_Production);
|
||||
|
||||
if (mipFormat == gpu::Element::COLOR_COMPRESSED_HDR_RGB) {
|
||||
compressionOptions.setFormat(nvtt::Format_BC6);
|
||||
} else if (mipFormat == gpu::Element::COLOR_RGB9E5) {
|
||||
compressionOptions.setFormat(nvtt::Format_RGB);
|
||||
compressionOptions.setPixelType(nvtt::PixelType_Float);
|
||||
compressionOptions.setPixelFormat(32, 32, 32, 0);
|
||||
} else if (mipFormat == gpu::Element::COLOR_R11G11B10) {
|
||||
compressionOptions.setFormat(nvtt::Format_RGB);
|
||||
compressionOptions.setPixelType(nvtt::PixelType_Float);
|
||||
compressionOptions.setPixelFormat(32, 32, 32, 0);
|
||||
} else {
|
||||
qCWarning(imagelogging) << "Unknown mip format";
|
||||
Q_UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
if (HDR_FORMAT == gpu::Element::COLOR_RGB9E5) {
|
||||
unpackFunc = glm::unpackF3x9_E1x5;
|
||||
} else if (HDR_FORMAT == gpu::Element::COLOR_R11G11B10) {
|
||||
unpackFunc = glm::unpackF2x11_1x10;
|
||||
} else {
|
||||
qCWarning(imagelogging) << "Unknown HDR encoding format in QImage";
|
||||
Q_UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
data.resize(width*height);
|
||||
dataIt = data.begin();
|
||||
for (auto lineNb = 0; lineNb < height; lineNb++) {
|
||||
const uint32* srcPixelIt = reinterpret_cast<const uint32*>( image.constScanLine(lineNb) );
|
||||
const uint32* srcPixelEnd = srcPixelIt + width;
|
||||
|
||||
while (srcPixelIt < srcPixelEnd) {
|
||||
*dataIt = glm::vec4(unpackFunc(*srcPixelIt), 1.0f);
|
||||
++srcPixelIt;
|
||||
++dataIt;
|
||||
}
|
||||
}
|
||||
assert(dataIt == data.end());
|
||||
|
||||
nvtt::OutputOptions outputOptions;
|
||||
outputOptions.setOutputHeader(false);
|
||||
std::unique_ptr<nvtt::OutputHandler> outputHandler;
|
||||
MyErrorHandler errorHandler;
|
||||
outputOptions.setErrorHandler(&errorHandler);
|
||||
nvtt::Context context;
|
||||
int mipLevel = 0;
|
||||
|
||||
if (mipFormat == gpu::Element::COLOR_RGB9E5 || mipFormat == gpu::Element::COLOR_R11G11B10) {
|
||||
// Don't use NVTT (at least version 2.1) as it outputs wrong RGB9E5 and R11G11B10F values from floats
|
||||
outputHandler.reset(new PackedFloatOutputHandler(texture, face, mipFormat));
|
||||
} else {
|
||||
outputHandler.reset( new OutputHandler(texture, face) );
|
||||
}
|
||||
|
||||
outputOptions.setOutputHandler(outputHandler.get());
|
||||
|
||||
nvtt::Surface surface;
|
||||
surface.setImage(inputFormat, width, height, 1, &(*data.begin()));
|
||||
surface.setAlphaMode(alphaMode);
|
||||
surface.setWrapMode(wrapMode);
|
||||
|
||||
SequentialTaskDispatcher dispatcher(abortProcessing);
|
||||
nvtt::Compressor compressor;
|
||||
context.setTaskDispatcher(&dispatcher);
|
||||
|
||||
context.compress(surface, face, mipLevel++, compressionOptions, outputOptions);
|
||||
while (surface.canMakeNextMipmap() && !abortProcessing.load()) {
|
||||
surface.buildNextMipmap(nvtt::MipmapFilter_Box);
|
||||
context.compress(surface, face, mipLevel++, compressionOptions, outputOptions);
|
||||
}
|
||||
}
|
||||
|
||||
void generateLDRMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>& abortProcessing, int face) {
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
@ -400,10 +572,10 @@ void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>&
|
|||
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
||||
compressionOptions.setPitchAlignment(4);
|
||||
compressionOptions.setPixelFormat(32,
|
||||
0x000000FF,
|
||||
0x0000FF00,
|
||||
0x00FF0000,
|
||||
0xFF000000);
|
||||
0x000000FF,
|
||||
0x0000FF00,
|
||||
0x00FF0000,
|
||||
0xFF000000);
|
||||
inputGamma = 1.0f;
|
||||
outputGamma = 1.0f;
|
||||
} else if (mipFormat == gpu::Element::COLOR_BGRA_32) {
|
||||
|
@ -411,10 +583,10 @@ void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>&
|
|||
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
||||
compressionOptions.setPitchAlignment(4);
|
||||
compressionOptions.setPixelFormat(32,
|
||||
0x00FF0000,
|
||||
0x0000FF00,
|
||||
0x000000FF,
|
||||
0xFF000000);
|
||||
0x00FF0000,
|
||||
0x0000FF00,
|
||||
0x000000FF,
|
||||
0xFF000000);
|
||||
inputGamma = 1.0f;
|
||||
outputGamma = 1.0f;
|
||||
} else if (mipFormat == gpu::Element::COLOR_SRGBA_32) {
|
||||
|
@ -422,19 +594,19 @@ void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>&
|
|||
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
||||
compressionOptions.setPitchAlignment(4);
|
||||
compressionOptions.setPixelFormat(32,
|
||||
0x000000FF,
|
||||
0x0000FF00,
|
||||
0x00FF0000,
|
||||
0xFF000000);
|
||||
0x000000FF,
|
||||
0x0000FF00,
|
||||
0x00FF0000,
|
||||
0xFF000000);
|
||||
} else if (mipFormat == gpu::Element::COLOR_SBGRA_32) {
|
||||
compressionOptions.setFormat(nvtt::Format_RGBA);
|
||||
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
||||
compressionOptions.setPitchAlignment(4);
|
||||
compressionOptions.setPixelFormat(32,
|
||||
0x00FF0000,
|
||||
0x0000FF00,
|
||||
0x000000FF,
|
||||
0xFF000000);
|
||||
0x00FF0000,
|
||||
0x0000FF00,
|
||||
0x000000FF,
|
||||
0xFF000000);
|
||||
} else if (mipFormat == gpu::Element::COLOR_R_8) {
|
||||
compressionOptions.setFormat(nvtt::Format_RGB);
|
||||
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
||||
|
@ -454,32 +626,26 @@ void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>&
|
|||
|
||||
nvtt::OutputOptions outputOptions;
|
||||
outputOptions.setOutputHeader(false);
|
||||
MyOutputHandler outputHandler(texture, face);
|
||||
OutputHandler outputHandler(texture, face);
|
||||
outputOptions.setOutputHandler(&outputHandler);
|
||||
MyErrorHandler errorHandler;
|
||||
outputOptions.setErrorHandler(&errorHandler);
|
||||
|
||||
class SequentialTaskDispatcher : public nvtt::TaskDispatcher {
|
||||
public:
|
||||
SequentialTaskDispatcher(const std::atomic<bool>& abortProcessing) : _abortProcessing(abortProcessing) {};
|
||||
|
||||
const std::atomic<bool>& _abortProcessing;
|
||||
|
||||
virtual void dispatch(nvtt::Task* task, void* context, int count) override {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (!_abortProcessing.load()) {
|
||||
task(context, i);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SequentialTaskDispatcher dispatcher(abortProcessing);
|
||||
nvtt::Compressor compressor;
|
||||
compressor.setTaskDispatcher(&dispatcher);
|
||||
compressor.process(inputOptions, compressionOptions, outputOptions);
|
||||
}
|
||||
|
||||
void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>& abortProcessing = false, int face = -1) {
|
||||
#if CPU_MIPMAPS
|
||||
PROFILE_RANGE(resource_parse, "generateMips");
|
||||
|
||||
if (image.format() == QIMAGE_HDR_FORMAT) {
|
||||
generateHDRMips(texture, image, abortProcessing, face);
|
||||
} else {
|
||||
generateLDRMips(texture, image, abortProcessing, face);
|
||||
}
|
||||
#else
|
||||
texture->setAutoGenerateMips(true);
|
||||
#endif
|
||||
|
@ -961,6 +1127,62 @@ const CubeLayout CubeLayout::CUBEMAP_LAYOUTS[] = {
|
|||
};
|
||||
const int CubeLayout::NUM_CUBEMAP_LAYOUTS = sizeof(CubeLayout::CUBEMAP_LAYOUTS) / sizeof(CubeLayout);
|
||||
|
||||
//#define DEBUG_COLOR_PACKING
|
||||
|
||||
QImage convertToHDRFormat(QImage srcImage, gpu::Element format) {
|
||||
QImage hdrImage(srcImage.width(), srcImage.height(), (QImage::Format)QIMAGE_HDR_FORMAT);
|
||||
std::function<uint32(const glm::vec3&)> packFunc;
|
||||
#ifdef DEBUG_COLOR_PACKING
|
||||
std::function<glm::vec3(uint32)> unpackFunc;
|
||||
#endif
|
||||
|
||||
switch (format.getSemantic()) {
|
||||
case gpu::R11G11B10:
|
||||
packFunc = packR11G11B10F;
|
||||
#ifdef DEBUG_COLOR_PACKING
|
||||
unpackFunc = glm::unpackF2x11_1x10;
|
||||
#endif
|
||||
break;
|
||||
case gpu::RGB9E5:
|
||||
packFunc = glm::packF3x9_E1x5;
|
||||
#ifdef DEBUG_COLOR_PACKING
|
||||
unpackFunc = glm::unpackF3x9_E1x5;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
qCWarning(imagelogging) << "Unsupported HDR format";
|
||||
Q_UNREACHABLE();
|
||||
return srcImage;
|
||||
}
|
||||
|
||||
srcImage = srcImage.convertToFormat(QImage::Format_ARGB32);
|
||||
for (auto y = 0; y < srcImage.height(); y++) {
|
||||
const QRgb* srcLineIt = reinterpret_cast<const QRgb*>( srcImage.constScanLine(y) );
|
||||
const QRgb* srcLineEnd = srcLineIt + srcImage.width();
|
||||
uint32* hdrLineIt = reinterpret_cast<uint32*>( hdrImage.scanLine(y) );
|
||||
glm::vec3 color;
|
||||
|
||||
while (srcLineIt < srcLineEnd) {
|
||||
color.r = qRed(*srcLineIt);
|
||||
color.g = qGreen(*srcLineIt);
|
||||
color.b = qBlue(*srcLineIt);
|
||||
// Normalize and apply gamma
|
||||
color /= 255.0f;
|
||||
color.r = powf(color.r, 2.2f);
|
||||
color.g = powf(color.g, 2.2f);
|
||||
color.b = powf(color.b, 2.2f);
|
||||
*hdrLineIt = packFunc(color);
|
||||
#ifdef DEBUG_COLOR_PACKING
|
||||
glm::vec3 ucolor = unpackFunc(*hdrLineIt);
|
||||
assert(glm::distance(color, ucolor) <= 5e-2);
|
||||
#endif
|
||||
++srcLineIt;
|
||||
++hdrLineIt;
|
||||
}
|
||||
}
|
||||
return hdrImage;
|
||||
}
|
||||
|
||||
gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName,
|
||||
bool generateIrradiance,
|
||||
const std::atomic<bool>& abortProcessing) {
|
||||
|
@ -969,18 +1191,19 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage&
|
|||
gpu::TexturePointer theTexture = nullptr;
|
||||
if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
|
||||
QImage image = processSourceImage(srcImage, true);
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
gpu::Element formatMip;
|
||||
gpu::Element formatGPU;
|
||||
if (isCubeTexturesCompressionEnabled()) {
|
||||
formatMip = gpu::Element::COLOR_COMPRESSED_SRGBA_HIGH;
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_SRGBA_HIGH;
|
||||
formatMip = gpu::Element::COLOR_COMPRESSED_HDR_RGB;
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_HDR_RGB;
|
||||
} else {
|
||||
formatMip = gpu::Element::COLOR_SRGBA_32;
|
||||
formatGPU = gpu::Element::COLOR_SRGBA_32;
|
||||
formatMip = HDR_FORMAT;
|
||||
formatGPU = HDR_FORMAT;
|
||||
}
|
||||
|
||||
if (image.format() != QIMAGE_HDR_FORMAT) {
|
||||
image = convertToHDRFormat(image, HDR_FORMAT);
|
||||
}
|
||||
|
||||
// Find the layout of the cubemap in the 2D image
|
||||
|
@ -1028,9 +1251,9 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage&
|
|||
// Generate irradiance while we are at it
|
||||
if (generateIrradiance) {
|
||||
PROFILE_RANGE(resource_parse, "generateIrradiance");
|
||||
auto irradianceTexture = gpu::Texture::createCube(gpu::Element::COLOR_SRGBA_32, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
||||
auto irradianceTexture = gpu::Texture::createCube(HDR_FORMAT, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
||||
irradianceTexture->setSource(srcImageName);
|
||||
irradianceTexture->setStoredMipFormat(gpu::Element::COLOR_SBGRA_32);
|
||||
irradianceTexture->setStoredMipFormat(HDR_FORMAT);
|
||||
for (uint8 face = 0; face < faces.size(); ++face) {
|
||||
irradianceTexture->assignStoredMipFace(0, face, faces[face].byteCount(), faces[face].constBits());
|
||||
}
|
||||
|
|
|
@ -209,6 +209,137 @@ namespace khronos {
|
|||
COMPRESSED_SIGNED_RG11_EAC = 0x9273,
|
||||
};
|
||||
|
||||
inline uint8_t evalUncompressedBlockBitSize(InternalFormat format) {
|
||||
switch (format) {
|
||||
case InternalFormat::R8:
|
||||
case InternalFormat::R8_SNORM:
|
||||
return 8;
|
||||
case InternalFormat::R16:
|
||||
case InternalFormat::R16_SNORM:
|
||||
case InternalFormat::RG8:
|
||||
case InternalFormat::RG8_SNORM:
|
||||
return 16;
|
||||
case InternalFormat::RG16:
|
||||
case InternalFormat::RG16_SNORM:
|
||||
return 16;
|
||||
case InternalFormat::R3_G3_B2:
|
||||
return 8;
|
||||
case InternalFormat::RGB4:
|
||||
return 12;
|
||||
case InternalFormat::RGB5:
|
||||
case InternalFormat::RGB565:
|
||||
return 16;
|
||||
case InternalFormat::RGB8:
|
||||
case InternalFormat::RGB8_SNORM:
|
||||
return 24;
|
||||
case InternalFormat::RGB10:
|
||||
// TODO: check if this is really the case
|
||||
return 32;
|
||||
case InternalFormat::RGB12:
|
||||
// TODO: check if this is really the case
|
||||
return 48;
|
||||
case InternalFormat::RGB16:
|
||||
case InternalFormat::RGB16_SNORM:
|
||||
return 48;
|
||||
case InternalFormat::RGBA2:
|
||||
return 8;
|
||||
case InternalFormat::RGBA4:
|
||||
case InternalFormat::RGB5_A1:
|
||||
return 16;
|
||||
case InternalFormat::RGBA8:
|
||||
case InternalFormat::RGBA8_SNORM:
|
||||
case InternalFormat::RGB10_A2:
|
||||
case InternalFormat::RGB10_A2UI:
|
||||
return 32;
|
||||
case InternalFormat::RGBA12:
|
||||
return 48;
|
||||
case InternalFormat::RGBA16:
|
||||
case InternalFormat::RGBA16_SNORM:
|
||||
return 64;
|
||||
case InternalFormat::SRGB8:
|
||||
return 24;
|
||||
case InternalFormat::SRGB8_ALPHA8:
|
||||
return 32;
|
||||
case InternalFormat::R16F:
|
||||
return 16;
|
||||
case InternalFormat::RG16F:
|
||||
return 32;
|
||||
case InternalFormat::RGB16F:
|
||||
return 48;
|
||||
case InternalFormat::RGBA16F:
|
||||
return 64;
|
||||
case InternalFormat::R32F:
|
||||
return 32;
|
||||
case InternalFormat::RG32F:
|
||||
return 64;
|
||||
case InternalFormat::RGB32F:
|
||||
return 96;
|
||||
case InternalFormat::RGBA32F:
|
||||
return 128;
|
||||
case InternalFormat::R11F_G11F_B10F:
|
||||
case InternalFormat::RGB9_E5:
|
||||
return 32;
|
||||
case InternalFormat::R8I:
|
||||
case InternalFormat::R8UI:
|
||||
return 8;
|
||||
case InternalFormat::R16I:
|
||||
case InternalFormat::R16UI:
|
||||
return 16;
|
||||
case InternalFormat::R32I:
|
||||
case InternalFormat::R32UI:
|
||||
return 32;
|
||||
case InternalFormat::RG8I:
|
||||
case InternalFormat::RG8UI:
|
||||
return 16;
|
||||
case InternalFormat::RG16I:
|
||||
case InternalFormat::RG16UI:
|
||||
return 32;
|
||||
case InternalFormat::RG32I:
|
||||
case InternalFormat::RG32UI:
|
||||
return 64;
|
||||
case InternalFormat::RGB8I:
|
||||
case InternalFormat::RGB8UI:
|
||||
return 24;
|
||||
case InternalFormat::RGB16I:
|
||||
case InternalFormat::RGB16UI:
|
||||
return 48;
|
||||
case InternalFormat::RGB32I:
|
||||
case InternalFormat::RGB32UI:
|
||||
return 96;
|
||||
case InternalFormat::RGBA8I:
|
||||
case InternalFormat::RGBA8UI:
|
||||
return 32;
|
||||
case InternalFormat::RGBA16I:
|
||||
case InternalFormat::RGBA16UI:
|
||||
return 64;
|
||||
case InternalFormat::RGBA32I:
|
||||
case InternalFormat::RGBA32UI:
|
||||
return 128;
|
||||
case InternalFormat::DEPTH_COMPONENT16:
|
||||
return 16;
|
||||
case InternalFormat::DEPTH_COMPONENT24:
|
||||
return 24;
|
||||
case InternalFormat::DEPTH_COMPONENT32:
|
||||
case InternalFormat::DEPTH_COMPONENT32F:
|
||||
case InternalFormat::DEPTH24_STENCIL8:
|
||||
return 32;
|
||||
case InternalFormat::DEPTH32F_STENCIL8:
|
||||
// TODO : check if this true
|
||||
return 40;
|
||||
case InternalFormat::STENCIL_INDEX1:
|
||||
return 1;
|
||||
case InternalFormat::STENCIL_INDEX4:
|
||||
return 4;
|
||||
case InternalFormat::STENCIL_INDEX8:
|
||||
return 8;
|
||||
case InternalFormat::STENCIL_INDEX16:
|
||||
return 16;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <uint32_t ALIGNMENT>
|
||||
inline uint32_t evalAlignedCompressedBlockCount(uint32_t value) {
|
||||
enum { val = ALIGNMENT && !(ALIGNMENT & (ALIGNMENT - 1)) };
|
||||
|
@ -225,6 +356,7 @@ namespace khronos {
|
|||
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: // BC3
|
||||
case InternalFormat::COMPRESSED_RED_RGTC1: // BC4
|
||||
case InternalFormat::COMPRESSED_RG_RGTC2: // BC5
|
||||
case InternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: // BC6
|
||||
case InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM: // BC7
|
||||
return evalAlignedCompressedBlockCount<4>(value);
|
||||
|
||||
|
@ -241,6 +373,7 @@ namespace khronos {
|
|||
return 8;
|
||||
|
||||
case InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||
case InternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
|
||||
case InternalFormat::COMPRESSED_RG_RGTC2:
|
||||
return 16;
|
||||
|
@ -250,6 +383,10 @@ namespace khronos {
|
|||
}
|
||||
}
|
||||
|
||||
inline uint8_t evalCompressedBlockBitSize(InternalFormat format) {
|
||||
return evalCompressedBlockSize(format) * 8;
|
||||
}
|
||||
|
||||
enum class BaseInternalFormat : uint32_t {
|
||||
// GL 4.4 Table 8.11
|
||||
DEPTH_COMPONENT = 0x1902,
|
||||
|
|
|
@ -54,15 +54,13 @@ uint32_t Header::evalPixelOrBlockDepth(uint32_t level) const {
|
|||
return evalMipDimension(level, getPixelDepth());
|
||||
}
|
||||
|
||||
size_t Header::evalPixelOrBlockSize() const {
|
||||
size_t Header::evalPixelOrBlockBitSize() const {
|
||||
size_t result = 0;
|
||||
auto format = getGLInternaFormat();
|
||||
if (isCompressed()) {
|
||||
auto format = getGLInternaFormat();
|
||||
result = khronos::gl::texture::evalCompressedBlockSize(format);
|
||||
result = khronos::gl::texture::evalCompressedBlockBitSize(format);
|
||||
} else {
|
||||
// FIXME should really be using the internal format, not the base internal format
|
||||
auto baseFormat = getGLBaseInternalFormat();
|
||||
result = khronos::gl::texture::evalComponentCount(baseFormat);
|
||||
result = khronos::gl::texture::evalUncompressedBlockBitSize(format);
|
||||
}
|
||||
|
||||
if (0 == result) {
|
||||
|
@ -73,11 +71,14 @@ size_t Header::evalPixelOrBlockSize() const {
|
|||
|
||||
size_t Header::evalRowSize(uint32_t level) const {
|
||||
auto pixWidth = evalPixelOrBlockWidth(level);
|
||||
auto pixSize = evalPixelOrBlockSize();
|
||||
auto pixSize = evalPixelOrBlockBitSize();
|
||||
if (pixSize == 0) {
|
||||
return 0;
|
||||
}
|
||||
return evalPaddedSize(pixWidth * pixSize);
|
||||
auto totalByteSize = pixWidth * pixSize;
|
||||
// Round to the nearest upper byte size
|
||||
totalByteSize = (totalByteSize / 8) + (((totalByteSize % 8) != 0) & 1);
|
||||
return evalPaddedSize(totalByteSize);
|
||||
}
|
||||
|
||||
size_t Header::evalFaceSize(uint32_t level) const {
|
||||
|
|
|
@ -170,7 +170,7 @@ namespace ktx {
|
|||
uint32_t evalPixelOrBlockHeight(uint32_t level) const;
|
||||
uint32_t evalPixelOrBlockDepth(uint32_t level) const;
|
||||
|
||||
size_t evalPixelOrBlockSize() const;
|
||||
size_t evalPixelOrBlockBitSize() const;
|
||||
size_t evalRowSize(uint32_t level) const;
|
||||
size_t evalFaceSize(uint32_t level) const;
|
||||
size_t evalImageSize(uint32_t level) const;
|
||||
|
|
|
@ -71,14 +71,14 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) {
|
|||
} else {
|
||||
QUrl url = _url.resolved(filename);
|
||||
|
||||
QString texdir = mapping.value("texdir").toString();
|
||||
QString texdir = mapping.value(TEXDIR_FIELD).toString();
|
||||
if (!texdir.isNull()) {
|
||||
if (!texdir.endsWith('/')) {
|
||||
texdir += '/';
|
||||
}
|
||||
_textureBaseUrl = resolveTextureBaseUrl(url, _url.resolved(texdir));
|
||||
} else {
|
||||
_textureBaseUrl = _effectiveBaseURL;
|
||||
_textureBaseUrl = url.resolved(QUrl("."));
|
||||
}
|
||||
|
||||
auto animGraphVariant = mapping.value("animGraphUrl");
|
||||
|
@ -241,8 +241,10 @@ private:
|
|||
};
|
||||
|
||||
void GeometryDefinitionResource::downloadFinished(const QByteArray& data) {
|
||||
_url = _effectiveBaseURL;
|
||||
_textureBaseUrl = _effectiveBaseURL;
|
||||
if (_url != _effectiveBaseURL) {
|
||||
_url = _effectiveBaseURL;
|
||||
_textureBaseUrl = _effectiveBaseURL;
|
||||
}
|
||||
QThreadPool::globalInstance()->start(new GeometryReader(_self, _effectiveBaseURL, _mapping, data, _combineParts));
|
||||
}
|
||||
|
||||
|
|
|
@ -155,6 +155,7 @@ void AssetResourceRequest::requestHash(const AssetHash& hash) {
|
|||
case AssetRequest::Error::NoError:
|
||||
_data = req->getData();
|
||||
_result = Success;
|
||||
recordBytesDownloadedInStats(STAT_ATP_RESOURCE_TOTAL_BYTES, _data.size());
|
||||
break;
|
||||
case AssetRequest::InvalidHash:
|
||||
_result = InvalidURL;
|
||||
|
@ -202,9 +203,8 @@ void AssetResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytes
|
|||
emit progress(bytesReceived, bytesTotal);
|
||||
|
||||
auto now = p_high_resolution_clock::now();
|
||||
|
||||
// Recording ATP bytes downloaded in stats
|
||||
DependencyManager::get<StatTracker>()->updateStat(STAT_ATP_RESOURCE_TOTAL_BYTES, bytesReceived);
|
||||
|
||||
recordBytesDownloadedInStats(STAT_ATP_RESOURCE_TOTAL_BYTES, bytesReceived);
|
||||
|
||||
// if we haven't received the full asset check if it is time to output progress to log
|
||||
// we do so every X seconds to assist with ATP download tracking
|
||||
|
|
|
@ -41,6 +41,8 @@ private:
|
|||
AssetRequest* _assetRequest { nullptr };
|
||||
|
||||
p_high_resolution_clock::time_point _lastProgressDebug;
|
||||
|
||||
int64_t _lastRecordedBytesDownloaded { 0 };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -69,8 +69,7 @@ void FileResourceRequest::doSend() {
|
|||
|
||||
if (_result == ResourceRequest::Success) {
|
||||
statTracker->incrementStat(STAT_FILE_REQUEST_SUCCESS);
|
||||
// Recording FILE bytes downloaded in stats
|
||||
statTracker->updateStat(STAT_FILE_RESOURCE_TOTAL_BYTES,fileSize);
|
||||
statTracker->updateStat(STAT_FILE_RESOURCE_TOTAL_BYTES, fileSize);
|
||||
} else {
|
||||
statTracker->incrementStat(STAT_FILE_REQUEST_FAILED);
|
||||
}
|
||||
|
|
|
@ -141,6 +141,8 @@ void HTTPResourceRequest::onRequestFinished() {
|
|||
}
|
||||
}
|
||||
|
||||
recordBytesDownloadedInStats(STAT_HTTP_RESOURCE_TOTAL_BYTES, _data.size());
|
||||
|
||||
break;
|
||||
|
||||
case QNetworkReply::TimeoutError:
|
||||
|
@ -201,11 +203,8 @@ void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesT
|
|||
_sendTimer->start();
|
||||
|
||||
emit progress(bytesReceived, bytesTotal);
|
||||
|
||||
// Recording HTTP bytes downloaded in stats
|
||||
DependencyManager::get<StatTracker>()->updateStat(STAT_HTTP_RESOURCE_TOTAL_BYTES, bytesReceived);
|
||||
|
||||
|
||||
|
||||
recordBytesDownloadedInStats(STAT_HTTP_RESOURCE_TOTAL_BYTES, bytesReceived);
|
||||
}
|
||||
|
||||
void HTTPResourceRequest::onTimeout() {
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
#include "ResourceRequest.h"
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <StatTracker.h>
|
||||
|
||||
#include <QtCore/QThread>
|
||||
|
||||
ResourceRequest::ResourceRequest(const QUrl& url) : _url(url) { }
|
||||
|
@ -40,3 +43,11 @@ QString ResourceRequest::getResultString() const {
|
|||
default: return "Unspecified Error";
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceRequest::recordBytesDownloadedInStats(const QString& statName, int64_t bytesReceived) {
|
||||
auto dBytes = bytesReceived - _lastRecordedBytesDownloaded;
|
||||
if (dBytes > 0) {
|
||||
_lastRecordedBytesDownloaded = bytesReceived;
|
||||
DependencyManager::get<StatTracker>()->updateStat(statName, dBytes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ signals:
|
|||
|
||||
protected:
|
||||
virtual void doSend() = 0;
|
||||
void recordBytesDownloadedInStats(const QString& statName, int64_t bytesReceived);
|
||||
|
||||
QUrl _url;
|
||||
QUrl _relativePathURL;
|
||||
|
@ -97,6 +98,7 @@ protected:
|
|||
ByteRange _byteRange;
|
||||
bool _rangeRequestSuccessful { false };
|
||||
uint64_t _totalSizeOfResource { 0 };
|
||||
int64_t _lastRecordedBytesDownloaded { 0 };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,4 +33,13 @@ void DisplayPlugin::waitForPresent() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> DisplayPlugin::getHUDOperator() {
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> hudOperator;
|
||||
{
|
||||
QMutexLocker locker(&_presentMutex);
|
||||
hudOperator = _hudOperator;
|
||||
}
|
||||
return hudOperator;
|
||||
}
|
|
@ -156,8 +156,8 @@ public:
|
|||
return aspect(getRecommendedRenderSize());
|
||||
}
|
||||
|
||||
// The recommended bounds for primary overlay placement
|
||||
virtual QRect getRecommendedOverlayRect() const {
|
||||
// The recommended bounds for primary HUD placement
|
||||
virtual QRect getRecommendedHUDRect() const {
|
||||
const int DESKTOP_SCREEN_PADDING = 50;
|
||||
auto recommendedSize = getRecommendedUiSize() - glm::uvec2(DESKTOP_SCREEN_PADDING);
|
||||
return QRect(0, 0, recommendedSize.x, recommendedSize.y);
|
||||
|
@ -204,8 +204,9 @@ public:
|
|||
|
||||
void waitForPresent();
|
||||
|
||||
static const QString& MENU_PATH();
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator();
|
||||
|
||||
static const QString& MENU_PATH();
|
||||
|
||||
signals:
|
||||
void recommendedFramebufferSizeChanged(const QSize& size);
|
||||
|
@ -217,6 +218,8 @@ protected:
|
|||
|
||||
gpu::ContextPointer _gpuContext;
|
||||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> _hudOperator { std::function<void(gpu::Batch&, const gpu::TexturePointer&)>() };
|
||||
|
||||
private:
|
||||
QMutex _presentMutex;
|
||||
QWaitCondition _presentCondition;
|
||||
|
|
|
@ -68,8 +68,6 @@ static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT;
|
|||
|
||||
static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normals
|
||||
static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3);
|
||||
static const gpu::Type SHAPE_INDEX_TYPE = gpu::UINT32;
|
||||
static const uint SHAPE_INDEX_SIZE = sizeof(gpu::uint32);
|
||||
|
||||
template <size_t SIDES>
|
||||
std::vector<vec3> polygon() {
|
||||
|
@ -84,67 +82,83 @@ std::vector<vec3> polygon() {
|
|||
}
|
||||
|
||||
void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices) {
|
||||
gpu::Buffer::Size offset = vertexBuffer->getSize();
|
||||
vertexBuffer->append(vertices);
|
||||
|
||||
_positionView = gpu::BufferView(vertexBuffer, 0,
|
||||
vertexBuffer->getSize(), SHAPE_VERTEX_STRIDE, POSITION_ELEMENT);
|
||||
_normalView = gpu::BufferView(vertexBuffer, SHAPE_NORMALS_OFFSET,
|
||||
vertexBuffer->getSize(), SHAPE_VERTEX_STRIDE, NORMAL_ELEMENT);
|
||||
gpu::Buffer::Size viewSize = vertices.size() * 2 * sizeof(glm::vec3);
|
||||
|
||||
_positionView = gpu::BufferView(vertexBuffer, offset,
|
||||
viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT);
|
||||
_normalView = gpu::BufferView(vertexBuffer, offset + SHAPE_NORMALS_OFFSET,
|
||||
viewSize, SHAPE_VERTEX_STRIDE, NORMAL_ELEMENT);
|
||||
}
|
||||
|
||||
void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices) {
|
||||
_indices = indexBuffer;
|
||||
gpu::Buffer::Size offset = indexBuffer->getSize();
|
||||
if (!indices.empty()) {
|
||||
_indexOffset = indexBuffer->getSize() / SHAPE_INDEX_SIZE;
|
||||
_indexCount = indices.size();
|
||||
indexBuffer->append(indices);
|
||||
for (uint32_t i = 0; i < indices.size(); ++i) {
|
||||
indexBuffer->append((uint16_t)indices[i]);
|
||||
}
|
||||
}
|
||||
gpu::Size viewSize = indices.size() * sizeof(uint16_t);
|
||||
_indicesView = gpu::BufferView(indexBuffer, offset, viewSize, gpu::Element::INDEX_UINT16);
|
||||
|
||||
offset = indexBuffer->getSize();
|
||||
if (!wireIndices.empty()) {
|
||||
_wireIndexOffset = indexBuffer->getSize() / SHAPE_INDEX_SIZE;
|
||||
_wireIndexCount = wireIndices.size();
|
||||
indexBuffer->append(wireIndices);
|
||||
for (uint32_t i = 0; i < wireIndices.size(); ++i) {
|
||||
indexBuffer->append((uint16_t)wireIndices[i]);
|
||||
}
|
||||
}
|
||||
viewSize = wireIndices.size() * sizeof(uint16_t);
|
||||
_wireIndicesView = gpu::BufferView(indexBuffer, offset, viewSize, gpu::Element::INDEX_UINT16);
|
||||
}
|
||||
|
||||
void GeometryCache::ShapeData::setupBatch(gpu::Batch& batch) const {
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, _positionView);
|
||||
batch.setInputBuffer(gpu::Stream::NORMAL, _normalView);
|
||||
batch.setIndexBuffer(SHAPE_INDEX_TYPE, _indices, 0);
|
||||
batch.setIndexBuffer(_indicesView);
|
||||
}
|
||||
|
||||
void GeometryCache::ShapeData::draw(gpu::Batch& batch) const {
|
||||
if (_indexCount) {
|
||||
uint32_t numIndices = (uint32_t)_indicesView.getNumElements();
|
||||
if (numIndices > 0) {
|
||||
setupBatch(batch);
|
||||
batch.drawIndexed(gpu::TRIANGLES, (gpu::uint32)_indexCount, (gpu::uint32)_indexOffset);
|
||||
batch.drawIndexed(gpu::TRIANGLES, numIndices, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryCache::ShapeData::drawWire(gpu::Batch& batch) const {
|
||||
if (_wireIndexCount) {
|
||||
setupBatch(batch);
|
||||
batch.drawIndexed(gpu::LINES, (gpu::uint32)_wireIndexCount, (gpu::uint32)_wireIndexOffset);
|
||||
uint32_t numIndices = (uint32_t)_wireIndicesView.getNumElements();
|
||||
if (numIndices > 0) {
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, _positionView);
|
||||
batch.setInputBuffer(gpu::Stream::NORMAL, _normalView);
|
||||
batch.setIndexBuffer(_wireIndicesView);
|
||||
batch.drawIndexed(gpu::LINES, numIndices, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryCache::ShapeData::drawInstances(gpu::Batch& batch, size_t count) const {
|
||||
if (_indexCount) {
|
||||
uint32_t numIndices = (uint32_t)_indicesView.getNumElements();
|
||||
if (numIndices > 0) {
|
||||
setupBatch(batch);
|
||||
batch.drawIndexedInstanced((gpu::uint32)count, gpu::TRIANGLES, (gpu::uint32)_indexCount, (gpu::uint32)_indexOffset);
|
||||
batch.drawIndexedInstanced((gpu::uint32)count, gpu::TRIANGLES, numIndices, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryCache::ShapeData::drawWireInstances(gpu::Batch& batch, size_t count) const {
|
||||
if (_wireIndexCount) {
|
||||
setupBatch(batch);
|
||||
batch.drawIndexedInstanced((gpu::uint32)count, gpu::LINES, (gpu::uint32)_wireIndexCount, (gpu::uint32)_wireIndexOffset);
|
||||
uint32_t numIndices = (uint32_t)_wireIndicesView.getNumElements();
|
||||
if (numIndices > 0) {
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, _positionView);
|
||||
batch.setInputBuffer(gpu::Stream::NORMAL, _normalView);
|
||||
batch.setIndexBuffer(_wireIndicesView);
|
||||
batch.drawIndexedInstanced((gpu::uint32)count, gpu::LINES, numIndices, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static const size_t ICOSAHEDRON_TO_SPHERE_TESSELATION_COUNT = 3;
|
||||
|
||||
size_t GeometryCache::getShapeTriangleCount(Shape shape) {
|
||||
return _shapes[shape]._indexCount / VERTICES_PER_TRIANGLE;
|
||||
return _shapes[shape]._indicesView.getNumElements() / VERTICES_PER_TRIANGLE;
|
||||
}
|
||||
|
||||
size_t GeometryCache::getSphereTriangleCount() {
|
||||
|
@ -168,7 +182,6 @@ static IndexPair indexToken(geometry::Index a, geometry::Index b) {
|
|||
template <size_t N>
|
||||
void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
|
||||
using namespace geometry;
|
||||
Index baseVertex = (Index)(vertexBuffer->getSize() / SHAPE_VERTEX_STRIDE);
|
||||
VertexVector vertices;
|
||||
IndexVector solidIndices, wireIndices;
|
||||
IndexPairs wireSeenIndices;
|
||||
|
@ -179,6 +192,7 @@ void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N
|
|||
vertices.reserve(N * faceCount * 2);
|
||||
solidIndices.reserve(faceIndexCount * faceCount);
|
||||
|
||||
Index baseVertex = 0;
|
||||
for (size_t f = 0; f < faceCount; f++) {
|
||||
const Face<N>& face = shape.faces[f];
|
||||
// Compute the face normal
|
||||
|
@ -219,7 +233,6 @@ void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N
|
|||
template <size_t N>
|
||||
void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
|
||||
using namespace geometry;
|
||||
Index baseVertex = (Index)(vertexBuffer->getSize() / SHAPE_VERTEX_STRIDE);
|
||||
|
||||
VertexVector vertices;
|
||||
vertices.reserve(shape.vertices.size() * 2);
|
||||
|
@ -236,6 +249,7 @@ void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid
|
|||
|
||||
solidIndices.reserve(faceIndexCount * faceCount);
|
||||
|
||||
Index baseVertex = 0;
|
||||
for (size_t f = 0; f < faceCount; f++) {
|
||||
const Face<N>& face = shape.faces[f];
|
||||
// Create the wire indices for unseen edges
|
||||
|
@ -265,7 +279,6 @@ void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid
|
|||
template <uint32_t N>
|
||||
void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer, bool isConical = false) {
|
||||
using namespace geometry;
|
||||
Index baseVertex = (Index)(vertexBuffer->getSize() / SHAPE_VERTEX_STRIDE);
|
||||
VertexVector vertices;
|
||||
IndexVector solidIndices, wireIndices;
|
||||
|
||||
|
@ -286,6 +299,7 @@ void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& ver
|
|||
vertices.push_back(vec3(v.x, -0.5f, v.z));
|
||||
vertices.push_back(vec3(0.0f, -1.0f, 0.0f));
|
||||
}
|
||||
Index baseVertex = 0;
|
||||
for (uint32_t i = 2; i < N; i++) {
|
||||
solidIndices.push_back(baseVertex + 0);
|
||||
solidIndices.push_back(baseVertex + i);
|
||||
|
@ -343,7 +357,6 @@ void drawCircle(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexB
|
|||
// Draw a circle with radius 1/4th the size of the bounding box
|
||||
using namespace geometry;
|
||||
|
||||
Index baseVertex = (Index)(vertexBuffer->getSize() / SHAPE_VERTEX_STRIDE);
|
||||
VertexVector vertices;
|
||||
IndexVector solidIndices, wireIndices;
|
||||
const int NUM_CIRCLE_VERTICES = 64;
|
||||
|
@ -354,6 +367,7 @@ void drawCircle(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexB
|
|||
vertices.push_back(vec3(0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
Index baseVertex = 0;
|
||||
for (uint32_t i = 2; i < NUM_CIRCLE_VERTICES; i++) {
|
||||
solidIndices.push_back(baseVertex + 0);
|
||||
solidIndices.push_back(baseVertex + i);
|
||||
|
@ -403,7 +417,6 @@ void GeometryCache::buildShapes() {
|
|||
|
||||
// Line
|
||||
{
|
||||
Index baseVertex = (Index)(_shapeVertices->getSize() / SHAPE_VERTEX_STRIDE);
|
||||
ShapeData& shapeData = _shapes[Line];
|
||||
shapeData.setupVertices(_shapeVertices, VertexVector {
|
||||
vec3(-0.5f, 0.0f, 0.0f), vec3(-0.5f, 0.0f, 0.0f),
|
||||
|
@ -411,8 +424,8 @@ void GeometryCache::buildShapes() {
|
|||
});
|
||||
IndexVector wireIndices;
|
||||
// Only two indices
|
||||
wireIndices.push_back(0 + baseVertex);
|
||||
wireIndices.push_back(1 + baseVertex);
|
||||
wireIndices.push_back(0);
|
||||
wireIndices.push_back(1);
|
||||
shapeData.setupIndices(_shapeIndices, IndexVector(), wireIndices);
|
||||
}
|
||||
|
||||
|
|
|
@ -339,14 +339,10 @@ public:
|
|||
void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false);
|
||||
|
||||
struct ShapeData {
|
||||
size_t _indexOffset{ 0 };
|
||||
size_t _indexCount{ 0 };
|
||||
size_t _wireIndexOffset{ 0 };
|
||||
size_t _wireIndexCount{ 0 };
|
||||
|
||||
gpu::BufferView _positionView;
|
||||
gpu::BufferView _normalView;
|
||||
gpu::BufferPointer _indices;
|
||||
gpu::BufferView _indicesView;
|
||||
gpu::BufferView _wireIndicesView;
|
||||
|
||||
void setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices);
|
||||
void setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices);
|
||||
|
|
|
@ -385,7 +385,7 @@ ItemKey ModelMeshPartPayload::getKey() const {
|
|||
builder.withInvisible();
|
||||
}
|
||||
|
||||
if (model->isLayeredInFront()) {
|
||||
if (model->isLayeredInFront() || model->isLayeredInHUD()) {
|
||||
builder.withLayered();
|
||||
}
|
||||
|
||||
|
@ -404,15 +404,15 @@ ItemKey ModelMeshPartPayload::getKey() const {
|
|||
}
|
||||
|
||||
int ModelMeshPartPayload::getLayer() const {
|
||||
// MAgic number while we are defining the layering mechanism:
|
||||
const int LAYER_3D_FRONT = 1;
|
||||
const int LAYER_3D = 0;
|
||||
ModelPointer model = _model.lock();
|
||||
if (model && model->isLayeredInFront()) {
|
||||
return LAYER_3D_FRONT;
|
||||
} else {
|
||||
return LAYER_3D;
|
||||
if (model) {
|
||||
if (model->isLayeredInFront()) {
|
||||
return Item::LAYER_3D_FRONT;
|
||||
} else if (model->isLayeredInHUD()) {
|
||||
return Item::LAYER_3D_HUD;
|
||||
}
|
||||
}
|
||||
return Item::LAYER_3D;
|
||||
}
|
||||
|
||||
ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
||||
|
|
|
@ -603,6 +603,21 @@ void Model::setLayeredInFront(bool layered, const render::ScenePointer& scene) {
|
|||
}
|
||||
}
|
||||
|
||||
void Model::setLayeredInHUD(bool layered, const render::ScenePointer& scene) {
|
||||
if (_isLayeredInHUD != layered) {
|
||||
_isLayeredInHUD = layered;
|
||||
|
||||
render::Transaction transaction;
|
||||
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
|
||||
transaction.resetItem(item, _modelMeshRenderItemsMap[item]);
|
||||
}
|
||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||
transaction.resetItem(item, _collisionRenderItemsMap[item]);
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
bool Model::addToScene(const render::ScenePointer& scene,
|
||||
render::Transaction& transaction,
|
||||
render::Item::Status::Getters& statusGetters) {
|
||||
|
|
|
@ -84,6 +84,7 @@ public:
|
|||
// new Scene/Engine rendering support
|
||||
void setVisibleInScene(bool newValue, const render::ScenePointer& scene);
|
||||
void setLayeredInFront(bool layered, const render::ScenePointer& scene);
|
||||
void setLayeredInHUD(bool layered, const render::ScenePointer& scene);
|
||||
bool needsFixupInScene() const;
|
||||
|
||||
bool needsReload() const { return _needsReload; }
|
||||
|
@ -101,6 +102,7 @@ public:
|
|||
bool isVisible() const { return _isVisible; }
|
||||
|
||||
bool isLayeredInFront() const { return _isLayeredInFront; }
|
||||
bool isLayeredInHUD() const { return _isLayeredInHUD; }
|
||||
|
||||
virtual void updateRenderItems();
|
||||
void setRenderItemsNeedUpdate();
|
||||
|
@ -411,6 +413,7 @@ protected:
|
|||
int _renderInfoHasTransparent { false };
|
||||
|
||||
bool _isLayeredInFront { false };
|
||||
bool _isLayeredInHUD { false };
|
||||
|
||||
private:
|
||||
float _loadingPriority { 0.0f };
|
||||
|
|
|
@ -186,15 +186,20 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
task.addJob<DrawBounds>("DrawZones", zones);
|
||||
}
|
||||
|
||||
// Overlays
|
||||
const auto overlayOpaquesInputs = DrawOverlay3D::Inputs(overlayOpaques, lightingModel).asVarying();
|
||||
const auto overlayTransparentsInputs = DrawOverlay3D::Inputs(overlayTransparents, lightingModel).asVarying();
|
||||
task.addJob<DrawOverlay3D>("DrawOverlay3DOpaque", overlayOpaquesInputs, true);
|
||||
task.addJob<DrawOverlay3D>("DrawOverlay3DTransparent", overlayTransparentsInputs, false);
|
||||
// Layered Overlays
|
||||
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, Item::LAYER_3D_FRONT);
|
||||
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, Item::LAYER_3D_FRONT);
|
||||
const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(0);
|
||||
const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(0);
|
||||
|
||||
{ // Debug the bounds of the rendered Overlay items, still look at the zbuffer
|
||||
task.addJob<DrawBounds>("DrawOverlayOpaqueBounds", overlayOpaques);
|
||||
task.addJob<DrawBounds>("DrawOverlayTransparentBounds", overlayTransparents);
|
||||
const auto overlayInFrontOpaquesInputs = DrawOverlay3D::Inputs(overlaysInFrontOpaque, lightingModel).asVarying();
|
||||
const auto overlayInFrontTransparentsInputs = DrawOverlay3D::Inputs(overlaysInFrontTransparent, lightingModel).asVarying();
|
||||
task.addJob<DrawOverlay3D>("DrawOverlayInFrontOpaque", overlayInFrontOpaquesInputs, true);
|
||||
task.addJob<DrawOverlay3D>("DrawOverlayInFrontTransparent", overlayInFrontTransparentsInputs, false);
|
||||
|
||||
{ // Debug the bounds of the rendered Overlay items that are marked drawInFront, still look at the zbuffer
|
||||
task.addJob<DrawBounds>("DrawOverlayInFrontOpaqueBounds", overlaysInFrontOpaque);
|
||||
task.addJob<DrawBounds>("DrawOverlayInFrontTransparentBounds", overlaysInFrontTransparent);
|
||||
}
|
||||
|
||||
// Debugging stages
|
||||
|
@ -233,6 +238,22 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
// AA job to be revisited
|
||||
task.addJob<Antialiasing>("Antialiasing", primaryFramebuffer);
|
||||
|
||||
// Composite the HUD and HUD overlays
|
||||
task.addJob<CompositeHUD>("HUD");
|
||||
|
||||
const auto overlaysHUDOpaque = filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(1);
|
||||
const auto overlaysHUDTransparent = filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(1);
|
||||
|
||||
const auto overlayHUDOpaquesInputs = DrawOverlay3D::Inputs(overlaysHUDOpaque, lightingModel).asVarying();
|
||||
const auto overlayHUDTransparentsInputs = DrawOverlay3D::Inputs(overlaysHUDTransparent, lightingModel).asVarying();
|
||||
task.addJob<DrawOverlay3D>("DrawOverlayHUDOpaque", overlayHUDOpaquesInputs, true);
|
||||
task.addJob<DrawOverlay3D>("DrawOverlayHUDTransparent", overlayHUDTransparentsInputs, false);
|
||||
|
||||
{ // Debug the bounds of the rendered Overlay items that are marked drawHUDLayer, still look at the zbuffer
|
||||
task.addJob<DrawBounds>("DrawOverlayHUDOpaqueBounds", overlaysHUDOpaque);
|
||||
task.addJob<DrawBounds>("DrawOverlayHUDTransparentBounds", overlaysHUDTransparent);
|
||||
}
|
||||
|
||||
task.addJob<EndGPURangeTimer>("ToneAndPostRangeTimer", toneAndPostRangeTimer);
|
||||
|
||||
// Blit!
|
||||
|
@ -407,6 +428,18 @@ void DrawOverlay3D::run(const RenderContextPointer& renderContext, const Inputs&
|
|||
}
|
||||
}
|
||||
|
||||
void CompositeHUD::run(const RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_context);
|
||||
|
||||
// Grab the HUD texture
|
||||
gpu::doInBatch(renderContext->args->_context, [&](gpu::Batch& batch) {
|
||||
if (renderContext->args->_hudOperator) {
|
||||
renderContext->args->_hudOperator(batch, renderContext->args->_hudTexture);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Blit::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_context);
|
||||
|
|
|
@ -155,6 +155,14 @@ protected:
|
|||
bool _opaquePass { true };
|
||||
};
|
||||
|
||||
class CompositeHUD {
|
||||
public:
|
||||
using JobModel = render::Job::Model<CompositeHUD>;
|
||||
|
||||
CompositeHUD() {}
|
||||
void run(const render::RenderContextPointer& renderContext);
|
||||
};
|
||||
|
||||
class Blit {
|
||||
public:
|
||||
using JobModel = render::Job::ModelI<Blit, gpu::FramebufferPointer>;
|
||||
|
|
37
libraries/render-utils/src/hmd_ui.slf
Normal file
37
libraries/render-utils/src/hmd_ui.slf
Normal file
|
@ -0,0 +1,37 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// hmd_ui.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gondelman on 9/28/17.
|
||||
// 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
|
||||
//
|
||||
|
||||
uniform sampler2D hudTexture;
|
||||
|
||||
struct HUDData {
|
||||
float alpha;
|
||||
};
|
||||
|
||||
layout(std140) uniform hudBuffer {
|
||||
HUDData hud;
|
||||
};
|
||||
|
||||
in vec2 _texCoord0;
|
||||
|
||||
out vec4 fragColor0;
|
||||
|
||||
void main() {
|
||||
vec4 color = texture(hudTexture, _texCoord0);
|
||||
color.a *= hud.alpha;
|
||||
if (color.a <= 0.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
fragColor0 = color;
|
||||
}
|
36
libraries/render-utils/src/hmd_ui.slv
Normal file
36
libraries/render-utils/src/hmd_ui.slv
Normal file
|
@ -0,0 +1,36 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// hmd_ui.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Sam Gondelman on 9/28/17.
|
||||
// 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
|
||||
//
|
||||
|
||||
<@include gpu/Inputs.slh@>
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
struct HUDData {
|
||||
float alpha;
|
||||
};
|
||||
|
||||
layout(std140) uniform hudBuffer {
|
||||
HUDData hud;
|
||||
};
|
||||
|
||||
out vec2 _texCoord0;
|
||||
|
||||
void main() {
|
||||
_texCoord0 = inTexCoord0.st;
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
|
||||
}
|
|
@ -121,6 +121,9 @@ namespace render {
|
|||
RenderDetails _details;
|
||||
render::ScenePointer _scene;
|
||||
int8_t _cameraMode { -1 };
|
||||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> _hudOperator;
|
||||
gpu::TexturePointer _hudTexture;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -21,19 +21,24 @@
|
|||
|
||||
using namespace render;
|
||||
|
||||
void FilterLayeredItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
|
||||
void FilterLayeredItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, Outputs& outputs) {
|
||||
auto& scene = renderContext->_scene;
|
||||
|
||||
// Clear previous values
|
||||
outItems.clear();
|
||||
ItemBounds matchedItems;
|
||||
ItemBounds nonMatchItems;
|
||||
|
||||
// For each item, filter it into one bucket
|
||||
for (auto& itemBound : inItems) {
|
||||
auto& item = scene->getItem(itemBound.id);
|
||||
if (item.getLayer() == _keepLayer) {
|
||||
outItems.emplace_back(itemBound);
|
||||
matchedItems.emplace_back(itemBound);
|
||||
} else {
|
||||
nonMatchItems.emplace_back(itemBound);
|
||||
}
|
||||
}
|
||||
|
||||
outputs.edit0() = matchedItems;
|
||||
outputs.edit1() = nonMatchItems;
|
||||
}
|
||||
|
||||
void SliceItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
|
||||
|
|
|
@ -65,15 +65,15 @@ namespace render {
|
|||
// Filter the items belonging to the job's keep layer
|
||||
class FilterLayeredItems {
|
||||
public:
|
||||
using JobModel = Job::ModelIO<FilterLayeredItems, ItemBounds, ItemBounds>;
|
||||
using Outputs = render::VaryingSet2<ItemBounds, ItemBounds>;
|
||||
using JobModel = Job::ModelIO<FilterLayeredItems, ItemBounds, Outputs>;
|
||||
|
||||
FilterLayeredItems() {}
|
||||
FilterLayeredItems(int keepLayer) :
|
||||
_keepLayer(keepLayer) {}
|
||||
|
||||
int _keepLayer { 0 };
|
||||
int _keepLayer;
|
||||
|
||||
void run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems);
|
||||
void run(const RenderContextPointer& renderContext, const ItemBounds& inItems, Outputs& outputs);
|
||||
};
|
||||
|
||||
// SliceItems job config defining the slice range
|
||||
|
|
|
@ -29,6 +29,11 @@ const float Item::Status::Value::CYAN = 180.0f;
|
|||
const float Item::Status::Value::BLUE = 240.0f;
|
||||
const float Item::Status::Value::MAGENTA = 300.0f;
|
||||
|
||||
const int Item::LAYER_2D = 0;
|
||||
const int Item::LAYER_3D = 1;
|
||||
const int Item::LAYER_3D_FRONT = 2;
|
||||
const int Item::LAYER_3D_HUD = 3;
|
||||
|
||||
void Item::Status::Value::setScale(float scale) {
|
||||
_scale = (std::numeric_limits<unsigned short>::max() -1) * 0.5f * (1.0f + std::max(std::min(scale, 1.0f), 0.0f));
|
||||
}
|
||||
|
|
|
@ -356,9 +356,14 @@ public:
|
|||
// Get the bound of the item expressed in world space (or eye space depending on the key.isWorldSpace())
|
||||
const Bound getBound() const { return _payload->getBound(); }
|
||||
|
||||
// Get the layer where the item belongs. 0 by default meaning NOT LAYERED
|
||||
// Get the layer where the item belongs.
|
||||
int getLayer() const { return _payload->getLayer(); }
|
||||
|
||||
static const int LAYER_2D;
|
||||
static const int LAYER_3D;
|
||||
static const int LAYER_3D_FRONT;
|
||||
static const int LAYER_3D_HUD;
|
||||
|
||||
// Render call for the item
|
||||
void render(RenderArgs* args) const { _payload->render(args); }
|
||||
|
||||
|
|
|
@ -14,15 +14,15 @@ StatTracker::StatTracker() {
|
|||
|
||||
QVariant StatTracker::getStat(const QString& name) {
|
||||
std::lock_guard<std::mutex> lock(_statsLock);
|
||||
return _stats[name];
|
||||
return QVariant::fromValue<int64_t>(_stats[name]);
|
||||
}
|
||||
|
||||
void StatTracker::setStat(const QString& name, int value) {
|
||||
void StatTracker::setStat(const QString& name, int64_t value) {
|
||||
Lock lock(_statsLock);
|
||||
_stats[name] = value;
|
||||
}
|
||||
|
||||
void StatTracker::updateStat(const QString& name, int value) {
|
||||
void StatTracker::updateStat(const QString& name, int64_t value) {
|
||||
Lock lock(_statsLock);
|
||||
auto itr = _stats.find(name);
|
||||
if (_stats.end() == itr) {
|
||||
|
|
|
@ -24,15 +24,15 @@ class StatTracker : public Dependency {
|
|||
public:
|
||||
StatTracker();
|
||||
QVariant getStat(const QString& name);
|
||||
void setStat(const QString& name, int value);
|
||||
void updateStat(const QString& name, int mod);
|
||||
void setStat(const QString& name, int64_t value);
|
||||
void updateStat(const QString& name, int64_t mod);
|
||||
void incrementStat(const QString& name);
|
||||
void decrementStat(const QString& name);
|
||||
private:
|
||||
using Mutex = std::mutex;
|
||||
using Lock = std::lock_guard<Mutex>;
|
||||
Mutex _statsLock;
|
||||
QHash<QString, int> _stats;
|
||||
QHash<QString, int64_t> _stats;
|
||||
};
|
||||
|
||||
class CounterStat {
|
||||
|
|
|
@ -178,15 +178,26 @@ Column {
|
|||
onCheckedChanged: { mainViewTask.getConfig("DrawTransparentBounds")["enabled"] = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Overlay Opaques"
|
||||
checked: mainViewTask.getConfig("DrawOverlayOpaqueBounds")["enabled"]
|
||||
onCheckedChanged: { mainViewTask.getConfig("DrawOverlayOpaqueBounds")["enabled"] = checked }
|
||||
text: "Opaques in Front"
|
||||
checked: mainViewTask.getConfig("DrawOverlayInFrontOpaqueBounds")["enabled"]
|
||||
onCheckedChanged: { mainViewTask.getConfig("DrawOverlayInFrontOpaqueBounds")["enabled"] = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Overlay Transparents"
|
||||
checked: mainViewTask.getConfig("DrawOverlayTransparentBounds")["enabled"]
|
||||
onCheckedChanged: { mainViewTask.getConfig("DrawOverlayTransparentBounds")["enabled"] = checked }
|
||||
text: "Transparents in Front"
|
||||
checked: mainViewTask.getConfig("DrawOverlayInFrontTransparentBounds")["enabled"]
|
||||
onCheckedChanged: { mainViewTask.getConfig("DrawOverlayInFrontTransparentBounds")["enabled"] = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Opaques in HUD"
|
||||
checked: mainViewTask.getConfig("DrawOverlayHUDOpaqueBounds")["enabled"]
|
||||
onCheckedChanged: { mainViewTask.getConfig("DrawOverlayHUDOpaqueBounds")["enabled"] = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Transparents in HUD"
|
||||
checked: mainViewTask.getConfig("DrawOverlayHUDTransparentBounds")["enabled"]
|
||||
onCheckedChanged: { mainViewTask.getConfig("DrawOverlayHUDTransparentBounds")["enabled"] = checked }
|
||||
}
|
||||
|
||||
}
|
||||
Column {
|
||||
CheckBox {
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
(function () { // BEGIN LOCAL_SCOPE
|
||||
Script.include("/~/system/libraries/accountUtils.js");
|
||||
|
||||
var MARKETPLACE_URL = "https://metaverse.highfidelity.com/marketplace";
|
||||
|
||||
// Function Name: onButtonClicked()
|
||||
//
|
||||
// Description:
|
||||
|
@ -88,6 +90,9 @@
|
|||
case 'goToPurchases':
|
||||
tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH);
|
||||
break;
|
||||
case 'goToMarketplaceItemPage':
|
||||
tablet.gotoWebScreen(MARKETPLACE_URL + '/items/' + message.itemId, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
break;
|
||||
default:
|
||||
print('Unrecognized message from QML:', JSON.stringify(message));
|
||||
}
|
||||
|
|
|
@ -119,6 +119,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
this.reticleMaxX;
|
||||
this.reticleMinY = MARGIN;
|
||||
this.reticleMaxY;
|
||||
this.madeDynamic = false;
|
||||
|
||||
var ACTION_TTL = 15; // seconds
|
||||
|
||||
|
@ -344,6 +345,13 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
||||
Entities.callEntityMethod(this.grabbedThingID, "releaseGrab", args);
|
||||
|
||||
if (this.madeDynamic) {
|
||||
var props = {};
|
||||
props.dynamic = false;
|
||||
props.localVelocity = {x: 0, y: 0, z: 0};
|
||||
Entities.editEntity(this.grabbedThingID, props);
|
||||
this.madeDynamic = false;
|
||||
}
|
||||
this.actionID = null;
|
||||
this.grabbedThingID = null;
|
||||
};
|
||||
|
@ -428,7 +436,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
this.distanceRotating = false;
|
||||
|
||||
if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) {
|
||||
this.updateLaserPointer(controllerData);
|
||||
this.prepareDistanceRotatingData(controllerData);
|
||||
return makeRunningValues(true, [], []);
|
||||
} else {
|
||||
|
@ -503,7 +510,13 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
this.destroyContextOverlay();
|
||||
}
|
||||
|
||||
if (entityIsDistanceGrabbable(targetProps)) {
|
||||
if (entityIsGrabbable(targetProps)) {
|
||||
if (!entityIsDistanceGrabbable(targetProps)) {
|
||||
targetProps.dynamic = true;
|
||||
Entities.editEntity(entityID, targetProps);
|
||||
this.madeDynamic = true;
|
||||
}
|
||||
|
||||
if (!this.distanceRotating) {
|
||||
this.grabbedThingID = entityID;
|
||||
this.grabbedDistance = rayPickInfo.distance;
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawHUDLayer: true, // Even when burried inside of something, show it.
|
||||
drawHUDLayer: true,
|
||||
parentID: AVATAR_SELF_ID
|
||||
};
|
||||
var halfEnd = {
|
||||
|
@ -40,7 +40,7 @@
|
|||
color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
ignoreRayIntersection: true,
|
||||
drawHUDLayer: true, // Even when burried inside of something, show it.
|
||||
drawHUDLayer: true,
|
||||
visible: true
|
||||
};
|
||||
var fullPath = {
|
||||
|
@ -52,7 +52,7 @@
|
|||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawHUDLayer: true, // Even when burried inside of something, show it.
|
||||
drawHUDLayer: true,
|
||||
parentID: AVATAR_SELF_ID
|
||||
};
|
||||
var fullEnd = {
|
||||
|
@ -61,7 +61,7 @@
|
|||
color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE,
|
||||
alpha: 0.9,
|
||||
ignoreRayIntersection: true,
|
||||
drawHUDLayer: true, // Even when burried inside of something, show it.
|
||||
drawHUDLayer: true,
|
||||
visible: true
|
||||
};
|
||||
var holdPath = {
|
||||
|
@ -73,7 +73,7 @@
|
|||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawHUDLayer: true, // Even when burried inside of something, show it.
|
||||
drawHUDLayer: true,
|
||||
parentID: AVATAR_SELF_ID
|
||||
};
|
||||
|
||||
|
|
|
@ -248,17 +248,20 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
}
|
||||
};
|
||||
|
||||
this.nearGrabWantsToRun = function(controllerData) {
|
||||
var moduleName = this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay";
|
||||
var module = getEnabledModuleByName(moduleName);
|
||||
var ready = module ? module.isReady(controllerData) : makeRunningValues(false, [], []);
|
||||
return ready.active;
|
||||
this.otherModuleNeedsToRun = function(controllerData) {
|
||||
var grabOverlayModuleName = this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay";
|
||||
var grabOverlayModule = getEnabledModuleByName(grabOverlayModuleName);
|
||||
var grabOverlayModuleReady = grabOverlayModule ? grabOverlayModule.isReady(controllerData) : makeRunningValues(false, [], []);
|
||||
var farGrabModuleName = this.hand === RIGHT_HAND ? "RightFarActionGrabEntity" : "LeftFarActionGrabEntity";
|
||||
var farGrabModule = getEnabledModuleByName(farGrabModuleName);
|
||||
var farGrabModuleReady = farGrabModule ? farGrabModule.isReady(controllerData) : makeRunningValues(false, [], []);
|
||||
return grabOverlayModuleReady.active || farGrabModuleReady.active;
|
||||
};
|
||||
|
||||
this.processStylus = function(controllerData) {
|
||||
this.updateStylusTip();
|
||||
|
||||
if (!this.stylusTip.valid || this.overlayLaserActive(controllerData) || this.nearGrabWantsToRun(controllerData)) {
|
||||
if (!this.stylusTip.valid || this.overlayLaserActive(controllerData) || this.otherModuleNeedsToRun(controllerData)) {
|
||||
this.pointFinger(false);
|
||||
this.hideStylus();
|
||||
return false;
|
||||
|
|
|
@ -15,12 +15,13 @@
|
|||
//
|
||||
|
||||
/* global MyAvatar, Entities, Script, Camera, Vec3, Reticle, Overlays, getEntityCustomData, Messages, Quat, Controller,
|
||||
isInEditMode, HMD */
|
||||
isInEditMode, HMD entityIsGrabbable*/
|
||||
|
||||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
Script.include("/~/system/libraries/utils.js");
|
||||
Script.include("/~/system/libraries/utils.js");
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
var MAX_SOLID_ANGLE = 0.01; // objects that appear smaller than this can't be grabbed
|
||||
|
||||
var DELAY_FOR_30HZ = 33; // milliseconds
|
||||
|
@ -330,9 +331,11 @@ Grabber.prototype.pressEvent = function(event) {
|
|||
return;
|
||||
}
|
||||
|
||||
var isDynamic = Entities.getEntityProperties(pickResults.objectID, "dynamic").dynamic;
|
||||
if (!isDynamic) {
|
||||
// only grab dynamic objects
|
||||
var props = Entities.getEntityProperties(pickResults.objectID, ["dynamic", "userData", "locked", "type"]);
|
||||
var isDynamic = props.dynamic;
|
||||
var isGrabbable = props.grabbable;
|
||||
if (!entityIsGrabbable(props)) {
|
||||
// only grab grabbable objects
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -350,6 +353,7 @@ Grabber.prototype.pressEvent = function(event) {
|
|||
var entityProperties = Entities.getEntityProperties(clickedEntity);
|
||||
this.startPosition = entityProperties.position;
|
||||
this.lastRotation = entityProperties.rotation;
|
||||
this.madeDynamic = false;
|
||||
var cameraPosition = Camera.getPosition();
|
||||
|
||||
var objectBoundingDiameter = Vec3.length(entityProperties.dimensions);
|
||||
|
@ -361,6 +365,11 @@ Grabber.prototype.pressEvent = function(event) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (entityIsGrabbable(props) && !isDynamic) {
|
||||
entityProperties.dynamic = true;
|
||||
Entities.editEntity(clickedEntity, entityProperties);
|
||||
this.madeDynamic = true;
|
||||
}
|
||||
// this.activateEntity(clickedEntity, entityProperties);
|
||||
this.isGrabbing = true;
|
||||
|
||||
|
@ -416,6 +425,14 @@ Grabber.prototype.releaseEvent = function(event) {
|
|||
if (this.actionID) {
|
||||
Entities.deleteAction(this.entityID, this.actionID);
|
||||
}
|
||||
|
||||
if (this.madeDynamic) {
|
||||
var entityProps = {};
|
||||
entityProps.dynamic = false;
|
||||
entityProps.localVelocity = {x: 0, y: 0, z: 0};
|
||||
Entities.editEntity(this.entityID, entityProps);
|
||||
}
|
||||
|
||||
this.actionID = null;
|
||||
|
||||
LaserPointers.setRenderState(this.mouseRayEntities, "");
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
var xmlHttpRequest = null;
|
||||
var isPreparing = false; // Explicitly track download request status.
|
||||
|
||||
var confirmAllPurchases = false; // Set this to "true" to cause Checkout.qml to popup for all items, even if free
|
||||
var commerceMode = false;
|
||||
var userIsLoggedIn = false;
|
||||
var walletNeedsSetup = false;
|
||||
|
||||
|
@ -99,7 +99,9 @@
|
|||
}
|
||||
|
||||
function maybeAddSetupWalletButton() {
|
||||
if (userIsLoggedIn && walletNeedsSetup) {
|
||||
if (!$('body').hasClass("walletsetup-injected") && userIsLoggedIn && walletNeedsSetup) {
|
||||
$('body').addClass("walletsetup-injected");
|
||||
|
||||
var resultsElement = document.getElementById('results');
|
||||
var setupWalletElement = document.createElement('div');
|
||||
setupWalletElement.classList.add("row");
|
||||
|
@ -135,7 +137,8 @@
|
|||
}
|
||||
|
||||
function maybeAddLogInButton() {
|
||||
if (!userIsLoggedIn) {
|
||||
if (!$('body').hasClass("login-injected") && !userIsLoggedIn) {
|
||||
$('body').addClass("login-injected");
|
||||
var resultsElement = document.getElementById('results');
|
||||
var logInElement = document.createElement('div');
|
||||
logInElement.classList.add("row");
|
||||
|
@ -300,69 +303,72 @@
|
|||
}
|
||||
|
||||
function injectHiFiCode() {
|
||||
if (!$('body').hasClass("code-injected") && confirmAllPurchases) {
|
||||
|
||||
$('body').addClass("code-injected");
|
||||
|
||||
if (commerceMode) {
|
||||
maybeAddLogInButton();
|
||||
maybeAddSetupWalletButton();
|
||||
changeDropdownMenu();
|
||||
|
||||
var target = document.getElementById('templated-items');
|
||||
// MutationObserver is necessary because the DOM is populated after the page is loaded.
|
||||
// We're searching for changes to the element whose ID is '#templated-items' - this is
|
||||
// the element that gets filled in by the AJAX.
|
||||
var observer = new MutationObserver(function (mutations) {
|
||||
mutations.forEach(function (mutation) {
|
||||
injectBuyButtonOnMainPage();
|
||||
if (!$('body').hasClass("code-injected")) {
|
||||
|
||||
$('body').addClass("code-injected");
|
||||
changeDropdownMenu();
|
||||
|
||||
var target = document.getElementById('templated-items');
|
||||
// MutationObserver is necessary because the DOM is populated after the page is loaded.
|
||||
// We're searching for changes to the element whose ID is '#templated-items' - this is
|
||||
// the element that gets filled in by the AJAX.
|
||||
var observer = new MutationObserver(function (mutations) {
|
||||
mutations.forEach(function (mutation) {
|
||||
injectBuyButtonOnMainPage();
|
||||
});
|
||||
//observer.disconnect();
|
||||
});
|
||||
//observer.disconnect();
|
||||
});
|
||||
var config = { attributes: true, childList: true, characterData: true };
|
||||
observer.observe(target, config);
|
||||
var config = { attributes: true, childList: true, characterData: true };
|
||||
observer.observe(target, config);
|
||||
|
||||
// Try this here in case it works (it will if the user just pressed the "back" button,
|
||||
// since that doesn't trigger another AJAX request.
|
||||
injectBuyButtonOnMainPage();
|
||||
maybeAddPurchasesButton();
|
||||
// Try this here in case it works (it will if the user just pressed the "back" button,
|
||||
// since that doesn't trigger another AJAX request.
|
||||
injectBuyButtonOnMainPage();
|
||||
maybeAddPurchasesButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function injectHiFiItemPageCode() {
|
||||
if (!$('body').hasClass("code-injected") && confirmAllPurchases) {
|
||||
|
||||
$('body').addClass("code-injected");
|
||||
|
||||
if (commerceMode) {
|
||||
maybeAddLogInButton();
|
||||
maybeAddSetupWalletButton();
|
||||
changeDropdownMenu();
|
||||
|
||||
var purchaseButton = $('#side-info').find('.btn').first();
|
||||
if (!$('body').hasClass("code-injected")) {
|
||||
|
||||
var href = purchaseButton.attr('href');
|
||||
purchaseButton.attr('href', '#');
|
||||
purchaseButton.css({
|
||||
"background": "linear-gradient(#00b4ef, #0093C5)",
|
||||
"color": "#FFF",
|
||||
"font-weight": "600",
|
||||
"padding-bottom": "10px"
|
||||
});
|
||||
$('body').addClass("code-injected");
|
||||
changeDropdownMenu();
|
||||
|
||||
var cost = $('.item-cost').text();
|
||||
var purchaseButton = $('#side-info').find('.btn').first();
|
||||
|
||||
if (parseInt(cost) > 0 && $('#side-info').find('#buyItemButton').size() === 0) {
|
||||
purchaseButton.html('PURCHASE <span class="hifi-glyph hifi-glyph-hfc" style="filter:invert(1);background-size:20px;' +
|
||||
'width:20px;height:20px;position:relative;top:5px;"></span> ' + cost);
|
||||
var href = purchaseButton.attr('href');
|
||||
purchaseButton.attr('href', '#');
|
||||
purchaseButton.css({
|
||||
"background": "linear-gradient(#00b4ef, #0093C5)",
|
||||
"color": "#FFF",
|
||||
"font-weight": "600",
|
||||
"padding-bottom": "10px"
|
||||
});
|
||||
|
||||
var cost = $('.item-cost').text();
|
||||
|
||||
if (parseInt(cost) > 0 && $('#side-info').find('#buyItemButton').size() === 0) {
|
||||
purchaseButton.html('PURCHASE <span class="hifi-glyph hifi-glyph-hfc" style="filter:invert(1);background-size:20px;' +
|
||||
'width:20px;height:20px;position:relative;top:5px;"></span> ' + cost);
|
||||
}
|
||||
|
||||
purchaseButton.on('click', function () {
|
||||
buyButtonClicked(window.location.pathname.split("/")[3],
|
||||
$('#top-center').find('h1').text(),
|
||||
$('#creator').find('.value').text(),
|
||||
cost,
|
||||
href);
|
||||
});
|
||||
maybeAddPurchasesButton();
|
||||
}
|
||||
|
||||
purchaseButton.on('click', function () {
|
||||
buyButtonClicked(window.location.pathname.split("/")[3],
|
||||
$('#top-center').find('h1').text(),
|
||||
$('#creator').find('.value').text(),
|
||||
cost,
|
||||
href);
|
||||
});
|
||||
maybeAddPurchasesButton();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -623,7 +629,7 @@
|
|||
|
||||
if (parsedJsonMessage.type === "marketplaces") {
|
||||
if (parsedJsonMessage.action === "commerceSetting") {
|
||||
confirmAllPurchases = !!parsedJsonMessage.data.commerceMode;
|
||||
commerceMode = !!parsedJsonMessage.data.commerceMode;
|
||||
userIsLoggedIn = !!parsedJsonMessage.data.userIsLoggedIn;
|
||||
walletNeedsSetup = !!parsedJsonMessage.data.walletNeedsSetup;
|
||||
injectCode();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -370,7 +370,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
|
||||
var recommendedRect = Controller.getRecommendedOverlayRect();
|
||||
var recommendedRect = Controller.getRecommendedHUDRect();
|
||||
var recommendedDimmensions = { x: recommendedRect.width, y: recommendedRect.height };
|
||||
that.windowDimensions = recommendedDimmensions; // Controller.getViewportDimensions();
|
||||
that.origin = { x: recommendedRect.x, y: recommendedRect.y };
|
||||
|
@ -378,7 +378,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
// For example, maybe we want "keep the same percentage to whatever two edges are closest to the edge of screen".
|
||||
// If we change that, the places to do so are onResizeViewport, save (maybe), and the initial move based on Settings, below.
|
||||
that.onResizeViewport = function (newSize) { // Can be overridden or extended by clients.
|
||||
var recommendedRect = Controller.getRecommendedOverlayRect();
|
||||
var recommendedRect = Controller.getRecommendedHUDRect();
|
||||
var recommendedDimmensions = { x: recommendedRect.width, y: recommendedRect.height };
|
||||
var originRelativeX = (that.x - that.origin.x - that.offset.x);
|
||||
var originRelativeY = (that.y - that.origin.y - that.offset.y);
|
||||
|
@ -396,7 +396,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
// code once the new toolbar position is well established with users.
|
||||
this.isNewPositionKey = optionalPersistenceKey + '.isNewPosition';
|
||||
this.save = function () {
|
||||
var recommendedRect = Controller.getRecommendedOverlayRect();
|
||||
var recommendedRect = Controller.getRecommendedHUDRect();
|
||||
var screenSize = { x: recommendedRect.width, y: recommendedRect.height };
|
||||
if (screenSize.x > 0 && screenSize.y > 0) {
|
||||
// Guard against invalid screen size that can occur at shut-down.
|
||||
|
@ -443,7 +443,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
that.move(that.dragOffsetX + event.x, that.dragOffsetY + event.y);
|
||||
};
|
||||
that.checkResize = function () { // Can be overriden or extended, but usually not. See onResizeViewport.
|
||||
var recommendedRect = Controller.getRecommendedOverlayRect();
|
||||
var recommendedRect = Controller.getRecommendedHUDRect();
|
||||
var currentWindowSize = { x: recommendedRect.width, y: recommendedRect.height };
|
||||
|
||||
if ((currentWindowSize.x !== that.windowDimensions.x) || (currentWindowSize.y !== that.windowDimensions.y)) {
|
||||
|
@ -471,7 +471,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
var savedFraction = isNewPosition ? JSON.parse(Settings.getValue(this.fractionKey) || "0") : 0;
|
||||
Settings.setValue(this.isNewPositionKey, true);
|
||||
|
||||
var recommendedRect = Controller.getRecommendedOverlayRect();
|
||||
var recommendedRect = Controller.getRecommendedHUDRect();
|
||||
var screenSize = { x: recommendedRect.width, y: recommendedRect.height };
|
||||
if (savedFraction) {
|
||||
// If we have saved data, keep the toolbar at the same proportion of the screen width/height.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue