mirror of
https://github.com/overte-org/overte.git
synced 2025-04-07 20:14:22 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into punk
This commit is contained in:
commit
b24a2d33bf
134 changed files with 1446 additions and 913 deletions
20
BUILD.md
20
BUILD.md
|
@ -13,7 +13,7 @@
|
|||
|
||||
### CMake External Project Dependencies
|
||||
|
||||
These dependencies need not be installed manually. They are automatically downloaded on the platforms where they are required.
|
||||
These dependencies need not be installed manually. They are automatically downloaded on the platforms where they are required.
|
||||
- [Bullet Physics Engine](https://github.com/bulletphysics/bullet3/releases): 2.83
|
||||
- [glm](https://glm.g-truc.net/0.9.8/index.html): 0.9.8
|
||||
- [Oculus SDK](https://developer.oculus.com/downloads/): 1.11 (Win32) / 0.5 (Mac)
|
||||
|
@ -22,7 +22,7 @@ These dependencies need not be installed manually. They are automatically downlo
|
|||
- [QuaZip](https://sourceforge.net/projects/quazip/files/quazip/): 0.7.3
|
||||
- [SDL2](https://www.libsdl.org/download-2.0.php): 2.0.3
|
||||
- [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/): 4.3
|
||||
- [vcpkg](https://github.com/highfidelity/vcpkg):
|
||||
- [vcpkg](https://github.com/highfidelity/vcpkg):
|
||||
- [VHACD](https://github.com/virneo/v-hacd)
|
||||
- [zlib](http://www.zlib.net/): 1.28 (Win32 only)
|
||||
- [nvtt](https://github.com/highfidelity/nvidia-texture-tools): 2.1.1 (customized)
|
||||
|
@ -48,6 +48,18 @@ The path it needs to be set to will depend on where and how Qt5 was installed. e
|
|||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.10.1/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
|
||||
|
||||
#### Vcpkg
|
||||
|
||||
Hifi uses vcpkg to download and build dependencies.
|
||||
You do not need to install vcpkg.
|
||||
|
||||
Building the dependencies can be lengthy and the resulting files will be stored in your OS temp directory.
|
||||
However, those files can potentially get cleaned up by the OS, so in order to avoid this and having to redo the lengthy build step, you can set the following environment variable:
|
||||
|
||||
export HIFI_VCPKG_BASE=/path/to/directory
|
||||
|
||||
Where /path/to/directory is the path to a directory where you wish the build files to get stored.
|
||||
|
||||
#### Generating build files
|
||||
|
||||
Create a build directory in the root of your checkout and then run the CMake build from there. This will keep the rest of the directory clean.
|
||||
|
@ -80,7 +92,7 @@ In the examples below the variable $NAME would be replaced by the name of the de
|
|||
|
||||
### Optional Components
|
||||
|
||||
#### Build Options
|
||||
#### Build Options
|
||||
|
||||
The following build options can be used when running CMake
|
||||
|
||||
|
@ -89,7 +101,7 @@ The following build options can be used when running CMake
|
|||
* BUILD_TESTS
|
||||
* BUILD_TOOLS
|
||||
|
||||
#### Developer Build Options
|
||||
#### Developer Build Options
|
||||
|
||||
* USE_GLES
|
||||
* DISABLE_UI
|
||||
|
|
23
BUILD_WIN.md
23
BUILD_WIN.md
|
@ -19,7 +19,7 @@ If you do not wish to use the Python installation bundled with Visual Studio, yo
|
|||
|
||||
### Step 2. Installing CMake
|
||||
|
||||
Download and install the latest version of CMake 3.9.
|
||||
Download and install the latest version of CMake 3.9.
|
||||
|
||||
Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). You can access the installer on this [3.9 Version page](https://cmake.org/files/v3.9/). During installation, make sure to check "Add CMake to system PATH for all users" when prompted.
|
||||
|
||||
|
@ -35,20 +35,7 @@ Go to `Control Panel > System > Advanced System Settings > Environment Variables
|
|||
* Set "Variable name": `QT_CMAKE_PREFIX_PATH`
|
||||
* Set "Variable value": `C:\Qt\5.10.1\msvc2017_64\lib\cmake`
|
||||
|
||||
### Step 5. Installing [vcpkg](https://github.com/Microsoft/vcpkg)
|
||||
|
||||
* Clone the VCPKG [repository](https://github.com/Microsoft/vcpkg)
|
||||
* Follow the instructions in the [readme](https://github.com/Microsoft/vcpkg/blob/master/README.md) to bootstrap vcpkg
|
||||
* Note, you may need to do these in a _Developer Command Prompt_
|
||||
* Set an environment variable VCPKG_ROOT to the location of the cloned repository
|
||||
* Close and re-open any command prompts after setting the environment variable so that they will pick up the change
|
||||
|
||||
### Step 6. Installing OpenSSL via vcpkg
|
||||
|
||||
* In the vcpkg directory, install the 64 bit OpenSSL package with the command `.\vcpkg install openssl:x64-windows`
|
||||
* Once the build completes you should have a file `ssl.h` in `${VCPKG_ROOT}/installed/x64-windows/include/openssl`
|
||||
|
||||
### Step 7. Running CMake to Generate Build Files
|
||||
### Step 5. Running CMake to Generate Build Files
|
||||
|
||||
Run Command Prompt from Start and run the following commands:
|
||||
```
|
||||
|
@ -58,9 +45,9 @@ cd build
|
|||
cmake .. -G "Visual Studio 15 Win64"
|
||||
```
|
||||
|
||||
Where `%HIFI_DIR%` is the directory for the highfidelity repository.
|
||||
Where `%HIFI_DIR%` is the directory for the highfidelity repository.
|
||||
|
||||
### Step 8. Making a Build
|
||||
### Step 6. Making a Build
|
||||
|
||||
Open `%HIFI_DIR%\build\hifi.sln` using Visual Studio.
|
||||
|
||||
|
@ -68,7 +55,7 @@ Change the Solution Configuration (menu ribbon under the menu bar, next to the g
|
|||
|
||||
Run from the menu bar `Build > Build Solution`.
|
||||
|
||||
### Step 9. Testing Interface
|
||||
### Step 7. Testing Interface
|
||||
|
||||
Create another environment variable (see Step #4)
|
||||
* Set "Variable name": `_NO_DEBUG_HEAP`
|
||||
|
|
|
@ -152,6 +152,8 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
|
|||
if (packetTraitVersion > instanceVersionRef) {
|
||||
if (traitSize == AvatarTraits::DELETED_TRAIT_SIZE) {
|
||||
_avatar->processDeletedTraitInstance(traitType, instanceID);
|
||||
// Mixer doesn't need deleted IDs.
|
||||
_avatar->getAndClearRecentlyDetachedIDs();
|
||||
|
||||
// to track a deleted instance but keep version information
|
||||
// the avatar mixer uses the negative value of the sent version
|
||||
|
|
|
@ -18,9 +18,6 @@ $(document).ready(function(){
|
|||
Settings.extraGroupsAtIndex = Settings.extraDomainGroupsAtIndex;
|
||||
|
||||
Settings.afterReloadActions = function() {
|
||||
// append the domain selection modal
|
||||
appendDomainIDButtons();
|
||||
|
||||
// call our method to setup the HF account button
|
||||
setupHFAccountButton();
|
||||
|
||||
|
@ -52,6 +49,11 @@ $(document).ready(function(){
|
|||
if (cloudWizardExit != undefined) {
|
||||
$('#cloud-domains-alert').show();
|
||||
}
|
||||
|
||||
$(Settings.DOMAIN_ID_SELECTOR).siblings('span').append("</br><strong>Changing the domain ID for a Cloud Domain may result in an incorrect status for the domain on your Cloud Domains page.</strong>");
|
||||
} else {
|
||||
// append the domain selection modal
|
||||
appendDomainIDButtons();
|
||||
}
|
||||
|
||||
handleAction();
|
||||
|
@ -59,9 +61,9 @@ $(document).ready(function(){
|
|||
|
||||
Settings.handlePostSettings = function(formJSON) {
|
||||
|
||||
if (!verifyAvatarHeights()) {
|
||||
return false;
|
||||
}
|
||||
if (!verifyAvatarHeights()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if we've set the basic http password
|
||||
if (formJSON["security"]) {
|
||||
|
|
|
@ -70,8 +70,8 @@ OriginalDesktop.Desktop {
|
|||
anchors.horizontalCenter: settings.constrainToolbarToCenterX ? desktop.horizontalCenter : undefined;
|
||||
// Literal 50 is overwritten by settings from previous session, and sysToolbar.x comes from settings when not constrained.
|
||||
x: sysToolbar.x
|
||||
buttonModel: tablet.buttons;
|
||||
shown: tablet.toolbarMode;
|
||||
buttonModel: tablet ? tablet.buttons : null;
|
||||
shown: tablet ? tablet.toolbarMode : false;
|
||||
}
|
||||
|
||||
Settings {
|
||||
|
|
|
@ -36,6 +36,8 @@ Item {
|
|||
property bool isCurrentlySendingAsset: false;
|
||||
property string assetName: "";
|
||||
property string assetCertID: "";
|
||||
property string couponID: "";
|
||||
property string authorizationID: "";
|
||||
property string sendingPubliclyEffectImage;
|
||||
property var http;
|
||||
property var listModelName;
|
||||
|
@ -108,6 +110,27 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
onAuthorizeAssetTransferResult: {
|
||||
if (!root.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
root.isCurrentlySendingAsset = false;
|
||||
|
||||
if (result.status === 'success') {
|
||||
root.authorizationID = result.data.authorization_id;
|
||||
authorizationIDText.text = root.authorizationID;
|
||||
root.couponID = result.data.coupon_id;
|
||||
couponIDText.text = root.couponID
|
||||
if (couponIDTextField.text !== root.couponID) {
|
||||
console.log("SendAsset: Returned coupon ID doesn't match client-generated coupon ID!");
|
||||
}
|
||||
root.nextActiveView = 'paymentSuccess';
|
||||
} else {
|
||||
root.nextActiveView = 'paymentFailure';
|
||||
}
|
||||
}
|
||||
|
||||
onCertificateInfoResult: {
|
||||
if (result.status !== 'success') {
|
||||
console.log("Failed to get certificate info", result.data.message);
|
||||
|
@ -269,7 +292,7 @@ Item {
|
|||
|
||||
RalewaySemiBold {
|
||||
id: sendAssetText;
|
||||
text: root.assetCertID === "" ? "Send Money To:" : "Gift \"" + root.assetName + "\" To:";
|
||||
text: root.assetCertID === "" ? "Send Money To:" : "Send \"" + root.assetName + "\" To:";
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 26;
|
||||
|
@ -370,6 +393,51 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: createCouponButton;
|
||||
// Anchors
|
||||
anchors.top: nearbyButton.bottom;
|
||||
anchors.topMargin: 32;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
height: connectionButton.height;
|
||||
width: connectionButton.width;
|
||||
|
||||
Image {
|
||||
anchors.top: parent.top;
|
||||
source: "./images/coupon.svg";
|
||||
height: 70;
|
||||
width: parent.width;
|
||||
fillMode: Image.PreserveAspectFit;
|
||||
horizontalAlignment: Image.AlignHCenter;
|
||||
verticalAlignment: Image.AlignTop;
|
||||
mipmap: true;
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
text: "Create Coupon";
|
||||
// Anchors
|
||||
anchors.bottom: parent.bottom;
|
||||
height: 15;
|
||||
width: parent.width;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
onClicked: {
|
||||
sendAssetStep.referrer = "createCoupon";
|
||||
sendAssetStep.selectedRecipientNodeID = "";
|
||||
couponIDTextField.text = generateRandomCouponID();
|
||||
|
||||
root.nextActiveView = "sendAssetStep";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Button {
|
||||
id: backButton_sendAssetHome;
|
||||
visible: parentAppNavBarHeight === 0;
|
||||
|
@ -860,7 +928,7 @@ Item {
|
|||
id: sendAssetStep;
|
||||
z: 996;
|
||||
|
||||
property string referrer; // either "connections", "nearby", or "payIn"
|
||||
property string referrer; // either "connections", "nearby", "payIn", or "createCoupon"
|
||||
property string selectedRecipientNodeID;
|
||||
property string selectedRecipientDisplayName;
|
||||
property string selectedRecipientUserName;
|
||||
|
@ -872,7 +940,8 @@ Item {
|
|||
|
||||
RalewaySemiBold {
|
||||
id: sendAssetText_sendAssetStep;
|
||||
text: sendAssetStep.referrer === "payIn" && root.assetCertID !== "" ? "Send \"" + root.assetName + "\":" :
|
||||
text: ((sendAssetStep.referrer === "payIn" || sendAssetStep.referrer === "createCoupon") &&
|
||||
root.assetCertID !== "") ? "Send \"" + root.assetName + "\":" :
|
||||
(root.assetCertID === "" ? "Send Money To:" : "Gift \"" + root.assetName + "\" To:");
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
|
@ -901,12 +970,13 @@ Item {
|
|||
|
||||
RalewaySemiBold {
|
||||
id: sendToText_sendAssetStep;
|
||||
text: (root.assetCertID === "" || sendAssetStep.referrer === "payIn") ? "Send to:" : "Gift to:";
|
||||
text: sendAssetStep.referrer === "createCoupon" ? "Coupon ID:" :
|
||||
(root.assetCertID === "" || sendAssetStep.referrer === "payIn") ? "Send to:" : "Gift to:";
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: 90;
|
||||
width: paintedWidth;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
|
@ -915,8 +985,10 @@ Item {
|
|||
}
|
||||
|
||||
RecipientDisplay {
|
||||
visible: sendAssetStep.referrer !== "createCoupon";
|
||||
anchors.top: parent.top;
|
||||
anchors.left: sendToText_sendAssetStep.right;
|
||||
anchors.leftMargin: 16;
|
||||
anchors.right: changeButton.left;
|
||||
anchors.rightMargin: 12;
|
||||
height: parent.height;
|
||||
|
@ -929,6 +1001,68 @@ Item {
|
|||
multiLineDisplay: sendAssetStep.referrer === "nearby" || sendAssetStep.referrer === "payIn";
|
||||
}
|
||||
|
||||
Item {
|
||||
id: couponIDContainer;
|
||||
visible: sendAssetStep.referrer === "createCoupon";
|
||||
anchors.top: parent.top;
|
||||
anchors.left: sendToText_sendAssetStep.right;
|
||||
anchors.right: parent.right;
|
||||
height: parent.height;
|
||||
|
||||
RalewaySemiBold {
|
||||
id: couponIDHelp;
|
||||
text: "[?]";
|
||||
// Anchors
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 8;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
height: 30;
|
||||
width: paintedWidth;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.blueAccent;
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
onEntered: {
|
||||
parent.color = hifi.colors.blueHighlight;
|
||||
}
|
||||
onExited: {
|
||||
parent.color = hifi.colors.blueAccent;
|
||||
}
|
||||
onClicked: {
|
||||
lightboxPopup.titleText = "Coupon ID";
|
||||
lightboxPopup.bodyText = "This alphanumeric text string will be used to ensure " +
|
||||
"that only you can redeem the coupon for the asset that you are sending. Keep it private!";
|
||||
lightboxPopup.button1text = "CLOSE";
|
||||
lightboxPopup.button1method = function() {
|
||||
lightboxPopup.visible = false;
|
||||
}
|
||||
lightboxPopup.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.TextField {
|
||||
id: couponIDTextField;
|
||||
colorScheme: root.assetCertID === "" ? hifi.colorSchemes.dark : hifi.colorSchemes.light;
|
||||
// Anchors
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
anchors.left: couponIDHelp.right;
|
||||
anchors.leftMargin: 16;
|
||||
anchors.right: parent.right;
|
||||
height: 50;
|
||||
// Style
|
||||
activeFocusOnPress: true;
|
||||
activeFocusOnTab: true;
|
||||
|
||||
onAccepted: {
|
||||
optionalMessage.focus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "CHANGE" button
|
||||
HifiControlsUit.Button {
|
||||
id: changeButton;
|
||||
|
@ -939,7 +1073,7 @@ Item {
|
|||
height: 35;
|
||||
width: 100;
|
||||
text: "CHANGE";
|
||||
visible: sendAssetStep.referrer !== "payIn";
|
||||
visible: sendAssetStep.referrer !== "payIn" && sendAssetStep.referrer !== "createCoupon";
|
||||
onClicked: {
|
||||
if (sendAssetStep.referrer === "connections") {
|
||||
root.nextActiveView = "chooseRecipientConnection";
|
||||
|
@ -1263,6 +1397,11 @@ Item {
|
|||
root.assetCertID,
|
||||
parseInt(amountTextField.text),
|
||||
optionalMessage.text);
|
||||
} else if (sendAssetStep.referrer === "createCoupon") {
|
||||
Commerce.authorizeAssetTransfer(couponIDTextField.text || "",
|
||||
root.assetCertID,
|
||||
parseInt(amountTextField.text) || 1,
|
||||
optionalMessage.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1334,18 +1473,24 @@ Item {
|
|||
|
||||
Rectangle {
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? 15 : 125;
|
||||
anchors.topMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ||
|
||||
sendAssetStep.referrer === "createCoupon" ? 15 : 125;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? 15 : 50;
|
||||
anchors.leftMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ||
|
||||
sendAssetStep.referrer === "createCoupon" ? 15 : 50;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? 15 : 50;
|
||||
anchors.rightMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ||
|
||||
sendAssetStep.referrer === "createCoupon" ? 15 : 50;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.bottomMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? 15 : 125;
|
||||
anchors.bottomMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ||
|
||||
sendAssetStep.referrer === "createCoupon" ? 15 : 125;
|
||||
color: "#FFFFFF";
|
||||
|
||||
RalewaySemiBold {
|
||||
id: paymentSentText;
|
||||
text: root.assetCertID === "" ? "Payment Sent" : (sendAssetStep.referrer === "payIn" ? "Item Sent" : "Gift Sent");
|
||||
text: root.assetCertID === "" ? (sendAssetStep.referrer === "createCoupon" ? "Payment Authorized" : "Payment Sent") :
|
||||
(sendAssetStep.referrer === "createCoupon" ? "Item Transfer Authorized" :
|
||||
(sendAssetStep.referrer === "payIn" ? "Item Sent" : "Gift Sent"));
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 26;
|
||||
|
@ -1383,6 +1528,8 @@ Item {
|
|||
onClicked: {
|
||||
if (sendAssetStep.referrer === "payIn") {
|
||||
sendToScript({method: "closeSendAsset"});
|
||||
} else if (sendAssetStep.referrer === "createCoupon") {
|
||||
showDidYouCopyLightbox();
|
||||
} else {
|
||||
root.nextActiveView = "sendAssetHome";
|
||||
resetSendAssetData();
|
||||
|
@ -1402,38 +1549,176 @@ Item {
|
|||
anchors.leftMargin: 20;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 20;
|
||||
height: 80;
|
||||
height: childrenRect.height;
|
||||
|
||||
RalewaySemiBold {
|
||||
id: sendToText_paymentSuccess;
|
||||
text: "Sent To:";
|
||||
// Anchors
|
||||
Item {
|
||||
id: sendToScriptContainer_paymentSuccess;
|
||||
visible: sendAssetStep.referrer === "createCoupon";
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: 90;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
RecipientDisplay {
|
||||
anchors.top: parent.top;
|
||||
anchors.left: sendToText_paymentSuccess.right;
|
||||
anchors.right: parent.right;
|
||||
height: parent.height;
|
||||
textColor: hifi.colors.blueAccent;
|
||||
height: childrenRect.height;
|
||||
|
||||
displayName: sendAssetStep.selectedRecipientDisplayName;
|
||||
userName: sendAssetStep.selectedRecipientUserName;
|
||||
profilePic: sendAssetStep.selectedRecipientProfilePic !== "" ? ((0 === sendAssetStep.selectedRecipientProfilePic.indexOf("http")) ?
|
||||
sendAssetStep.selectedRecipientProfilePic : (Account.metaverseServerURL + sendAssetStep.selectedRecipientProfilePic)) : "";
|
||||
multiLineDisplay: sendAssetStep.referrer === "nearby" || sendAssetStep.referrer === "payIn";
|
||||
RalewaySemiBold {
|
||||
id: authorizationIDLabel;
|
||||
text: "Authorization ID:";
|
||||
// Anchors
|
||||
anchors.left: parent.left;
|
||||
anchors.top: authorizationIDText.top;
|
||||
width: paintedWidth;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: authorizationIDText;
|
||||
text: root.authorizationID;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: authorizationIDLabel.right;
|
||||
anchors.leftMargin: 16;
|
||||
anchors.right: authorizationIDClipboardButton.left;
|
||||
anchors.rightMargin: 16;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
wrapMode: Text.WrapAnywhere;
|
||||
}
|
||||
|
||||
Image {
|
||||
id: authorizationIDClipboardButton;
|
||||
source: "images/clipboard.svg"; // clipboard by Bieutuong Bon from the Noun Project
|
||||
fillMode: Image.PreserveAspectFit;
|
||||
// Anchors
|
||||
anchors.right: parent.right;
|
||||
anchors.top: authorizationIDText.top;
|
||||
height: 40;
|
||||
width: height;
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
onClicked: {
|
||||
Window.copyToClipboard(root.authorizationID);
|
||||
authorizationIDText.text = "Copied to Clipboard!\n";
|
||||
authorizationIDClipboardTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: authorizationIDClipboardTimer;
|
||||
interval: 2000;
|
||||
repeat: false;
|
||||
onTriggered: {
|
||||
authorizationIDText.text = root.authorizationID;
|
||||
}
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
id: couponIDLabel;
|
||||
text: "Coupon ID:";
|
||||
// Anchors
|
||||
anchors.left: parent.left;
|
||||
anchors.top: couponIDText.top;
|
||||
width: authorizationIDLabel.width;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: couponIDText;
|
||||
text: root.couponID;
|
||||
anchors.top: authorizationIDText.bottom;
|
||||
anchors.topMargin: 16;
|
||||
anchors.left: couponIDLabel.right;
|
||||
anchors.leftMargin: 16;
|
||||
anchors.right: couponIDClipboardButton.left;
|
||||
anchors.rightMargin: 16;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
wrapMode: Text.WrapAnywhere;
|
||||
}
|
||||
|
||||
Image {
|
||||
id: couponIDClipboardButton;
|
||||
source: "images/clipboard.svg"; // clipboard by Bieutuong Bon from the Noun Project
|
||||
fillMode: Image.PreserveAspectFit;
|
||||
// Anchors
|
||||
anchors.right: parent.right;
|
||||
anchors.top: couponIDText.top;
|
||||
height: 40;
|
||||
width: height;
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
onClicked: {
|
||||
Window.copyToClipboard(root.couponID);
|
||||
couponIDText.text = "Copied to Clipboard!\n";
|
||||
couponIDClipboardTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: couponIDClipboardTimer;
|
||||
interval: 2000;
|
||||
repeat: false;
|
||||
onTriggered: {
|
||||
couponIDText.text = root.couponID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Item {
|
||||
id: sendToRecipientContainer_paymentSuccess;
|
||||
visible: !sendToScriptContainer_paymentSuccess.visible;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: 80;
|
||||
|
||||
RalewaySemiBold {
|
||||
id: sendToText_paymentSuccess;
|
||||
text: "Sent To:";
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: 90;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
RecipientDisplay {
|
||||
anchors.top: parent.top;
|
||||
anchors.left: sendToText_paymentSuccess.right;
|
||||
anchors.right: parent.right;
|
||||
height: parent.height;
|
||||
textColor: hifi.colors.blueAccent;
|
||||
|
||||
displayName: sendAssetStep.selectedRecipientDisplayName;
|
||||
userName: sendAssetStep.selectedRecipientUserName;
|
||||
profilePic: sendAssetStep.selectedRecipientProfilePic !== "" ? ((0 === sendAssetStep.selectedRecipientProfilePic.indexOf("http")) ?
|
||||
sendAssetStep.selectedRecipientProfilePic : (Account.metaverseServerURL + sendAssetStep.selectedRecipientProfilePic)) : "";
|
||||
multiLineDisplay: sendAssetStep.referrer === "nearby" || sendAssetStep.referrer === "payIn";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: giftContainer_paymentSuccess;
|
||||
|
@ -1448,7 +1733,8 @@ Item {
|
|||
|
||||
RalewaySemiBold {
|
||||
id: gift_paymentSuccess;
|
||||
text: sendAssetStep.referrer === "payIn" ? "Item:" : "Gift:";
|
||||
text: sendAssetStep.referrer === "payIn" || sendAssetStep.referrer === "createCoupon" ?
|
||||
"Item:" : "Gift:";
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
|
@ -1566,6 +1852,8 @@ Item {
|
|||
onClicked: {
|
||||
if (sendAssetStep.referrer === "payIn") {
|
||||
sendToScript({method: "closeSendAsset"});
|
||||
} else if (sendAssetStep.referrer === "createCoupon") {
|
||||
showDidYouCopyLightbox();
|
||||
} else {
|
||||
root.nextActiveView = "sendAssetHome";
|
||||
resetSendAssetData();
|
||||
|
@ -1599,13 +1887,17 @@ Item {
|
|||
|
||||
Rectangle {
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? 15 : 150;
|
||||
anchors.topMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ||
|
||||
sendAssetStep.referrer === "createCoupon" ? 15 : 150;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? 15 : 50;
|
||||
anchors.leftMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ||
|
||||
sendAssetStep.referrer === "createCoupon" ? 15 : 50;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? 15 : 50;
|
||||
anchors.rightMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ||
|
||||
sendAssetStep.referrer === "createCoupon" ? 15 : 50;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.bottomMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? 15 : 300;
|
||||
anchors.bottomMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ||
|
||||
sendAssetStep.referrer === "createCoupon" ? 15 : 300;
|
||||
color: "#FFFFFF";
|
||||
|
||||
RalewaySemiBold {
|
||||
|
@ -1657,8 +1949,9 @@ Item {
|
|||
|
||||
RalewaySemiBold {
|
||||
id: paymentFailureDetailText;
|
||||
text: "The recipient you specified was unable to receive your " +
|
||||
(root.assetCertID === "" ? "payment." : (sendAssetStep.referrer === "payIn" ? "item." : "gift."));
|
||||
text: sendAssetStep.referrer === "createCoupon" ? "The server was unable to handle your request. Please try again later." :
|
||||
("The recipient you specified was unable to receive your " +
|
||||
(root.assetCertID === "" ? "payment." : (sendAssetStep.referrer === "payIn" ? "item." : "gift.")));
|
||||
anchors.top: paymentFailureText.bottom;
|
||||
anchors.topMargin: 20;
|
||||
anchors.left: parent.left;
|
||||
|
@ -1676,7 +1969,8 @@ Item {
|
|||
|
||||
Item {
|
||||
id: sendToContainer_paymentFailure;
|
||||
visible: root.assetCertID === "" || sendAssetStep.referrer === "payIn";
|
||||
visible: (root.assetCertID === "" || sendAssetStep.referrer === "payIn") &&
|
||||
sendAssetStep.referrer !== "createCoupon";
|
||||
anchors.top: paymentFailureDetailText.bottom;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: parent.left;
|
||||
|
@ -1718,7 +2012,8 @@ Item {
|
|||
Item {
|
||||
id: amountContainer_paymentFailure;
|
||||
visible: root.assetCertID === "";
|
||||
anchors.top: sendToContainer_paymentFailure.bottom;
|
||||
anchors.top: sendToContainer_paymentFailure.visible ?
|
||||
sendToContainer_paymentFailure.bottom : paymentFailureDetailText.bottom;
|
||||
anchors.topMargin: 16;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 20;
|
||||
|
@ -1839,6 +2134,11 @@ Item {
|
|||
root.assetCertID,
|
||||
parseInt(amountTextField.text),
|
||||
optionalMessage.text);
|
||||
} else if (sendAssetStep.referrer === "createCoupon") {
|
||||
Commerce.authorizeAssetTransfer(couponIDTextField.text || "",
|
||||
root.assetCertID,
|
||||
parseInt(amountTextField.text) || 1,
|
||||
optionalMessage.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1867,6 +2167,39 @@ Item {
|
|||
sendAssetStep.referrer = "";
|
||||
}
|
||||
|
||||
function generateRandomCouponID() {
|
||||
var RANDOM_COUPON_ID_LENGTH = 25;
|
||||
var randomCouponID = "";
|
||||
var possibleCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
for (var i = 0; i < RANDOM_COUPON_ID_LENGTH; i++) {
|
||||
randomCouponID += possibleCharacters.charAt(Math.floor(Math.random() * possibleCharacters.length));
|
||||
}
|
||||
|
||||
return randomCouponID;
|
||||
}
|
||||
|
||||
function showDidYouCopyLightbox() {
|
||||
lightboxPopup.titleText = "Close Confirmation";
|
||||
lightboxPopup.bodyText = "Did you copy your Authorization ID and your Coupon ID?\n\n" +
|
||||
"You won't be able to see your Authorization ID or your Coupon ID once " +
|
||||
"you close this window.";
|
||||
lightboxPopup.button1text = "GO BACK";
|
||||
lightboxPopup.button1method = function() {
|
||||
lightboxPopup.visible = false;
|
||||
}
|
||||
lightboxPopup.button2text = "I'M ALL SET";
|
||||
lightboxPopup.button2method = function() {
|
||||
lightboxPopup.visible = false;
|
||||
root.nextActiveView = "sendAssetHome";
|
||||
resetSendAssetData();
|
||||
if (root.assetName !== "") {
|
||||
sendSignalToParent({method: "closeSendAsset"});
|
||||
}
|
||||
}
|
||||
lightboxPopup.visible = true;
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: fromScript()
|
||||
//
|
||||
|
@ -1908,9 +2241,15 @@ Item {
|
|||
sendAssetStep.referrer = "payIn";
|
||||
sendAssetStep.selectedRecipientNodeID = "";
|
||||
sendAssetStep.selectedRecipientDisplayName = "Determined by script:";
|
||||
sendAssetStep.selectedRecipientUserName = message.username;
|
||||
sendAssetStep.selectedRecipientUserName = message.username || "";
|
||||
optionalMessage.text = message.message || "No Message Provided";
|
||||
|
||||
if (sendAssetStep.selectedRecipientUserName === "") {
|
||||
console.log("SendAsset: Script didn't specify a recipient username!");
|
||||
sendAssetHome.visible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
root.nextActiveView = "sendAssetStep";
|
||||
break;
|
||||
case 'inspectionCertificate_resetCert':
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 44 55" enable-background="new 0 0 44 44" xml:space="preserve"><path d="M30.201,10.811h-1.599v-0.076c0-0.754-0.612-1.367-1.366-1.367h-2.063c0.005-0.074,0.023-0.146,0.023-0.225 c0-1.766-1.432-3.197-3.197-3.197s-3.197,1.432-3.197,3.197c0,0.078,0.018,0.15,0.023,0.225h-2.063 c-0.754,0-1.366,0.613-1.366,1.367v0.076h-1.599c-1.38,0-2.502,1.123-2.502,2.502v22.24c0,1.379,1.122,2.502,2.502,2.502h16.402 c1.38,0,2.502-1.123,2.502-2.502v-22.24C32.703,11.934,31.581,10.811,30.201,10.811z M22,7.893c0.691,0,1.251,0.559,1.251,1.25 s-0.56,1.252-1.251,1.252s-1.251-0.561-1.251-1.252S21.309,7.893,22,7.893z M31.035,35.553c0,0.459-0.374,0.834-0.834,0.834H13.799 c-0.46,0-0.834-0.375-0.834-0.834v-22.24c0-0.459,0.374-0.834,0.834-0.834h1.599v1.443h13.205v-1.443h1.599 c0.46,0,0.834,0.375,0.834,0.834V35.553z"/><rect x="15.397" y="16.648" width="13.205" height="0.975"/><rect x="15.397" y="20.402" width="13.205" height="0.973"/><rect x="15.397" y="24.154" width="13.205" height="0.975"/><rect x="15.397" y="27.908" width="13.205" height="0.973"/><rect x="15.397" y="31.66" width="13.205" height="0.975"/><text x="0" y="59" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif">Created by Bieutuong Bon</text><text x="0" y="64" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif">from the Noun Project</text></svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,10 @@
|
|||
<svg width="55" height="67" viewBox="0 0 55 67" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="39" cy="21" r="2" fill="#1398BB"/>
|
||||
<circle cx="45" cy="21" r="2" fill="#1398BB"/>
|
||||
<path d="M45 32H10V65L14.5 60.5L18.5 65L23 60.5L27.5 65L32 60.5L36 65L40.5 60.5L45 65V32Z" stroke="#1398BB" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M45 2V16H10V2H45Z" stroke="#1398BB" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M45 42H49C51.2091 42 53 40.2091 53 38V20C53 17.7909 51.2091 16 49 16H6C3.79086 16 2 17.7909 2 20V38C2 40.2091 3.79086 42 6 42H10" stroke="#1398BB" stroke-width="3"/>
|
||||
<path d="M21 47L35 33" stroke="#1398BB" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="34" cy="46" r="3.5" stroke="#1398BB" stroke-width="3"/>
|
||||
<path d="M18.1273 32C17.7319 32.5669 17.5 33.2564 17.5 34C17.5 35.933 19.067 37.5 21 37.5C22.933 37.5 24.5 35.933 24.5 34C24.5 33.2564 24.2681 32.5669 23.8727 32" stroke="#1398BB" stroke-width="3"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1 KiB |
|
@ -270,9 +270,11 @@ Item {
|
|||
model: transactionHistoryModel;
|
||||
delegate: Item {
|
||||
width: parent.width;
|
||||
height: (model.transaction_type === "pendingCount" && model.count !== 0) ? 40 : ((model.status === "confirmed" || model.status === "invalidated") ? transactionText.height + 30 : 0);
|
||||
height: (model.transaction_type === "pendingCount" && model.count !== 0) ? 40 :
|
||||
(transactionContainer.visible ? transactionText.height + 30 : 0);
|
||||
|
||||
Item {
|
||||
id: pendingCountContainer;
|
||||
visible: model.transaction_type === "pendingCount" && model.count !== 0;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
|
@ -291,7 +293,9 @@ Item {
|
|||
}
|
||||
|
||||
Item {
|
||||
visible: model.transaction_type !== "pendingCount" && (model.status === "confirmed" || model.status === "invalidated");
|
||||
id: transactionContainer;
|
||||
visible: model.transaction_type !== "pendingCount" &&
|
||||
(model.status === "confirmed" || model.status === "invalidated");
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
width: parent.width;
|
||||
|
|
|
@ -115,9 +115,9 @@ Item {
|
|||
property int previousIndex: -1
|
||||
Repeater {
|
||||
id: pageRepeater
|
||||
model: Math.ceil(tabletProxy.buttons.rowCount() / TabletEnums.ButtonsOnPage)
|
||||
model: tabletProxy != null ? Math.ceil(tabletProxy.buttons.rowCount() / TabletEnums.ButtonsOnPage) : 0
|
||||
onItemAdded: {
|
||||
item.proxyModel.sourceModel = tabletProxy.buttons;
|
||||
item.proxyModel.sourceModel = tabletProxy != null ? tabletProxy.buttons : null;
|
||||
item.proxyModel.pageIndex = index;
|
||||
}
|
||||
|
||||
|
|
|
@ -6504,11 +6504,16 @@ void Application::resetSensors(bool andReload) {
|
|||
}
|
||||
|
||||
void Application::hmdVisibleChanged(bool visible) {
|
||||
// TODO
|
||||
// calling start and stop will change audio input and ouput to default audio devices.
|
||||
// we need to add a pause/unpause functionality to AudioClient for this to work properly
|
||||
#if 0
|
||||
if (visible) {
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "start", Qt::QueuedConnection);
|
||||
} else {
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "stop", Qt::QueuedConnection);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Application::updateWindowTitle() const {
|
||||
|
|
|
@ -58,7 +58,7 @@ void addAvatarEntities(const QVariantList& avatarEntities) {
|
|||
EntityItemPropertiesFromScriptValueHonorReadOnly(scriptProperties, entityProperties);
|
||||
|
||||
entityProperties.setParentID(myNodeID);
|
||||
entityProperties.setClientOnly(true);
|
||||
entityProperties.setEntityHostType(entity::HostType::AVATAR);
|
||||
entityProperties.setOwningAvatarID(myNodeID);
|
||||
entityProperties.setSimulationOwner(myNodeID, AVATAR_ENTITY_SIMULATION_PRIORITY);
|
||||
entityProperties.markAllChanged();
|
||||
|
|
|
@ -807,46 +807,6 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
// before we perform rig animations and IK.
|
||||
updateSensorToWorldMatrix();
|
||||
|
||||
// if we detect the hand controller is at rest, i.e. lying on the table, or the hand is too far away from the hmd
|
||||
// disable the associated hand controller input.
|
||||
{
|
||||
// NOTE: all poses are in sensor space.
|
||||
auto leftHandIter = _controllerPoseMap.find(controller::Action::LEFT_HAND);
|
||||
if (leftHandIter != _controllerPoseMap.end() && leftHandIter->second.isValid()) {
|
||||
_leftHandAtRestDetector.update(leftHandIter->second.getTranslation(), leftHandIter->second.getRotation());
|
||||
if (_leftHandAtRestDetector.isAtRest()) {
|
||||
leftHandIter->second.valid = false;
|
||||
}
|
||||
} else {
|
||||
_leftHandAtRestDetector.invalidate();
|
||||
}
|
||||
|
||||
auto rightHandIter = _controllerPoseMap.find(controller::Action::RIGHT_HAND);
|
||||
if (rightHandIter != _controllerPoseMap.end() && rightHandIter->second.isValid()) {
|
||||
_rightHandAtRestDetector.update(rightHandIter->second.getTranslation(), rightHandIter->second.getRotation());
|
||||
if (_rightHandAtRestDetector.isAtRest()) {
|
||||
rightHandIter->second.valid = false;
|
||||
}
|
||||
} else {
|
||||
_rightHandAtRestDetector.invalidate();
|
||||
}
|
||||
|
||||
auto headIter = _controllerPoseMap.find(controller::Action::HEAD);
|
||||
|
||||
// The 99th percentile man has a spine to fingertip to height ratio of 0.45. Lets increase that by about 10% to 0.5
|
||||
// then measure the distance the center of the eyes to the finger tips. To come up with this ratio.
|
||||
// From "The Measure of Man and Woman: Human Factors in Design, Revised Edition" by Alvin R. Tilley, Henry Dreyfuss Associates
|
||||
const float MAX_HEAD_TO_HAND_DISTANCE_RATIO = 0.52f;
|
||||
|
||||
float maxHeadHandDistance = getUserHeight() * MAX_HEAD_TO_HAND_DISTANCE_RATIO;
|
||||
if (glm::length(headIter->second.getTranslation() - leftHandIter->second.getTranslation()) > maxHeadHandDistance) {
|
||||
leftHandIter->second.valid = false;
|
||||
}
|
||||
if (glm::length(headIter->second.getTranslation() - rightHandIter->second.getTranslation()) > maxHeadHandDistance) {
|
||||
rightHandIter->second.valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("skeleton");
|
||||
|
||||
|
@ -927,8 +887,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
moveOperator.addEntityToMoveList(entity, newCube);
|
||||
}
|
||||
// send an edit packet to update the entity-server about the queryAABox
|
||||
// unless it is client-only
|
||||
if (packetSender && !entity->getClientOnly()) {
|
||||
if (packetSender && entity->isDomainEntity()) {
|
||||
EntityItemProperties properties = entity->getProperties();
|
||||
properties.setQueryAACubeDirty();
|
||||
properties.setLastEdited(now);
|
||||
|
@ -939,7 +898,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
|
||||
entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
EntityItemPointer entityDescendant = std::dynamic_pointer_cast<EntityItem>(descendant);
|
||||
if (entityDescendant && !entityDescendant->getClientOnly() && descendant->updateQueryAACube()) {
|
||||
if (entityDescendant && entityDescendant->isDomainEntity() && descendant->updateQueryAACube()) {
|
||||
EntityItemProperties descendantProperties;
|
||||
descendantProperties.setQueryAACube(descendant->getQueryAACube());
|
||||
descendantProperties.setLastEdited(now);
|
||||
|
|
|
@ -63,6 +63,7 @@ Handler(balance)
|
|||
Handler(inventory)
|
||||
Handler(transferAssetToNode)
|
||||
Handler(transferAssetToUsername)
|
||||
Handler(authorizeAssetTransfer)
|
||||
Handler(alreadyOwned)
|
||||
Handler(availableUpdates)
|
||||
Handler(updateItem)
|
||||
|
@ -203,6 +204,7 @@ QString transactionString(const QJsonObject& valueObject) {
|
|||
int sentMoney = valueObject["sent_money"].toInt();
|
||||
int receivedMoney = valueObject["received_money"].toInt();
|
||||
int dateInteger = valueObject["created_at"].toInt();
|
||||
QString transactionType = valueObject["transaction_type"].toString();
|
||||
QString message = valueObject["message"].toString();
|
||||
QDateTime createdAt(QDateTime::fromSecsSinceEpoch(dateInteger, Qt::UTC));
|
||||
QString result;
|
||||
|
@ -210,8 +212,12 @@ QString transactionString(const QJsonObject& valueObject) {
|
|||
if (sentCerts <= 0 && receivedCerts <= 0 && !KNOWN_USERS.contains(valueObject["sender_name"].toString())) {
|
||||
// this is an hfc transfer.
|
||||
if (sentMoney > 0) {
|
||||
QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString());
|
||||
result += QString("Money sent to %1").arg(recipient);
|
||||
if (transactionType == "escrow") {
|
||||
result += QString("Money transferred to coupon");
|
||||
} else {
|
||||
QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString());
|
||||
result += QString("Money sent to %1").arg(recipient);
|
||||
}
|
||||
} else {
|
||||
QString sender = userLink(valueObject["sender_name"].toString(), valueObject["place_name"].toString());
|
||||
result += QString("Money from %1").arg(sender);
|
||||
|
@ -226,8 +232,12 @@ QString transactionString(const QJsonObject& valueObject) {
|
|||
) {
|
||||
// this is a non-HFC asset transfer.
|
||||
if (sentCerts > 0) {
|
||||
QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString());
|
||||
result += QString("Gift sent to %1").arg(recipient);
|
||||
if (transactionType == "escrow") {
|
||||
result += QString("Item transferred to coupon");
|
||||
} else {
|
||||
QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString());
|
||||
result += QString("Gift sent to %1").arg(recipient);
|
||||
}
|
||||
} else {
|
||||
QString sender = userLink(valueObject["sender_name"].toString(), valueObject["place_name"].toString());
|
||||
result += QString("Gift from %1").arg(sender);
|
||||
|
@ -428,6 +438,7 @@ void Ledger::transferAssetToUsername(const QString& hfc_key, const QString& user
|
|||
transaction["username"] = username;
|
||||
transaction["quantity"] = amount;
|
||||
transaction["message"] = optionalMessage;
|
||||
transaction["place_name"] = DependencyManager::get<AddressManager>()->getPlaceName();
|
||||
if (!certificateID.isEmpty()) {
|
||||
transaction["certificate_id"] = certificateID;
|
||||
}
|
||||
|
@ -440,6 +451,20 @@ void Ledger::transferAssetToUsername(const QString& hfc_key, const QString& user
|
|||
}
|
||||
}
|
||||
|
||||
void Ledger::authorizeAssetTransfer(const QString& hfc_key, const QString& couponID, const QString& certificateID, const int& amount, const QString& optionalMessage) {
|
||||
QJsonObject transaction;
|
||||
transaction["public_key"] = hfc_key;
|
||||
transaction["coupon_id"] = couponID;
|
||||
transaction["quantity"] = amount;
|
||||
transaction["message"] = optionalMessage;
|
||||
if (!certificateID.isEmpty()) {
|
||||
transaction["certificate_id"] = certificateID;
|
||||
}
|
||||
QJsonDocument transactionDoc{ transaction };
|
||||
auto transactionString = transactionDoc.toJson(QJsonDocument::Compact);
|
||||
signedSend("transaction", transactionString, hfc_key, "authorize", "authorizeAssetTransferSuccess", "authorizeAssetTransferFailure");
|
||||
}
|
||||
|
||||
void Ledger::alreadyOwned(const QString& marketplaceId) {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
QString endpoint = "already_owned";
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
void certificateInfo(const QString& certificateId);
|
||||
void transferAssetToNode(const QString& hfc_key, const QString& nodeID, const QString& certificateID, const int& amount, const QString& optionalMessage);
|
||||
void transferAssetToUsername(const QString& hfc_key, const QString& username, const QString& certificateID, const int& amount, const QString& optionalMessage);
|
||||
void authorizeAssetTransfer(const QString& hfc_key, const QString& couponID, const QString& certificateID, const int& amount, const QString& optionalMessage);
|
||||
void alreadyOwned(const QString& marketplaceId);
|
||||
void getAvailableUpdates(const QString& itemId = "", const int& pageNumber = 1, const int& itemsPerPage = 10);
|
||||
void updateItem(const QString& hfc_key, const QString& certificate_id);
|
||||
|
@ -59,6 +60,7 @@ signals:
|
|||
void certificateInfoResult(QJsonObject result);
|
||||
void transferAssetToNodeResult(QJsonObject result);
|
||||
void transferAssetToUsernameResult(QJsonObject result);
|
||||
void authorizeAssetTransferResult(QJsonObject result);
|
||||
void alreadyOwnedResult(QJsonObject result);
|
||||
void availableUpdatesResult(QJsonObject result);
|
||||
void updateItemResult(QJsonObject result);
|
||||
|
@ -86,6 +88,8 @@ public slots:
|
|||
void transferAssetToNodeFailure(QNetworkReply* reply);
|
||||
void transferAssetToUsernameSuccess(QNetworkReply* reply);
|
||||
void transferAssetToUsernameFailure(QNetworkReply* reply);
|
||||
void authorizeAssetTransferSuccess(QNetworkReply* reply);
|
||||
void authorizeAssetTransferFailure(QNetworkReply* reply);
|
||||
void alreadyOwnedSuccess(QNetworkReply* reply);
|
||||
void alreadyOwnedFailure(QNetworkReply* reply);
|
||||
void availableUpdatesSuccess(QNetworkReply* reply);
|
||||
|
|
|
@ -38,6 +38,7 @@ QmlCommerce::QmlCommerce() {
|
|||
connect(ledger.data(), &Ledger::updateCertificateStatus, this, &QmlCommerce::updateCertificateStatus);
|
||||
connect(ledger.data(), &Ledger::transferAssetToNodeResult, this, &QmlCommerce::transferAssetToNodeResult);
|
||||
connect(ledger.data(), &Ledger::transferAssetToUsernameResult, this, &QmlCommerce::transferAssetToUsernameResult);
|
||||
connect(ledger.data(), &Ledger::authorizeAssetTransferResult, this, &QmlCommerce::authorizeAssetTransferResult);
|
||||
connect(ledger.data(), &Ledger::availableUpdatesResult, this, &QmlCommerce::availableUpdatesResult);
|
||||
connect(ledger.data(), &Ledger::updateItemResult, this, &QmlCommerce::updateItemResult);
|
||||
|
||||
|
@ -246,6 +247,21 @@ void QmlCommerce::transferAssetToUsername(const QString& username,
|
|||
ledger->transferAssetToUsername(key, username, certificateID, amount, optionalMessage);
|
||||
}
|
||||
|
||||
void QmlCommerce::authorizeAssetTransfer(const QString& couponID,
|
||||
const QString& certificateID,
|
||||
const int& amount,
|
||||
const QString& optionalMessage) {
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
QStringList keys = wallet->listPublicKeys();
|
||||
if (keys.count() == 0) {
|
||||
QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } };
|
||||
return emit authorizeAssetTransferResult(result);
|
||||
}
|
||||
QString key = keys[0];
|
||||
ledger->authorizeAssetTransfer(key, couponID, certificateID, amount, optionalMessage);
|
||||
}
|
||||
|
||||
void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& certificateID) {
|
||||
if (!certificateID.isEmpty()) {
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
|
|
|
@ -51,6 +51,7 @@ signals:
|
|||
|
||||
void transferAssetToNodeResult(QJsonObject result);
|
||||
void transferAssetToUsernameResult(QJsonObject result);
|
||||
void authorizeAssetTransferResult(QJsonObject result);
|
||||
|
||||
void contentSetChanged(const QString& contentSetHref);
|
||||
|
||||
|
@ -84,6 +85,7 @@ protected:
|
|||
|
||||
Q_INVOKABLE void transferAssetToNode(const QString& nodeID, const QString& certificateID, const int& amount, const QString& optionalMessage);
|
||||
Q_INVOKABLE void transferAssetToUsername(const QString& username, const QString& certificateID, const int& amount, const QString& optionalMessage);
|
||||
Q_INVOKABLE void authorizeAssetTransfer(const QString& couponID, const QString& certificateID, const int& amount, const QString& optionalMessage);
|
||||
|
||||
Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID);
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ void WalletScriptingInterface::proveAvatarEntityOwnershipVerification(const QUui
|
|||
QSharedPointer<ContextOverlayInterface> contextOverlayInterface = DependencyManager::get<ContextOverlayInterface>();
|
||||
EntityItemProperties entityProperties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID,
|
||||
contextOverlayInterface->getEntityPropertyFlags());
|
||||
if (entityProperties.getClientOnly()) {
|
||||
if (entityProperties.getEntityHostType() == entity::HostType::AVATAR) {
|
||||
if (!entityID.isNull() && entityProperties.getCertificateID().length() > 0) {
|
||||
contextOverlayInterface->requestOwnershipVerification(entityID);
|
||||
} else {
|
||||
|
|
|
@ -46,7 +46,7 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
|||
_entityPropertyFlags += PROP_DIMENSIONS;
|
||||
_entityPropertyFlags += PROP_REGISTRATION_POINT;
|
||||
_entityPropertyFlags += PROP_CERTIFICATE_ID;
|
||||
_entityPropertyFlags += PROP_CLIENT_ONLY;
|
||||
_entityPropertyFlags += PROP_ENTITY_HOST_TYPE;
|
||||
_entityPropertyFlags += PROP_OWNING_AVATAR_ID;
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>().data();
|
||||
|
@ -296,7 +296,7 @@ void ContextOverlayInterface::requestOwnershipVerification(const QUuid& entityID
|
|||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (entityProperties.verifyStaticCertificateProperties()) {
|
||||
if (entityProperties.getClientOnly()) {
|
||||
if (entityProperties.getEntityHostType() == entity::HostType::AVATAR) {
|
||||
SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer);
|
||||
|
||||
if (entityServer) {
|
||||
|
|
|
@ -310,7 +310,7 @@ void Avatar::updateAvatarEntities() {
|
|||
PerformanceTimer perfTimer("attachments");
|
||||
|
||||
// AVATAR ENTITY UPDATE FLOW
|
||||
// - if queueEditEntityMessage sees clientOnly flag it does _myAvatar->updateAvatarEntity()
|
||||
// - if queueEditEntityMessage sees avatarEntity flag it does _myAvatar->updateAvatarEntity()
|
||||
// - updateAvatarEntity saves the bytes and flags the trait instance for the entity as updated
|
||||
// - ClientTraitsHandler::sendChangedTraitsToMixer sends the entity bytes to the mixer which relays them to other interfaces
|
||||
// - AvatarHashMap::processBulkAvatarTraits on other interfaces calls avatar->processTraitInstace
|
||||
|
@ -389,7 +389,7 @@ void Avatar::updateAvatarEntities() {
|
|||
QScriptValue scriptProperties = variantMapToScriptValue(asMap, scriptEngine);
|
||||
EntityItemProperties properties;
|
||||
EntityItemPropertiesFromScriptValueHonorReadOnly(scriptProperties, properties);
|
||||
properties.setClientOnly(true);
|
||||
properties.setEntityHostType(entity::HostType::AVATAR);
|
||||
properties.setOwningAvatarID(getID());
|
||||
|
||||
// there's no entity-server to tell us we're the simulation owner, so always set the
|
||||
|
|
|
@ -2103,8 +2103,9 @@ void AvatarData::setJointMappingsFromNetworkReply() {
|
|||
|
||||
// before we process this update, make sure that the skeleton model URL hasn't changed
|
||||
// since we made the FST request
|
||||
if (networkReply->url() != _skeletonModelURL) {
|
||||
if (networkReply->error() != QNetworkReply::NoError || networkReply->url() != _skeletonModelURL) {
|
||||
qCDebug(avatars) << "Refusing to set joint mappings for FST URL that does not match the current URL";
|
||||
networkReply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2832,35 +2833,47 @@ void AvatarData::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) {
|
|||
qCDebug(avatars) << "discard suspect AvatarEntityData with size =" << avatarEntityData.size();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<QUuid> deletedEntityIDs;
|
||||
QList<QUuid> updatedEntityIDs;
|
||||
|
||||
_avatarEntitiesLock.withWriteLock([&] {
|
||||
if (_avatarEntityData != avatarEntityData) {
|
||||
|
||||
// keep track of entities that were attached to this avatar but no longer are
|
||||
AvatarEntityIDs previousAvatarEntityIDs = QSet<QUuid>::fromList(_avatarEntityData.keys());
|
||||
|
||||
_avatarEntityData = avatarEntityData;
|
||||
setAvatarEntityDataChanged(true);
|
||||
|
||||
deletedEntityIDs.reserve(previousAvatarEntityIDs.size());
|
||||
|
||||
foreach (auto entityID, previousAvatarEntityIDs) {
|
||||
if (!_avatarEntityData.contains(entityID)) {
|
||||
_avatarEntityDetached.insert(entityID);
|
||||
|
||||
if (_clientTraitsHandler) {
|
||||
// we have a client traits handler, so we flag this removed entity as deleted
|
||||
// so that changes are sent next frame
|
||||
_clientTraitsHandler->markInstancedTraitDeleted(AvatarTraits::AvatarEntity, entityID);
|
||||
}
|
||||
deletedEntityIDs.push_back(entityID);
|
||||
}
|
||||
}
|
||||
|
||||
if (_clientTraitsHandler) {
|
||||
// if we have a client traits handler, flag any updated or created entities
|
||||
// so that we send changes for them next frame
|
||||
foreach (auto entityID, _avatarEntityData.keys()) {
|
||||
_clientTraitsHandler->markInstancedTraitUpdated(AvatarTraits::AvatarEntity, entityID);
|
||||
}
|
||||
}
|
||||
updatedEntityIDs = _avatarEntityData.keys();
|
||||
}
|
||||
});
|
||||
|
||||
if (_clientTraitsHandler) {
|
||||
// we have a client traits handler
|
||||
|
||||
// flag removed entities as deleted so that changes are sent next frame
|
||||
for (auto& deletedEntityID : deletedEntityIDs) {
|
||||
_clientTraitsHandler->markInstancedTraitDeleted(AvatarTraits::AvatarEntity, deletedEntityID);
|
||||
}
|
||||
|
||||
// flag any updated or created entities so that we send changes for them next frame
|
||||
for (auto& entityID : updatedEntityIDs) {
|
||||
_clientTraitsHandler->markInstancedTraitUpdated(AvatarTraits::AvatarEntity, entityID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
AvatarEntityIDs AvatarData::getAndClearRecentlyDetachedIDs() {
|
||||
|
|
|
@ -66,7 +66,7 @@ void ClientTraitsHandler::resetForNewMixer() {
|
|||
}
|
||||
|
||||
void ClientTraitsHandler::sendChangedTraitsToMixer() {
|
||||
Lock lock(_traitLock);
|
||||
std::unique_lock<Mutex> lock(_traitLock);
|
||||
|
||||
if (hasChangedTraits() || _shouldPerformInitialSend) {
|
||||
// we have at least one changed trait to send
|
||||
|
@ -90,6 +90,14 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() {
|
|||
_traitStatuses.reset();
|
||||
_hasChangedTraits = false;
|
||||
|
||||
// if this was an initial send of all traits, consider it completed
|
||||
bool initialSend = _shouldPerformInitialSend;
|
||||
_shouldPerformInitialSend = false;
|
||||
|
||||
// we can release the lock here since we've taken a copy of statuses
|
||||
// and will setup the packet using the information in the copy
|
||||
lock.unlock();
|
||||
|
||||
auto simpleIt = traitStatusesCopy.simpleCBegin();
|
||||
while (simpleIt != traitStatusesCopy.simpleCEnd()) {
|
||||
// because the vector contains all trait types (for access using trait type as index)
|
||||
|
@ -111,12 +119,12 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() {
|
|||
auto instancedIt = traitStatusesCopy.instancedCBegin();
|
||||
while (instancedIt != traitStatusesCopy.instancedCEnd()) {
|
||||
for (auto& instanceIDValuePair : instancedIt->instances) {
|
||||
if ((_shouldPerformInitialSend && instanceIDValuePair.value != Deleted)
|
||||
if ((initialSend && instanceIDValuePair.value != Deleted)
|
||||
|| instanceIDValuePair.value == Updated) {
|
||||
// this is a changed trait we need to send or we haven't send out trait information yet
|
||||
// ask the owning avatar to pack it
|
||||
_owningAvatar->packTraitInstance(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList);
|
||||
} else if (!_shouldPerformInitialSend && instanceIDValuePair.value == Deleted) {
|
||||
} else if (!initialSend && instanceIDValuePair.value == Deleted) {
|
||||
// pack delete for this trait instance
|
||||
AvatarTraits::packInstancedTraitDelete(instancedIt->traitType, instanceIDValuePair.id,
|
||||
*traitsPacketList);
|
||||
|
@ -127,9 +135,6 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() {
|
|||
}
|
||||
|
||||
nodeList->sendPacketList(std::move(traitsPacketList), *avatarMixer);
|
||||
|
||||
// if this was an initial send of all traits, consider it completed
|
||||
_shouldPerformInitialSend = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,6 @@ void main(void) {
|
|||
ivec2 texCoord = ivec2(floor(varTexCoord0 * vec2(textureData.textureSize)));
|
||||
texCoord.x /= 2;
|
||||
int row = int(floor(gl_FragCoord.y));
|
||||
if (row % 2 > 0) {
|
||||
texCoord.x += (textureData.textureSize.x / 2);
|
||||
}
|
||||
texCoord.x += int(row % 2 > 0) * (textureData.textureSize.x / 2);
|
||||
outFragColor = vec4(pow(texelFetch(colorMap, texCoord, 0).rgb, vec3(2.2)), 1.0);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ layout(location=0) out vec4 outFragColor;
|
|||
float sRGBFloatToLinear(float value) {
|
||||
const float SRGB_ELBOW = 0.04045;
|
||||
|
||||
return (value <= SRGB_ELBOW) ? value / 12.92 : pow((value + 0.055) / 1.055, 2.4);
|
||||
return mix(pow((value + 0.055) / 1.055, 2.4), value / 12.92, float(value <= SRGB_ELBOW));
|
||||
}
|
||||
|
||||
vec3 colorToLinearRGB(vec3 srgb) {
|
||||
|
|
|
@ -39,7 +39,7 @@ enum class RenderItemStatusIcon {
|
|||
SIMULATION_OWNER = 3,
|
||||
HAS_ACTIONS = 4,
|
||||
OTHER_SIMULATION_OWNER = 5,
|
||||
CLIENT_ONLY = 6,
|
||||
ENTITY_HOST_TYPE = 6,
|
||||
NONE = 255
|
||||
};
|
||||
|
||||
|
@ -115,17 +115,20 @@ void EntityRenderer::makeStatusGetters(const EntityItemPointer& entity, Item::St
|
|||
});
|
||||
|
||||
statusGetters.push_back([entity, myNodeID] () -> render::Item::Status::Value {
|
||||
if (entity->getClientOnly()) {
|
||||
if (entity->isAvatarEntity()) {
|
||||
if (entity->getOwningAvatarID() == myNodeID) {
|
||||
return render::Item::Status::Value(1.0f, render::Item::Status::Value::GREEN,
|
||||
(unsigned char)RenderItemStatusIcon::CLIENT_ONLY);
|
||||
(unsigned char)RenderItemStatusIcon::ENTITY_HOST_TYPE);
|
||||
} else {
|
||||
return render::Item::Status::Value(1.0f, render::Item::Status::Value::RED,
|
||||
(unsigned char)RenderItemStatusIcon::CLIENT_ONLY);
|
||||
(unsigned char)RenderItemStatusIcon::ENTITY_HOST_TYPE);
|
||||
}
|
||||
} else if (entity->isLocalEntity()) {
|
||||
return render::Item::Status::Value(1.0f, render::Item::Status::Value::BLUE,
|
||||
(unsigned char)RenderItemStatusIcon::ENTITY_HOST_TYPE);
|
||||
}
|
||||
return render::Item::Status::Value(0.0f, render::Item::Status::Value::GREEN,
|
||||
(unsigned char)RenderItemStatusIcon::CLIENT_ONLY);
|
||||
(unsigned char)RenderItemStatusIcon::ENTITY_HOST_TYPE);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
|||
batch.setModelTransform(renderTransform);
|
||||
|
||||
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
|
||||
drawMaterial->setTextureTransforms(textureTransform);
|
||||
drawMaterial->setTextureTransforms(textureTransform, MaterialMappingMode::UV, true);
|
||||
|
||||
// bind the material
|
||||
RenderPipelines::bindMaterial(drawMaterial, batch, args->_enableTexturing);
|
||||
|
|
|
@ -80,10 +80,11 @@ float interpolate3Points(float y1, float y2, float y3, float u) {
|
|||
halfSlope = (y3 - y1) / 2.0f;
|
||||
float slope12 = y2 - y1;
|
||||
float slope23 = y3 - y2;
|
||||
if (abs(halfSlope) > abs(slope12)) {
|
||||
halfSlope = slope12;
|
||||
} else if (abs(halfSlope) > abs(slope23)) {
|
||||
halfSlope = slope23;
|
||||
|
||||
{
|
||||
float check = float(abs(halfSlope) > abs(slope12));
|
||||
halfSlope = mix(halfSlope, slope12, check);
|
||||
halfSlope = mix(halfSlope, slope23, (1.0 - check) * float(abs(halfSlope) > abs(slope23)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,16 +84,19 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type,
|
|||
EntityTreePointer entityTree,
|
||||
EntityItemID entityItemID,
|
||||
const EntityItemProperties& properties) {
|
||||
if (properties.getClientOnly()) {
|
||||
if (properties.getEntityHostType() == entity::HostType::AVATAR) {
|
||||
if (!_myAvatar) {
|
||||
qCWarning(entities) << "Suppressing entity edit message: cannot send clientOnly edit with no myAvatar";
|
||||
qCWarning(entities) << "Suppressing entity edit message: cannot send avatar entity edit with no myAvatar";
|
||||
} else if (properties.getOwningAvatarID() == _myAvatar->getID()) {
|
||||
// this is an avatar-based entity --> update our avatar-data rather than sending to the entity-server
|
||||
queueEditAvatarEntityMessage(type, entityTree, entityItemID, properties);
|
||||
} else {
|
||||
qCWarning(entities) << "Suppressing entity edit message: cannot send clientOnly edit for another avatar";
|
||||
qCWarning(entities) << "Suppressing entity edit message: cannot send avatar entity edit for another avatar";
|
||||
}
|
||||
return;
|
||||
} else if (properties.getEntityHostType() == entity::HostType::LOCAL) {
|
||||
// Don't send edits for local entities
|
||||
return;
|
||||
}
|
||||
|
||||
if (entityTree && entityTree->isServerlessMode()) {
|
||||
|
|
|
@ -119,7 +119,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
|
|||
requestedProperties += PROP_PARENT_JOINT_INDEX;
|
||||
requestedProperties += PROP_QUERY_AA_CUBE;
|
||||
|
||||
requestedProperties += PROP_CLIENT_ONLY;
|
||||
requestedProperties += PROP_ENTITY_HOST_TYPE;
|
||||
requestedProperties += PROP_OWNING_AVATAR_ID;
|
||||
|
||||
requestedProperties += PROP_LAST_EDITED_BY;
|
||||
|
@ -172,7 +172,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
|||
EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
|
||||
EntityPropertyFlags requestedProperties = getEntityProperties(params);
|
||||
|
||||
requestedProperties -= PROP_CLIENT_ONLY;
|
||||
requestedProperties -= PROP_ENTITY_HOST_TYPE;
|
||||
requestedProperties -= PROP_OWNING_AVATAR_ID;
|
||||
|
||||
// If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item,
|
||||
|
@ -1278,10 +1278,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire
|
|||
EntityItemProperties properties(propertyFlags);
|
||||
properties._id = getID();
|
||||
properties._idSet = true;
|
||||
properties._created = getCreated();
|
||||
properties._lastEdited = getLastEdited();
|
||||
properties.setClientOnly(getClientOnly());
|
||||
properties.setOwningAvatarID(getOwningAvatarID());
|
||||
|
||||
properties._type = getType();
|
||||
|
||||
|
@ -1337,7 +1334,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(localPosition, getLocalPosition);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(localRotation, getLocalOrientation);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(clientOnly, getClientOnly);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(entityHostType, getEntityHostType);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(owningAvatarID, getOwningAvatarID);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lastEditedBy, getLastEditedBy);
|
||||
|
@ -1479,7 +1476,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(queryAACube, setQueryAACube);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(clientOnly, setClientOnly);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(entityHostType, setEntityHostType);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(owningAvatarID, setOwningAvatarID);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lastEditedBy, setLastEditedBy);
|
||||
|
@ -2496,7 +2493,7 @@ void EntityItem::dimensionsChanged() {
|
|||
|
||||
bool EntityItem::getScalesWithParent() const {
|
||||
// keep this logic the same as in EntityItemProperties::getScalesWithParent
|
||||
if (getClientOnly()) {
|
||||
if (isAvatarEntity()) {
|
||||
QUuid ancestorID = findAncestorOfType(NestableType::Avatar);
|
||||
return !ancestorID.isNull();
|
||||
} else {
|
||||
|
@ -3277,7 +3274,7 @@ void EntityItem::prepareForSimulationOwnershipBid(EntityItemProperties& properti
|
|||
properties.setSimulationOwner(Physics::getSessionUUID(), priority);
|
||||
setPendingOwnershipPriority(priority);
|
||||
|
||||
properties.setClientOnly(getClientOnly());
|
||||
properties.setEntityHostType(getEntityHostType());
|
||||
properties.setOwningAvatarID(getOwningAvatarID());
|
||||
setLastBroadcast(now); // for debug/physics status icons
|
||||
}
|
||||
}
|
|
@ -64,6 +64,18 @@ const uint64_t MAX_INCOMING_SIMULATION_UPDATE_PERIOD = MAX_OUTGOING_SIMULATION_U
|
|||
|
||||
class MeshProxyList;
|
||||
|
||||
#ifdef DOMAIN
|
||||
#undef DOMAIN
|
||||
#endif
|
||||
|
||||
namespace entity {
|
||||
enum class HostType {
|
||||
DOMAIN = 0,
|
||||
AVATAR,
|
||||
LOCAL
|
||||
};
|
||||
}
|
||||
|
||||
/// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available
|
||||
/// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate
|
||||
/// one directly, instead you must only construct one of it's derived classes with additional features.
|
||||
|
@ -478,9 +490,13 @@ public:
|
|||
void setScriptHasFinishedPreload(bool value);
|
||||
bool isScriptPreloadFinished();
|
||||
|
||||
bool getClientOnly() const { return _clientOnly; }
|
||||
virtual void setClientOnly(bool clientOnly) { _clientOnly = clientOnly; }
|
||||
// if this entity is client-only, which avatar is it associated with?
|
||||
bool isDomainEntity() const { return _hostType == entity::HostType::DOMAIN; }
|
||||
bool isAvatarEntity() const { return _hostType == entity::HostType::AVATAR; }
|
||||
bool isLocalEntity() const { return _hostType == entity::HostType::LOCAL; }
|
||||
entity::HostType getEntityHostType() const { return _hostType; }
|
||||
virtual void setEntityHostType(entity::HostType hostType) { _hostType = hostType; }
|
||||
|
||||
// if this entity is an avatar entity, which avatar is it associated with?
|
||||
QUuid getOwningAvatarID() const { return _owningAvatarID; }
|
||||
virtual void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; }
|
||||
|
||||
|
@ -673,7 +689,7 @@ protected:
|
|||
|
||||
QUuid _sourceUUID; /// the server node UUID we came from
|
||||
|
||||
bool _clientOnly { false };
|
||||
entity::HostType _hostType { entity::HostType::DOMAIN };
|
||||
bool _transitingWithAvatar{ false };
|
||||
QUuid _owningAvatarID;
|
||||
|
||||
|
|
|
@ -306,6 +306,29 @@ void EntityItemProperties::setMaterialMappingModeFromString(const QString& mater
|
|||
}
|
||||
}
|
||||
|
||||
QString EntityItemProperties::getEntityHostTypeAsString() const {
|
||||
switch (_entityHostType) {
|
||||
case entity::HostType::DOMAIN:
|
||||
return "domain";
|
||||
case entity::HostType::AVATAR:
|
||||
return "avatar";
|
||||
case entity::HostType::LOCAL:
|
||||
return "local";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItemProperties::setEntityHostTypeFromString(const QString& entityHostType) {
|
||||
if (entityHostType == "domain") {
|
||||
_entityHostType = entity::HostType::DOMAIN;
|
||||
} else if (entityHostType == "avatar") {
|
||||
_entityHostType = entity::HostType::AVATAR;
|
||||
} else if (entityHostType == "local") {
|
||||
_entityHostType = entity::HostType::LOCAL;
|
||||
}
|
||||
}
|
||||
|
||||
EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||
EntityPropertyFlags changedProperties;
|
||||
|
||||
|
@ -385,6 +408,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_DATA, materialData);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_REPEAT, materialRepeat);
|
||||
CHECK_PROPERTY_CHANGE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera);
|
||||
CHECK_PROPERTY_CHANGE(PROP_PARTICLE_SPIN, particleSpin);
|
||||
CHECK_PROPERTY_CHANGE(PROP_SPIN_SPREAD, spinSpread);
|
||||
|
@ -453,7 +477,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_GHOSTING_ALLOWED, ghostingAllowed);
|
||||
CHECK_PROPERTY_CHANGE(PROP_FILTER_URL, filterURL);
|
||||
|
||||
CHECK_PROPERTY_CHANGE(PROP_CLIENT_ONLY, clientOnly);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ENTITY_HOST_TYPE, entityHostType);
|
||||
CHECK_PROPERTY_CHANGE(PROP_OWNING_AVATAR_ID, owningAvatarID);
|
||||
|
||||
CHECK_PROPERTY_CHANGE(PROP_SHAPE, shape);
|
||||
|
@ -489,12 +513,18 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* @property {Entities.EntityType} type - The entity type. You cannot change the type of an entity after it's created. (Though
|
||||
* its value may switch among <code>"Box"</code>, <code>"Shape"</code>, and <code>"Sphere"</code> depending on changes to
|
||||
* the <code>shape</code> property set for entities of these types.) <em>Read-only.</em>
|
||||
* @property {boolean} clientOnly=false - If <code>true</code> then the entity is an avatar entity; otherwise it is a server
|
||||
* entity. An avatar entity follows you to each domain you visit, rendering at the same world coordinates unless it's
|
||||
* parented to your avatar. <em>Value cannot be changed after the entity is created.</em><br />
|
||||
* The value can also be set at entity creation by using the <code>clientOnly</code> parameter in
|
||||
* @property {EntityHostType} entityHostType="domain" - How this entity will behave, including if and how it is sent to other people.
|
||||
* The value can only be set at entity creation by using the <code>entityHostType</code> parameter in
|
||||
* {@link Entities.addEntity}.
|
||||
* @property {Uuid} owningAvatarID=Uuid.NULL - The session ID of the owning avatar if <code>clientOnly</code> is
|
||||
* @property {boolean} avatarEntity=false - If <code>true</code> then the entity is an avatar entity; An avatar entity follows you to each domain you visit,
|
||||
* rendering at the same world coordinates unless it's parented to your avatar. <em>Value cannot be changed after the entity is created.</em><br />
|
||||
* The value can only be set at entity creation by using the <code>entityHostType</code> parameter in
|
||||
* {@link Entities.addEntity}. <code>clientOnly</code> is an alias.
|
||||
* @property {boolean} localEntity=false - If <code>true</code> then the entity is a local entity; Local entities only render for you and are not sent over the wire.
|
||||
* <em>Value cannot be changed after the entity is created.</em><br />
|
||||
* The value can only be set at entity creation by using the <code>entityHostType</code> parameter in
|
||||
* {@link Entities.addEntity}.
|
||||
* @property {Uuid} owningAvatarID=Uuid.NULL - The session ID of the owning avatar if <code>avatarEntity</code> is
|
||||
* <code>true</code>, otherwise {@link Uuid|Uuid.NULL}. <em>Read-only.</em>
|
||||
*
|
||||
* @property {string} created - The UTC date and time that the entity was created, in ISO 8601 format as
|
||||
|
@ -594,7 +624,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* @property {number} parentJointIndex=65535 - The joint of the entity or avatar that this entity is parented to. Use
|
||||
* <code>65535</code> or <code>-1</code> to parent to the entity or avatar's position and orientation rather than a joint.
|
||||
* @property {Vec3} localPosition=0,0,0 - The position of the entity relative to its parent if the entity is parented,
|
||||
* otherwise the same value as <code>position</code>. If the entity is parented to an avatar and is <code>clientOnly</code>
|
||||
* otherwise the same value as <code>position</code>. If the entity is parented to an avatar and is an <code>avatarEntity</code>
|
||||
* so that it scales with the avatar, this value remains the original local position value while the avatar scale changes.
|
||||
* @property {Quat} localRotation=0,0,0,1 - The rotation of the entity relative to its parent if the entity is parented,
|
||||
* otherwise the same value as <code>rotation</code>.
|
||||
|
@ -602,8 +632,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* otherwise the same value as <code>velocity</code>.
|
||||
* @property {Vec3} localAngularVelocity=0,0,0 - The angular velocity of the entity relative to its parent if the entity is
|
||||
* parented, otherwise the same value as <code>position</code>.
|
||||
* @property {Vec3} localDimensions - The dimensions of the entity. If the entity is parented to an avatar and is
|
||||
* <code>clientOnly</code> so that it scales with the avatar, this value remains the original dimensions value while the
|
||||
* @property {Vec3} localDimensions - The dimensions of the entity. If the entity is parented to an avatar and is an
|
||||
* <code>avatarEntity</code> so that it scales with the avatar, this value remains the original dimensions value while the
|
||||
* avatar scale changes.
|
||||
*
|
||||
* @property {Entities.BoundingBox} boundingBox - The axis-aligned bounding box that tightly encloses the entity.
|
||||
|
@ -628,7 +658,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* @property {boolean} cloneDynamic=false - If <code>true</code> then clones created from this entity will have their
|
||||
* <code>dynamic</code> property set to <code>true</code>.
|
||||
* @property {boolean} cloneAvatarEntity=false - If <code>true</code> then clones created from this entity will be created as
|
||||
* avatar entities: their <code>clientOnly</code> property will be set to <code>true</code>.
|
||||
* avatar entities: their <code>avatarEntity</code> property will be set to <code>true</code>.
|
||||
* @property {Uuid} cloneOriginID - The ID of the entity that this entity was cloned from.
|
||||
*
|
||||
* @property {Entities.Grab} grab - The grab-related properties.
|
||||
|
@ -739,7 +769,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* overlay's ID.
|
||||
* To apply a material to an avatar, set the material entity's <code>parentID</code> property to the avatar's session UUID.
|
||||
* To apply a material to your avatar such that it persists across domains and log-ins, create the material as an avatar entity
|
||||
* by setting the <code>clientOnly</code> parameter in {@link Entities.addEntity} to <code>true</code>.
|
||||
* by setting the <code>entityHostType</code> parameter in {@link Entities.addEntity} to <code>"avatar"</code>.
|
||||
* Material entities render as non-scalable spheres if they don't have their parent set.
|
||||
* @typedef {object} Entities.EntityProperties-Material
|
||||
* @property {string} materialURL="" - URL to a {@link MaterialResource}. If you append <code>?name</code> to the URL, the
|
||||
|
@ -754,7 +784,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* Otherwise the property value is parsed as an unsigned integer, specifying the mesh index to modify. Invalid values are
|
||||
* parsed to <code>0</code>.
|
||||
* @property {string} materialMappingMode="uv" - How the material is mapped to the entity. Either <code>"uv"</code> or
|
||||
* <code>"projected"</code>. <em>Currently, only <code>"uv"</code> is supported.
|
||||
* <code>"projected"</code>. In "uv" mode, the material will be evaluated within the UV space of the mesh it is applied to. In
|
||||
* "projected" mode, the 3D transform of the Material Entity will be used to evaluate the texture coordinates for the material.
|
||||
* @property {Vec2} materialMappingPos=0,0 - Offset position in UV-space of the top left of the material, range
|
||||
* <code>{ x: 0, y: 0 }</code> – <code>{ x: 1, y: 1 }</code>.
|
||||
* @property {Vec2} materialMappingScale=1,1 - How much to scale the material within the parent's UV-space.
|
||||
|
@ -762,6 +793,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* @property {string} materialData="" - Used to store {@link MaterialResource} data as a JSON string. You can use
|
||||
* <code>JSON.parse()</code> to parse the string into a JavaScript object which you can manipulate the properties of, and
|
||||
* use <code>JSON.stringify()</code> to convert the object into a string to put in the property.
|
||||
* @property {boolean} materialRepeat=true - If true, the material will repeat. If false, fragments outside of texCoord 0 - 1 will be discarded.
|
||||
* Works in both "uv" and "projected" modes.
|
||||
* @example <caption>Color a sphere using a Material entity.</caption>
|
||||
* var entityID = Entities.addEntity({
|
||||
* type: "Sphere",
|
||||
|
@ -1485,6 +1518,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_DATA, materialData);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_REPEAT, materialRepeat);
|
||||
}
|
||||
|
||||
/**jsdoc
|
||||
|
@ -1527,8 +1561,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ANGULAR_VELOCITY, localAngularVelocity);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_DIMENSIONS, localDimensions);
|
||||
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLIENT_ONLY, clientOnly); // Gettable but not settable except at entity creation
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID); // Gettable but not settable
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ENTITY_HOST_TYPE, entityHostType, getEntityHostTypeAsString()); // Gettable but not settable except at entity creation
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID); // Gettable but not settable
|
||||
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE, cloneable);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_LIFETIME, cloneLifetime);
|
||||
|
@ -1567,12 +1601,14 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(renderInfo, renderInfo); // Gettable but not settable
|
||||
}
|
||||
|
||||
// FIXME: These properties should already have been set above.
|
||||
if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::ClientOnly)) {
|
||||
properties.setProperty("clientOnly", convertScriptValue(engine, getClientOnly()));
|
||||
properties.setProperty("clientOnly", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR));
|
||||
}
|
||||
if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::OwningAvatarID)) {
|
||||
properties.setProperty("owningAvatarID", convertScriptValue(engine, getOwningAvatarID()));
|
||||
if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::AvatarEntity)) {
|
||||
properties.setProperty("avatarEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR));
|
||||
}
|
||||
if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::LocalEntity)) {
|
||||
properties.setProperty("localEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::LOCAL));
|
||||
}
|
||||
|
||||
// FIXME - I don't think these properties are supported any more
|
||||
|
@ -1666,6 +1702,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingScale, vec2, setMaterialMappingScale);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingRot, float, setMaterialMappingRot);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialData, QString, setMaterialData);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialRepeat, bool, setMaterialRepeat);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(isVisibleInSecondaryCamera, bool, setIsVisibleInSecondaryCamera);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(particleSpin, float, setParticleSpin);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(spinSpread, float, setSpinSpread);
|
||||
|
@ -1761,7 +1798,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(ghostingAllowed, bool, setGhostingAllowed);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(filterURL, QString, setFilterURL);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(clientOnly, bool, setClientOnly);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(entityHostType, EntityHostType);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(owningAvatarID, QUuid, setOwningAvatarID);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(dpi, uint16_t, setDPI);
|
||||
|
@ -1927,7 +1964,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
|
|||
COPY_PROPERTY_IF_CHANGED(ghostingAllowed);
|
||||
COPY_PROPERTY_IF_CHANGED(filterURL);
|
||||
|
||||
COPY_PROPERTY_IF_CHANGED(clientOnly);
|
||||
COPY_PROPERTY_IF_CHANGED(entityHostType);
|
||||
COPY_PROPERTY_IF_CHANGED(owningAvatarID);
|
||||
|
||||
COPY_PROPERTY_IF_CHANGED(dpi);
|
||||
|
@ -2061,6 +2098,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
|||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, vec2);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_DATA, MaterialData, materialData, QString);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_REPEAT, MaterialRepeat, materialRepeat, bool);
|
||||
|
||||
ADD_PROPERTY_TO_MAP(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool);
|
||||
|
||||
|
@ -2511,6 +2549,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
|||
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, properties.getMaterialMappingScale());
|
||||
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, properties.getMaterialMappingRot());
|
||||
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_DATA, properties.getMaterialData());
|
||||
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_REPEAT, properties.getMaterialRepeat());
|
||||
}
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
|
||||
|
@ -2898,6 +2937,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_SCALE, vec2, setMaterialMappingScale);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_ROT, float, setMaterialMappingRot);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_DATA, QString, setMaterialData);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_REPEAT, bool, setMaterialRepeat);
|
||||
}
|
||||
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
|
||||
|
@ -3137,6 +3177,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_materialMappingScaleChanged = true;
|
||||
_materialMappingRotChanged = true;
|
||||
_materialDataChanged = true;
|
||||
_materialRepeatChanged = true;
|
||||
|
||||
// Certifiable Properties
|
||||
_itemNameChanged = true;
|
||||
|
@ -3213,7 +3254,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_ghostingAllowedChanged = true;
|
||||
_filterURLChanged = true;
|
||||
|
||||
_clientOnlyChanged = true;
|
||||
_entityHostTypeChanged = true;
|
||||
_owningAvatarIDChanged = true;
|
||||
|
||||
_dpiChanged = true;
|
||||
|
@ -3587,6 +3628,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
if (materialDataChanged()) {
|
||||
out += "materialData";
|
||||
}
|
||||
if (materialRepeatChanged()) {
|
||||
out += "materialRepeat";
|
||||
}
|
||||
if (isVisibleInSecondaryCameraChanged()) {
|
||||
out += "isVisibleInSecondaryCamera";
|
||||
}
|
||||
|
@ -3712,8 +3756,8 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
out += "queryAACube";
|
||||
}
|
||||
|
||||
if (clientOnlyChanged()) {
|
||||
out += "clientOnly";
|
||||
if (entityHostTypeChanged()) {
|
||||
out += "entityHostType";
|
||||
}
|
||||
if (owningAvatarIDChanged()) {
|
||||
out += "owningAvatarID";
|
||||
|
@ -3788,7 +3832,7 @@ bool EntityItemProperties::getScalesWithParent() const {
|
|||
if (success && parent) {
|
||||
bool avatarAncestor = (parent->getNestableType() == NestableType::Avatar ||
|
||||
parent->hasAncestorOfType(NestableType::Avatar));
|
||||
scalesWithParent = getClientOnly() && avatarAncestor;
|
||||
scalesWithParent = getEntityHostType() == entity::HostType::AVATAR && avatarAncestor;
|
||||
}
|
||||
}
|
||||
return scalesWithParent;
|
||||
|
@ -3946,7 +3990,13 @@ void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityID
|
|||
setParentJointIndex(-1);
|
||||
setLifetime(getCloneLifetime());
|
||||
setDynamic(getCloneDynamic());
|
||||
setClientOnly(getCloneAvatarEntity());
|
||||
if (getEntityHostType() != entity::HostType::LOCAL) {
|
||||
setEntityHostType(getCloneAvatarEntity() ? entity::HostType::AVATAR : entity::HostType::DOMAIN);
|
||||
} else {
|
||||
// Local Entities clone as local entities
|
||||
setEntityHostType(entity::HostType::LOCAL);
|
||||
setCollisionless(true);
|
||||
}
|
||||
setCreated(usecTimestampNow());
|
||||
setLastEdited(usecTimestampNow());
|
||||
setCloneable(ENTITY_ITEM_DEFAULT_CLONEABLE);
|
||||
|
|
|
@ -241,6 +241,7 @@ public:
|
|||
DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, glm::vec2, glm::vec2(1.0f));
|
||||
DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float, 0);
|
||||
DEFINE_PROPERTY_REF(PROP_MATERIAL_DATA, MaterialData, materialData, QString, "");
|
||||
DEFINE_PROPERTY_REF(PROP_MATERIAL_REPEAT, MaterialRepeat, materialRepeat, bool, true);
|
||||
|
||||
DEFINE_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool, ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA);
|
||||
|
||||
|
@ -279,7 +280,7 @@ public:
|
|||
DEFINE_PROPERTY(PROP_GHOSTING_ALLOWED, GhostingAllowed, ghostingAllowed, bool, ZoneEntityItem::DEFAULT_GHOSTING_ALLOWED);
|
||||
DEFINE_PROPERTY(PROP_FILTER_URL, FilterURL, filterURL, QString, ZoneEntityItem::DEFAULT_FILTER_URL);
|
||||
|
||||
DEFINE_PROPERTY(PROP_CLIENT_ONLY, ClientOnly, clientOnly, bool, false);
|
||||
DEFINE_PROPERTY_REF_ENUM(PROP_ENTITY_HOST_TYPE, EntityHostType, entityHostType, entity::HostType, entity::HostType::DOMAIN);
|
||||
DEFINE_PROPERTY_REF(PROP_OWNING_AVATAR_ID, OwningAvatarID, owningAvatarID, QUuid, UNKNOWN_ENTITY_ID);
|
||||
|
||||
DEFINE_PROPERTY_REF(PROP_DPI, DPI, dpi, uint16_t, ENTITY_ITEM_DEFAULT_DPI);
|
||||
|
@ -589,7 +590,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
|||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, GhostingAllowed, ghostingAllowed, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, FilterURL, filterURL, "");
|
||||
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ClientOnly, clientOnly, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, EntityHostTypeAsString, entityHostType, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, OwningAvatarID, owningAvatarID, "");
|
||||
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, LastEditedBy, lastEditedBy, "");
|
||||
|
|
|
@ -121,7 +121,7 @@ QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f) {
|
|||
result = f.getHasProperty(PROP_FALLOFF_RADIUS) ? result + "falloffRadius " : result;
|
||||
result = f.getHasProperty(PROP_FLYING_ALLOWED) ? result + "flyingAllowed " : result;
|
||||
result = f.getHasProperty(PROP_GHOSTING_ALLOWED) ? result + "ghostingAllowed " : result;
|
||||
result = f.getHasProperty(PROP_CLIENT_ONLY) ? result + "clientOnly " : result;
|
||||
result = f.getHasProperty(PROP_ENTITY_HOST_TYPE) ? result + "entityHostType " : result;
|
||||
result = f.getHasProperty(PROP_OWNING_AVATAR_ID) ? result + "owningAvatarID " : result;
|
||||
result = f.getHasProperty(PROP_SHAPE) ? result + "shape " : result;
|
||||
result = f.getHasProperty(PROP_DPI) ? result + "dpi " : result;
|
||||
|
@ -175,6 +175,7 @@ QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f) {
|
|||
result = f.getHasProperty(PROP_MATERIAL_MAPPING_SCALE) ? result + "materialMappingScale " : result;
|
||||
result = f.getHasProperty(PROP_MATERIAL_MAPPING_ROT) ? result + "materialMappingRot " : result;
|
||||
result = f.getHasProperty(PROP_MATERIAL_DATA) ? result + "materialData " : result;
|
||||
result = f.getHasProperty(PROP_MATERIAL_REPEAT) ? result + "materialRepeat " : result;
|
||||
result = f.getHasProperty(PROP_VISIBLE_IN_SECONDARY_CAMERA) ? result + "visibleInSecondaryCamera " : result;
|
||||
result = f.getHasProperty(PROP_PARTICLE_SPIN) ? result + "particleSpin " : result;
|
||||
result = f.getHasProperty(PROP_SPIN_START) ? result + "spinStart " : result;
|
||||
|
|
|
@ -176,7 +176,7 @@ enum EntityPropertyList {
|
|||
PROP_FLYING_ALLOWED, // can avatars in a zone fly?
|
||||
PROP_GHOSTING_ALLOWED, // can avatars in a zone turn off physics?
|
||||
|
||||
PROP_CLIENT_ONLY, // doesn't go over wire
|
||||
PROP_ENTITY_HOST_TYPE, // doesn't go over wire
|
||||
PROP_OWNING_AVATAR_ID, // doesn't go over wire
|
||||
|
||||
PROP_SHAPE,
|
||||
|
@ -275,6 +275,8 @@ enum EntityPropertyList {
|
|||
PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE,
|
||||
PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET,
|
||||
|
||||
PROP_MATERIAL_REPEAT,
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ATTENTION: add new properties to end of list just ABOVE this line
|
||||
PROP_AFTER_LAST_ITEM,
|
||||
|
|
|
@ -32,6 +32,8 @@ namespace EntityPsuedoPropertyFlag {
|
|||
RenderInfo,
|
||||
ClientOnly,
|
||||
OwningAvatarID,
|
||||
AvatarEntity,
|
||||
LocalEntity,
|
||||
|
||||
NumFlags
|
||||
};
|
||||
|
|
|
@ -470,7 +470,7 @@ void synchronizeEditedGrabProperties(EntityItemProperties& properties, const QSt
|
|||
}
|
||||
|
||||
|
||||
QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties, bool clientOnly) {
|
||||
QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties, const QString& entityHostTypeString) {
|
||||
PROFILE_RANGE(script_entities, __FUNCTION__);
|
||||
|
||||
_activityTracking.addedEntityCount++;
|
||||
|
@ -479,9 +479,13 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
|
|||
const auto sessionID = nodeList->getSessionUUID();
|
||||
|
||||
EntityItemProperties propertiesWithSimID = properties;
|
||||
if (clientOnly) {
|
||||
propertiesWithSimID.setClientOnly(clientOnly);
|
||||
propertiesWithSimID.setEntityHostTypeFromString(entityHostTypeString);
|
||||
if (propertiesWithSimID.getEntityHostType() == entity::HostType::AVATAR) {
|
||||
propertiesWithSimID.setOwningAvatarID(sessionID);
|
||||
} else if (propertiesWithSimID.getEntityHostType() == entity::HostType::LOCAL) {
|
||||
// For now, local entities are always collisionless
|
||||
// TODO: create a separate, local physics simulation that just handles local entities (and MyAvatar?)
|
||||
propertiesWithSimID.setCollisionless(true);
|
||||
}
|
||||
|
||||
propertiesWithSimID.setLastEditedBy(sessionID);
|
||||
|
@ -570,8 +574,11 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) {
|
|||
bool cloneAvatarEntity = properties.getCloneAvatarEntity();
|
||||
properties.convertToCloneProperties(entityIDToClone);
|
||||
|
||||
if (cloneAvatarEntity) {
|
||||
return addEntity(properties, true);
|
||||
if (properties.getEntityHostType() == entity::HostType::LOCAL) {
|
||||
// Local entities are only cloned locally
|
||||
return addEntity(properties, "local");
|
||||
} else if (cloneAvatarEntity) {
|
||||
return addEntity(properties, "avatar");
|
||||
} else {
|
||||
// setLastEdited timestamp to 0 to ensure this entity gets updated with the properties
|
||||
// from the server-created entity, don't change this unless you know what you are doing
|
||||
|
@ -683,6 +690,10 @@ QScriptValue EntityScriptingInterface::getMultipleEntityPropertiesInternal(QScri
|
|||
psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::ClientOnly);
|
||||
} else if (extendedPropertyString == "owningAvatarID") {
|
||||
psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::OwningAvatarID);
|
||||
} else if (extendedPropertyString == "avatarEntity") {
|
||||
psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::AvatarEntity);
|
||||
} else if (extendedPropertyString == "localEntity") {
|
||||
psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::LocalEntity);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -786,7 +797,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
|||
return;
|
||||
}
|
||||
|
||||
if (entity->getClientOnly() && entity->getOwningAvatarID() != sessionID) {
|
||||
if (entity->isAvatarEntity() && entity->getOwningAvatarID() != sessionID) {
|
||||
// don't edit other avatar's avatarEntities
|
||||
properties = EntityItemProperties();
|
||||
return;
|
||||
|
@ -829,7 +840,11 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
|||
}
|
||||
|
||||
// set these to make EntityItemProperties::getScalesWithParent() work correctly
|
||||
properties.setClientOnly(entity->getClientOnly());
|
||||
entity::HostType entityHostType = entity->getEntityHostType();
|
||||
properties.setEntityHostType(entityHostType);
|
||||
if (entityHostType == entity::HostType::LOCAL) {
|
||||
properties.setCollisionless(true);
|
||||
}
|
||||
properties.setOwningAvatarID(entity->getOwningAvatarID());
|
||||
|
||||
properties.setActionData(entity->getDynamicData());
|
||||
|
@ -956,7 +971,7 @@ void EntityScriptingInterface::deleteEntity(QUuid id) {
|
|||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
const QUuid myNodeID = nodeList->getSessionUUID();
|
||||
if (entity->getClientOnly() && entity->getOwningAvatarID() != myNodeID) {
|
||||
if (entity->isAvatarEntity() && entity->getOwningAvatarID() != myNodeID) {
|
||||
// don't delete other avatar's avatarEntities
|
||||
shouldSendDeleteToServer = false;
|
||||
return;
|
||||
|
@ -966,11 +981,11 @@ void EntityScriptingInterface::deleteEntity(QUuid id) {
|
|||
shouldSendDeleteToServer = false;
|
||||
} else {
|
||||
// only delete local entities, server entities will round trip through the server filters
|
||||
if (entity->getClientOnly() || _entityTree->isServerlessMode()) {
|
||||
if (entity->isAvatarEntity() || _entityTree->isServerlessMode()) {
|
||||
shouldSendDeleteToServer = false;
|
||||
_entityTree->deleteEntity(entityID);
|
||||
|
||||
if (entity->getClientOnly() && getEntityPacketSender()->getMyAvatar()) {
|
||||
if (entity->isAvatarEntity() && getEntityPacketSender()->getMyAvatar()) {
|
||||
getEntityPacketSender()->getMyAvatar()->clearAvatarEntity(entityID, false);
|
||||
}
|
||||
}
|
||||
|
@ -1637,14 +1652,14 @@ bool EntityScriptingInterface::actionWorker(const QUuid& entityID,
|
|||
return;
|
||||
}
|
||||
|
||||
if (entity->getClientOnly() && entity->getOwningAvatarID() != myNodeID) {
|
||||
if (entity->isAvatarEntity() && entity->getOwningAvatarID() != myNodeID) {
|
||||
return;
|
||||
}
|
||||
|
||||
doTransmit = actor(simulation, entity);
|
||||
_entityTree->entityChanged(entity);
|
||||
if (doTransmit) {
|
||||
properties.setClientOnly(entity->getClientOnly());
|
||||
properties.setEntityHostType(entity->getEntityHostType());
|
||||
properties.setOwningAvatarID(entity->getOwningAvatarID());
|
||||
}
|
||||
});
|
||||
|
|
|
@ -233,13 +233,29 @@ public slots:
|
|||
*/
|
||||
Q_INVOKABLE bool canReplaceContent();
|
||||
|
||||
/**jsdoc
|
||||
* <p>How an entity is sent over the wire.</p>
|
||||
* <table>
|
||||
* <thead>
|
||||
* <tr><th>Value</th><th>Description</th></tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr><td><code>domain</code></td><td>Domain entities are sent over the entity server to everyone else</td></tr>
|
||||
* <tr><td><code>avatar</code></td><td>Avatar entities are sent over the avatar entity and are associated with one avatar</td></tr>
|
||||
* <tr><td><code>local</code></td><td>Local entities are not sent over the wire and will only render for you, locally</td></tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* @typedef {string} EntityHostType
|
||||
*/
|
||||
|
||||
/**jsdoc
|
||||
* Add a new entity with specified properties.
|
||||
* @function Entities.addEntity
|
||||
* @param {Entities.EntityProperties} properties - The properties of the entity to create.
|
||||
* @param {boolean} [clientOnly=false] - If <code>true</code>, or if <code>clientOnly</code> is set <code>true</code> in
|
||||
* the properties, the entity is created as an avatar entity; otherwise it is created on the server. An avatar entity
|
||||
* @param {EntityHostType} [entityHostType="domain"] - If <code>"avatar"</code> the entity is created as an avatar entity. An avatar entity
|
||||
* follows you to each domain you visit, rendering at the same world coordinates unless it's parented to your avatar.
|
||||
* If <code>"local"</code>, the entity is created as a local entity, which will only render for you and isn't sent over the wire.
|
||||
* Otherwise it is created as a normal entity and sent over the entity server.
|
||||
* @returns {Uuid} The ID of the entity if successfully created, otherwise {@link Uuid|Uuid.NULL}.
|
||||
* @example <caption>Create a box entity in front of your avatar.</caption>
|
||||
* var entityID = Entities.addEntity({
|
||||
|
@ -250,7 +266,19 @@ public slots:
|
|||
* });
|
||||
* print("Entity created: " + entityID);
|
||||
*/
|
||||
Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties, bool clientOnly = false);
|
||||
Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties, const QString& entityHostTypeString);
|
||||
|
||||
/**jsdoc
|
||||
* Add a new entity with specified properties.
|
||||
* @function Entities.addEntity
|
||||
* @param {Entities.EntityProperties} properties - The properties of the entity to create.
|
||||
* @param {boolean} [avatarEntity=false] - Whether to create an avatar entity or a domain entity
|
||||
* @returns {Uuid} The ID of the entity if successfully created, otherwise {@link Uuid|Uuid.NULL}.
|
||||
*/
|
||||
Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties, bool avatarEntity = false) {
|
||||
QString entityHostType = avatarEntity ? "avatar" : "domain";
|
||||
return addEntity(properties, entityHostType);
|
||||
}
|
||||
|
||||
/// temporary method until addEntity can be used from QJSEngine
|
||||
/// Deliberately not adding jsdoc, only used internally.
|
||||
|
@ -896,8 +924,7 @@ public slots:
|
|||
Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point);
|
||||
|
||||
/**jsdoc
|
||||
* Dumps debug information about all entities in Interface's local in-memory tree of entities it knows about — domain
|
||||
* and client-only — to the program log.
|
||||
* Dumps debug information about all entities in Interface's local in-memory tree of entities it knows about to the program log.
|
||||
* @function Entities.dumpTree
|
||||
*/
|
||||
Q_INVOKABLE void dumpTree() const;
|
||||
|
@ -1870,7 +1897,7 @@ signals:
|
|||
/**jsdoc
|
||||
* Triggered when an entity is added to Interface's local in-memory tree of entities it knows about. This may occur when
|
||||
* entities are loaded upon visiting a domain, when the user rotates their view so that more entities become visible, and
|
||||
* when a domain or client-only entity is added (e.g., by {@Entities.addEntity|addEntity}).
|
||||
* when any type of entity is added (e.g., by {@Entities.addEntity|addEntity}).
|
||||
* @function Entities.addingEntity
|
||||
* @param {Uuid} entityID - The ID of the entity added.
|
||||
* @returns {Signal}
|
||||
|
|
|
@ -542,7 +542,7 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (!properties.getClientOnly() && getIsClient() &&
|
||||
if (properties.getEntityHostType() == entity::HostType::DOMAIN && getIsClient() &&
|
||||
!nodeList->getThisNodeCanRez() && !nodeList->getThisNodeCanRezTmp() &&
|
||||
!nodeList->getThisNodeCanRezCertified() && !nodeList->getThisNodeCanRezTmpCertified() && !_serverlessDomain && !isClone) {
|
||||
return nullptr;
|
||||
|
@ -2669,7 +2669,15 @@ bool EntityTree::readFromMap(QVariantMap& map) {
|
|||
entityItemID = EntityItemID(QUuid::createUuid());
|
||||
}
|
||||
|
||||
if (properties.getClientOnly()) {
|
||||
// Convert old clientOnly bool to new entityHostType enum
|
||||
// (must happen before setOwningAvatarID below)
|
||||
if (contentVersion < (int)EntityVersion::EntityHostTypes) {
|
||||
if (entityMap.contains("clientOnly")) {
|
||||
properties.setEntityHostType(entityMap["clientOnly"].toBool() ? entity::HostType::AVATAR : entity::HostType::DOMAIN);
|
||||
}
|
||||
}
|
||||
|
||||
if (properties.getEntityHostType() == entity::HostType::AVATAR) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
const QUuid myNodeID = nodeList->getSessionUUID();
|
||||
properties.setOwningAvatarID(myNodeID);
|
||||
|
|
|
@ -41,6 +41,7 @@ EntityItemProperties MaterialEntityItem::getProperties(const EntityPropertyFlags
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingScale, getMaterialMappingScale);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingRot, getMaterialMappingRot);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialData, getMaterialData);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialRepeat, getMaterialRepeat);
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
@ -55,6 +56,7 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingScale, setMaterialMappingScale);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingRot, setMaterialMappingRot);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialData, setMaterialData);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialRepeat, setMaterialRepeat);
|
||||
|
||||
if (somethingChanged) {
|
||||
bool wantDebug = false;
|
||||
|
@ -85,6 +87,7 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da
|
|||
READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, glm::vec2, setMaterialMappingScale);
|
||||
READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, float, setMaterialMappingRot);
|
||||
READ_ENTITY_PROPERTY(PROP_MATERIAL_DATA, QString, setMaterialData);
|
||||
READ_ENTITY_PROPERTY(PROP_MATERIAL_REPEAT, bool, setMaterialRepeat);
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
@ -99,6 +102,7 @@ EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParam
|
|||
requestedProperties += PROP_MATERIAL_MAPPING_SCALE;
|
||||
requestedProperties += PROP_MATERIAL_MAPPING_ROT;
|
||||
requestedProperties += PROP_MATERIAL_DATA;
|
||||
requestedProperties += PROP_MATERIAL_REPEAT;
|
||||
return requestedProperties;
|
||||
}
|
||||
|
||||
|
@ -119,6 +123,7 @@ void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, Encode
|
|||
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, getMaterialMappingScale());
|
||||
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, getMaterialMappingRot());
|
||||
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_DATA, getMaterialData());
|
||||
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_REPEAT, getMaterialRepeat());
|
||||
}
|
||||
|
||||
void MaterialEntityItem::debugDump() const {
|
||||
|
@ -128,6 +133,7 @@ void MaterialEntityItem::debugDump() const {
|
|||
qCDebug(entities) << " material url:" << _materialURL;
|
||||
qCDebug(entities) << " current material name:" << _currentMaterialName.c_str();
|
||||
qCDebug(entities) << " material mapping mode:" << _materialMappingMode;
|
||||
qCDebug(entities) << " material repeat:" << _materialRepeat;
|
||||
qCDebug(entities) << " priority:" << _priority;
|
||||
qCDebug(entities) << " parent material name:" << _parentMaterialName;
|
||||
qCDebug(entities) << " material mapping pos:" << _materialMappingPos;
|
||||
|
@ -140,7 +146,12 @@ void MaterialEntityItem::debugDump() const {
|
|||
}
|
||||
|
||||
void MaterialEntityItem::setUnscaledDimensions(const glm::vec3& value) {
|
||||
EntityItem::setUnscaledDimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS);
|
||||
_desiredDimensions = value;
|
||||
if (_materialMappingMode == MaterialMappingMode::UV) {
|
||||
EntityItem::setUnscaledDimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS);
|
||||
} else if (_materialMappingMode == MaterialMappingMode::PROJECTED) {
|
||||
EntityItem::setUnscaledDimensions(value);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<NetworkMaterial> MaterialEntityItem::getMaterial() const {
|
||||
|
@ -208,6 +219,23 @@ void MaterialEntityItem::setMaterialData(const QString& materialData) {
|
|||
}
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setMaterialMappingMode(MaterialMappingMode mode) {
|
||||
if (_materialMappingMode != mode) {
|
||||
removeMaterial();
|
||||
_materialMappingMode = mode;
|
||||
setUnscaledDimensions(_desiredDimensions);
|
||||
applyMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setMaterialRepeat(bool repeat) {
|
||||
if (_materialRepeat != repeat) {
|
||||
removeMaterial();
|
||||
_materialRepeat = repeat;
|
||||
applyMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setMaterialMappingPos(const glm::vec2& materialMappingPos) {
|
||||
if (_materialMappingPos != materialMappingPos) {
|
||||
removeMaterial();
|
||||
|
@ -256,6 +284,22 @@ void MaterialEntityItem::setParentID(const QUuid& parentID) {
|
|||
}
|
||||
}
|
||||
|
||||
void MaterialEntityItem::locationChanged(bool tellPhysics) {
|
||||
EntityItem::locationChanged();
|
||||
if (_materialMappingMode == MaterialMappingMode::PROJECTED) {
|
||||
removeMaterial();
|
||||
applyMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialEntityItem::dimensionsChanged() {
|
||||
EntityItem::dimensionsChanged();
|
||||
if (_materialMappingMode == MaterialMappingMode::PROJECTED) {
|
||||
removeMaterial();
|
||||
applyMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialEntityItem::removeMaterial() {
|
||||
graphics::MaterialPointer material = getMaterial();
|
||||
if (!material) {
|
||||
|
@ -289,11 +333,19 @@ void MaterialEntityItem::applyMaterial() {
|
|||
if (!material || parentID.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Transform textureTransform;
|
||||
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0.0f));
|
||||
textureTransform.setRotation(glm::vec3(0.0f, 0.0f, glm::radians(_materialMappingRot)));
|
||||
textureTransform.setScale(glm::vec3(_materialMappingScale, 1.0f));
|
||||
material->setTextureTransforms(textureTransform);
|
||||
if (_materialMappingMode == MaterialMappingMode::UV) {
|
||||
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0.0f));
|
||||
textureTransform.setRotation(glm::vec3(0.0f, 0.0f, glm::radians(_materialMappingRot)));
|
||||
textureTransform.setScale(glm::vec3(_materialMappingScale, 1.0f));
|
||||
} else if (_materialMappingMode == MaterialMappingMode::PROJECTED) {
|
||||
textureTransform = getTransform();
|
||||
textureTransform.postScale(getUnscaledDimensions());
|
||||
// Pass the inverse transform here so we don't need to compute it in the shaders
|
||||
textureTransform.evalFromRawMatrix(textureTransform.getInverseMatrix());
|
||||
}
|
||||
material->setTextureTransforms(textureTransform, _materialMappingMode, _materialRepeat);
|
||||
|
||||
graphics::MaterialLayer materialLayer = graphics::MaterialLayer(material, getPriority());
|
||||
|
||||
|
|
|
@ -58,7 +58,10 @@ public:
|
|||
void setCurrentMaterialName(const std::string& currentMaterialName);
|
||||
|
||||
MaterialMappingMode getMaterialMappingMode() const { return _materialMappingMode; }
|
||||
void setMaterialMappingMode(MaterialMappingMode mode) { _materialMappingMode = mode; }
|
||||
void setMaterialMappingMode(MaterialMappingMode mode);
|
||||
|
||||
bool getMaterialRepeat() const { return _materialRepeat; }
|
||||
void setMaterialRepeat(bool repeat);
|
||||
|
||||
quint16 getPriority() const { return _priority; }
|
||||
void setPriority(quint16 priority);
|
||||
|
@ -80,6 +83,9 @@ public:
|
|||
|
||||
void setParentID(const QUuid& parentID) override;
|
||||
|
||||
void locationChanged(bool tellPhysics) override;
|
||||
void dimensionsChanged() override;
|
||||
|
||||
void applyMaterial();
|
||||
void removeMaterial();
|
||||
|
||||
|
@ -104,8 +110,10 @@ private:
|
|||
// emissiveMap, albedoMap (set opacityMap = albedoMap for transparency), metallicMap or specularMap, roughnessMap or glossMap,
|
||||
// normalMap or bumpMap, occlusionMap, lightmapMap (broken, FIXME), scatteringMap (only works if normal mapped)
|
||||
QString _materialURL;
|
||||
// Type of material. "uv" or "projected". NOT YET IMPLEMENTED, only UV is used
|
||||
// Type of material. "uv" or "projected".
|
||||
MaterialMappingMode _materialMappingMode { UV };
|
||||
bool _materialRepeat { true };
|
||||
glm::vec3 _desiredDimensions;
|
||||
// Priority for this material when applying it to its parent. Only the highest priority material will be used. Materials with the same priority are (essentially) randomly sorted.
|
||||
// Base materials that come with models always have priority 0.
|
||||
quint16 _priority { 0 };
|
||||
|
|
|
@ -231,7 +231,8 @@ float snoise(vec2 v) {
|
|||
|
||||
// Other corners
|
||||
vec2 i1;
|
||||
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
|
||||
float check = float(x0.x > x0.y);
|
||||
i1 = vec2(check, 1.0 - check);
|
||||
vec4 x12 = x0.xyxy + C.xxzz;
|
||||
x12.xy -= i1;
|
||||
|
||||
|
|
|
@ -130,9 +130,11 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur
|
|||
if (channel == MaterialKey::LIGHTMAP_MAP) {
|
||||
// update the texcoord1 with lightmap
|
||||
_schemaBuffer.edit<Schema>()._texcoordTransforms[1] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4());
|
||||
_schemaBuffer.edit<Schema>()._lightmapParams = (textureMap ? glm::vec4(textureMap->getLightmapOffsetScale(), 0.0, 0.0) : glm::vec4(0.0, 1.0, 0.0, 0.0));
|
||||
_schemaBuffer.edit<Schema>()._lightmapParams = (textureMap ? glm::vec2(textureMap->getLightmapOffsetScale()) : glm::vec2(0.0, 1.0));
|
||||
}
|
||||
|
||||
_schemaBuffer.edit<Schema>()._materialParams = (textureMap ? glm::vec2(textureMap->getMappingMode(), textureMap->getRepeat()) : glm::vec2(MaterialMappingMode::UV, 1.0));
|
||||
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
|
||||
}
|
||||
|
@ -211,13 +213,16 @@ bool Material::calculateMaterialInfo() const {
|
|||
return _hasCalculatedTextureInfo;
|
||||
}
|
||||
|
||||
void Material::setTextureTransforms(const Transform& transform) {
|
||||
void Material::setTextureTransforms(const Transform& transform, MaterialMappingMode mode, bool repeat) {
|
||||
for (auto &textureMapItem : _textureMaps) {
|
||||
if (textureMapItem.second) {
|
||||
textureMapItem.second->setTextureTransform(transform);
|
||||
textureMapItem.second->setMappingMode(mode);
|
||||
textureMapItem.second->setRepeat(repeat);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < NUM_TEXCOORD_TRANSFORMS; i++) {
|
||||
_schemaBuffer.edit<Schema>()._texcoordTransforms[i] = transform.getMatrix();
|
||||
}
|
||||
}
|
||||
_schemaBuffer.edit<Schema>()._materialParams = glm::vec2(mode, repeat);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <gpu/Resource.h>
|
||||
#include <gpu/TextureTable.h>
|
||||
|
||||
#include "MaterialMappingMode.h"
|
||||
|
||||
class Transform;
|
||||
|
||||
namespace graphics {
|
||||
|
@ -330,7 +332,11 @@ public:
|
|||
// Texture Coord Transform Array
|
||||
glm::mat4 _texcoordTransforms[NUM_TEXCOORD_TRANSFORMS];
|
||||
|
||||
glm::vec4 _lightmapParams{ 0.0, 1.0, 0.0, 0.0 };
|
||||
glm::vec2 _lightmapParams { 0.0, 1.0 };
|
||||
|
||||
// x: material mode (0 for UV, 1 for PROJECTED)
|
||||
// y: 1 for texture repeat, 0 for discard outside of 0 - 1
|
||||
glm::vec2 _materialParams { 0.0, 1.0 };
|
||||
|
||||
Schema() {}
|
||||
};
|
||||
|
@ -353,7 +359,7 @@ public:
|
|||
size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; }
|
||||
bool hasTextureInfo() const { return _hasCalculatedTextureInfo; }
|
||||
|
||||
void setTextureTransforms(const Transform& transform);
|
||||
void setTextureTransforms(const Transform& transform, MaterialMappingMode mode, bool repeat);
|
||||
|
||||
const std::string& getName() const { return _name; }
|
||||
|
||||
|
|
|
@ -19,20 +19,25 @@ const int MAX_TEXCOORDS = 2;
|
|||
struct TexMapArray {
|
||||
mat4 _texcoordTransforms0;
|
||||
mat4 _texcoordTransforms1;
|
||||
vec4 _lightmapParams;
|
||||
vec2 _lightmapParams;
|
||||
vec2 _materialParams;
|
||||
};
|
||||
|
||||
<@func declareMaterialTexMapArrayBuffer()@>
|
||||
|
||||
<@func evalTexMapArrayTexcoord0(texMapArray, inTexcoord0, outTexcoord0)@>
|
||||
<@func evalTexMapArrayTexcoord0(texMapArray, inTexcoord0, worldPosition, outTexcoord0)@>
|
||||
{
|
||||
<$outTexcoord0$> = (<$texMapArray$>._texcoordTransforms0 * vec4(<$inTexcoord0$>.st, 0.0, 1.0)).st;
|
||||
<$outTexcoord0$> = mix(<$texMapArray$>._texcoordTransforms0 * vec4(<$inTexcoord0$>.st, 0.0, 1.0),
|
||||
<$texMapArray$>._texcoordTransforms0 * <$worldPosition$> + vec4(0.5),
|
||||
<$texMapArray$>._materialParams.x).st;
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func evalTexMapArrayTexcoord1(texMapArray, inTexcoord1, outTexcoord1)@>
|
||||
<@func evalTexMapArrayTexcoord1(texMapArray, inTexcoord1, worldPosition, outTexcoord1)@>
|
||||
{
|
||||
<$outTexcoord1$> = (<$texMapArray$>._texcoordTransforms1 * vec4(<$inTexcoord1$>.st, 0.0, 1.0)).st;
|
||||
<$outTexcoord1$> = mix(<$texMapArray$>._texcoordTransforms1 * vec4(<$inTexcoord1$>.st, 0.0, 1.0),
|
||||
<$texMapArray$>._texcoordTransforms1 * <$worldPosition$> + vec4(0.5),
|
||||
<$texMapArray$>._materialParams.x).st;
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
|
|
|
@ -151,29 +151,32 @@ float fetchScatteringMap(vec2 uv) {
|
|||
|
||||
|
||||
<@func fetchMaterialTexturesCoord0(matKey, texcoord0, albedo, roughness, normal, metallic, emissive, scattering)@>
|
||||
if (getTexMapArray()._materialParams.y != 1.0 && clamp(<$texcoord0$>, vec2(0.0), vec2(1.0)) != <$texcoord0$>) {
|
||||
discard;
|
||||
}
|
||||
<@if albedo@>
|
||||
vec4 <$albedo$> = (((<$matKey$> & (ALBEDO_MAP_BIT | OPACITY_MASK_MAP_BIT | OPACITY_TRANSLUCENT_MAP_BIT)) != 0) ? fetchAlbedoMap(<$texcoord0$>) : vec4(1.0));
|
||||
vec4 <$albedo$> = mix(vec4(1.0), fetchAlbedoMap(<$texcoord0$>), float((<$matKey$> & (ALBEDO_MAP_BIT | OPACITY_MASK_MAP_BIT | OPACITY_TRANSLUCENT_MAP_BIT)) != 0));
|
||||
<@endif@>
|
||||
<@if roughness@>
|
||||
float <$roughness$> = (((<$matKey$> & ROUGHNESS_MAP_BIT) != 0) ? fetchRoughnessMap(<$texcoord0$>) : 1.0);
|
||||
float <$roughness$> = mix(1.0, fetchRoughnessMap(<$texcoord0$>), float((<$matKey$> & ROUGHNESS_MAP_BIT) != 0));
|
||||
<@endif@>
|
||||
<@if normal@>
|
||||
vec3 <$normal$> = (((<$matKey$> & NORMAL_MAP_BIT) != 0) ? fetchNormalMap(<$texcoord0$>) : vec3(0.0, 1.0, 0.0));
|
||||
vec3 <$normal$> = mix(vec3(0.0, 1.0, 0.0), fetchNormalMap(<$texcoord0$>), float((<$matKey$> & NORMAL_MAP_BIT) != 0));
|
||||
<@endif@>
|
||||
<@if metallic@>
|
||||
float <$metallic$> = (((<$matKey$> & METALLIC_MAP_BIT) != 0) ? fetchMetallicMap(<$texcoord0$>) : 0.0);
|
||||
float <$metallic$> = float((<$matKey$> & METALLIC_MAP_BIT) != 0) * fetchMetallicMap(<$texcoord0$>);
|
||||
<@endif@>
|
||||
<@if emissive@>
|
||||
vec3 <$emissive$> = (((<$matKey$> & EMISSIVE_MAP_BIT) != 0) ? fetchEmissiveMap(<$texcoord0$>) : vec3(0.0));
|
||||
vec3 <$emissive$> = float((<$matKey$> & EMISSIVE_MAP_BIT) != 0) * fetchEmissiveMap(<$texcoord0$>);
|
||||
<@endif@>
|
||||
<@if scattering@>
|
||||
float <$scattering$> = (((<$matKey$> & SCATTERING_MAP_BIT) != 0) ? fetchScatteringMap(<$texcoord0$>) : 0.0);
|
||||
float <$scattering$> = float((<$matKey$> & SCATTERING_MAP_BIT) != 0) * fetchScatteringMap(<$texcoord0$>);
|
||||
<@endif@>
|
||||
<@endfunc@>
|
||||
|
||||
<@func fetchMaterialTexturesCoord1(matKey, texcoord1, occlusion, lightmap)@>
|
||||
<@if occlusion@>
|
||||
float <$occlusion$> = (((<$matKey$> & OCCLUSION_MAP_BIT) != 0) ? fetchOcclusionMap(<$texcoord1$>) : 1.0);
|
||||
float <$occlusion$> = mix(1.0, fetchOcclusionMap(<$texcoord1$>), float((<$matKey$> & OCCLUSION_MAP_BIT) != 0));
|
||||
<@endif@>
|
||||
<@if lightmap@>
|
||||
vec3 <$lightmap$> = fetchLightmapMap(<$texcoord1$>);
|
||||
|
@ -188,7 +191,7 @@ float fetchScatteringMap(vec2 uv) {
|
|||
|
||||
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap;
|
||||
vec3 fetchLightmapMap(vec2 uv) {
|
||||
vec2 lightmapParams = getTexMapArray()._lightmapParams.xy;
|
||||
vec2 lightmapParams = getTexMapArray()._lightmapParams;
|
||||
return (vec3(lightmapParams.x) + lightmapParams.y * texture(emissiveMap, uv).rgb);
|
||||
}
|
||||
<@endfunc@>
|
||||
|
@ -207,20 +210,19 @@ vec3 fetchLightmapMap(vec2 uv) {
|
|||
|
||||
<@func evalMaterialAlbedo(fetchedAlbedo, materialAlbedo, matKey, albedo)@>
|
||||
{
|
||||
<$albedo$>.xyz = (((<$matKey$> & ALBEDO_VAL_BIT) != 0) ? <$materialAlbedo$> : vec3(1.0));
|
||||
|
||||
if (((<$matKey$> & ALBEDO_MAP_BIT) != 0)) {
|
||||
<$albedo$>.xyz *= <$fetchedAlbedo$>.xyz;
|
||||
}
|
||||
<$albedo$>.xyz = mix(vec3(1.0), <$materialAlbedo$>, float((<$matKey$> & ALBEDO_VAL_BIT) != 0));
|
||||
<$albedo$>.xyz *= mix(vec3(1.0), <$fetchedAlbedo$>.xyz, float((<$matKey$> & ALBEDO_MAP_BIT) != 0));
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func evalMaterialOpacity(fetchedOpacity, materialOpacity, matKey, opacity)@>
|
||||
{
|
||||
const float OPACITY_MASK_THRESHOLD = 0.5;
|
||||
<$opacity$> = (((<$matKey$> & (OPACITY_TRANSLUCENT_MAP_BIT | OPACITY_MASK_MAP_BIT)) != 0) ?
|
||||
(((<$matKey$> & OPACITY_MASK_MAP_BIT) != 0) ? step(OPACITY_MASK_THRESHOLD, <$fetchedOpacity$>) : <$fetchedOpacity$>) :
|
||||
1.0) * <$materialOpacity$>;
|
||||
<$opacity$> = mix(1.0,
|
||||
mix(<$fetchedOpacity$>,
|
||||
step(OPACITY_MASK_THRESHOLD, <$fetchedOpacity$>),
|
||||
float((<$matKey$> & OPACITY_MASK_MAP_BIT) != 0)),
|
||||
float((<$matKey$> & (OPACITY_TRANSLUCENT_MAP_BIT | OPACITY_MASK_MAP_BIT)) != 0)) * <$materialOpacity$>;
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
|
@ -241,19 +243,19 @@ vec3 fetchLightmapMap(vec2 uv) {
|
|||
|
||||
<@func evalMaterialRoughness(fetchedRoughness, materialRoughness, matKey, roughness)@>
|
||||
{
|
||||
<$roughness$> = (((<$matKey$> & ROUGHNESS_MAP_BIT) != 0) ? <$fetchedRoughness$> : <$materialRoughness$>);
|
||||
<$roughness$> = mix(<$materialRoughness$>, <$fetchedRoughness$>, float((<$matKey$> & ROUGHNESS_MAP_BIT) != 0));
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func evalMaterialMetallic(fetchedMetallic, materialMetallic, matKey, metallic)@>
|
||||
{
|
||||
<$metallic$> = (((<$matKey$> & METALLIC_MAP_BIT) != 0) ? <$fetchedMetallic$> : <$materialMetallic$>);
|
||||
<$metallic$> = mix(<$materialMetallic$>, <$fetchedMetallic$>, float((<$matKey$> & METALLIC_MAP_BIT) != 0));
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func evalMaterialEmissive(fetchedEmissive, materialEmissive, matKey, emissive)@>
|
||||
{
|
||||
<$emissive$> = (((<$matKey$> & EMISSIVE_MAP_BIT) != 0) ? <$fetchedEmissive$> : <$materialEmissive$>);
|
||||
<$emissive$> = mix(<$materialEmissive$>, <$fetchedEmissive$>, float((<$matKey$> & EMISSIVE_MAP_BIT) != 0));
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
|
@ -265,7 +267,7 @@ vec3 fetchLightmapMap(vec2 uv) {
|
|||
|
||||
<@func evalMaterialScattering(fetchedScattering, materialScattering, matKey, scattering)@>
|
||||
{
|
||||
<$scattering$> = (((<$matKey$> & SCATTERING_MAP_BIT) != 0) ? <$fetchedScattering$> : <$materialScattering$>);
|
||||
<$scattering$> = mix(<$materialScattering$>, <$fetchedScattering$>, float((<$matKey$> & SCATTERING_MAP_BIT) != 0));
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "gpu/Texture.h"
|
||||
|
||||
#include "Transform.h"
|
||||
#include "MaterialMappingMode.h"
|
||||
|
||||
namespace graphics {
|
||||
|
||||
|
@ -30,6 +31,12 @@ public:
|
|||
void setTextureTransform(const Transform& texcoordTransform);
|
||||
const Transform& getTextureTransform() const { return _texcoordTransform; }
|
||||
|
||||
void setMappingMode(MaterialMappingMode mode) { _mappingMode = mode; }
|
||||
MaterialMappingMode getMappingMode() const { return _mappingMode; }
|
||||
|
||||
void setRepeat(bool repeat) { _repeat = repeat; }
|
||||
bool getRepeat() const { return _repeat; }
|
||||
|
||||
void setUseAlphaChannel(bool useAlpha) { _useAlphaChannel = useAlpha; }
|
||||
bool useAlphaChannel() const { return _useAlphaChannel; }
|
||||
|
||||
|
@ -41,6 +48,8 @@ protected:
|
|||
|
||||
Transform _texcoordTransform;
|
||||
glm::vec2 _lightmapOffsetScale{ 0.0f, 1.0f };
|
||||
MaterialMappingMode _mappingMode { MaterialMappingMode::UV };
|
||||
bool _repeat { true };
|
||||
|
||||
bool _useAlphaChannel{ false };
|
||||
};
|
||||
|
|
|
@ -30,11 +30,9 @@ void main(void) {
|
|||
vec3 color = skybox.color.rgb;
|
||||
|
||||
// blend is only set if there is a cubemap
|
||||
if (skybox.color.a > 0.0) {
|
||||
color = texture(cubeMap, coord).rgb;
|
||||
if (skybox.color.a < 1.0) {
|
||||
color *= skybox.color.rgb;
|
||||
}
|
||||
}
|
||||
float check = float(skybox.color.a > 0.0);
|
||||
color = mix(color, texture(cubeMap, coord).rgb, check);
|
||||
color *= mix(vec3(1.0), skybox.color.rgb, check * float(skybox.color.a < 1.0));
|
||||
|
||||
_fragColor = vec4(color, 0.0);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::EntityEdit:
|
||||
case PacketType::EntityData:
|
||||
case PacketType::EntityPhysics:
|
||||
return static_cast<PacketVersion>(EntityVersion::FixedLightSerialization);
|
||||
return static_cast<PacketVersion>(EntityVersion::EntityHostTypes);
|
||||
case PacketType::EntityQuery:
|
||||
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums);
|
||||
case PacketType::AvatarIdentity:
|
||||
|
|
|
@ -244,7 +244,9 @@ enum class EntityVersion : PacketVersion {
|
|||
BloomEffect,
|
||||
GrabProperties,
|
||||
ScriptGlmVectors,
|
||||
FixedLightSerialization
|
||||
FixedLightSerialization,
|
||||
MaterialRepeat,
|
||||
EntityHostTypes
|
||||
};
|
||||
|
||||
enum class EntityScriptCallMethodVersion : PacketVersion {
|
||||
|
|
|
@ -80,8 +80,8 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer
|
|||
// rather than pass the legit shape pointer to the ObjectMotionState ctor above.
|
||||
setShape(shape);
|
||||
|
||||
if (_entity->getClientOnly() && _entity->getOwningAvatarID() != Physics::getSessionUUID()) {
|
||||
// client-only entities are always thus, so we cache this fact in _ownershipState
|
||||
if (_entity->isAvatarEntity() && _entity->getOwningAvatarID() != Physics::getSessionUUID()) {
|
||||
// avatar entities entities are always thus, so we cache this fact in _ownershipState
|
||||
_ownershipState = EntityMotionState::OwnershipState::Unownable;
|
||||
}
|
||||
|
||||
|
@ -430,7 +430,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
|
|||
assert(entityTreeIsLocked());
|
||||
|
||||
// this case is prevented by setting _ownershipState to UNOWNABLE in EntityMotionState::ctor
|
||||
assert(!(_entity->getClientOnly() && _entity->getOwningAvatarID() != Physics::getSessionUUID()));
|
||||
assert(!(_entity->isAvatarEntity() && _entity->getOwningAvatarID() != Physics::getSessionUUID()));
|
||||
|
||||
if (_entity->getTransitingWithAvatar()) {
|
||||
return false;
|
||||
|
@ -595,7 +595,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
EntityTreeElementPointer element = _entity->getElement();
|
||||
EntityTreePointer tree = element ? element->getTree() : nullptr;
|
||||
|
||||
properties.setClientOnly(_entity->getClientOnly());
|
||||
properties.setEntityHostType(_entity->getEntityHostType());
|
||||
properties.setOwningAvatarID(_entity->getOwningAvatarID());
|
||||
|
||||
entityPacketSender->queueEditEntityMessage(PacketType::EntityPhysics, tree, id, properties);
|
||||
|
@ -610,7 +610,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
EntityItemProperties newQueryCubeProperties;
|
||||
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
|
||||
newQueryCubeProperties.setLastEdited(properties.getLastEdited());
|
||||
newQueryCubeProperties.setClientOnly(entityDescendant->getClientOnly());
|
||||
newQueryCubeProperties.setEntityHostType(entityDescendant->getEntityHostType());
|
||||
newQueryCubeProperties.setOwningAvatarID(entityDescendant->getOwningAvatarID());
|
||||
|
||||
entityPacketSender->queueEditEntityMessage(PacketType::EntityPhysics, tree,
|
||||
|
|
|
@ -79,7 +79,7 @@ void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) {
|
|||
_deadEntities.insert(entity);
|
||||
}
|
||||
}
|
||||
if (entity->getClientOnly()) {
|
||||
if (entity->isAvatarEntity()) {
|
||||
_deadAvatarEntities.insert(entity);
|
||||
}
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ void PhysicalEntitySimulation::handleDeactivatedMotionStates(const VectorOfMotio
|
|||
EntityItemPointer entity = entityState->getEntity();
|
||||
_entitiesToSort.insert(entity);
|
||||
if (!serverlessMode) {
|
||||
if (entity->getClientOnly()) {
|
||||
if (entity->isAvatarEntity()) {
|
||||
switch (entityState->getOwnershipState()) {
|
||||
case EntityMotionState::OwnershipState::PendingBid:
|
||||
_bids.removeFirst(entityState);
|
||||
|
|
|
@ -389,6 +389,10 @@ void OffscreenSurface::finishQmlLoad(QQmlComponent* qmlComponent,
|
|||
}
|
||||
// Allow child windows to be destroyed from JS
|
||||
QQmlEngine::setObjectOwnership(newObject, QQmlEngine::JavaScriptOwnership);
|
||||
|
||||
// add object to the manual deletion list
|
||||
_sharedObject->addToDeletionList(newObject);
|
||||
|
||||
newObject->setParent(parent);
|
||||
newItem->setParentItem(parent);
|
||||
} else {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QtQml/QQmlEngine>
|
||||
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QPointer>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include <shared/NsightHelpers.h>
|
||||
|
@ -96,6 +97,15 @@ SharedObject::~SharedObject() {
|
|||
}
|
||||
#endif
|
||||
|
||||
// already deleted objects will be reset to null by QPointer so it should be safe just iterate here
|
||||
for (auto qmlObject : _deletionList) {
|
||||
if (qmlObject) {
|
||||
// manually delete not-deleted-yet qml items
|
||||
QQmlEngine::setObjectOwnership(qmlObject, QQmlEngine::CppOwnership);
|
||||
delete qmlObject;
|
||||
}
|
||||
}
|
||||
|
||||
if (_rootItem) {
|
||||
delete _rootItem;
|
||||
_rootItem = nullptr;
|
||||
|
@ -412,6 +422,11 @@ bool SharedObject::fetchTexture(TextureAndFence& textureAndFence) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void hifi::qml::impl::SharedObject::addToDeletionList(QObject * object)
|
||||
{
|
||||
_deletionList.append(QPointer<QObject>(object));
|
||||
}
|
||||
|
||||
void SharedObject::setProxyWindow(QWindow* window) {
|
||||
#ifndef DISABLE_QML
|
||||
_proxyWindow = window;
|
||||
|
|
|
@ -66,7 +66,7 @@ public:
|
|||
void resume();
|
||||
bool isPaused() const;
|
||||
bool fetchTexture(TextureAndFence& textureAndFence);
|
||||
|
||||
void addToDeletionList(QObject* object);
|
||||
|
||||
private:
|
||||
bool event(QEvent* e) override;
|
||||
|
@ -91,6 +91,8 @@ private:
|
|||
void onAboutToQuit();
|
||||
void updateTextureAndFence(const TextureAndFence& newTextureAndFence);
|
||||
|
||||
QList<QPointer<QObject>> _deletionList;
|
||||
|
||||
// Texture management
|
||||
TextureAndFence _latestTextureAndFence{ 0, 0 };
|
||||
QQuickItem* _item{ nullptr };
|
||||
|
|
|
@ -76,15 +76,10 @@ DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) {
|
|||
|
||||
// Diffuse color and unpack the mode and the metallicness
|
||||
frag.albedo = diffuseVal.xyz;
|
||||
frag.scattering = 0.0;
|
||||
unpackModeMetallic(diffuseVal.w, frag.mode, frag.metallic);
|
||||
|
||||
frag.obscurance = min(specularVal.w, frag.obscurance);
|
||||
|
||||
if (frag.mode == FRAG_MODE_SCATTERING) {
|
||||
frag.scattering = specularVal.x;
|
||||
}
|
||||
|
||||
frag.scattering = float(frag.mode == FRAG_MODE_SCATTERING) * specularVal.x;
|
||||
frag.fresnel = getFresnelF0(frag.metallic, diffuseVal.xyz);
|
||||
|
||||
return frag;
|
||||
|
@ -122,14 +117,11 @@ DeferredFragment unpackDeferredFragmentNoPositionNoAmbient(vec2 texcoord) {
|
|||
<$declareDeferredFrameTransform()$>
|
||||
|
||||
vec4 unpackDeferredPosition(float depthValue, vec2 texcoord) {
|
||||
int side = 0;
|
||||
if (isStereo()) {
|
||||
if (texcoord.x > 0.5) {
|
||||
texcoord.x -= 0.5;
|
||||
side = 1;
|
||||
}
|
||||
texcoord.x *= 2.0;
|
||||
}
|
||||
float check = float(isStereo());
|
||||
float check2 = check * float(texcoord.x > 0.5);
|
||||
texcoord.x -= check2 * 0.5;
|
||||
int side = int(check2);
|
||||
texcoord.x *= 1.0 + check;
|
||||
|
||||
return vec4(evalEyePositionFromZdb(side, depthValue, texcoord), 1.0);
|
||||
}
|
||||
|
@ -142,19 +134,17 @@ vec4 unpackDeferredPositionFromZdb(vec2 texcoord) {
|
|||
|
||||
vec4 unpackDeferredPositionFromZeye(vec2 texcoord) {
|
||||
float Zeye = -texture(linearZeyeMap, texcoord).x;
|
||||
int side = 0;
|
||||
if (isStereo()) {
|
||||
if (texcoord.x > 0.5) {
|
||||
texcoord.x -= 0.5;
|
||||
side = 1;
|
||||
}
|
||||
texcoord.x *= 2.0;
|
||||
}
|
||||
|
||||
float check = float(isStereo());
|
||||
float check2 = check * float(texcoord.x > 0.5);
|
||||
texcoord.x -= check2 * 0.5;
|
||||
int side = int(check2);
|
||||
texcoord.x *= 1.0 + check;
|
||||
|
||||
return vec4(evalEyePositionFromZeye(side, Zeye, texcoord), 1.0);
|
||||
}
|
||||
|
||||
DeferredFragment unpackDeferredFragment(DeferredFrameTransform deferredTransform, vec2 texcoord) {
|
||||
|
||||
float depthValue = texture(depthMap, texcoord).r;
|
||||
|
||||
DeferredFragment frag = unpackDeferredFragmentNoPosition(texcoord);
|
||||
|
|
|
@ -32,9 +32,11 @@ void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, float roughness
|
|||
if (alpha != 1.0) {
|
||||
discard;
|
||||
}
|
||||
_fragColor0 = vec4(albedo, ((scattering > 0.0) ? packScatteringMetallic(metallic) : packShadedMetallic(metallic)));
|
||||
|
||||
float check = float(scattering > 0.0);
|
||||
_fragColor0 = vec4(albedo, mix(packShadedMetallic(metallic), packScatteringMetallic(metallic), check));
|
||||
_fragColor1 = vec4(packNormal(normal), clamp(roughness, 0.0, 1.0));
|
||||
_fragColor2 = vec4(((scattering > 0.0) ? vec3(scattering) : emissive), occlusion);
|
||||
_fragColor2 = vec4(mix(emissive, vec3(scattering), check), occlusion);
|
||||
|
||||
_fragColor3 = vec4(isEmissiveEnabled() * emissive, 1.0);
|
||||
}
|
||||
|
|
|
@ -116,6 +116,7 @@ bool isStereo() {
|
|||
float getStereoSideWidth(int resolutionLevel) {
|
||||
return float(int(frameTransform._stereoInfo.y) >> resolutionLevel);
|
||||
}
|
||||
|
||||
float getStereoSideHeight(int resolutionLevel) {
|
||||
return float(int(frameTransform._pixelInfo.w) >> resolutionLevel);
|
||||
}
|
||||
|
@ -125,7 +126,7 @@ vec2 getStereoSideSize(int resolutionLevel) {
|
|||
}
|
||||
|
||||
ivec4 getStereoSideInfoFromWidth(int xPos, int sideWidth) {
|
||||
return ivec4(xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth), sideWidth, isStereo());
|
||||
return ivec4((1 - int(xPos < sideWidth)) * ivec2(1, sideWidth), sideWidth, isStereo());
|
||||
}
|
||||
|
||||
ivec4 getStereoSideInfo(int xPos, int resolutionLevel) {
|
||||
|
|
|
@ -85,10 +85,8 @@ float evalFadeGradient(FadeObjectParams params, vec3 position) {
|
|||
}
|
||||
|
||||
float evalFadeAlpha(FadeObjectParams params, vec3 position) {
|
||||
float alpha = evalFadeGradient(params, position)-params.threshold;
|
||||
if (fadeParameters[params.category]._isInverted != 0) {
|
||||
alpha = -alpha;
|
||||
}
|
||||
float alpha = evalFadeGradient(params, position) - params.threshold;
|
||||
alpha *= 1.0 - 2.0 * float(fadeParameters[params.category]._isInverted);
|
||||
return alpha;
|
||||
}
|
||||
|
||||
|
@ -166,4 +164,4 @@ layout(location=RENDER_UTILS_ATTR_FADE3) out vec4 _fadeData3;
|
|||
_fadeData3 = inTexCoord4;
|
||||
<@endfunc@>
|
||||
|
||||
<@endif@>
|
||||
<@endif@>
|
||||
|
|
|
@ -25,14 +25,13 @@ LAYOUT(binding=RENDER_UTILS_TEXTURE_HAZE_LINEAR_DEPTH) uniform sampler2D linearD
|
|||
|
||||
vec4 unpackPositionFromZeye(vec2 texcoord) {
|
||||
float Zeye = -texture(linearDepthMap, texcoord).x;
|
||||
int side = 0;
|
||||
if (isStereo()) {
|
||||
if (texcoord.x > 0.5) {
|
||||
texcoord.x -= 0.5;
|
||||
side = 1;
|
||||
}
|
||||
texcoord.x *= 2.0;
|
||||
}
|
||||
|
||||
float check = float(isStereo());
|
||||
float check2 = check * float(texcoord.x > 0.5);
|
||||
texcoord.x -= check2 * 0.5;
|
||||
int side = int(check2);
|
||||
texcoord.x *= 1.0 + check;
|
||||
|
||||
return vec4(evalEyePositionFromZeye(side, Zeye, texcoord), 1.0);
|
||||
}
|
||||
|
||||
|
|
|
@ -63,20 +63,17 @@ vec3 computeHazeColorKeyLightAttenuation(vec3 color, vec3 lightDirectionWS, vec3
|
|||
// Height at which haze density is reduced by 95% (default set to 2000.0 for safety ,this should never happen)
|
||||
float height_95p = 2000.0;
|
||||
const float log_p_005 = log(0.05);
|
||||
|
||||
if (hazeParams.hazeKeyLightAltitudeFactor > 0.0f) {
|
||||
height_95p = -log_p_005 / hazeParams.hazeKeyLightAltitudeFactor;
|
||||
}
|
||||
|
||||
// Note that we need the sine to be positive
|
||||
float sin_pitch = abs(lightDirectionWS.y);
|
||||
|
||||
float distance;
|
||||
const float minimumSinPitch = 0.001;
|
||||
if (sin_pitch < minimumSinPitch) {
|
||||
distance = height_95p / minimumSinPitch;
|
||||
} else {
|
||||
distance = height_95p / sin_pitch;
|
||||
}
|
||||
float sin_pitch = abs(lightDirectionWS.y);
|
||||
sin_pitch = max(sin_pitch, minimumSinPitch);
|
||||
|
||||
float distance = height_95p / sin_pitch;
|
||||
|
||||
// Integration is from the fragment towards the light source
|
||||
// Note that the haze base reference affects only the haze density as function of altitude
|
||||
|
@ -128,6 +125,7 @@ vec4 computeHazeColor(vec3 fragPositionES, vec3 fragPositionWS, vec3 eyePosition
|
|||
}
|
||||
|
||||
vec4 potentialFragColor;
|
||||
const float EPSILON = 0.0000001f;
|
||||
|
||||
if ((hazeParams.hazeMode & HAZE_MODE_IS_MODULATE_COLOR) == HAZE_MODE_IS_MODULATE_COLOR) {
|
||||
// Compute separately for each colour
|
||||
|
@ -143,9 +141,9 @@ vec4 computeHazeColor(vec3 fragPositionES, vec3 fragPositionWS, vec3 eyePosition
|
|||
|
||||
const float slopeThreshold = 0.01;
|
||||
float deltaHeight = fragPositionWS.y - eyeWorldHeight;
|
||||
if (abs(deltaHeight) > slopeThreshold) {
|
||||
float t = hazeParams.hazeHeightFactor * deltaHeight;
|
||||
hazeIntegral *= (1.0 - exp (-t)) / t;
|
||||
float t = hazeParams.hazeHeightFactor * deltaHeight;
|
||||
if (abs(t) > EPSILON) {
|
||||
hazeIntegral *= mix(1.0, (1.0 - exp(-t)) / t, float(abs(deltaHeight) > slopeThreshold));
|
||||
}
|
||||
|
||||
vec3 hazeAmount = 1.0 - exp(-hazeIntegral);
|
||||
|
@ -171,13 +169,9 @@ vec4 computeHazeColor(vec3 fragPositionES, vec3 fragPositionWS, vec3 eyePosition
|
|||
|
||||
const float slopeThreshold = 0.01;
|
||||
float deltaHeight = fragPositionWS.y - eyeWorldHeight;
|
||||
if (abs(deltaHeight) > slopeThreshold) {
|
||||
float t = hazeParams.hazeHeightFactor * deltaHeight;
|
||||
// Protect from wild values
|
||||
const float EPSILON = 0.0000001f;
|
||||
if (abs(t) > EPSILON) {
|
||||
hazeIntegral *= (1.0 - exp (-t)) / t;
|
||||
}
|
||||
float t = hazeParams.hazeHeightFactor * deltaHeight;
|
||||
if (abs(t) > EPSILON) {
|
||||
hazeIntegral *= mix(1.0, (1.0 - exp(-t)) / t, float(abs(deltaHeight) > slopeThreshold));
|
||||
}
|
||||
|
||||
float hazeAmount = 1.0 - exp(-hazeIntegral);
|
||||
|
@ -189,9 +183,7 @@ vec4 computeHazeColor(vec3 fragPositionES, vec3 fragPositionWS, vec3 eyePosition
|
|||
// Mix with background at far range
|
||||
const float BLEND_DISTANCE = 27000.0f;
|
||||
vec4 outFragColor = potentialFragColor;
|
||||
if (distance > BLEND_DISTANCE) {
|
||||
outFragColor.a *= hazeParams.backgroundBlend;
|
||||
}
|
||||
outFragColor.a *= mix(1.0, hazeParams.backgroundBlend, float(distance > BLEND_DISTANCE));
|
||||
|
||||
return outFragColor;
|
||||
}
|
||||
|
|
|
@ -45,11 +45,9 @@ void main(void) {
|
|||
highlightedDepth = -evalZeyeFromZdb(highlightedDepth);
|
||||
sceneDepth = -evalZeyeFromZdb(sceneDepth);
|
||||
|
||||
if (sceneDepth < highlightedDepth) {
|
||||
outFragColor = vec4(params._fillOccludedColor, params._fillOccludedAlpha);
|
||||
} else {
|
||||
outFragColor = vec4(params._fillUnoccludedColor, params._fillUnoccludedAlpha);
|
||||
}
|
||||
outFragColor = mix(vec4(params._fillUnoccludedColor, params._fillUnoccludedAlpha),
|
||||
vec4(params._fillOccludedColor, params._fillOccludedAlpha),
|
||||
float(sceneDepth < highlightedDepth));
|
||||
<@else@>
|
||||
discard;
|
||||
<@endif@>
|
||||
|
@ -67,14 +65,13 @@ void main(void) {
|
|||
float outlinedDepth = 0.0;
|
||||
float sumOutlineDepth = 0.0;
|
||||
|
||||
for (y=0 ; y<params._blurKernelSize ; y++) {
|
||||
for (y = 0; y < params._blurKernelSize; y++) {
|
||||
uv = lineStartUv;
|
||||
lineStartUv.y += deltaUv.y;
|
||||
|
||||
if (uv.y>=0.0 && uv.y<=1.0) {
|
||||
for (x=0 ; x<params._blurKernelSize ; x++) {
|
||||
if (uv.x>=0.0 && uv.x<=1.0)
|
||||
{
|
||||
if (uv.y >= 0.0 && uv.y <= 1.0) {
|
||||
for (x = 0; x < params._blurKernelSize; x++) {
|
||||
if (uv.x >= 0.0 && uv.x <= 1.0) {
|
||||
outlinedDepth = texture(highlightedDepthMap, uv).x;
|
||||
float touch = (outlinedDepth < FAR_Z) ? 1.0 : 0.0;
|
||||
sumOutlineDepth = max(outlinedDepth * touch, sumOutlineDepth);
|
||||
|
@ -86,11 +83,7 @@ void main(void) {
|
|||
}
|
||||
}
|
||||
|
||||
if (intensity > 0.0) {
|
||||
// sumOutlineDepth /= intensity;
|
||||
} else {
|
||||
sumOutlineDepth = FAR_Z;
|
||||
}
|
||||
sumOutlineDepth = mix(FAR_Z, sumOutlineDepth, float(intensity > 0.0));
|
||||
|
||||
intensity /= weight;
|
||||
if (intensity < OPACITY_EPSILON) {
|
||||
|
@ -106,11 +99,9 @@ void main(void) {
|
|||
sceneDepth = -evalZeyeFromZdb(sceneDepth);
|
||||
|
||||
// Are we occluded?
|
||||
if (sceneDepth < outlinedDepth) {
|
||||
outFragColor = vec4(params._outlineOccludedColor, intensity * params._outlineOccludedAlpha);
|
||||
} else {
|
||||
outFragColor = vec4(params._outlineUnoccludedColor, intensity * params._outlineUnoccludedAlpha);
|
||||
}
|
||||
outFragColor = mix(vec4(params._outlineUnoccludedColor, intensity * params._outlineUnoccludedAlpha),
|
||||
vec4(params._outlineOccludedColor, intensity * params._outlineOccludedAlpha),
|
||||
float(sceneDepth < outlinedDepth));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ int clusterGrid_getClusterLightId(int index, int offset) {
|
|||
return element;
|
||||
*/
|
||||
int element = _clusterGridContent[GRID_FETCH_BUFFER((elementIndex >> 1))];
|
||||
return (((elementIndex & 0x00000001) == 1) ? (element >> 16) : element) & 0x0000FFFF;
|
||||
return (element >> (16 * int((elementIndex & 0x00000001) == 1))) & 0x0000FFFF;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,6 +5,14 @@
|
|||
#define float_exp2 exp2
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
# define _MIN glm::min
|
||||
# define _ABS(x) (int)fabsf(x)
|
||||
#else
|
||||
# define _MIN min
|
||||
# define _ABS abs
|
||||
#endif
|
||||
|
||||
float frustumGrid_depthRampGridToVolume(float ngrid) {
|
||||
// return ngrid;
|
||||
// return sqrt(ngrid);
|
||||
|
@ -87,14 +95,9 @@ ivec3 frustumGrid_indexToCluster(int index) {
|
|||
}
|
||||
|
||||
vec3 frustumGrid_clusterPosToEye(vec3 clusterPos) {
|
||||
|
||||
vec3 cvpos = clusterPos;
|
||||
|
||||
|
||||
vec3 volumePos = frustumGrid_gridToVolume(cvpos, frustumGrid.dims);
|
||||
|
||||
vec3 eyePos = frustumGrid_volumeToEye(volumePos, frustumGrid.eyeToGridProj, frustumGrid.rangeNear, frustumGrid.rangeFar);
|
||||
|
||||
return eyePos;
|
||||
}
|
||||
|
||||
|
@ -116,27 +119,19 @@ int frustumGrid_eyeDepthToClusterLayer(float eyeZ) {
|
|||
|
||||
int gridZ = int(frustumGrid_volumeToGridDepth(volumeZ, frustumGrid.dims));
|
||||
|
||||
if (gridZ >= frustumGrid.dims.z) {
|
||||
gridZ = frustumGrid.dims.z;
|
||||
}
|
||||
|
||||
|
||||
return gridZ;
|
||||
return _MIN(gridZ, frustumGrid.dims.z);
|
||||
}
|
||||
|
||||
ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) {
|
||||
|
||||
// make sure the frontEyePos is always in the front to eval the grid pos correctly
|
||||
vec3 frontEyePos = eyePos;
|
||||
frontEyePos.z = (eyePos.z > 0.0f ? -eyePos.z : eyePos.z);
|
||||
frontEyePos.z = -_ABS(eyePos.z);
|
||||
vec3 volumePos = frustumGrid_eyeToVolume(frontEyePos, frustumGrid.eyeToGridProj, frustumGrid.rangeNear, frustumGrid.rangeFar);
|
||||
|
||||
|
||||
vec3 gridPos = frustumGrid_volumeToGrid(volumePos, frustumGrid.dims);
|
||||
|
||||
if (gridPos.z >= float(frustumGrid.dims.z)) {
|
||||
gridPos.z = float(frustumGrid.dims.z);
|
||||
}
|
||||
gridPos.z = _MIN(gridPos.z, float(frustumGrid.dims.z));
|
||||
|
||||
ivec3 igridPos = ivec3(floor(gridPos));
|
||||
|
||||
|
@ -154,7 +149,7 @@ ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) {
|
|||
|
||||
int frustumGrid_eyeToClusterDirH(vec3 eyeDir) {
|
||||
if (eyeDir.z >= 0.0f) {
|
||||
return (eyeDir.x > 0.0f ? frustumGrid.dims.x : -1);
|
||||
return int(eyeDir.x > 0.0f) * (frustumGrid.dims.x + 1) - 1;
|
||||
}
|
||||
|
||||
float eyeDepth = -eyeDir.z;
|
||||
|
@ -168,7 +163,7 @@ int frustumGrid_eyeToClusterDirH(vec3 eyeDir) {
|
|||
|
||||
int frustumGrid_eyeToClusterDirV(vec3 eyeDir) {
|
||||
if (eyeDir.z >= 0.0f) {
|
||||
return (eyeDir.y > 0.0f ? frustumGrid.dims.y : -1);
|
||||
return int(eyeDir.y > 0.0f) * (frustumGrid.dims.y + 1) - 1;
|
||||
}
|
||||
|
||||
float eyeDepth = -eyeDir.z;
|
||||
|
@ -196,4 +191,4 @@ vec4 frustumGrid_worldToEye(vec4 worldPos) {
|
|||
|
||||
// <@if 1@>
|
||||
// Trigger Scribe include
|
||||
// <@endif@> <!def that !> End C++ compatible
|
||||
// <@endif@> <!def that !> End C++ compatible
|
||||
|
|
|
@ -41,12 +41,10 @@ void evalLightingPoint(out vec3 diffuse, out vec3 specular, Light light,
|
|||
specular *= lightEnergy * isSpecularEnabled();
|
||||
|
||||
if (isShowLightContour() > 0.0) {
|
||||
// Show edge
|
||||
// Show edges
|
||||
float edge = abs(2.0 * ((lightVolume_getRadius(light.volume) - fragLightDistance) / (0.1)) - 1.0);
|
||||
if (edge < 1.0) {
|
||||
float edgeCoord = exp2(-8.0*edge*edge);
|
||||
diffuse = vec3(edgeCoord * edgeCoord * getLightColor(light));
|
||||
}
|
||||
float edgeCoord = exp2(-8.0 * edge * edge);
|
||||
diffuse = mix(diffuse, vec3(edgeCoord * edgeCoord * getLightColor(light)), float(edge < 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,13 +57,11 @@ bool evalLightPointEdge(out vec3 color, Light light, vec4 fragLightDirLen, vec3
|
|||
// Allright we re valid in the volume
|
||||
float fragLightDistance = fragLightDirLen.w;
|
||||
vec3 fragLightDir = fragLightDirLen.xyz;
|
||||
|
||||
|
||||
// Show edges
|
||||
float edge = abs(2.0 * ((lightVolume_getRadius(light.volume) - fragLightDistance) / (0.1)) - 1.0);
|
||||
if (edge < 1.0) {
|
||||
float edgeCoord = exp2(-8.0*edge*edge);
|
||||
color = vec3(edgeCoord * edgeCoord * getLightColor(light));
|
||||
}
|
||||
float edgeCoord = exp2(-8.0 * edge * edge);
|
||||
color = mix(color, vec3(edgeCoord * edgeCoord * getLightColor(light)), float(edge < 1.0));
|
||||
|
||||
return (edge < 1.0);
|
||||
}
|
||||
|
|
|
@ -46,11 +46,9 @@ void evalLightingSpot(out vec3 diffuse, out vec3 specular, Light light,
|
|||
float edgeDistR = (lightVolume_getRadius(light.volume) - fragLightDistance);
|
||||
float edgeDistS = dot(fragLightDistance * vec2(cosSpotAngle, sqrt(1.0 - cosSpotAngle * cosSpotAngle)), -lightVolume_getSpotOutsideNormal2(light.volume));
|
||||
float edgeDist = min(edgeDistR, edgeDistS);
|
||||
float edge = abs(2.0 * (edgeDist / (0.1)) - 1.0);
|
||||
if (edge < 1.0) {
|
||||
float edgeCoord = exp2(-8.0*edge*edge);
|
||||
diffuse = vec3(edgeCoord * edgeCoord * getLightColor(light));
|
||||
}
|
||||
float edge = abs(2.0 * (edgeDist * 10.0) - 1.0);
|
||||
float edgeCoord = exp2(-8.0 * edge * edge);
|
||||
diffuse = mix(diffuse, vec3(edgeCoord * edgeCoord * getLightColor(light)), float(edge < 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,15 +65,11 @@ bool evalLightSpotEdge(out vec3 color, Light light, vec4 fragLightDirLen, float
|
|||
float edgeDistR = (lightVolume_getRadius(light.volume) - fragLightDistance);
|
||||
float edgeDistS = dot(fragLightDistance * vec2(cosSpotAngle, sqrt(1.0 - cosSpotAngle * cosSpotAngle)), -lightVolume_getSpotOutsideNormal2(light.volume));
|
||||
float edgeDist = min(edgeDistR, edgeDistS);
|
||||
float edge = abs(2.0 * (edgeDist / (0.1)) - 1.0);
|
||||
if (edge < 1.0) {
|
||||
float edgeCoord = exp2(-8.0*edge*edge);
|
||||
color = vec3(edgeCoord * edgeCoord * getLightColor(light));
|
||||
}
|
||||
float edge = abs(2.0 * (edgeDist * 10.0) - 1.0);
|
||||
float edgeCoord = exp2(-8.0 * edge * edge);
|
||||
color = mix(color, vec3(edgeCoord * edgeCoord * getLightColor(light)), float(edge < 1.0));
|
||||
|
||||
return (edge < 1.0);
|
||||
}
|
||||
|
||||
<@endfunc@>
|
||||
|
||||
|
||||
|
|
|
@ -115,18 +115,10 @@ float evalShadowAttenuation(vec3 worldLightDir, vec4 worldPosition, float viewDe
|
|||
isPixelOnCascade.z = isShadowCascadeProjectedOnPixel(cascadeShadowCoords[2]);
|
||||
isPixelOnCascade.w = isShadowCascadeProjectedOnPixel(cascadeShadowCoords[3]);
|
||||
|
||||
if (isPixelOnCascade.x) {
|
||||
cascadeAttenuations.x = evalShadowCascadeAttenuation(0, offsets, cascadeShadowCoords[0], oneMinusNdotL);
|
||||
}
|
||||
if (isPixelOnCascade.y) {
|
||||
cascadeAttenuations.y = evalShadowCascadeAttenuation(1, offsets, cascadeShadowCoords[1], oneMinusNdotL);
|
||||
}
|
||||
if (isPixelOnCascade.z) {
|
||||
cascadeAttenuations.z = evalShadowCascadeAttenuation(2, offsets, cascadeShadowCoords[2], oneMinusNdotL);
|
||||
}
|
||||
if (isPixelOnCascade.w) {
|
||||
cascadeAttenuations.w = evalShadowCascadeAttenuation(3, offsets, cascadeShadowCoords[3], oneMinusNdotL);
|
||||
}
|
||||
cascadeAttenuations.x = mix(1.0, evalShadowCascadeAttenuation(0, offsets, cascadeShadowCoords[0], oneMinusNdotL), float(isPixelOnCascade.x));
|
||||
cascadeAttenuations.y = mix(1.0, evalShadowCascadeAttenuation(1, offsets, cascadeShadowCoords[1], oneMinusNdotL), float(isPixelOnCascade.y));
|
||||
cascadeAttenuations.z = mix(1.0, evalShadowCascadeAttenuation(2, offsets, cascadeShadowCoords[2], oneMinusNdotL), float(isPixelOnCascade.z));
|
||||
cascadeAttenuations.w = mix(1.0, evalShadowCascadeAttenuation(3, offsets, cascadeShadowCoords[3], oneMinusNdotL), float(isPixelOnCascade.w));
|
||||
|
||||
cascadeWeights.x = evalShadowCascadeWeight(cascadeShadowCoords[0]);
|
||||
cascadeWeights.y = evalShadowCascadeWeight(cascadeShadowCoords[1]);
|
||||
|
|
|
@ -81,9 +81,7 @@ void evalSkinning(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio
|
|||
|
||||
// to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
|
||||
float dqClusterWeight = clusterWeight;
|
||||
if (dot(real, polarityReference) < 0.0) {
|
||||
dqClusterWeight = -clusterWeight;
|
||||
}
|
||||
dqClusterWeight *= mix(1.0, -1.0, float(dot(real, polarityReference) < 0.0));
|
||||
|
||||
sAccum += scale * clusterWeight;
|
||||
rAccum += real * dqClusterWeight;
|
||||
|
@ -102,12 +100,11 @@ void evalSkinning(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio
|
|||
// sAccum.w indicates the amount of cauterization for this vertex.
|
||||
// 0 indicates no cauterization and 1 indicates full cauterization.
|
||||
// TODO: make this cauterization smoother or implement full dual-quaternion scale support.
|
||||
const float CAUTERIZATION_THRESHOLD = 0.1;
|
||||
if (sAccum.w > CAUTERIZATION_THRESHOLD) {
|
||||
skinnedPosition = cAccum;
|
||||
} else {
|
||||
sAccum.w = 1.0;
|
||||
skinnedPosition = m * (sAccum * inPosition);
|
||||
{
|
||||
const float CAUTERIZATION_THRESHOLD = 0.1;
|
||||
float check = float(sAccum.w > CAUTERIZATION_THRESHOLD);
|
||||
sAccum.w = mix(1.0, sAccum.w, check);
|
||||
skinnedPosition = mix(m * (sAccum * inPosition), cAccum, check);
|
||||
}
|
||||
|
||||
<@if USE_NORMAL@>
|
||||
|
|
|
@ -82,8 +82,6 @@ vec3 integrate(float cosTheta, float skinRadius) {
|
|||
while (a <= (_PI)) {
|
||||
float sampleAngle = theta + a;
|
||||
float diffuse = clamp(cos(sampleAngle), 0.0, 1.0);
|
||||
//if (diffuse < 0.0) diffuse = 0.0;
|
||||
//if (diffuse > 1.0) diffuse = 1.0;
|
||||
|
||||
// Distance.
|
||||
float sampleDist = abs(2.0 * skinRadius * sin(a * 0.5));
|
||||
|
@ -180,7 +178,8 @@ vec3 evalSkinBRDF(vec3 lightDir, vec3 normal, vec3 midNormal, vec3 lowNormal, fl
|
|||
return lowNormal * 0.5 + vec3(0.5);
|
||||
}
|
||||
if (showCurvature()) {
|
||||
return (curvature > 0.0 ? vec3(curvature, 0.0, 0.0) : vec3(0.0, 0.0, -curvature));
|
||||
float check = float(curvature > 0.0);
|
||||
return vec3(check * curvature, 0.0, (1.0 - check) * -curvature);
|
||||
}
|
||||
|
||||
vec3 bentNdotL = evalScatteringBentNdotL(normal, midNormal, lowNormal, lightDir);
|
||||
|
|
|
@ -37,9 +37,7 @@ void main(void) {
|
|||
#ifdef GPU_TRANSFORM_IS_STEREO
|
||||
#ifdef GPU_TRANSFORM_STEREO_SPLIT_SCREEN
|
||||
#else
|
||||
if (cam_isStereo()) {
|
||||
projected.x = 0.5 * (projected.x + cam_getStereoSide());
|
||||
}
|
||||
projected.x = mix(projected.x, 0.5 * (projected.x + cam_getStereoSide()), float(cam_isStereo()));
|
||||
#endif
|
||||
#endif
|
||||
_texCoord01 = vec4(projected.xy, 0.0, 1.0) * gl_Position.w;
|
||||
|
@ -66,9 +64,7 @@ void main(void) {
|
|||
#ifdef GPU_TRANSFORM_IS_STEREO
|
||||
#ifdef GPU_TRANSFORM_STEREO_SPLIT_SCREEN
|
||||
#else
|
||||
if (cam_isStereo()) {
|
||||
_texCoord01.x = 0.5 * (_texCoord01.x + cam_getStereoSide());
|
||||
}
|
||||
_texCoord01.x = mix(_texCoord01.x, 0.5 * (_texCoord01.x + cam_getStereoSide()), float(cam_isStereo()));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -47,8 +47,6 @@ void main(void) {
|
|||
vec4 projected = gl_Position / gl_Position.w;
|
||||
projected.xy = (projected.xy + 1.0) * 0.5;
|
||||
|
||||
if (cam_isStereo()) {
|
||||
projected.x = 0.5 * (projected.x + cam_getStereoSide());
|
||||
}
|
||||
projected.x = mix(projected.x, 0.5 * (projected.x + cam_getStereoSide()), float(cam_isStereo()));
|
||||
_texCoord0 = vec4(projected.xy, 0.0, 1.0) * gl_Position.w;
|
||||
}
|
||||
|
|
|
@ -60,9 +60,7 @@ void main(void) {
|
|||
#ifdef GPU_TRANSFORM_IS_STEREO
|
||||
#ifdef GPU_TRANSFORM_STEREO_SPLIT_SCREEN
|
||||
#else
|
||||
if (cam_isStereo()) {
|
||||
projected.x = 0.5 * (projected.x + cam_getStereoSide());
|
||||
}
|
||||
projected.x = mix(projected.x, 0.5 * (projected.x + cam_getStereoSide()), float(cam_isStereo()));
|
||||
#endif
|
||||
#endif
|
||||
_texCoord0 = vec4(projected.xy, 0.0, 1.0) * gl_Position.w;
|
||||
|
|
|
@ -44,13 +44,13 @@ void main(void) {
|
|||
_color.rgb = color_sRGBToLinear(inColor.rgb);
|
||||
_color.a = inColor.a;
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord01.xy)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _texCoord01.zw)$>
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToWorldAndEyeAndClipPos(cam, obj, deformedPosition, _positionWS, _positionES, gl_Position)$>
|
||||
<$transformModelToWorldDir(cam, obj, deformedNormal, _normalWS.xyz)$>
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _positionWS, _texCoord01.xy)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _positionWS, _texCoord01.zw)$>
|
||||
}
|
||||
|
|
|
@ -41,13 +41,13 @@ void main(void) {
|
|||
_color.rgb = color_sRGBToLinear(inColor.rgb);
|
||||
_color.a = inColor.a;
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord01.xy)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _texCoord01.zw)$>
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToWorldAndEyeAndClipPos(cam, obj, deformedPosition, _positionWS, _positionES, gl_Position)$>
|
||||
<$transformModelToWorldDir(cam, obj, deformedNormal, _normalWS.xyz)$>
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _positionWS, _texCoord01.xy)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _positionWS, _texCoord01.zw)$>
|
||||
}
|
||||
|
|
|
@ -43,14 +43,14 @@ void main(void) {
|
|||
_color.rgb = color_sRGBToLinear(inColor.rgb);
|
||||
_color.a = inColor.a;
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord01.xy)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _texCoord01.zw)$>
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToWorldAndEyeAndClipPos(cam, obj, deformedPosition, _positionWS, _positionES, gl_Position)$>
|
||||
<$transformModelToWorldDir(cam, obj, deformedNormal, _normalWS.xyz)$>
|
||||
<$transformModelToWorldDir(cam, obj, deformedTangent, _tangentWS.xyz)$>
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _positionWS, _texCoord01.xy)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _positionWS, _texCoord01.zw)$>
|
||||
}
|
||||
|
|
|
@ -44,14 +44,14 @@ void main(void) {
|
|||
_color.rgb = color_sRGBToLinear(inColor.rgb);
|
||||
_color.a = inColor.a;
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord01.xy)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _texCoord01.zw)$>
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToWorldAndEyeAndClipPos(cam, obj, deformedPosition, _positionWS, _positionES, gl_Position)$>
|
||||
<$transformModelToWorldDir(cam, obj, deformedNormal, _normalWS.xyz)$>
|
||||
<$transformModelToWorldDir(cam, obj, deformedTangent, _tangentWS.xyz)$>
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _positionWS, _texCoord01.xy)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _positionWS, _texCoord01.zw)$>
|
||||
}
|
||||
|
|
|
@ -33,16 +33,15 @@ void main(void) {
|
|||
|
||||
float shadowAttenuation = 1.0;
|
||||
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
discard;
|
||||
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
if (frag.mode == FRAG_MODE_UNLIT || frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
discard;
|
||||
} else {
|
||||
vec4 midNormalCurvature = vec4(0);
|
||||
vec4 lowNormalCurvature = vec4(0);
|
||||
if (frag.mode == FRAG_MODE_SCATTERING) {
|
||||
unpackMidLowNormalCurvature(_texCoord0, midNormalCurvature, lowNormalCurvature);
|
||||
}
|
||||
unpackMidLowNormalCurvature(_texCoord0, midNormalCurvature, lowNormalCurvature);
|
||||
float check = float(frag.mode == FRAG_MODE_SCATTERING);
|
||||
midNormalCurvature = check * midNormalCurvature;
|
||||
lowNormalCurvature = check * lowNormalCurvature;
|
||||
|
||||
vec3 color = evalAmbientSphereGlobalColor(
|
||||
getViewInverse(),
|
||||
|
|
|
@ -35,16 +35,16 @@ void main(void) {
|
|||
vec3 worldLightDirection = getLightDirection(shadowLight);
|
||||
float shadowAttenuation = evalShadowAttenuation(worldLightDirection, worldPos, -viewPos.z, frag.normal);
|
||||
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
discard;
|
||||
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
if (frag.mode == FRAG_MODE_UNLIT || frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
discard;
|
||||
} else {
|
||||
vec4 midNormalCurvature = vec4(0);
|
||||
vec4 lowNormalCurvature = vec4(0);
|
||||
if (frag.mode == FRAG_MODE_SCATTERING) {
|
||||
unpackMidLowNormalCurvature(_texCoord0, midNormalCurvature, lowNormalCurvature);
|
||||
}
|
||||
unpackMidLowNormalCurvature(_texCoord0, midNormalCurvature, lowNormalCurvature);
|
||||
float check = float(frag.mode == FRAG_MODE_SCATTERING);
|
||||
midNormalCurvature = check * midNormalCurvature;
|
||||
lowNormalCurvature = check * lowNormalCurvature;
|
||||
|
||||
vec3 color = evalAmbientSphereGlobalColor(
|
||||
getViewInverse(),
|
||||
shadowAttenuation,
|
||||
|
|
|
@ -31,16 +31,16 @@ void main(void) {
|
|||
float shadowAttenuation = 1.0;
|
||||
|
||||
// Light mapped or not ?
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
discard;
|
||||
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
if (frag.mode == FRAG_MODE_UNLIT || frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
discard;
|
||||
} else {
|
||||
vec4 midNormalCurvature = vec4(0);
|
||||
vec4 lowNormalCurvature = vec4(0);
|
||||
if (frag.mode == FRAG_MODE_SCATTERING) {
|
||||
unpackMidLowNormalCurvature(_texCoord0, midNormalCurvature, lowNormalCurvature);
|
||||
}
|
||||
unpackMidLowNormalCurvature(_texCoord0, midNormalCurvature, lowNormalCurvature);
|
||||
float check = float(frag.mode == FRAG_MODE_SCATTERING);
|
||||
midNormalCurvature = check * midNormalCurvature;
|
||||
lowNormalCurvature = check * lowNormalCurvature;
|
||||
|
||||
vec3 color = evalSkyboxGlobalColor(
|
||||
getViewInverse(),
|
||||
shadowAttenuation,
|
||||
|
|
|
@ -36,16 +36,16 @@ void main(void) {
|
|||
float shadowAttenuation = evalShadowAttenuation(worldLightDirection, worldPos, -viewPos.z, frag.normal);
|
||||
|
||||
// Light mapped or not ?
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
discard;
|
||||
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
if (frag.mode == FRAG_MODE_UNLIT || frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
discard;
|
||||
} else {
|
||||
vec4 midNormalCurvature = vec4(0);
|
||||
vec4 lowNormalCurvature = vec4(0);
|
||||
if (frag.mode == FRAG_MODE_SCATTERING) {
|
||||
unpackMidLowNormalCurvature(_texCoord0, midNormalCurvature, lowNormalCurvature);
|
||||
}
|
||||
unpackMidLowNormalCurvature(_texCoord0, midNormalCurvature, lowNormalCurvature);
|
||||
float check = float(frag.mode == FRAG_MODE_SCATTERING);
|
||||
midNormalCurvature = check * midNormalCurvature;
|
||||
lowNormalCurvature = check * lowNormalCurvature;
|
||||
|
||||
vec3 color = evalSkyboxGlobalColor(
|
||||
getViewInverse(),
|
||||
shadowAttenuation,
|
||||
|
|
|
@ -62,7 +62,5 @@ void main(void) {
|
|||
|
||||
varColor = vec4(REGION_COLOR[region].xyz, proxy.sphere.w);
|
||||
|
||||
if (region == 4) {
|
||||
gl_Position = vec4(0.0);
|
||||
}
|
||||
gl_Position = mix(gl_Position, vec4(0.0), float(region == 4));
|
||||
}
|
||||
|
|
|
@ -53,14 +53,9 @@ void main(void) {
|
|||
|
||||
// Add or subtract the orthogonal vector based on a different vertex ID
|
||||
// calculation
|
||||
if (gl_VertexID < 2) {
|
||||
distanceFromCenter = -1.0;
|
||||
eye.xyz -= orthogonal;
|
||||
} else {
|
||||
distanceFromCenter = 1.0;
|
||||
eye.xyz += orthogonal;
|
||||
}
|
||||
distanceFromCenter = 1.0 - 2.0 * float(gl_VertexID < 2);
|
||||
eye.xyz += distanceFromCenter * orthogonal;
|
||||
|
||||
// Finally, put the eyespace vertex into clip space
|
||||
<$transformEyeToClipPos(cam, eye, gl_Position)$>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,12 +34,10 @@ layout(location=0) out vec4 outFragColor;
|
|||
void main(void) {
|
||||
Grid grid = getGrid();
|
||||
|
||||
float alpha;
|
||||
if (grid.edge.z == 0.0) {
|
||||
alpha = paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.edge.xy);
|
||||
} else {
|
||||
alpha = paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.edge);
|
||||
}
|
||||
float alpha = mix(paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.edge),
|
||||
paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.edge.xy),
|
||||
float(grid.edge.z == 0.0));
|
||||
|
||||
if (alpha == 0.0) {
|
||||
discard;
|
||||
}
|
||||
|
|
|
@ -90,6 +90,6 @@ void main(void) {
|
|||
numLightTouching++;
|
||||
}
|
||||
|
||||
_fragColor = vec4(colorRamp(1.0 - (float(numLightTouching) / 12.0f)), (numLightTouching > 0 ? 0.5 + 0.5 * numLightsScale : 0.0));
|
||||
_fragColor = vec4(colorRamp(1.0 - (float(numLightTouching) / 12.0f)), float(numLightTouching > 0) * (0.5 + 0.5 * numLightsScale));
|
||||
}
|
||||
|
||||
|
|
|
@ -69,5 +69,5 @@ void main(void) {
|
|||
TransformCamera cam = getTransformCamera();
|
||||
<$transformWorldToClipPos(cam, worldPos, gl_Position)$>
|
||||
|
||||
varColor = vec4(colorWheel(fract(float(gpu_InstanceID()) / float(frustumGrid_numClusters()))), (numLights >0 ? 0.9 : 0.1));
|
||||
varColor = vec4(colorWheel(fract(float(gpu_InstanceID()) / float(frustumGrid_numClusters()))), 0.1 + 0.8 * float(numLights > 0));
|
||||
}
|
|
@ -62,12 +62,10 @@ void main(void) {
|
|||
|
||||
float relClusterId = float(clusterPos.z * summedDims.x + clusterPos.y * summedDims.y + clusterPos.x) / float(frustumGrid_numClusters());
|
||||
|
||||
if (relClusterId < 0.0) {
|
||||
_fragColor = vec4(0.0);
|
||||
} else if (relClusterId >= 1.0) {
|
||||
_fragColor = vec4(vec3(1.0), 0.2);
|
||||
} else {
|
||||
_fragColor = vec4(colorWheel(fract(relClusterId)), (numLights > 0 ? 0.05 + 0.95 * numLightsScale : 0.0));
|
||||
}
|
||||
_fragColor = mix(mix(vec4(colorWheel(fract(relClusterId)), float(numLights > 0) * (0.05 + 0.95 * numLightsScale)),
|
||||
vec4(vec3(1.0), 0.2),
|
||||
float(relClusterId >= 1.0)),
|
||||
vec4(0.0),
|
||||
float(relClusterId < 0.0));
|
||||
}
|
||||
|
||||
|
|
|
@ -62,5 +62,5 @@ void main(void) {
|
|||
TransformCamera cam = getTransformCamera();
|
||||
<$transformWorldToClipPos(cam, worldPos, gl_Position)$>
|
||||
|
||||
varColor = vec4(colorWheel(fract(float(gpu_InstanceID()) / float(frustumGrid_numClusters()))), 0.9);
|
||||
varColor = vec4(colorWheel(fract(float(gpu_InstanceID()) / float(frustumGrid_numClusters()))), 0.9);
|
||||
}
|
|
@ -69,5 +69,5 @@ void main(void) {
|
|||
TransformCamera cam = getTransformCamera();
|
||||
<$transformWorldToClipPos(cam, worldPos, gl_Position)$>
|
||||
|
||||
varColor = vec4(colorWheel(fract(float(gpu_InstanceID()) / float(frustumGrid_numClusters()))), (numLights > 0 ? 0.9 : 0.0));
|
||||
varColor = vec4(colorWheel(fract(float(gpu_InstanceID()) / float(frustumGrid_numClusters()))), float(numLights > 0) * 0.9);
|
||||
}
|
|
@ -96,9 +96,8 @@ void main(void) {
|
|||
vec3 fragLightDir = fragLightDirLen.xyz;
|
||||
|
||||
vec3 color = vec3(0.0);
|
||||
if (evalLightPointEdge(color, light, fragLightDirLen, fragEyeDir)) {
|
||||
_fragColor.rgb += color;
|
||||
}
|
||||
float check = float(evalLightPointEdge(color, light, fragLightDirLen, fragEyeDir));
|
||||
_fragColor.rgb += check * color;
|
||||
}
|
||||
|
||||
for (int i = cluster.x; i < numLights; i++) {
|
||||
|
@ -130,10 +129,8 @@ void main(void) {
|
|||
numLightTouching++;
|
||||
|
||||
vec3 color = vec3(0.0);
|
||||
|
||||
if (evalLightSpotEdge(color, light, fragLightDirLen, cosSpotAngle, fragEyeDir)) {
|
||||
_fragColor.rgb += color;
|
||||
}
|
||||
float check = float(evalLightSpotEdge(color, light, fragLightDirLen, cosSpotAngle, fragEyeDir));
|
||||
_fragColor.rgb += check * color;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,13 +31,13 @@ void main(void) {
|
|||
_color.rgb = color_sRGBToLinear(inColor.rgb);
|
||||
_color.a = inColor.a;
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord01.xy)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _texCoord01.zw)$>
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToWorldAndEyeAndClipPos(cam, obj, inPosition, _positionWS, _positionES, gl_Position)$>
|
||||
<$transformModelToWorldDir(cam, obj, inNormal.xyz, _normalWS)$>
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _positionWS, _texCoord01.xy)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _positionWS, _texCoord01.zw)$>
|
||||
}
|
||||
|
|
|
@ -32,14 +32,14 @@ void main(void) {
|
|||
_color.rgb = color_sRGBToLinear(inColor.rgb);
|
||||
_color.a = inColor.a;
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord01.xy)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _texCoord01.zw)$>
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToWorldAndEyeAndClipPos(cam, obj, inPosition, _positionWS, _positionES, gl_Position)$>
|
||||
<$transformModelToWorldDir(cam, obj, inNormal.xyz, _normalWS)$>
|
||||
<$transformModelToWorldDir(cam, obj, inTangent.xyz, _tangentWS)$>
|
||||
|
||||
TexMapArray texMapArray = getTexMapArray();
|
||||
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _positionWS, _texCoord01.xy)$>
|
||||
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _positionWS, _texCoord01.zw)$>
|
||||
}
|
||||
|
|
|
@ -48,11 +48,8 @@ void main(void) {
|
|||
} else {
|
||||
normal = vec4(normalize(cross(_parabolaData.velocity, _parabolaData.acceleration)), 0);
|
||||
}
|
||||
if (gl_VertexID % 2 == 0) {
|
||||
pos += 0.5 * _parabolaData.width * normal;
|
||||
} else {
|
||||
pos -= 0.5 * _parabolaData.width * normal;
|
||||
}
|
||||
|
||||
pos += 0.5 * _parabolaData.width * normal * (-1.0 + 2.0 * float(gl_VertexID % 2 == 0));
|
||||
|
||||
<$transformModelToClipPos(cam, obj, pos, gl_Position)$>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,13 +39,8 @@ const float taaBias = pow(2.0, TAA_TEXTURE_LOD_BIAS);
|
|||
float evalSDF(vec2 texCoord) {
|
||||
// retrieve signed distance
|
||||
float sdf = textureLod(Font, texCoord, TAA_TEXTURE_LOD_BIAS).g;
|
||||
if (params.outline.x > 0.0) {
|
||||
if (sdf > interiorCutoff) {
|
||||
sdf = 1.0 - sdf;
|
||||
} else {
|
||||
sdf += outlineExpansion;
|
||||
}
|
||||
}
|
||||
sdf = mix(sdf, mix(sdf + outlineExpansion, 1.0 - sdf, float(sdf > interiorCutoff)), float(params.outline.x > 0.0));
|
||||
|
||||
// Rely on TAA for anti-aliasing
|
||||
return step(0.5, sdf);
|
||||
}
|
||||
|
@ -57,16 +52,11 @@ void main() {
|
|||
// Perform 4x supersampling for anisotropic filtering
|
||||
float a;
|
||||
a = evalSDF(_texCoord0);
|
||||
a += evalSDF(_texCoord0+dxTexCoord);
|
||||
a += evalSDF(_texCoord0+dyTexCoord);
|
||||
a += evalSDF(_texCoord0+dxTexCoord+dyTexCoord);
|
||||
a += evalSDF(_texCoord0 + dxTexCoord);
|
||||
a += evalSDF(_texCoord0 + dyTexCoord);
|
||||
a += evalSDF(_texCoord0 + dxTexCoord + dyTexCoord);
|
||||
a *= 0.25;
|
||||
|
||||
// discard if invisible
|
||||
if (a < 0.01) {
|
||||
discard;
|
||||
}
|
||||
|
||||
packDeferredFragment(
|
||||
normalize(_normalWS),
|
||||
a * params.color.a,
|
||||
|
|
|
@ -30,31 +30,32 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
|
|||
#define _texCoord0 _texCoord01.xy
|
||||
#define _texCoord1 _texCoord01.zw
|
||||
|
||||
const float gamma = 2.2;
|
||||
const float smoothing = 32.0;
|
||||
#define TAA_TEXTURE_LOD_BIAS -3.0
|
||||
|
||||
const float interiorCutoff = 0.8;
|
||||
const float outlineExpansion = 0.2;
|
||||
const float taaBias = pow(2.0, TAA_TEXTURE_LOD_BIAS);
|
||||
|
||||
float evalSDF(vec2 texCoord) {
|
||||
// retrieve signed distance
|
||||
float sdf = textureLod(Font, texCoord, TAA_TEXTURE_LOD_BIAS).g;
|
||||
sdf = mix(sdf, mix(sdf + outlineExpansion, 1.0 - sdf, float(sdf > interiorCutoff)), float(params.outline.x > 0.0));
|
||||
|
||||
// Rely on TAA for anti-aliasing
|
||||
return step(0.5, sdf);
|
||||
}
|
||||
|
||||
void main() {
|
||||
// retrieve signed distance
|
||||
float sdf = texture(Font, _texCoord0).g;
|
||||
if (params.outline.x > 0.0) {
|
||||
if (sdf > interiorCutoff) {
|
||||
sdf = 1.0 - sdf;
|
||||
} else {
|
||||
sdf += outlineExpansion;
|
||||
}
|
||||
}
|
||||
// perform adaptive anti-aliasing of the edges
|
||||
// The larger we're rendering, the less anti-aliasing we need
|
||||
float s = smoothing * length(fwidth(_texCoord0));
|
||||
float w = clamp(s, 0.0, 0.5);
|
||||
float a = smoothstep(0.5 - w, 0.5 + w, sdf);
|
||||
|
||||
// discard if invisible
|
||||
if (a < 0.01) {
|
||||
discard;
|
||||
}
|
||||
vec2 dxTexCoord = dFdx(_texCoord0) * 0.5 * taaBias;
|
||||
vec2 dyTexCoord = dFdy(_texCoord0) * 0.5 * taaBias;
|
||||
|
||||
// Perform 4x supersampling for anisotropic filtering
|
||||
float a;
|
||||
a = evalSDF(_texCoord0);
|
||||
a += evalSDF(_texCoord0 + dxTexCoord);
|
||||
a += evalSDF(_texCoord0 + dyTexCoord);
|
||||
a += evalSDF(_texCoord0 + dxTexCoord + dyTexCoord);
|
||||
a *= 0.25;
|
||||
|
||||
packDeferredFragmentTranslucent(
|
||||
normalize(_normalWS),
|
||||
|
|
|
@ -54,7 +54,7 @@ void main(void) {
|
|||
vec3 specular = DEFAULT_SPECULAR;
|
||||
float shininess = DEFAULT_SHININESS;
|
||||
float emissiveAmount = 0.0;
|
||||
|
||||
|
||||
#ifdef PROCEDURAL
|
||||
|
||||
#ifdef PROCEDURAL_V1
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include gpu/Color.slh@>
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
<@include render-utils/ShaderConstants.h@>
|
||||
|
@ -28,11 +29,13 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
|
|||
|
||||
void main(void) {
|
||||
vec4 texel = texture(originalTexture, _texCoord0);
|
||||
texel = mix(color_sRGBAToLinear(texel), texel, float(_color.a <= 0.0));
|
||||
texel.rgb *= _color.rgb;
|
||||
|
||||
packDeferredFragment(
|
||||
normalize(_normalWS),
|
||||
1.0,
|
||||
_color.rgb * texel.rgb,
|
||||
texel.rgb,
|
||||
DEFAULT_ROUGHNESS,
|
||||
DEFAULT_METALLIC,
|
||||
DEFAULT_EMISSIVE,
|
||||
|
|
|
@ -39,26 +39,24 @@ void main(void) {
|
|||
|
||||
<$fetchFadeObjectParamsInstanced(fadeParams)$>
|
||||
applyFade(fadeParams, _positionWS.xyz, fadeEmissive);
|
||||
|
||||
|
||||
vec4 texel = texture(originalTexture, _texCoord0);
|
||||
float colorAlpha = _color.a;
|
||||
if (_color.a <= 0.0) {
|
||||
texel = color_sRGBAToLinear(texel);
|
||||
colorAlpha = -_color.a;
|
||||
}
|
||||
texel = mix(color_sRGBAToLinear(texel), texel, float(_color.a <= 0.0));
|
||||
texel.rgb *= _color.rgb;
|
||||
texel.a = abs(_color.a);
|
||||
|
||||
const float ALPHA_THRESHOLD = 0.999;
|
||||
if (colorAlpha * texel.a < ALPHA_THRESHOLD) {
|
||||
if (texel.a < ALPHA_THRESHOLD) {
|
||||
packDeferredFragmentTranslucent(
|
||||
normalize(_normalWS),
|
||||
colorAlpha * texel.a,
|
||||
_color.rgb * texel.rgb + fadeEmissive,
|
||||
texel.a,
|
||||
texel.rgb + fadeEmissive,
|
||||
DEFAULT_ROUGHNESS);
|
||||
} else {
|
||||
packDeferredFragment(
|
||||
normalize(_normalWS),
|
||||
1.0,
|
||||
_color.rgb * texel.rgb,
|
||||
texel.rgb,
|
||||
DEFAULT_ROUGHNESS,
|
||||
DEFAULT_METALLIC,
|
||||
DEFAULT_EMISSIVE + fadeEmissive,
|
||||
|
|
|
@ -28,24 +28,22 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
|
|||
#define _texCoord1 _texCoord01.zw
|
||||
|
||||
void main(void) {
|
||||
vec4 texel = texture(originalTexture, _texCoord0.st);
|
||||
float colorAlpha = _color.a;
|
||||
if (_color.a <= 0.0) {
|
||||
texel = color_sRGBAToLinear(texel);
|
||||
colorAlpha = -_color.a;
|
||||
}
|
||||
vec4 texel = texture(originalTexture, _texCoord0);
|
||||
texel = mix(color_sRGBAToLinear(texel), texel, float(_color.a <= 0.0));
|
||||
texel.rgb *= _color.rgb;
|
||||
texel.a = abs(_color.a);
|
||||
|
||||
const float ALPHA_THRESHOLD = 0.999;
|
||||
if (colorAlpha * texel.a < ALPHA_THRESHOLD) {
|
||||
if (texel.a < ALPHA_THRESHOLD) {
|
||||
packDeferredFragmentTranslucent(
|
||||
normalize(_normalWS),
|
||||
colorAlpha * texel.a,
|
||||
_color.rgb * texel.rgb,
|
||||
texel.a,
|
||||
texel.rgb,
|
||||
DEFAULT_ROUGHNESS);
|
||||
} else {
|
||||
packDeferredFragmentUnlit(
|
||||
normalize(_normalWS),
|
||||
1.0,
|
||||
_color.rgb * texel.rgb);
|
||||
texel.rgb);
|
||||
}
|
||||
}
|
|
@ -40,24 +40,22 @@ void main(void) {
|
|||
<$fetchFadeObjectParamsInstanced(fadeParams)$>
|
||||
applyFade(fadeParams, _positionWS.xyz, fadeEmissive);
|
||||
|
||||
vec4 texel = texture(originalTexture, _texCoord0.st);
|
||||
float colorAlpha = _color.a;
|
||||
if (_color.a <= 0.0) {
|
||||
texel = color_sRGBAToLinear(texel);
|
||||
colorAlpha = -_color.a;
|
||||
}
|
||||
vec4 texel = texture(originalTexture, _texCoord0);
|
||||
texel = mix(color_sRGBAToLinear(texel), texel, float(_color.a <= 0.0));
|
||||
texel.rgb *= _color.rgb;
|
||||
texel.a = abs(_color.a);
|
||||
|
||||
const float ALPHA_THRESHOLD = 0.999;
|
||||
if (colorAlpha * texel.a < ALPHA_THRESHOLD) {
|
||||
if (texel.a < ALPHA_THRESHOLD) {
|
||||
packDeferredFragmentTranslucent(
|
||||
normalize(_normalWS),
|
||||
colorAlpha * texel.a,
|
||||
_color.rgb * texel.rgb+fadeEmissive,
|
||||
texel.a,
|
||||
texel.rgb + fadeEmissive,
|
||||
DEFAULT_ROUGHNESS);
|
||||
} else {
|
||||
packDeferredFragmentUnlit(
|
||||
normalize(_normalWS),
|
||||
1.0,
|
||||
_color.rgb * texel.rgb+fadeEmissive);
|
||||
texel.rgb + fadeEmissive);
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include gpu/Color.slh@>
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
<@include render-utils/ShaderConstants.h@>
|
||||
|
@ -28,11 +29,13 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
|
|||
|
||||
void main(void) {
|
||||
vec4 texel = texture(originalTexture, _texCoord0);
|
||||
float colorAlpha = _color.a * texel.a;
|
||||
texel = mix(color_sRGBAToLinear(texel), texel, float(_color.a <= 0.0));
|
||||
texel.rgb *= _color.rgb;
|
||||
texel.a *= abs(_color.a);
|
||||
|
||||
packDeferredFragmentTranslucent(
|
||||
normalize(_normalWS),
|
||||
colorAlpha,
|
||||
_color.rgb * texel.rgb,
|
||||
texel.a,
|
||||
texel.rgb,
|
||||
DEFAULT_ROUGHNESS);
|
||||
}
|
|
@ -46,14 +46,10 @@ void main(void) {
|
|||
<$fetchFadeObjectParamsInstanced(fadeParams)$>
|
||||
applyFade(fadeParams, _positionWS.xyz, fadeEmissive);
|
||||
|
||||
vec4 texel = texture(originalTexture, _texCoord0.st);
|
||||
float opacity = _color.a;
|
||||
if (_color.a <= 0.0) {
|
||||
texel = color_sRGBAToLinear(texel);
|
||||
opacity = -_color.a;
|
||||
}
|
||||
opacity *= texel.a;
|
||||
vec3 albedo = _color.rgb * texel.rgb;
|
||||
vec4 texel = texture(originalTexture, _texCoord0);
|
||||
texel = mix(color_sRGBAToLinear(texel), texel, float(_color.a <= 0.0));
|
||||
texel.rgb *= _color.rgb;
|
||||
texel.a *= abs(_color.a);
|
||||
|
||||
vec3 fragPosition = _positionES.xyz;
|
||||
vec3 fragNormal = normalize(_normalWS);
|
||||
|
@ -66,12 +62,11 @@ void main(void) {
|
|||
1.0,
|
||||
fragPosition,
|
||||
fragNormal,
|
||||
albedo,
|
||||
texel.rgb,
|
||||
DEFAULT_FRESNEL,
|
||||
0.0f,
|
||||
fadeEmissive,
|
||||
DEFAULT_ROUGHNESS,
|
||||
opacity),
|
||||
opacity);
|
||||
|
||||
texel.a),
|
||||
texel.a);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue